View Javadoc
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 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         /**
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