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