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.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 * Requests the focus to the embedder. 365 * 366 * @return {@code true} if focus request was successful, and {@code false} otherwise. 367 */ 368 public boolean requestFocusToEmbedder() { 369 return false; 370 } 371 372 /** 373 * Moves this embedded frame to a new location. The top-left corner of 374 * the new location is specified by the <code>x</code> and <code>y</code> 375 * parameters relative to the native parent component. 376 * <p> 377 * setLocation() and setBounds() for EmbeddedFrame really don't move it 378 * within the native parent. These methods always put embedded frame to 379 * (0, 0) for backward compatibility. To allow moving embedded frame 380 * setLocationPrivate() and setBoundsPrivate() were introduced, and they 381 * work just the same way as setLocation() and setBounds() for usual, 382 * non-embedded components. 383 * </p> 384 * <p> 385 * Using usual get/setLocation() and get/setBounds() together with new 386 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 387 * For example, calling getBoundsPrivate() after setLocation() works fine, 388 * but getBounds() after setBoundsPrivate() may return unpredictable value. 389 * </p> 390 * @param x the new <i>x</i>-coordinate relative to the parent component 391 * @param y the new <i>y</i>-coordinate relative to the parent component 392 * @see java.awt.Component#setLocation 393 * @see #getLocationPrivate 394 * @see #setBoundsPrivate 395 * @see #getBoundsPrivate 396 * @since 1.5 397 */ 398 protected void setLocationPrivate(int x, int y) { 399 Dimension size = getSize(); 400 setBoundsPrivate(x, y, size.width, size.height); 401 } 402 403 /** 404 * Gets the location of this embedded frame as a point specifying the 405 * top-left corner relative to parent component. 406 * <p> 407 * setLocation() and setBounds() for EmbeddedFrame really don't move it 408 * within the native parent. These methods always put embedded frame to 409 * (0, 0) for backward compatibility. To allow getting location and size 410 * of embedded frame getLocationPrivate() and getBoundsPrivate() were 411 * introduced, and they work just the same way as getLocation() and getBounds() 412 * for ususal, non-embedded components. 413 * </p> 414 * <p> 415 * Using usual get/setLocation() and get/setBounds() together with new 416 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 417 * For example, calling getBoundsPrivate() after setLocation() works fine, 418 * but getBounds() after setBoundsPrivate() may return unpredictable value. 419 * </p> 420 * @return a point indicating this embedded frame's top-left corner 421 * @see java.awt.Component#getLocation 422 * @see #setLocationPrivate 423 * @see #setBoundsPrivate 424 * @see #getBoundsPrivate 425 * @since 1.6 426 */ 427 protected Point getLocationPrivate() { 428 Rectangle bounds = getBoundsPrivate(); 429 return new Point(bounds.x, bounds.y); 430 } 431 432 /** 433 * Moves and resizes this embedded frame. The new location of the top-left 434 * corner is specified by <code>x</code> and <code>y</code> parameters 435 * relative to the native parent component. The new size is specified by 436 * <code>width</code> and <code>height</code>. 437 * <p> 438 * setLocation() and setBounds() for EmbeddedFrame really don't move it 439 * within the native parent. These methods always put embedded frame to 440 * (0, 0) for backward compatibility. To allow moving embedded frames 441 * setLocationPrivate() and setBoundsPrivate() were introduced, and they 442 * work just the same way as setLocation() and setBounds() for usual, 443 * non-embedded components. 444 * </p> 445 * <p> 446 * Using usual get/setLocation() and get/setBounds() together with new 447 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 448 * For example, calling getBoundsPrivate() after setLocation() works fine, 449 * but getBounds() after setBoundsPrivate() may return unpredictable value. 450 * </p> 451 * @param x the new <i>x</i>-coordinate relative to the parent component 452 * @param y the new <i>y</i>-coordinate relative to the parent component 453 * @param width the new <code>width</code> of this embedded frame 454 * @param height the new <code>height</code> of this embedded frame 455 * @see java.awt.Component#setBounds 456 * @see #setLocationPrivate 457 * @see #getLocationPrivate 458 * @see #getBoundsPrivate 459 * @since 1.5 460 */ 461 @SuppressWarnings("deprecation") 462 protected void setBoundsPrivate(int x, int y, int width, int height) { 463 final FramePeer peer = (FramePeer)getPeer(); 464 if (peer != null) { 465 peer.setBoundsPrivate(x, y, width, height); 466 } 467 } 468 469 /** 470 * Gets the bounds of this embedded frame as a rectangle specifying the 471 * width, height and location relative to the native parent component. 472 * <p> 473 * setLocation() and setBounds() for EmbeddedFrame really don't move it 474 * within the native parent. These methods always put embedded frame to 475 * (0, 0) for backward compatibility. To allow getting location and size 476 * of embedded frames getLocationPrivate() and getBoundsPrivate() were 477 * introduced, and they work just the same way as getLocation() and getBounds() 478 * for ususal, non-embedded components. 479 * </p> 480 * <p> 481 * Using usual get/setLocation() and get/setBounds() together with new 482 * get/setLocationPrivate() and get/setBoundsPrivate() is not recommended. 483 * For example, calling getBoundsPrivate() after setLocation() works fine, 484 * but getBounds() after setBoundsPrivate() may return unpredictable value. 485 * </p> 486 * @return a rectangle indicating this embedded frame's bounds 487 * @see java.awt.Component#getBounds 488 * @see #setLocationPrivate 489 * @see #getLocationPrivate 490 * @see #setBoundsPrivate 491 * @since 1.6 492 */ 493 @SuppressWarnings("deprecation") 494 protected Rectangle getBoundsPrivate() { 495 final FramePeer peer = (FramePeer)getPeer(); 496 if (peer != null) { 497 return peer.getBoundsPrivate(); 498 } 499 else { 500 return getBounds(); 501 } 502 } 503 504 public void toFront() {} 505 public void toBack() {} 506 507 public abstract void registerAccelerator(AWTKeyStroke stroke); 508 public abstract void unregisterAccelerator(AWTKeyStroke stroke); 509 510 /** 511 * Checks if the component is in an EmbeddedFrame. If so, 512 * returns the applet found in the hierarchy or null if 513 * not found. 514 * @return the parent applet or {@ null} 515 * @since 1.6 516 */ 517 public static Applet getAppletIfAncestorOf(Component comp) { 518 Container parent = comp.getParent(); 519 Applet applet = null; 520 while (parent != null && !(parent instanceof EmbeddedFrame)) { 521 if (parent instanceof Applet) { 522 applet = (Applet)parent; 523 } 524 parent = parent.getParent(); 525 } 526 return parent == null ? null : applet; 527 } 528 529 /** 530 * This method should be overriden in subclasses. It is 531 * called when window this frame is within should be blocked 532 * by some modal dialog. 533 */ 534 public void notifyModalBlocked(Dialog blocker, boolean blocked) { 535 } 536 537 private static class NullEmbeddedFramePeer 538 extends NullComponentPeer implements FramePeer { 539 public void setTitle(String title) {} 540 public void setIconImage(Image im) {} 541 public void updateIconImages() {} 542 public void setMenuBar(MenuBar mb) {} 543 public void setResizable(boolean resizeable) {} 544 public void setState(int state) {} 545 public int getState() { return Frame.NORMAL; } 546 public void setMaximizedBounds(Rectangle b) {} 547 public void toFront() {} 548 public void toBack() {} 549 public void updateFocusableWindowState() {} 550 public void updateAlwaysOnTop() {} 551 public void updateAlwaysOnTopState() {} 552 public Component getGlobalHeavyweightFocusOwner() { return null; } 553 public void setBoundsPrivate(int x, int y, int width, int height) { 554 setBounds(x, y, width, height, SET_BOUNDS); 555 } 556 public Rectangle getBoundsPrivate() { 557 return getBounds(); 558 } 559 public void setModalBlocked(Dialog blocker, boolean blocked) {} 560 561 /** 562 * @see java.awt.peer.ContainerPeer#restack 563 */ 564 public void restack() { 565 throw new UnsupportedOperationException(); 566 } 567 568 /** 569 * @see java.awt.peer.ContainerPeer#isRestackSupported 570 */ 571 public boolean isRestackSupported() { 572 return false; 573 } 574 public boolean requestWindowFocus() { 575 return false; 576 } 577 public void updateMinimumSize() { 578 } 579 580 public void setOpacity(float opacity) { 581 } 582 583 public void setOpaque(boolean isOpaque) { 584 } 585 586 public void updateWindow() { 587 } 588 589 public void repositionSecurityWarning() { 590 } 591 592 public void emulateActivation(boolean activate) { 593 } 594 } 595 } // class EmbeddedFrame