1 /* 2 * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.awt; 27 28 import java.awt.*; 29 import java.awt.event.*; 30 import java.awt.peer.*; 31 import java.beans.PropertyChangeListener; 32 import java.beans.PropertyChangeEvent; 33 import java.util.Set; 34 import java.awt.AWTKeyStroke; 35 import java.applet.Applet; 36 37 /** 38 * A generic container used for embedding Java components, usually applets. 39 * An EmbeddedFrame has two related uses: 40 * 41 * . Within a Java-based application, an EmbeddedFrame serves as a sort of 42 * firewall, preventing the contained components or applets from using 43 * getParent() to find parent components, such as menubars. 44 * 45 * . Within a C-based application, an EmbeddedFrame contains a window handle 46 * which was created by the application, which serves as the top-level 47 * Java window. EmbeddedFrames created for this purpose are passed-in a 48 * handle of an existing window created by the application. The window 49 * handle should be of the appropriate native type for a specific 50 * platform, as stored in the pData field of the ComponentPeer. 51 * 52 * @author Thomas Ball 53 */ 54 public abstract class EmbeddedFrame extends Frame 55 implements KeyEventDispatcher, PropertyChangeListener { 56 57 private boolean isCursorAllowed = true; 58 private boolean supportsXEmbed = false; 59 @SuppressWarnings("serial") // Not statically typed as Serializable 60 private KeyboardFocusManager appletKFM; 61 // JDK 1.1 compatibility 62 private static final long serialVersionUID = 2967042741780317130L; 63 64 /* 65 * The constants define focus traversal directions. 66 * Use them in {@code traverseIn}, {@code traverseOut} methods. 67 */ 68 protected static final boolean FORWARD = true; 69 protected static final boolean BACKWARD = false; 70 71 public boolean supportsXEmbed() { 72 return supportsXEmbed && SunToolkit.needsXEmbed(); 73 } 74 75 protected EmbeddedFrame(boolean supportsXEmbed) { 76 this((long)0, supportsXEmbed); 77 } 78 79 80 protected EmbeddedFrame() { 81 this((long)0); 82 } 83 84 /** 85 * @deprecated This constructor will be removed in 1.5 86 */ 87 @Deprecated 88 protected EmbeddedFrame(int handle) { 89 this((long)handle); 90 } 91 92 protected EmbeddedFrame(long handle) { 93 this(handle, false); 94 } 95 96 protected EmbeddedFrame(long handle, boolean supportsXEmbed) { 97 this.supportsXEmbed = supportsXEmbed; 98 registerListeners(); 99 } 100 101 /** 102 * Block introspection of a parent window by this child. 103 */ 104 public Container getParent() { 105 return null; 106 } 107 108 /** 109 * Needed to track which KeyboardFocusManager is current. We want to avoid memory 110 * leaks, so when KFM stops being current, we remove ourselves as listeners. 111 */ 112 public void propertyChange(PropertyChangeEvent evt) { 113 // We don't handle any other properties. Skip it. 114 if (!evt.getPropertyName().equals("managingFocus")) { 115 return; 116 } 117 118 // We only do it if it stops being current. Technically, we should 119 // never get an event about KFM starting being current. 120 if (evt.getNewValue() == Boolean.TRUE) { 121 return; 122 } 123 124 // should be the same as appletKFM 125 removeTraversingOutListeners((KeyboardFocusManager)evt.getSource()); 126 127 appletKFM = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 128 if (isVisible()) { 129 addTraversingOutListeners(appletKFM); 130 } 131 } 132 133 /** 134 * Register us as KeyEventDispatcher and property "managingFocus" listeners. 135 */ 136 private void addTraversingOutListeners(KeyboardFocusManager kfm) { 137 kfm.addKeyEventDispatcher(this); 138 kfm.addPropertyChangeListener("managingFocus", this); 139 } 140 141 /** 142 * Deregister us as KeyEventDispatcher and property "managingFocus" listeners. 143 */ 144 private void removeTraversingOutListeners(KeyboardFocusManager kfm) { 145 kfm.removeKeyEventDispatcher(this); 146 kfm.removePropertyChangeListener("managingFocus", this); 147 } 148 149 /** 150 * Because there may be many AppContexts, and we can't be sure where this 151 * EmbeddedFrame is first created or shown, we can't automatically determine 152 * the correct KeyboardFocusManager to attach to as KeyEventDispatcher. 153 * Those who want to use the functionality of traversing out of the EmbeddedFrame 154 * must call this method on the Applet's AppContext. After that, all the changes 155 * can be handled automatically, including possible replacement of 156 * KeyboardFocusManager. 157 */ 158 public void registerListeners() { 159 if (appletKFM != null) { 160 removeTraversingOutListeners(appletKFM); 161 } 162 appletKFM = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 163 if (isVisible()) { 164 addTraversingOutListeners(appletKFM); 165 } 166 } 167 168 /** 169 * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with 170 * KeyboardFocusManager of applet's AppContext. We don't want the KFM to keep 171 * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we 172 * add listeners in show() and remove them in hide(). 173 */ 174 @SuppressWarnings("deprecation") 175 public void show() { 176 if (appletKFM != null) { 177 addTraversingOutListeners(appletKFM); 178 } 179 super.show(); 180 } 181 182 /** 183 * Needed to avoid memory leak: we register this EmbeddedFrame as a listener with 184 * KeyboardFocusManager of applet's AppContext. We don't want the KFM to keep 185 * reference to our EmbeddedFrame forever if the Frame is no longer in use, so we 186 * add listeners in show() and remove them in hide(). 187 */ 188 @SuppressWarnings("deprecation") 189 public void hide() { 190 if (appletKFM != null) { 191 removeTraversingOutListeners(appletKFM); 192 } 193 super.hide(); 194 } 195 196 /** 197 * Need this method to detect when the focus may have chance to leave the 198 * focus cycle root which is EmbeddedFrame. Mostly, the code here is copied 199 * from DefaultKeyboardFocusManager.processKeyEvent with some minor 200 * modifications. 201 */ 202 public boolean dispatchKeyEvent(KeyEvent e) { 203 204 Container currentRoot = AWTAccessor.getKeyboardFocusManagerAccessor() 205 .getCurrentFocusCycleRoot(); 206 207 // if we are not in EmbeddedFrame's cycle, we should not try to leave. 208 if (this != currentRoot) { 209 return false; 210 } 211 212 // KEY_TYPED events cannot be focus traversal keys 213 if (e.getID() == KeyEvent.KEY_TYPED) { 214 return false; 215 } 216 217 if (!getFocusTraversalKeysEnabled() || e.isConsumed()) { 218 return false; 219 } 220 221 AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e); 222 Set<AWTKeyStroke> toTest; 223 Component currentFocused = e.getComponent(); 224 225 toTest = getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 226 if (toTest.contains(stroke)) { 227 // 6581899: performance improvement for SortingFocusTraversalPolicy 228 Component last = getFocusTraversalPolicy().getLastComponent(this); 229 if (currentFocused == last || last == null) { 230 if (traverseOut(FORWARD)) { 231 e.consume(); 232 return true; 233 } 234 } 235 } 236 237 toTest = getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS); 238 if (toTest.contains(stroke)) { 239 // 6581899: performance improvement for SortingFocusTraversalPolicy 240 Component first = getFocusTraversalPolicy().getFirstComponent(this); 241 if (currentFocused == first || first == null) { 242 if (traverseOut(BACKWARD)) { 243 e.consume(); 244 return true; 245 } 246 } 247 } 248 return false; 249 } 250 251 /** 252 * This method is called by the embedder when we should receive focus as element 253 * of the traversal chain. The method requests focus on: 254 * 1. the first Component of this EmbeddedFrame if user moves focus forward 255 * in the focus traversal cycle. 256 * 2. the last Component of this EmbeddedFrame if user moves focus backward 257 * in the focus traversal cycle. 258 * 259 * The direction parameter specifies which of the two mentioned cases is 260 * happening. Use FORWARD and BACKWARD constants defined in the EmbeddedFrame class 261 * to avoid confusing boolean values. 262 * 263 * A concrete implementation of this method is defined in the platform-dependent 264 * subclasses. 265 * 266 * @param direction FORWARD or BACKWARD 267 * @return true, if the EmbeddedFrame wants to get focus, false otherwise. 268 */ 269 public boolean traverseIn(boolean direction) { 270 Component comp = null; 271 272 if (direction == FORWARD) { 273 comp = getFocusTraversalPolicy().getFirstComponent(this); 274 } else { 275 comp = getFocusTraversalPolicy().getLastComponent(this); 276 } 277 if (comp != null) { 278 // comp.requestFocus(); - Leads to a hung. 279 280 AWTAccessor.getKeyboardFocusManagerAccessor().setMostRecentFocusOwner(this, comp); 281 synthesizeWindowActivation(true); 282 } 283 return (null != comp); 284 } 285 286 /** 287 * This method is called from dispatchKeyEvent in the following two cases: 288 * 1. The focus is on the first Component of this EmbeddedFrame and we are 289 * about to transfer the focus backward. 290 * 2. The focus in on the last Component of this EmbeddedFrame and we are 291 * about to transfer the focus forward. 292 * This is needed to give the opportuity for keyboard focus to leave the 293 * EmbeddedFrame. Override this method, initiate focus transfer in it and 294 * return true if you want the focus to leave EmbeddedFrame's cycle. 295 * The direction parameter specifies which of the two mentioned cases is 296 * happening. Use FORWARD and BACKWARD constants defined in EmbeddedFrame 297 * to avoid confusing boolean values. 298 * 299 * @param direction FORWARD or BACKWARD 300 * @return true, if EmbeddedFrame wants the focus to leave it, 301 * false otherwise. 302 */ 303 protected boolean traverseOut(boolean direction) { 304 return false; 305 } 306 307 /** 308 * Block modifying any frame attributes, since they aren't applicable 309 * for EmbeddedFrames. 310 */ 311 public void setTitle(String title) {} 312 public void setIconImage(Image image) {} 313 public void setIconImages(java.util.List<? extends Image> icons) {} 314 public void setMenuBar(MenuBar mb) {} 315 public void setResizable(boolean resizable) {} 316 public void remove(MenuComponent m) {} 317 318 public boolean isResizable() { 319 return true; 320 } 321 322 public void addNotify() { 323 synchronized (getTreeLock()) { 324 if (!isDisplayable()) { 325 setPeer(new NullEmbeddedFramePeer()); 326 } 327 super.addNotify(); 328 } 329 } 330 331 // These three functions consitute RFE 4100710. Do not remove. 332 public void setCursorAllowed(boolean isCursorAllowed) { 333 this.isCursorAllowed = isCursorAllowed; 334 final FramePeer peer = AWTAccessor.getComponentAccessor().getPeer(this); 335 peer.updateCursorImmediately(); 336 } 337 public boolean isCursorAllowed() { 338 return isCursorAllowed; 339 } 340 public Cursor getCursor() { 341 return (isCursorAllowed) 342 ? super.getCursor() 343 : Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); 344 } 345 346 protected void setPeer(final ComponentPeer p){ 347 AWTAccessor.getComponentAccessor().setPeer(EmbeddedFrame.this, p); 348 }; 349 350 /** 351 * Synthesize native message to activate or deactivate EmbeddedFrame window 352 * depending on the value of parameter {@code b}. 353 * Peers should override this method if they are to implement 354 * this functionality. 355 * @param doActivate if {@code true}, activates the window; 356 * otherwise, deactivates the window 357 */ 358 public void synthesizeWindowActivation(boolean doActivate) {} 359 360 /** 361 * Moves this embedded frame to a new location. The top-left corner of 362 * the new location is specified by the {@code x} and {@code y} 363 * parameters relative to the native parent component. 364 * <p> 365 * setLocation() and setBounds() for EmbeddedFrame really don't move it 366 * within the native parent. These methods always put embedded frame to 367 * (0, 0) for backward compatibility. To allow moving embedded frame 368 * setLocationPrivate() and setBoundsPrivate() were introduced, and they 369 * work just the same way as setLocation() and setBounds() for usual, 370 * non-embedded components. 371 * </p> 372 * <p> 373 * Using usual get/setLocation() and get/setBounds() together with new 374 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 375 * For example, calling getBoundsPrivate() after setLocation() works fine, 376 * but getBounds() after setBoundsPrivate() may return unpredictable value. 377 * </p> 378 * @param x the new <i>x</i>-coordinate relative to the parent component 379 * @param y the new <i>y</i>-coordinate relative to the parent component 380 * @see java.awt.Component#setLocation 381 * @see #getLocationPrivate 382 * @see #setBoundsPrivate 383 * @see #getBoundsPrivate 384 * @since 1.5 385 */ 386 protected void setLocationPrivate(int x, int y) { 387 Dimension size = getSize(); 388 setBoundsPrivate(x, y, size.width, size.height); 389 } 390 391 /** 392 * Gets the location of this embedded frame as a point specifying the 393 * top-left corner relative to parent component. 394 * <p> 395 * setLocation() and setBounds() for EmbeddedFrame really don't move it 396 * within the native parent. These methods always put embedded frame to 397 * (0, 0) for backward compatibility. To allow getting location and size 398 * of embedded frame getLocationPrivate() and getBoundsPrivate() were 399 * introduced, and they work just the same way as getLocation() and getBounds() 400 * for ususal, non-embedded components. 401 * </p> 402 * <p> 403 * Using usual get/setLocation() and get/setBounds() together with new 404 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 405 * For example, calling getBoundsPrivate() after setLocation() works fine, 406 * but getBounds() after setBoundsPrivate() may return unpredictable value. 407 * </p> 408 * @return a point indicating this embedded frame's top-left corner 409 * @see java.awt.Component#getLocation 410 * @see #setLocationPrivate 411 * @see #setBoundsPrivate 412 * @see #getBoundsPrivate 413 * @since 1.6 414 */ 415 protected Point getLocationPrivate() { 416 Rectangle bounds = getBoundsPrivate(); 417 return new Point(bounds.x, bounds.y); 418 } 419 420 /** 421 * Moves and resizes this embedded frame. The new location of the top-left 422 * corner is specified by {@code x} and {@code y} parameters 423 * relative to the native parent component. The new size is specified by 424 * {@code width} and {@code height}. 425 * <p> 426 * setLocation() and setBounds() for EmbeddedFrame really don't move it 427 * within the native parent. These methods always put embedded frame to 428 * (0, 0) for backward compatibility. To allow moving embedded frames 429 * setLocationPrivate() and setBoundsPrivate() were introduced, and they 430 * work just the same way as setLocation() and setBounds() for usual, 431 * non-embedded components. 432 * </p> 433 * <p> 434 * Using usual get/setLocation() and get/setBounds() together with new 435 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 436 * For example, calling getBoundsPrivate() after setLocation() works fine, 437 * but getBounds() after setBoundsPrivate() may return unpredictable value. 438 * </p> 439 * @param x the new <i>x</i>-coordinate relative to the parent component 440 * @param y the new <i>y</i>-coordinate relative to the parent component 441 * @param width the new {@code width} of this embedded frame 442 * @param height the new {@code height} of this embedded frame 443 * @see java.awt.Component#setBounds 444 * @see #setLocationPrivate 445 * @see #getLocationPrivate 446 * @see #getBoundsPrivate 447 * @since 1.5 448 */ 449 protected void setBoundsPrivate(int x, int y, int width, int height) { 450 final FramePeer peer = AWTAccessor.getComponentAccessor().getPeer(this); 451 if (peer != null) { 452 peer.setBoundsPrivate(x, y, width, height); 453 } 454 } 455 456 /** 457 * Gets the bounds of this embedded frame as a rectangle specifying the 458 * width, height and location relative to the native parent component. 459 * <p> 460 * setLocation() and setBounds() for EmbeddedFrame really don't move it 461 * within the native parent. These methods always put embedded frame to 462 * (0, 0) for backward compatibility. To allow getting location and size 463 * of embedded frames getLocationPrivate() and getBoundsPrivate() were 464 * introduced, and they work just the same way as getLocation() and getBounds() 465 * for ususal, non-embedded components. 466 * </p> 467 * <p> 468 * Using usual get/setLocation() and get/setBounds() together with new 469 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 470 * For example, calling getBoundsPrivate() after setLocation() works fine, 471 * but getBounds() after setBoundsPrivate() may return unpredictable value. 472 * </p> 473 * @return a rectangle indicating this embedded frame's bounds 474 * @see java.awt.Component#getBounds 475 * @see #setLocationPrivate 476 * @see #getLocationPrivate 477 * @see #setBoundsPrivate 478 * @since 1.6 479 */ 480 protected Rectangle getBoundsPrivate() { 481 final FramePeer peer = AWTAccessor.getComponentAccessor().getPeer(this); 482 if (peer != null) { 483 return peer.getBoundsPrivate(); 484 } 485 else { 486 return getBounds(); 487 } 488 } 489 490 public void toFront() {} 491 public void toBack() {} 492 493 public abstract void registerAccelerator(AWTKeyStroke stroke); 494 public abstract void unregisterAccelerator(AWTKeyStroke stroke); 495 496 /** 497 * Checks if the component is in an EmbeddedFrame. If so, 498 * returns the applet found in the hierarchy or null if 499 * not found. 500 * @return the parent applet or {@code null} 501 * @since 1.6 502 * 503 * @deprecated The Applet API is deprecated. See the 504 * <a href="../../java/applet/package-summary.html"> java.applet package 505 * documentation</a> for further information. 506 */ 507 @Deprecated(since = "9") 508 public static Applet getAppletIfAncestorOf(Component comp) { 509 Container parent = comp.getParent(); 510 Applet applet = null; 511 while (parent != null && !(parent instanceof EmbeddedFrame)) { 512 if (parent instanceof Applet) { 513 applet = (Applet)parent; 514 } 515 parent = parent.getParent(); 516 } 517 return parent == null ? null : applet; 518 } 519 520 /** 521 * This method should be overriden in subclasses. It is 522 * called when window this frame is within should be blocked 523 * by some modal dialog. 524 */ 525 public void notifyModalBlocked(Dialog blocker, boolean blocked) { 526 } 527 528 private static class NullEmbeddedFramePeer 529 extends NullComponentPeer implements FramePeer { 530 public void setTitle(String title) {} 531 public void setIconImage(Image im) {} 532 public void updateIconImages() {} 533 public void setMenuBar(MenuBar mb) {} 534 public void setResizable(boolean resizeable) {} 535 public void setState(int state) {} 536 public int getState() { return Frame.NORMAL; } 537 public void setMaximizedBounds(Rectangle b) {} 538 public void toFront() {} 539 public void toBack() {} 540 public void updateFocusableWindowState() {} 541 public void updateAlwaysOnTop() {} 542 public void updateAlwaysOnTopState() {} 543 public Component getGlobalHeavyweightFocusOwner() { return null; } 544 public void setBoundsPrivate(int x, int y, int width, int height) { 545 setBounds(x, y, width, height, SET_BOUNDS); 546 } 547 public Rectangle getBoundsPrivate() { 548 return getBounds(); 549 } 550 public void setModalBlocked(Dialog blocker, boolean blocked) {} 551 552 public void restack() { 553 throw new UnsupportedOperationException(); 554 } 555 556 public boolean isRestackSupported() { 557 return false; 558 } 559 public boolean requestWindowFocus() { 560 return false; 561 } 562 public void updateMinimumSize() { 563 } 564 565 public void setOpacity(float opacity) { 566 } 567 568 public void setOpaque(boolean isOpaque) { 569 } 570 571 public void updateWindow() { 572 } 573 574 public void repositionSecurityWarning() { 575 } 576 577 public void emulateActivation(boolean activate) { 578 } 579 } 580 } // class EmbeddedFrame