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