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