/* * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt; import java.io.PrintStream; import java.io.PrintWriter; import java.util.Objects; import java.util.Vector; import java.util.Locale; import java.util.EventListener; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.Collections; import java.awt.peer.ComponentPeer; import java.awt.peer.ContainerPeer; import java.awt.peer.LightweightPeer; import java.awt.image.BufferStrategy; import java.awt.image.ImageObserver; import java.awt.image.ImageProducer; import java.awt.image.ColorModel; import java.awt.image.VolatileImage; import java.awt.event.*; import java.io.Serializable; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.Transient; import java.awt.im.InputContext; import java.awt.im.InputMethodRequests; import java.awt.dnd.DropTarget; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; import java.security.AccessControlContext; import javax.accessibility.*; import java.applet.Applet; import sun.security.action.GetPropertyAction; import sun.awt.AppContext; import sun.awt.AWTAccessor; import sun.awt.ConstrainableGraphics; import sun.awt.SubRegionShowable; import sun.awt.SunToolkit; import sun.awt.WindowClosingListener; import sun.awt.CausedFocusEvent; import sun.awt.EmbeddedFrame; import sun.awt.dnd.SunDropTargetEvent; import sun.awt.im.CompositionArea; import sun.font.FontManager; import sun.font.FontManagerFactory; import sun.font.SunFontManager; import sun.java2d.SunGraphics2D; import sun.java2d.pipe.Region; import sun.awt.image.VSyncedBSManager; import sun.java2d.pipe.hw.ExtendedBufferCapabilities; import static sun.java2d.pipe.hw.ExtendedBufferCapabilities.VSyncType.*; import sun.awt.RequestFocusController; import sun.java2d.SunGraphicsEnvironment; import sun.util.logging.PlatformLogger; /** * A component is an object having a graphical representation * that can be displayed on the screen and that can interact with the * user. Examples of components are the buttons, checkboxes, and scrollbars * of a typical graphical user interface.

* The Component class is the abstract superclass of * the nonmenu-related Abstract Window Toolkit components. Class * Component can also be extended directly to create a * lightweight component. A lightweight component is a component that is * not associated with a native window. On the contrary, a heavyweight * component is associated with a native window. The {@link #isLightweight()} * method may be used to distinguish between the two kinds of the components. *

* Lightweight and heavyweight components may be mixed in a single component * hierarchy. However, for correct operating of such a mixed hierarchy of * components, the whole hierarchy must be valid. When the hierarchy gets * invalidated, like after changing the bounds of components, or * adding/removing components to/from containers, the whole hierarchy must be * validated afterwards by means of the {@link Container#validate()} method * invoked on the top-most invalid container of the hierarchy. * *

Serialization

* It is important to note that only AWT listeners which conform * to the Serializable protocol will be saved when * the object is stored. If an AWT object has listeners that * aren't marked serializable, they will be dropped at * writeObject time. Developers will need, as always, * to consider the implications of making an object serializable. * One situation to watch out for is this: *
 *    import java.awt.*;
 *    import java.awt.event.*;
 *    import java.io.Serializable;
 *
 *    class MyApp implements ActionListener, Serializable
 *    {
 *        BigObjectThatShouldNotBeSerializedWithAButton bigOne;
 *        Button aButton = new Button();
 *
 *        MyApp()
 *        {
 *            // Oops, now aButton has a listener with a reference
 *            // to bigOne!
 *            aButton.addActionListener(this);
 *        }
 *
 *        public void actionPerformed(ActionEvent e)
 *        {
 *            System.out.println("Hello There");
 *        }
 *    }
 * 
* In this example, serializing aButton by itself * will cause MyApp and everything it refers to * to be serialized as well. The problem is that the listener * is serializable by coincidence, not by design. To separate * the decisions about MyApp and the * ActionListener being serializable one can use a * nested class, as in the following example: *
 *    import java.awt.*;
 *    import java.awt.event.*;
 *    import java.io.Serializable;
 *
 *    class MyApp implements java.io.Serializable
 *    {
 *         BigObjectThatShouldNotBeSerializedWithAButton bigOne;
 *         Button aButton = new Button();
 *
 *         static class MyActionListener implements ActionListener
 *         {
 *             public void actionPerformed(ActionEvent e)
 *             {
 *                 System.out.println("Hello There");
 *             }
 *         }
 *
 *         MyApp()
 *         {
 *             aButton.addActionListener(new MyActionListener());
 *         }
 *    }
 * 
*

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. *

* For details on the focus subsystem, see * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the * Focus Specification * for more information. * * @author Arthur van Hoff * @author Sami Shaio */ public abstract class Component implements ImageObserver, MenuContainer, Serializable { private static final PlatformLogger log = PlatformLogger.getLogger("java.awt.Component"); private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.Component"); private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.Component"); private static final PlatformLogger mixingLog = PlatformLogger.getLogger("java.awt.mixing.Component"); /** * The peer of the component. The peer implements the component's * behavior. The peer is set when the Component is * added to a container that also is a peer. * @see #addNotify * @see #removeNotify */ transient ComponentPeer peer; /** * The parent of the object. It may be null * for top-level components. * @see #getParent */ transient Container parent; /** * The AppContext of the component. Applets/Plugin may * change the AppContext. */ transient AppContext appContext; /** * The x position of the component in the parent's coordinate system. * * @serial * @see #getLocation */ int x; /** * The y position of the component in the parent's coordinate system. * * @serial * @see #getLocation */ int y; /** * The width of the component. * * @serial * @see #getSize */ int width; /** * The height of the component. * * @serial * @see #getSize */ int height; /** * The foreground color for this component. * foreground can be null. * * @serial * @see #getForeground * @see #setForeground */ Color foreground; /** * The background color for this component. * background can be null. * * @serial * @see #getBackground * @see #setBackground */ Color background; /** * The font used by this component. * The font can be null. * * @serial * @see #getFont * @see #setFont */ volatile Font font; /** * The font which the peer is currently using. * (null if no peer exists.) */ Font peerFont; /** * The cursor displayed when pointer is over this component. * This value can be null. * * @serial * @see #getCursor * @see #setCursor */ Cursor cursor; /** * The locale for the component. * * @serial * @see #getLocale * @see #setLocale */ Locale locale; /** * A reference to a GraphicsConfiguration object * used to describe the characteristics of a graphics * destination. * This value can be null. * * @since 1.3 * @serial * @see GraphicsConfiguration * @see #getGraphicsConfiguration */ private transient volatile GraphicsConfiguration graphicsConfig; /** * A reference to a BufferStrategy object * used to manipulate the buffers on this component. * * @since 1.4 * @see java.awt.image.BufferStrategy * @see #getBufferStrategy() */ transient BufferStrategy bufferStrategy = null; /** * True when the object should ignore all repaint events. * * @since 1.4 * @serial * @see #setIgnoreRepaint * @see #getIgnoreRepaint */ boolean ignoreRepaint = false; /** * True when the object is visible. An object that is not * visible is not drawn on the screen. * * @serial * @see #isVisible * @see #setVisible */ boolean visible = true; /** * True when the object is enabled. An object that is not * enabled does not interact with the user. * * @serial * @see #isEnabled * @see #setEnabled */ boolean enabled = true; /** * True when the object is valid. An invalid object needs to * be layed out. This flag is set to false when the object * size is changed. * * @serial * @see #isValid * @see #validate * @see #invalidate */ private volatile boolean valid = false; /** * The DropTarget associated with this component. * * @since 1.2 * @serial * @see #setDropTarget * @see #getDropTarget */ DropTarget dropTarget; /** * @serial * @see #add */ Vector popups; /** * A component's name. * This field can be null. * * @serial * @see #getName * @see #setName(String) */ private String name; /** * A bool to determine whether the name has * been set explicitly. nameExplicitlySet will * be false if the name has not been set and * true if it has. * * @serial * @see #getName * @see #setName(String) */ private boolean nameExplicitlySet = false; /** * Indicates whether this Component can be focused. * * @serial * @see #setFocusable * @see #isFocusable * @since 1.4 */ private boolean focusable = true; private static final int FOCUS_TRAVERSABLE_UNKNOWN = 0; private static final int FOCUS_TRAVERSABLE_DEFAULT = 1; private static final int FOCUS_TRAVERSABLE_SET = 2; /** * Tracks whether this Component is relying on default focus travesability. * * @serial * @since 1.4 */ private int isFocusTraversableOverridden = FOCUS_TRAVERSABLE_UNKNOWN; /** * The focus traversal keys. These keys will generate focus traversal * behavior for Components for which focus traversal keys are enabled. If a * value of null is specified for a traversal key, this Component inherits * that traversal key from its parent. If all ancestors of this Component * have null specified for that traversal key, then the current * KeyboardFocusManager's default traversal key is used. * * @serial * @see #setFocusTraversalKeys * @see #getFocusTraversalKeys * @since 1.4 */ Set[] focusTraversalKeys; private static final String[] focusTraversalKeyPropertyNames = { "forwardFocusTraversalKeys", "backwardFocusTraversalKeys", "upCycleFocusTraversalKeys", "downCycleFocusTraversalKeys" }; /** * Indicates whether focus traversal keys are enabled for this Component. * Components for which focus traversal keys are disabled receive key * events for focus traversal keys. Components for which focus traversal * keys are enabled do not see these events; instead, the events are * automatically converted to traversal operations. * * @serial * @see #setFocusTraversalKeysEnabled * @see #getFocusTraversalKeysEnabled * @since 1.4 */ private boolean focusTraversalKeysEnabled = true; /** * The locking object for AWT component-tree and layout operations. * * @see #getTreeLock */ static final Object LOCK = new AWTTreeLock(); static class AWTTreeLock {} /* * The component's AccessControlContext. */ private transient volatile AccessControlContext acc = AccessController.getContext(); /** * Minimum size. * (This field perhaps should have been transient). * * @serial */ Dimension minSize; /** * Whether or not setMinimumSize has been invoked with a non-null value. */ boolean minSizeSet; /** * Preferred size. * (This field perhaps should have been transient). * * @serial */ Dimension prefSize; /** * Whether or not setPreferredSize has been invoked with a non-null value. */ boolean prefSizeSet; /** * Maximum size * * @serial */ Dimension maxSize; /** * Whether or not setMaximumSize has been invoked with a non-null value. */ boolean maxSizeSet; /** * The orientation for this component. * @see #getComponentOrientation * @see #setComponentOrientation */ transient ComponentOrientation componentOrientation = ComponentOrientation.UNKNOWN; /** * newEventsOnly will be true if the event is * one of the event types enabled for the component. * It will then allow for normal processing to * continue. If it is false the event is passed * to the component's parent and up the ancestor * tree until the event has been consumed. * * @serial * @see #dispatchEvent */ boolean newEventsOnly = false; transient ComponentListener componentListener; transient FocusListener focusListener; transient HierarchyListener hierarchyListener; transient HierarchyBoundsListener hierarchyBoundsListener; transient KeyListener keyListener; transient MouseListener mouseListener; transient MouseMotionListener mouseMotionListener; transient MouseWheelListener mouseWheelListener; transient InputMethodListener inputMethodListener; transient RuntimeException windowClosingException = null; /** Internal, constants for serialization */ final static String actionListenerK = "actionL"; final static String adjustmentListenerK = "adjustmentL"; final static String componentListenerK = "componentL"; final static String containerListenerK = "containerL"; final static String focusListenerK = "focusL"; final static String itemListenerK = "itemL"; final static String keyListenerK = "keyL"; final static String mouseListenerK = "mouseL"; final static String mouseMotionListenerK = "mouseMotionL"; final static String mouseWheelListenerK = "mouseWheelL"; final static String textListenerK = "textL"; final static String ownedWindowK = "ownedL"; final static String windowListenerK = "windowL"; final static String inputMethodListenerK = "inputMethodL"; final static String hierarchyListenerK = "hierarchyL"; final static String hierarchyBoundsListenerK = "hierarchyBoundsL"; final static String windowStateListenerK = "windowStateL"; final static String windowFocusListenerK = "windowFocusL"; /** * The eventMask is ONLY set by subclasses via * enableEvents. * The mask should NOT be set when listeners are registered * so that we can distinguish the difference between when * listeners request events and subclasses request them. * One bit is used to indicate whether input methods are * enabled; this bit is set by enableInputMethods and is * on by default. * * @serial * @see #enableInputMethods * @see AWTEvent */ long eventMask = AWTEvent.INPUT_METHODS_ENABLED_MASK; /** * Static properties for incremental drawing. * @see #imageUpdate */ static boolean isInc; static int incRate; static { /* ensure that the necessary native libraries are loaded */ Toolkit.loadLibraries(); /* initialize JNI field and method ids */ if (!GraphicsEnvironment.isHeadless()) { initIDs(); } String s = java.security.AccessController.doPrivileged( new GetPropertyAction("awt.image.incrementaldraw")); isInc = (s == null || s.equals("true")); s = java.security.AccessController.doPrivileged( new GetPropertyAction("awt.image.redrawrate")); incRate = (s != null) ? Integer.parseInt(s) : 100; } /** * Ease-of-use constant for getAlignmentY(). * Specifies an alignment to the top of the component. * @see #getAlignmentY */ public static final float TOP_ALIGNMENT = 0.0f; /** * Ease-of-use constant for getAlignmentY and * getAlignmentX. Specifies an alignment to * the center of the component * @see #getAlignmentX * @see #getAlignmentY */ public static final float CENTER_ALIGNMENT = 0.5f; /** * Ease-of-use constant for getAlignmentY. * Specifies an alignment to the bottom of the component. * @see #getAlignmentY */ public static final float BOTTOM_ALIGNMENT = 1.0f; /** * Ease-of-use constant for getAlignmentX. * Specifies an alignment to the left side of the component. * @see #getAlignmentX */ public static final float LEFT_ALIGNMENT = 0.0f; /** * Ease-of-use constant for getAlignmentX. * Specifies an alignment to the right side of the component. * @see #getAlignmentX */ public static final float RIGHT_ALIGNMENT = 1.0f; /* * JDK 1.1 serialVersionUID */ private static final long serialVersionUID = -7644114512714619750L; /** * If any PropertyChangeListeners have been registered, * the changeSupport field describes them. * * @serial * @since 1.2 * @see #addPropertyChangeListener * @see #removePropertyChangeListener * @see #firePropertyChange */ private PropertyChangeSupport changeSupport; /* * In some cases using "this" as an object to synchronize by * can lead to a deadlock if client code also uses synchronization * by a component object. For every such situation revealed we should * consider possibility of replacing "this" with the package private * objectLock object introduced below. So far there're 3 issues known: * - CR 6708322 (the getName/setName methods); * - CR 6608764 (the PropertyChangeListener machinery); * - CR 7108598 (the Container.paint/KeyboardFocusManager.clearMostRecentFocusOwner methods). * * Note: this field is considered final, though readObject() prohibits * initializing final fields. */ private transient Object objectLock = new Object(); Object getObjectLock() { return objectLock; } /* * Returns the acc this component was constructed with. */ final AccessControlContext getAccessControlContext() { if (acc == null) { throw new SecurityException("Component is missing AccessControlContext"); } return acc; } boolean isPacked = false; /** * Pseudoparameter for direct Geometry API (setLocation, setBounds setSize * to signal setBounds what's changing. Should be used under TreeLock. * This is only needed due to the inability to change the cross-calling * order of public and deprecated methods. */ private int boundsOp = ComponentPeer.DEFAULT_OPERATION; /** * Enumeration of the common ways the baseline of a component can * change as the size changes. The baseline resize behavior is * primarily for layout managers that need to know how the * position of the baseline changes as the component size changes. * In general the baseline resize behavior will be valid for sizes * greater than or equal to the minimum size (the actual minimum * size; not a developer specified minimum size). For sizes * smaller than the minimum size the baseline may change in a way * other than the baseline resize behavior indicates. Similarly, * as the size approaches Integer.MAX_VALUE and/or * Short.MAX_VALUE the baseline may change in a way * other than the baseline resize behavior indicates. * * @see #getBaselineResizeBehavior * @see #getBaseline(int,int) * @since 1.6 */ public enum BaselineResizeBehavior { /** * Indicates the baseline remains fixed relative to the * y-origin. That is, getBaseline returns * the same value regardless of the height or width. For example, a * JLabel containing non-empty text with a * vertical alignment of TOP should have a * baseline type of CONSTANT_ASCENT. */ CONSTANT_ASCENT, /** * Indicates the baseline remains fixed relative to the height * and does not change as the width is varied. That is, for * any height H the difference between H and * getBaseline(w, H) is the same. For example, a * JLabel containing non-empty text with a * vertical alignment of BOTTOM should have a * baseline type of CONSTANT_DESCENT. */ CONSTANT_DESCENT, /** * Indicates the baseline remains a fixed distance from * the center of the component. That is, for any height H the * difference between getBaseline(w, H) and * H / 2 is the same (plus or minus one depending upon * rounding error). *

* Because of possible rounding errors it is recommended * you ask for the baseline with two consecutive heights and use * the return value to determine if you need to pad calculations * by 1. The following shows how to calculate the baseline for * any height: *

         *   Dimension preferredSize = component.getPreferredSize();
         *   int baseline = getBaseline(preferredSize.width,
         *                              preferredSize.height);
         *   int nextBaseline = getBaseline(preferredSize.width,
         *                                  preferredSize.height + 1);
         *   // Amount to add to height when calculating where baseline
         *   // lands for a particular height:
         *   int padding = 0;
         *   // Where the baseline is relative to the mid point
         *   int baselineOffset = baseline - height / 2;
         *   if (preferredSize.height % 2 == 0 &&
         *       baseline != nextBaseline) {
         *       padding = 1;
         *   }
         *   else if (preferredSize.height % 2 == 1 &&
         *            baseline == nextBaseline) {
         *       baselineOffset--;
         *       padding = 1;
         *   }
         *   // The following calculates where the baseline lands for
         *   // the height z:
         *   int calculatedBaseline = (z + padding) / 2 + baselineOffset;
         * 
*/ CENTER_OFFSET, /** * Indicates the baseline resize behavior can not be expressed using * any of the other constants. This may also indicate the baseline * varies with the width of the component. This is also returned * by components that do not have a baseline. */ OTHER } /* * The shape set with the applyCompoundShape() method. It uncludes the result * of the HW/LW mixing related shape computation. It may also include * the user-specified shape of the component. * The 'null' value means the component has normal shape (or has no shape at all) * and applyCompoundShape() will skip the following shape identical to normal. */ private transient Region compoundShape = null; /* * Represents the shape of this lightweight component to be cut out from * heavyweight components should they intersect. Possible values: * 1. null - consider the shape rectangular * 2. EMPTY_REGION - nothing gets cut out (children still get cut out) * 3. non-empty - this shape gets cut out. */ private transient Region mixingCutoutRegion = null; /* * Indicates whether addNotify() is complete * (i.e. the peer is created). */ private transient boolean isAddNotifyComplete = false; /** * Should only be used in subclass getBounds to check that part of bounds * is actualy changing */ int getBoundsOp() { assert Thread.holdsLock(getTreeLock()); return boundsOp; } void setBoundsOp(int op) { assert Thread.holdsLock(getTreeLock()); if (op == ComponentPeer.RESET_OPERATION) { boundsOp = ComponentPeer.DEFAULT_OPERATION; } else if (boundsOp == ComponentPeer.DEFAULT_OPERATION) { boundsOp = op; } } // Whether this Component has had the background erase flag // specified via SunToolkit.disableBackgroundErase(). This is // needed in order to make this function work on X11 platforms, // where currently there is no chance to interpose on the creation // of the peer and therefore the call to XSetBackground. transient boolean backgroundEraseDisabled; static { AWTAccessor.setComponentAccessor(new AWTAccessor.ComponentAccessor() { public void setBackgroundEraseDisabled(Component comp, boolean disabled) { comp.backgroundEraseDisabled = disabled; } public boolean getBackgroundEraseDisabled(Component comp) { return comp.backgroundEraseDisabled; } public Rectangle getBounds(Component comp) { return new Rectangle(comp.x, comp.y, comp.width, comp.height); } public void setMixingCutoutShape(Component comp, Shape shape) { Region region = shape == null ? null : Region.getInstance(shape, null); synchronized (comp.getTreeLock()) { boolean needShowing = false; boolean needHiding = false; if (!comp.isNonOpaqueForMixing()) { needHiding = true; } comp.mixingCutoutRegion = region; if (!comp.isNonOpaqueForMixing()) { needShowing = true; } if (comp.isMixingNeeded()) { if (needHiding) { comp.mixOnHiding(comp.isLightweight()); } if (needShowing) { comp.mixOnShowing(); } } } } public void setGraphicsConfiguration(Component comp, GraphicsConfiguration gc) { comp.setGraphicsConfiguration(gc); } public boolean requestFocus(Component comp, CausedFocusEvent.Cause cause) { return comp.requestFocus(cause); } public boolean canBeFocusOwner(Component comp) { return comp.canBeFocusOwner(); } public boolean isVisible(Component comp) { return comp.isVisible_NoClientCode(); } public void setRequestFocusController (RequestFocusController requestController) { Component.setRequestFocusController(requestController); } public AppContext getAppContext(Component comp) { return comp.appContext; } public void setAppContext(Component comp, AppContext appContext) { comp.appContext = appContext; } public Container getParent(Component comp) { return comp.getParent_NoClientCode(); } public void setParent(Component comp, Container parent) { comp.parent = parent; } public void setSize(Component comp, int width, int height) { comp.width = width; comp.height = height; } public Point getLocation(Component comp) { return comp.location_NoClientCode(); } public void setLocation(Component comp, int x, int y) { comp.x = x; comp.y = y; } public boolean isEnabled(Component comp) { return comp.isEnabledImpl(); } public boolean isDisplayable(Component comp) { return comp.peer != null; } public Cursor getCursor(Component comp) { return comp.getCursor_NoClientCode(); } public ComponentPeer getPeer(Component comp) { return comp.peer; } public void setPeer(Component comp, ComponentPeer peer) { comp.peer = peer; } public boolean isLightweight(Component comp) { return (comp.peer instanceof LightweightPeer); } public boolean getIgnoreRepaint(Component comp) { return comp.ignoreRepaint; } public int getWidth(Component comp) { return comp.width; } public int getHeight(Component comp) { return comp.height; } public int getX(Component comp) { return comp.x; } public int getY(Component comp) { return comp.y; } public Color getForeground(Component comp) { return comp.foreground; } public Color getBackground(Component comp) { return comp.background; } public void setBackground(Component comp, Color background) { comp.background = background; } public Font getFont(Component comp) { return comp.getFont_NoClientCode(); } public void processEvent(Component comp, AWTEvent e) { comp.processEvent(e); } public AccessControlContext getAccessControlContext(Component comp) { return comp.getAccessControlContext(); } public void revalidateSynchronously(Component comp) { comp.revalidateSynchronously(); } }); } /** * Constructs a new component. Class Component can be * extended directly to create a lightweight component that does not * utilize an opaque native window. A lightweight component must be * hosted by a native container somewhere higher up in the component * tree (for example, by a Frame object). */ protected Component() { appContext = AppContext.getAppContext(); } @SuppressWarnings({"rawtypes", "unchecked"}) void initializeFocusTraversalKeys() { focusTraversalKeys = new Set[3]; } /** * Constructs a name for this component. Called by getName * when the name is null. */ String constructComponentName() { return null; // For strict compliance with prior platform versions, a Component // that doesn't set its name should return null from // getName() } /** * Gets the name of the component. * @return this component's name * @see #setName * @since JDK1.1 */ public String getName() { if (name == null && !nameExplicitlySet) { synchronized(getObjectLock()) { if (name == null && !nameExplicitlySet) name = constructComponentName(); } } return name; } /** * Sets the name of the component to the specified string. * @param name the string that is to be this * component's name * @see #getName * @since JDK1.1 */ public void setName(String name) { String oldName; synchronized(getObjectLock()) { oldName = this.name; this.name = name; nameExplicitlySet = true; } firePropertyChange("name", oldName, name); } /** * Gets the parent of this component. * @return the parent container of this component * @since JDK1.0 */ public Container getParent() { return getParent_NoClientCode(); } // NOTE: This method may be called by privileged threads. // This functionality is implemented in a package-private method // to insure that it cannot be overridden by client subclasses. // DO NOT INVOKE CLIENT CODE ON THIS THREAD! final Container getParent_NoClientCode() { return parent; } // This method is overridden in the Window class to return null, // because the parent field of the Window object contains // the owner of the window, not its parent. Container getContainer() { return getParent_NoClientCode(); } /** * @deprecated As of JDK version 1.1, * programs should not directly manipulate peers; * replaced by boolean isDisplayable(). */ @Deprecated public ComponentPeer getPeer() { return peer; } /** * Associate a DropTarget with this component. * The Component will receive drops only if it * is enabled. * * @see #isEnabled * @param dt The DropTarget */ public synchronized void setDropTarget(DropTarget dt) { if (dt == dropTarget || (dropTarget != null && dropTarget.equals(dt))) return; DropTarget old; if ((old = dropTarget) != null) { if (peer != null) dropTarget.removeNotify(peer); DropTarget t = dropTarget; dropTarget = null; try { t.setComponent(null); } catch (IllegalArgumentException iae) { // ignore it. } } // if we have a new one, and we have a peer, add it! if ((dropTarget = dt) != null) { try { dropTarget.setComponent(this); if (peer != null) dropTarget.addNotify(peer); } catch (IllegalArgumentException iae) { if (old != null) { try { old.setComponent(this); if (peer != null) dropTarget.addNotify(peer); } catch (IllegalArgumentException iae1) { // ignore it! } } } } } /** * Gets the DropTarget associated with this * Component. */ public synchronized DropTarget getDropTarget() { return dropTarget; } /** * Gets the GraphicsConfiguration associated with this * Component. * If the Component has not been assigned a specific * GraphicsConfiguration, * the GraphicsConfiguration of the * Component object's top-level container is * returned. * If the Component has been created, but not yet added * to a Container, this method returns null. * * @return the GraphicsConfiguration used by this * Component or null * @since 1.3 */ public GraphicsConfiguration getGraphicsConfiguration() { return getGraphicsConfiguration_NoClientCode(); } final GraphicsConfiguration getGraphicsConfiguration_NoClientCode() { return graphicsConfig; } void setGraphicsConfiguration(GraphicsConfiguration gc) { synchronized(getTreeLock()) { if (updateGraphicsData(gc)) { removeNotify(); addNotify(); } } } boolean updateGraphicsData(GraphicsConfiguration gc) { checkTreeLock(); if (graphicsConfig == gc) { return false; } graphicsConfig = gc; ComponentPeer peer = getPeer(); if (peer != null) { return peer.updateGraphicsData(gc); } return false; } /** * Checks that this component's GraphicsDevice * idString matches the string argument. */ void checkGD(String stringID) { if (graphicsConfig != null) { if (!graphicsConfig.getDevice().getIDstring().equals(stringID)) { throw new IllegalArgumentException( "adding a container to a container on a different GraphicsDevice"); } } } /** * Gets this component's locking object (the object that owns the thread * synchronization monitor) for AWT component-tree and layout * operations. * @return this component's locking object */ public final Object getTreeLock() { return LOCK; } final void checkTreeLock() { if (!Thread.holdsLock(getTreeLock())) { throw new IllegalStateException("This function should be called while holding treeLock"); } } /** * Gets the toolkit of this component. Note that * the frame that contains a component controls which * toolkit is used by that component. Therefore if the component * is moved from one frame to another, the toolkit it uses may change. * @return the toolkit of this component * @since JDK1.0 */ public Toolkit getToolkit() { return getToolkitImpl(); } /* * This is called by the native code, so client code can't * be called on the toolkit thread. */ final Toolkit getToolkitImpl() { Container parent = this.parent; if (parent != null) { return parent.getToolkitImpl(); } return Toolkit.getDefaultToolkit(); } /** * Determines whether this component is valid. A component is valid * when it is correctly sized and positioned within its parent * container and all its children are also valid. * In order to account for peers' size requirements, components are invalidated * before they are first shown on the screen. By the time the parent container * is fully realized, all its components will be valid. * @return true if the component is valid, false * otherwise * @see #validate * @see #invalidate * @since JDK1.0 */ public boolean isValid() { return (peer != null) && valid; } /** * Determines whether this component is displayable. A component is * displayable when it is connected to a native screen resource. *

* A component is made displayable either when it is added to * a displayable containment hierarchy or when its containment * hierarchy is made displayable. * A containment hierarchy is made displayable when its ancestor * window is either packed or made visible. *

* A component is made undisplayable either when it is removed from * a displayable containment hierarchy or when its containment hierarchy * is made undisplayable. A containment hierarchy is made * undisplayable when its ancestor window is disposed. * * @return true if the component is displayable, * false otherwise * @see Container#add(Component) * @see Window#pack * @see Window#show * @see Container#remove(Component) * @see Window#dispose * @since 1.2 */ public boolean isDisplayable() { return getPeer() != null; } /** * Determines whether this component should be visible when its * parent is visible. Components are * initially visible, with the exception of top level components such * as Frame objects. * @return true if the component is visible, * false otherwise * @see #setVisible * @since JDK1.0 */ @Transient public boolean isVisible() { return isVisible_NoClientCode(); } final boolean isVisible_NoClientCode() { return visible; } /** * Determines whether this component will be displayed on the screen. * @return true if the component and all of its ancestors * until a toplevel window or null parent are visible, * false otherwise */ boolean isRecursivelyVisible() { return visible && (parent == null || parent.isRecursivelyVisible()); } /** * Determines the bounds of a visible part of the component relative to its * parent. * * @return the visible part of bounds */ private Rectangle getRecursivelyVisibleBounds() { final Component container = getContainer(); final Rectangle bounds = getBounds(); if (container == null) { // we are top level window or haven't a container, return our bounds return bounds; } // translate the container's bounds to our coordinate space final Rectangle parentsBounds = container.getRecursivelyVisibleBounds(); parentsBounds.setLocation(0, 0); return parentsBounds.intersection(bounds); } /** * Translates absolute coordinates into coordinates in the coordinate * space of this component. */ Point pointRelativeToComponent(Point absolute) { Point compCoords = getLocationOnScreen(); return new Point(absolute.x - compCoords.x, absolute.y - compCoords.y); } /** * Assuming that mouse location is stored in PointerInfo passed * to this method, it finds a Component that is in the same * Window as this Component and is located under the mouse pointer. * If no such Component exists, null is returned. * NOTE: this method should be called under the protection of * tree lock, as it is done in Component.getMousePosition() and * Container.getMousePosition(boolean). */ Component findUnderMouseInWindow(PointerInfo pi) { if (!isShowing()) { return null; } Window win = getContainingWindow(); if (!Toolkit.getDefaultToolkit().getMouseInfoPeer().isWindowUnderMouse(win)) { return null; } final boolean INCLUDE_DISABLED = true; Point relativeToWindow = win.pointRelativeToComponent(pi.getLocation()); Component inTheSameWindow = win.findComponentAt(relativeToWindow.x, relativeToWindow.y, INCLUDE_DISABLED); return inTheSameWindow; } /** * Returns the position of the mouse pointer in this Component's * coordinate space if the Component is directly under the mouse * pointer, otherwise returns null. * If the Component is not showing on the screen, this method * returns null even if the mouse pointer is above the area * where the Component would be displayed. * If the Component is partially or fully obscured by other * Components or native windows, this method returns a non-null * value only if the mouse pointer is located above the unobscured part of the * Component. *

* For Containers it returns a non-null value if the mouse is * above the Container itself or above any of its descendants. * Use {@link Container#getMousePosition(boolean)} if you need to exclude children. *

* Sometimes the exact mouse coordinates are not important, and the only thing * that matters is whether a specific Component is under the mouse * pointer. If the return value of this method is null, mouse * pointer is not directly above the Component. * * @exception HeadlessException if GraphicsEnvironment.isHeadless() returns true * @see #isShowing * @see Container#getMousePosition * @return mouse coordinates relative to this Component, or null * @since 1.5 */ public Point getMousePosition() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } PointerInfo pi = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public PointerInfo run() { return MouseInfo.getPointerInfo(); } } ); synchronized (getTreeLock()) { Component inTheSameWindow = findUnderMouseInWindow(pi); if (!isSameOrAncestorOf(inTheSameWindow, true)) { return null; } return pointRelativeToComponent(pi.getLocation()); } } /** * Overridden in Container. Must be called under TreeLock. */ boolean isSameOrAncestorOf(Component comp, boolean allowChildren) { return comp == this; } /** * Determines whether this component is showing on screen. This means * that the component must be visible, and it must be in a container * that is visible and showing. *

* Note: sometimes there is no way to detect whether the * {@code Component} is actually visible to the user. This can happen when: *

* @return true if the component is showing, * false otherwise * @see #setVisible * @since JDK1.0 */ public boolean isShowing() { if (visible && (peer != null)) { Container parent = this.parent; return (parent == null) || parent.isShowing(); } return false; } /** * Determines whether this component is enabled. An enabled component * can respond to user input and generate events. Components are * enabled initially by default. A component may be enabled or disabled by * calling its setEnabled method. * @return true if the component is enabled, * false otherwise * @see #setEnabled * @since JDK1.0 */ public boolean isEnabled() { return isEnabledImpl(); } /* * This is called by the native code, so client code can't * be called on the toolkit thread. */ final boolean isEnabledImpl() { return enabled; } /** * Enables or disables this component, depending on the value of the * parameter b. An enabled component can respond to user * input and generate events. Components are enabled initially by default. * *

Note: Disabling a lightweight component does not prevent it from * receiving MouseEvents. *

Note: Disabling a heavyweight container prevents all components * in this container from receiving any input events. But disabling a * lightweight container affects only this container. * * @param b If true, this component is * enabled; otherwise this component is disabled * @see #isEnabled * @see #isLightweight * @since JDK1.1 */ public void setEnabled(boolean b) { enable(b); } /** * @deprecated As of JDK version 1.1, * replaced by setEnabled(boolean). */ @Deprecated public void enable() { if (!enabled) { synchronized (getTreeLock()) { enabled = true; ComponentPeer peer = this.peer; if (peer != null) { peer.setEnabled(true); if (visible && !getRecursivelyVisibleBounds().isEmpty()) { updateCursorImmediately(); } } } if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.ENABLED); } } } /** * @deprecated As of JDK version 1.1, * replaced by setEnabled(boolean). */ @Deprecated public void enable(boolean b) { if (b) { enable(); } else { disable(); } } /** * @deprecated As of JDK version 1.1, * replaced by setEnabled(boolean). */ @Deprecated public void disable() { if (enabled) { KeyboardFocusManager.clearMostRecentFocusOwner(this); synchronized (getTreeLock()) { enabled = false; // A disabled lw container is allowed to contain a focus owner. if ((isFocusOwner() || (containsFocus() && !isLightweight())) && KeyboardFocusManager.isAutoFocusTransferEnabled()) { // Don't clear the global focus owner. If transferFocus // fails, we want the focus to stay on the disabled // Component so that keyboard traversal, et. al. still // makes sense to the user. transferFocus(false); } ComponentPeer peer = this.peer; if (peer != null) { peer.setEnabled(false); if (visible && !getRecursivelyVisibleBounds().isEmpty()) { updateCursorImmediately(); } } } if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.ENABLED); } } } /** * Returns true if this component is painted to an offscreen image * ("buffer") that's copied to the screen later. Component * subclasses that support double buffering should override this * method to return true if double buffering is enabled. * * @return false by default */ public boolean isDoubleBuffered() { return false; } /** * Enables or disables input method support for this component. If input * method support is enabled and the component also processes key events, * incoming events are offered to * the current input method and will only be processed by the component or * dispatched to its listeners if the input method does not consume them. * By default, input method support is enabled. * * @param enable true to enable, false to disable * @see #processKeyEvent * @since 1.2 */ public void enableInputMethods(boolean enable) { if (enable) { if ((eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0) return; // If this component already has focus, then activate the // input method by dispatching a synthesized focus gained // event. if (isFocusOwner()) { InputContext inputContext = getInputContext(); if (inputContext != null) { FocusEvent focusGainedEvent = new FocusEvent(this, FocusEvent.FOCUS_GAINED); inputContext.dispatchEvent(focusGainedEvent); } } eventMask |= AWTEvent.INPUT_METHODS_ENABLED_MASK; } else { if ((eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0) { InputContext inputContext = getInputContext(); if (inputContext != null) { inputContext.endComposition(); inputContext.removeNotify(this); } } eventMask &= ~AWTEvent.INPUT_METHODS_ENABLED_MASK; } } /** * Shows or hides this component depending on the value of parameter * b. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param b if true, shows this component; * otherwise, hides this component * @see #isVisible * @see #invalidate * @since JDK1.1 */ public void setVisible(boolean b) { show(b); } /** * @deprecated As of JDK version 1.1, * replaced by setVisible(boolean). */ @Deprecated public void show() { if (!visible) { synchronized (getTreeLock()) { visible = true; mixOnShowing(); ComponentPeer peer = this.peer; if (peer != null) { peer.setVisible(true); createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, this, parent, HierarchyEvent.SHOWING_CHANGED, Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); if (peer instanceof LightweightPeer) { repaint(); } updateCursorImmediately(); } if (componentListener != null || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.COMPONENT_EVENT_MASK)) { ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_SHOWN); Toolkit.getEventQueue().postEvent(e); } } Container parent = this.parent; if (parent != null) { parent.invalidate(); } } } /** * @deprecated As of JDK version 1.1, * replaced by setVisible(boolean). */ @Deprecated public void show(boolean b) { if (b) { show(); } else { hide(); } } boolean containsFocus() { return isFocusOwner(); } void clearMostRecentFocusOwnerOnHide() { KeyboardFocusManager.clearMostRecentFocusOwner(this); } void clearCurrentFocusCycleRootOnHide() { /* do nothing */ } /** * @deprecated As of JDK version 1.1, * replaced by setVisible(boolean). */ @Deprecated public void hide() { isPacked = false; if (visible) { clearCurrentFocusCycleRootOnHide(); clearMostRecentFocusOwnerOnHide(); synchronized (getTreeLock()) { visible = false; mixOnHiding(isLightweight()); if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabled()) { transferFocus(true); } ComponentPeer peer = this.peer; if (peer != null) { peer.setVisible(false); createHierarchyEvents(HierarchyEvent.HIERARCHY_CHANGED, this, parent, HierarchyEvent.SHOWING_CHANGED, Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)); if (peer instanceof LightweightPeer) { repaint(); } updateCursorImmediately(); } if (componentListener != null || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.COMPONENT_EVENT_MASK)) { ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_HIDDEN); Toolkit.getEventQueue().postEvent(e); } } Container parent = this.parent; if (parent != null) { parent.invalidate(); } } } /** * Gets the foreground color of this component. * @return this component's foreground color; if this component does * not have a foreground color, the foreground color of its parent * is returned * @see #setForeground * @since JDK1.0 * @beaninfo * bound: true */ @Transient public Color getForeground() { Color foreground = this.foreground; if (foreground != null) { return foreground; } Container parent = this.parent; return (parent != null) ? parent.getForeground() : null; } /** * Sets the foreground color of this component. * @param c the color to become this component's * foreground color; if this parameter is null * then this component will inherit * the foreground color of its parent * @see #getForeground * @since JDK1.0 */ public void setForeground(Color c) { Color oldColor = foreground; ComponentPeer peer = this.peer; foreground = c; if (peer != null) { c = getForeground(); if (c != null) { peer.setForeground(c); } } // This is a bound property, so report the change to // any registered listeners. (Cheap if there are none.) firePropertyChange("foreground", oldColor, c); } /** * Returns whether the foreground color has been explicitly set for this * Component. If this method returns false, this Component is * inheriting its foreground color from an ancestor. * * @return true if the foreground color has been explicitly * set for this Component; false otherwise. * @since 1.4 */ public boolean isForegroundSet() { return (foreground != null); } /** * Gets the background color of this component. * @return this component's background color; if this component does * not have a background color, * the background color of its parent is returned * @see #setBackground * @since JDK1.0 */ @Transient public Color getBackground() { Color background = this.background; if (background != null) { return background; } Container parent = this.parent; return (parent != null) ? parent.getBackground() : null; } /** * Sets the background color of this component. *

* The background color affects each component differently and the * parts of the component that are affected by the background color * may differ between operating systems. * * @param c the color to become this component's color; * if this parameter is null, then this * component will inherit the background color of its parent * @see #getBackground * @since JDK1.0 * @beaninfo * bound: true */ public void setBackground(Color c) { Color oldColor = background; ComponentPeer peer = this.peer; background = c; if (peer != null) { c = getBackground(); if (c != null) { peer.setBackground(c); } } // This is a bound property, so report the change to // any registered listeners. (Cheap if there are none.) firePropertyChange("background", oldColor, c); } /** * Returns whether the background color has been explicitly set for this * Component. If this method returns false, this Component is * inheriting its background color from an ancestor. * * @return true if the background color has been explicitly * set for this Component; false otherwise. * @since 1.4 */ public boolean isBackgroundSet() { return (background != null); } /** * Gets the font of this component. * @return this component's font; if a font has not been set * for this component, the font of its parent is returned * @see #setFont * @since JDK1.0 */ @Transient public Font getFont() { return getFont_NoClientCode(); } // NOTE: This method may be called by privileged threads. // This functionality is implemented in a package-private method // to insure that it cannot be overridden by client subclasses. // DO NOT INVOKE CLIENT CODE ON THIS THREAD! final Font getFont_NoClientCode() { Font font = this.font; if (font != null) { return font; } Container parent = this.parent; return (parent != null) ? parent.getFont_NoClientCode() : null; } /** * Sets the font of this component. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param f the font to become this component's font; * if this parameter is null then this * component will inherit the font of its parent * @see #getFont * @see #invalidate * @since JDK1.0 * @beaninfo * bound: true */ public void setFont(Font f) { Font oldFont, newFont; synchronized(getTreeLock()) { oldFont = font; newFont = font = f; ComponentPeer peer = this.peer; if (peer != null) { f = getFont(); if (f != null) { peer.setFont(f); peerFont = f; } } } // This is a bound property, so report the change to // any registered listeners. (Cheap if there are none.) firePropertyChange("font", oldFont, newFont); // This could change the preferred size of the Component. // Fix for 6213660. Should compare old and new fonts and do not // call invalidate() if they are equal. if (f != oldFont && (oldFont == null || !oldFont.equals(f))) { invalidateIfValid(); } } /** * Returns whether the font has been explicitly set for this Component. If * this method returns false, this Component is inheriting its * font from an ancestor. * * @return true if the font has been explicitly set for this * Component; false otherwise. * @since 1.4 */ public boolean isFontSet() { return (font != null); } /** * Gets the locale of this component. * @return this component's locale; if this component does not * have a locale, the locale of its parent is returned * @see #setLocale * @exception IllegalComponentStateException if the Component * does not have its own locale and has not yet been added to * a containment hierarchy such that the locale can be determined * from the containing parent * @since JDK1.1 */ public Locale getLocale() { Locale locale = this.locale; if (locale != null) { return locale; } Container parent = this.parent; if (parent == null) { throw new IllegalComponentStateException("This component must have a parent in order to determine its locale"); } else { return parent.getLocale(); } } /** * Sets the locale of this component. This is a bound property. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param l the locale to become this component's locale * @see #getLocale * @see #invalidate * @since JDK1.1 */ public void setLocale(Locale l) { Locale oldValue = locale; locale = l; // This is a bound property, so report the change to // any registered listeners. (Cheap if there are none.) firePropertyChange("locale", oldValue, l); // This could change the preferred size of the Component. invalidateIfValid(); } /** * Gets the instance of ColorModel used to display * the component on the output device. * @return the color model used by this component * @see java.awt.image.ColorModel * @see java.awt.peer.ComponentPeer#getColorModel() * @see Toolkit#getColorModel() * @since JDK1.0 */ public ColorModel getColorModel() { ComponentPeer peer = this.peer; if ((peer != null) && ! (peer instanceof LightweightPeer)) { return peer.getColorModel(); } else if (GraphicsEnvironment.isHeadless()) { return ColorModel.getRGBdefault(); } // else return getToolkit().getColorModel(); } /** * Gets the location of this component in the form of a * point specifying the component's top-left corner. * The location will be relative to the parent's coordinate space. *

* Due to the asynchronous nature of native event handling, this * method can return outdated values (for instance, after several calls * of setLocation() in rapid succession). For this * reason, the recommended method of obtaining a component's position is * within java.awt.event.ComponentListener.componentMoved(), * which is called after the operating system has finished moving the * component. *

* @return an instance of Point representing * the top-left corner of the component's bounds in * the coordinate space of the component's parent * @see #setLocation * @see #getLocationOnScreen * @since JDK1.1 */ public Point getLocation() { return location(); } /** * Gets the location of this component in the form of a point * specifying the component's top-left corner in the screen's * coordinate space. * @return an instance of Point representing * the top-left corner of the component's bounds in the * coordinate space of the screen * @throws IllegalComponentStateException if the * component is not showing on the screen * @see #setLocation * @see #getLocation */ public Point getLocationOnScreen() { synchronized (getTreeLock()) { return getLocationOnScreen_NoTreeLock(); } } /* * a package private version of getLocationOnScreen * used by GlobalCursormanager to update cursor */ final Point getLocationOnScreen_NoTreeLock() { if (peer != null && isShowing()) { if (peer instanceof LightweightPeer) { // lightweight component location needs to be translated // relative to a native component. Container host = getNativeContainer(); Point pt = host.peer.getLocationOnScreen(); for(Component c = this; c != host; c = c.getParent()) { pt.x += c.x; pt.y += c.y; } return pt; } else { Point pt = peer.getLocationOnScreen(); return pt; } } else { throw new IllegalComponentStateException("component must be showing on the screen to determine its location"); } } /** * @deprecated As of JDK version 1.1, * replaced by getLocation(). */ @Deprecated public Point location() { return location_NoClientCode(); } private Point location_NoClientCode() { return new Point(x, y); } /** * Moves this component to a new location. The top-left corner of * the new location is specified by the x and y * parameters in the coordinate space of this component's parent. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param x the x-coordinate of the new location's * top-left corner in the parent's coordinate space * @param y the y-coordinate of the new location's * top-left corner in the parent's coordinate space * @see #getLocation * @see #setBounds * @see #invalidate * @since JDK1.1 */ public void setLocation(int x, int y) { move(x, y); } /** * @deprecated As of JDK version 1.1, * replaced by setLocation(int, int). */ @Deprecated public void move(int x, int y) { synchronized(getTreeLock()) { setBoundsOp(ComponentPeer.SET_LOCATION); setBounds(x, y, width, height); } } /** * Moves this component to a new location. The top-left corner of * the new location is specified by point p. Point * p is given in the parent's coordinate space. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param p the point defining the top-left corner * of the new location, given in the coordinate space of this * component's parent * @see #getLocation * @see #setBounds * @see #invalidate * @since JDK1.1 */ public void setLocation(Point p) { setLocation(p.x, p.y); } /** * Returns the size of this component in the form of a * Dimension object. The height * field of the Dimension object contains * this component's height, and the width * field of the Dimension object contains * this component's width. * @return a Dimension object that indicates the * size of this component * @see #setSize * @since JDK1.1 */ public Dimension getSize() { return size(); } /** * @deprecated As of JDK version 1.1, * replaced by getSize(). */ @Deprecated public Dimension size() { return new Dimension(width, height); } /** * Resizes this component so that it has width width * and height height. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param width the new width of this component in pixels * @param height the new height of this component in pixels * @see #getSize * @see #setBounds * @see #invalidate * @since JDK1.1 */ public void setSize(int width, int height) { resize(width, height); } /** * @deprecated As of JDK version 1.1, * replaced by setSize(int, int). */ @Deprecated public void resize(int width, int height) { synchronized(getTreeLock()) { setBoundsOp(ComponentPeer.SET_SIZE); setBounds(x, y, width, height); } } /** * Resizes this component so that it has width d.width * and height d.height. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param d the dimension specifying the new size * of this component * @throws NullPointerException if {@code d} is {@code null} * @see #setSize * @see #setBounds * @see #invalidate * @since JDK1.1 */ public void setSize(Dimension d) { resize(d); } /** * @deprecated As of JDK version 1.1, * replaced by setSize(Dimension). */ @Deprecated public void resize(Dimension d) { setSize(d.width, d.height); } /** * Gets the bounds of this component in the form of a * Rectangle object. The bounds specify this * component's width, height, and location relative to * its parent. * @return a rectangle indicating this component's bounds * @see #setBounds * @see #getLocation * @see #getSize */ public Rectangle getBounds() { return bounds(); } /** * @deprecated As of JDK version 1.1, * replaced by getBounds(). */ @Deprecated public Rectangle bounds() { return new Rectangle(x, y, width, height); } /** * Moves and resizes this component. The new location of the top-left * corner is specified by x and y, and the * new size is specified by width and height. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param x the new x-coordinate of this component * @param y the new y-coordinate of this component * @param width the new width of this component * @param height the new height of this * component * @see #getBounds * @see #setLocation(int, int) * @see #setLocation(Point) * @see #setSize(int, int) * @see #setSize(Dimension) * @see #invalidate * @since JDK1.1 */ public void setBounds(int x, int y, int width, int height) { reshape(x, y, width, height); } /** * @deprecated As of JDK version 1.1, * replaced by setBounds(int, int, int, int). */ @Deprecated public void reshape(int x, int y, int width, int height) { synchronized (getTreeLock()) { try { setBoundsOp(ComponentPeer.SET_BOUNDS); boolean resized = (this.width != width) || (this.height != height); boolean moved = (this.x != x) || (this.y != y); if (!resized && !moved) { return; } int oldX = this.x; int oldY = this.y; int oldWidth = this.width; int oldHeight = this.height; this.x = x; this.y = y; this.width = width; this.height = height; if (resized) { isPacked = false; } boolean needNotify = true; mixOnReshaping(); if (peer != null) { // LightwightPeer is an empty stub so can skip peer.reshape if (!(peer instanceof LightweightPeer)) { reshapeNativePeer(x, y, width, height, getBoundsOp()); // Check peer actualy changed coordinates resized = (oldWidth != this.width) || (oldHeight != this.height); moved = (oldX != this.x) || (oldY != this.y); // fix for 5025858: do not send ComponentEvents for toplevel // windows here as it is done from peer or native code when // the window is really resized or moved, otherwise some // events may be sent twice if (this instanceof Window) { needNotify = false; } } if (resized) { invalidate(); } if (parent != null) { parent.invalidateIfValid(); } } if (needNotify) { notifyNewBounds(resized, moved); } repaintParentIfNeeded(oldX, oldY, oldWidth, oldHeight); } finally { setBoundsOp(ComponentPeer.RESET_OPERATION); } } } private void repaintParentIfNeeded(int oldX, int oldY, int oldWidth, int oldHeight) { if (parent != null && peer instanceof LightweightPeer && isShowing()) { // Have the parent redraw the area this component occupied. parent.repaint(oldX, oldY, oldWidth, oldHeight); // Have the parent redraw the area this component *now* occupies. repaint(); } } private void reshapeNativePeer(int x, int y, int width, int height, int op) { // native peer might be offset by more than direct // parent since parent might be lightweight. int nativeX = x; int nativeY = y; for (Component c = parent; (c != null) && (c.peer instanceof LightweightPeer); c = c.parent) { nativeX += c.x; nativeY += c.y; } peer.setBounds(nativeX, nativeY, width, height, op); } @SuppressWarnings("deprecation") private void notifyNewBounds(boolean resized, boolean moved) { if (componentListener != null || (eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.COMPONENT_EVENT_MASK)) { if (resized) { ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_RESIZED); Toolkit.getEventQueue().postEvent(e); } if (moved) { ComponentEvent e = new ComponentEvent(this, ComponentEvent.COMPONENT_MOVED); Toolkit.getEventQueue().postEvent(e); } } else { if (this instanceof Container && ((Container)this).countComponents() > 0) { boolean enabledOnToolkit = Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK); if (resized) { ((Container)this).createChildHierarchyEvents( HierarchyEvent.ANCESTOR_RESIZED, 0, enabledOnToolkit); } if (moved) { ((Container)this).createChildHierarchyEvents( HierarchyEvent.ANCESTOR_MOVED, 0, enabledOnToolkit); } } } } /** * Moves and resizes this component to conform to the new * bounding rectangle r. This component's new * position is specified by r.x and r.y, * and its new size is specified by r.width and * r.height *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @param r the new bounding rectangle for this component * @throws NullPointerException if {@code r} is {@code null} * @see #getBounds * @see #setLocation(int, int) * @see #setLocation(Point) * @see #setSize(int, int) * @see #setSize(Dimension) * @see #invalidate * @since JDK1.1 */ public void setBounds(Rectangle r) { setBounds(r.x, r.y, r.width, r.height); } /** * Returns the current x coordinate of the components origin. * This method is preferable to writing * component.getBounds().x, * or component.getLocation().x because it doesn't * cause any heap allocations. * * @return the current x coordinate of the components origin * @since 1.2 */ public int getX() { return x; } /** * Returns the current y coordinate of the components origin. * This method is preferable to writing * component.getBounds().y, * or component.getLocation().y because it * doesn't cause any heap allocations. * * @return the current y coordinate of the components origin * @since 1.2 */ public int getY() { return y; } /** * Returns the current width of this component. * This method is preferable to writing * component.getBounds().width, * or component.getSize().width because it * doesn't cause any heap allocations. * * @return the current width of this component * @since 1.2 */ public int getWidth() { return width; } /** * Returns the current height of this component. * This method is preferable to writing * component.getBounds().height, * or component.getSize().height because it * doesn't cause any heap allocations. * * @return the current height of this component * @since 1.2 */ public int getHeight() { return height; } /** * Stores the bounds of this component into "return value" rv and * return rv. If rv is null a new * Rectangle is allocated. * This version of getBounds is useful if the caller * wants to avoid allocating a new Rectangle object * on the heap. * * @param rv the return value, modified to the components bounds * @return rv */ public Rectangle getBounds(Rectangle rv) { if (rv == null) { return new Rectangle(getX(), getY(), getWidth(), getHeight()); } else { rv.setBounds(getX(), getY(), getWidth(), getHeight()); return rv; } } /** * Stores the width/height of this component into "return value" rv * and return rv. If rv is null a new * Dimension object is allocated. This version of * getSize is useful if the caller wants to avoid * allocating a new Dimension object on the heap. * * @param rv the return value, modified to the components size * @return rv */ public Dimension getSize(Dimension rv) { if (rv == null) { return new Dimension(getWidth(), getHeight()); } else { rv.setSize(getWidth(), getHeight()); return rv; } } /** * Stores the x,y origin of this component into "return value" rv * and return rv. If rv is null a new * Point is allocated. * This version of getLocation is useful if the * caller wants to avoid allocating a new Point * object on the heap. * * @param rv the return value, modified to the components location * @return rv */ public Point getLocation(Point rv) { if (rv == null) { return new Point(getX(), getY()); } else { rv.setLocation(getX(), getY()); return rv; } } /** * Returns true if this component is completely opaque, returns * false by default. *

* An opaque component paints every pixel within its * rectangular region. A non-opaque component paints only some of * its pixels, allowing the pixels underneath it to "show through". * A component that does not fully paint its pixels therefore * provides a degree of transparency. *

* Subclasses that guarantee to always completely paint their * contents should override this method and return true. * * @return true if this component is completely opaque * @see #isLightweight * @since 1.2 */ public boolean isOpaque() { if (getPeer() == null) { return false; } else { return !isLightweight(); } } /** * A lightweight component doesn't have a native toolkit peer. * Subclasses of Component and Container, * other than the ones defined in this package like Button * or Scrollbar, are lightweight. * All of the Swing components are lightweights. *

* This method will always return false if this component * is not displayable because it is impossible to determine the * weight of an undisplayable component. * * @return true if this component has a lightweight peer; false if * it has a native peer or no peer * @see #isDisplayable * @since 1.2 */ public boolean isLightweight() { return getPeer() instanceof LightweightPeer; } /** * Sets the preferred size of this component to a constant * value. Subsequent calls to getPreferredSize will always * return this value. Setting the preferred size to null * restores the default behavior. * * @param preferredSize The new preferred size, or null * @see #getPreferredSize * @see #isPreferredSizeSet * @since 1.5 */ public void setPreferredSize(Dimension preferredSize) { Dimension old; // If the preferred size was set, use it as the old value, otherwise // use null to indicate we didn't previously have a set preferred // size. if (prefSizeSet) { old = this.prefSize; } else { old = null; } this.prefSize = preferredSize; prefSizeSet = (preferredSize != null); firePropertyChange("preferredSize", old, preferredSize); } /** * Returns true if the preferred size has been set to a * non-null value otherwise returns false. * * @return true if setPreferredSize has been invoked * with a non-null value. * @since 1.5 */ public boolean isPreferredSizeSet() { return prefSizeSet; } /** * Gets the preferred size of this component. * @return a dimension object indicating this component's preferred size * @see #getMinimumSize * @see LayoutManager */ public Dimension getPreferredSize() { return preferredSize(); } /** * @deprecated As of JDK version 1.1, * replaced by getPreferredSize(). */ @Deprecated public Dimension preferredSize() { /* Avoid grabbing the lock if a reasonable cached size value * is available. */ Dimension dim = prefSize; if (dim == null || !(isPreferredSizeSet() || isValid())) { synchronized (getTreeLock()) { prefSize = (peer != null) ? peer.getPreferredSize() : getMinimumSize(); dim = prefSize; } } return new Dimension(dim); } /** * Sets the minimum size of this component to a constant * value. Subsequent calls to getMinimumSize will always * return this value. Setting the minimum size to null * restores the default behavior. * * @param minimumSize the new minimum size of this component * @see #getMinimumSize * @see #isMinimumSizeSet * @since 1.5 */ public void setMinimumSize(Dimension minimumSize) { Dimension old; // If the minimum size was set, use it as the old value, otherwise // use null to indicate we didn't previously have a set minimum // size. if (minSizeSet) { old = this.minSize; } else { old = null; } this.minSize = minimumSize; minSizeSet = (minimumSize != null); firePropertyChange("minimumSize", old, minimumSize); } /** * Returns whether or not setMinimumSize has been * invoked with a non-null value. * * @return true if setMinimumSize has been invoked with a * non-null value. * @since 1.5 */ public boolean isMinimumSizeSet() { return minSizeSet; } /** * Gets the minimum size of this component. * @return a dimension object indicating this component's minimum size * @see #getPreferredSize * @see LayoutManager */ public Dimension getMinimumSize() { return minimumSize(); } /** * @deprecated As of JDK version 1.1, * replaced by getMinimumSize(). */ @Deprecated public Dimension minimumSize() { /* Avoid grabbing the lock if a reasonable cached size value * is available. */ Dimension dim = minSize; if (dim == null || !(isMinimumSizeSet() || isValid())) { synchronized (getTreeLock()) { minSize = (peer != null) ? peer.getMinimumSize() : size(); dim = minSize; } } return new Dimension(dim); } /** * Sets the maximum size of this component to a constant * value. Subsequent calls to getMaximumSize will always * return this value. Setting the maximum size to null * restores the default behavior. * * @param maximumSize a Dimension containing the * desired maximum allowable size * @see #getMaximumSize * @see #isMaximumSizeSet * @since 1.5 */ public void setMaximumSize(Dimension maximumSize) { // If the maximum size was set, use it as the old value, otherwise // use null to indicate we didn't previously have a set maximum // size. Dimension old; if (maxSizeSet) { old = this.maxSize; } else { old = null; } this.maxSize = maximumSize; maxSizeSet = (maximumSize != null); firePropertyChange("maximumSize", old, maximumSize); } /** * Returns true if the maximum size has been set to a non-null * value otherwise returns false. * * @return true if maximumSize is non-null, * false otherwise * @since 1.5 */ public boolean isMaximumSizeSet() { return maxSizeSet; } /** * Gets the maximum size of this component. * @return a dimension object indicating this component's maximum size * @see #getMinimumSize * @see #getPreferredSize * @see LayoutManager */ public Dimension getMaximumSize() { if (isMaximumSizeSet()) { return new Dimension(maxSize); } return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); } /** * Returns the alignment along the x axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. */ public float getAlignmentX() { return CENTER_ALIGNMENT; } /** * Returns the alignment along the y axis. This specifies how * the component would like to be aligned relative to other * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. */ public float getAlignmentY() { return CENTER_ALIGNMENT; } /** * Returns the baseline. The baseline is measured from the top of * the component. This method is primarily meant for * LayoutManagers to align components along their * baseline. A return value less than 0 indicates this component * does not have a reasonable baseline and that * LayoutManagers should not align this component on * its baseline. *

* The default implementation returns -1. Subclasses that support * baseline should override appropriately. If a value >= 0 is * returned, then the component has a valid baseline for any * size >= the minimum size and getBaselineResizeBehavior * can be used to determine how the baseline changes with size. * * @param width the width to get the baseline for * @param height the height to get the baseline for * @return the baseline or < 0 indicating there is no reasonable * baseline * @throws IllegalArgumentException if width or height is < 0 * @see #getBaselineResizeBehavior * @see java.awt.FontMetrics * @since 1.6 */ public int getBaseline(int width, int height) { if (width < 0 || height < 0) { throw new IllegalArgumentException( "Width and height must be >= 0"); } return -1; } /** * Returns an enum indicating how the baseline of the component * changes as the size changes. This method is primarily meant for * layout managers and GUI builders. *

* The default implementation returns * BaselineResizeBehavior.OTHER. Subclasses that have a * baseline should override appropriately. Subclasses should * never return null; if the baseline can not be * calculated return BaselineResizeBehavior.OTHER. Callers * should first ask for the baseline using * getBaseline and if a value >= 0 is returned use * this method. It is acceptable for this method to return a * value other than BaselineResizeBehavior.OTHER even if * getBaseline returns a value less than 0. * * @return an enum indicating how the baseline changes as the component * size changes * @see #getBaseline(int, int) * @since 1.6 */ public BaselineResizeBehavior getBaselineResizeBehavior() { return BaselineResizeBehavior.OTHER; } /** * Prompts the layout manager to lay out this component. This is * usually called when the component (more specifically, container) * is validated. * @see #validate * @see LayoutManager */ public void doLayout() { layout(); } /** * @deprecated As of JDK version 1.1, * replaced by doLayout(). */ @Deprecated public void layout() { } /** * Validates this component. *

* The meaning of the term validating is defined by the ancestors of * this class. See {@link Container#validate} for more details. * * @see #invalidate * @see #doLayout() * @see LayoutManager * @see Container#validate * @since JDK1.0 */ public void validate() { synchronized (getTreeLock()) { ComponentPeer peer = this.peer; boolean wasValid = isValid(); if (!wasValid && peer != null) { Font newfont = getFont(); Font oldfont = peerFont; if (newfont != oldfont && (oldfont == null || !oldfont.equals(newfont))) { peer.setFont(newfont); peerFont = newfont; } peer.layout(); } valid = true; if (!wasValid) { mixOnValidating(); } } } /** * Invalidates this component and its ancestors. *

* By default, all the ancestors of the component up to the top-most * container of the hierarchy are marked invalid. If the {@code * java.awt.smartInvalidate} system property is set to {@code true}, * invalidation stops on the nearest validate root of this component. * Marking a container invalid indicates that the container needs to * be laid out. *

* This method is called automatically when any layout-related information * changes (e.g. setting the bounds of the component, or adding the * component to a container). *

* This method might be called often, so it should work fast. * * @see #validate * @see #doLayout * @see LayoutManager * @see java.awt.Container#isValidateRoot * @since JDK1.0 */ public void invalidate() { synchronized (getTreeLock()) { /* Nullify cached layout and size information. * For efficiency, propagate invalidate() upwards only if * some other component hasn't already done so first. */ valid = false; if (!isPreferredSizeSet()) { prefSize = null; } if (!isMinimumSizeSet()) { minSize = null; } if (!isMaximumSizeSet()) { maxSize = null; } invalidateParent(); } } /** * Invalidates the parent of this component if any. * * This method MUST BE invoked under the TreeLock. */ void invalidateParent() { if (parent != null) { parent.invalidateIfValid(); } } /** Invalidates the component unless it is already invalid. */ final void invalidateIfValid() { if (isValid()) { invalidate(); } } /** * Revalidates the component hierarchy up to the nearest validate root. *

* This method first invalidates the component hierarchy starting from this * component up to the nearest validate root. Afterwards, the component * hierarchy is validated starting from the nearest validate root. *

* This is a convenience method supposed to help application developers * avoid looking for validate roots manually. Basically, it's equivalent to * first calling the {@link #invalidate()} method on this component, and * then calling the {@link #validate()} method on the nearest validate * root. * * @see Container#isValidateRoot * @since 1.7 */ public void revalidate() { revalidateSynchronously(); } /** * Revalidates the component synchronously. */ final void revalidateSynchronously() { synchronized (getTreeLock()) { invalidate(); Container root = getContainer(); if (root == null) { // There's no parents. Just validate itself. validate(); } else { while (!root.isValidateRoot()) { if (root.getContainer() == null) { // If there's no validate roots, we'll validate the // topmost container break; } root = root.getContainer(); } root.validate(); } } } /** * Creates a graphics context for this component. This method will * return null if this component is currently not * displayable. * @return a graphics context for this component, or null * if it has none * @see #paint * @since JDK1.0 */ public Graphics getGraphics() { if (peer instanceof LightweightPeer) { // This is for a lightweight component, need to // translate coordinate spaces and clip relative // to the parent. if (parent == null) return null; Graphics g = parent.getGraphics(); if (g == null) return null; if (g instanceof ConstrainableGraphics) { ((ConstrainableGraphics) g).constrain(x, y, width, height); } else { g.translate(x,y); g.setClip(0, 0, width, height); } g.setFont(getFont()); return g; } else { ComponentPeer peer = this.peer; return (peer != null) ? peer.getGraphics() : null; } } final Graphics getGraphics_NoClientCode() { ComponentPeer peer = this.peer; if (peer instanceof LightweightPeer) { // This is for a lightweight component, need to // translate coordinate spaces and clip relative // to the parent. Container parent = this.parent; if (parent == null) return null; Graphics g = parent.getGraphics_NoClientCode(); if (g == null) return null; if (g instanceof ConstrainableGraphics) { ((ConstrainableGraphics) g).constrain(x, y, width, height); } else { g.translate(x,y); g.setClip(0, 0, width, height); } g.setFont(getFont_NoClientCode()); return g; } else { return (peer != null) ? peer.getGraphics() : null; } } /** * Gets the font metrics for the specified font. * Warning: Since Font metrics are affected by the * {@link java.awt.font.FontRenderContext FontRenderContext} and * this method does not provide one, it can return only metrics for * the default render context which may not match that used when * rendering on the Component if {@link Graphics2D} functionality is being * used. Instead metrics can be obtained at rendering time by calling * {@link Graphics#getFontMetrics()} or text measurement APIs on the * {@link Font Font} class. * @param font the font for which font metrics is to be * obtained * @return the font metrics for font * @see #getFont * @see #getPeer * @see java.awt.peer.ComponentPeer#getFontMetrics(Font) * @see Toolkit#getFontMetrics(Font) * @since JDK1.0 */ public FontMetrics getFontMetrics(Font font) { // This is an unsupported hack, but left in for a customer. // Do not remove. FontManager fm = FontManagerFactory.getInstance(); if (fm instanceof SunFontManager && ((SunFontManager) fm).usePlatformFontMetrics()) { if (peer != null && !(peer instanceof LightweightPeer)) { return peer.getFontMetrics(font); } } return sun.font.FontDesignMetrics.getMetrics(font); } /** * Sets the cursor image to the specified cursor. This cursor * image is displayed when the contains method for * this component returns true for the current cursor location, and * this Component is visible, displayable, and enabled. Setting the * cursor of a Container causes that cursor to be displayed * within all of the container's subcomponents, except for those * that have a non-null cursor. *

* The method may have no visual effect if the Java platform * implementation and/or the native system do not support * changing the mouse cursor shape. * @param cursor One of the constants defined * by the Cursor class; * if this parameter is null * then this component will inherit * the cursor of its parent * @see #isEnabled * @see #isShowing * @see #getCursor * @see #contains * @see Toolkit#createCustomCursor * @see Cursor * @since JDK1.1 */ public void setCursor(Cursor cursor) { this.cursor = cursor; updateCursorImmediately(); } /** * Updates the cursor. May not be invoked from the native * message pump. */ final void updateCursorImmediately() { if (peer instanceof LightweightPeer) { Container nativeContainer = getNativeContainer(); if (nativeContainer == null) return; ComponentPeer cPeer = nativeContainer.getPeer(); if (cPeer != null) { cPeer.updateCursorImmediately(); } } else if (peer != null) { peer.updateCursorImmediately(); } } /** * Gets the cursor set in the component. If the component does * not have a cursor set, the cursor of its parent is returned. * If no cursor is set in the entire hierarchy, * Cursor.DEFAULT_CURSOR is returned. * @see #setCursor * @since JDK1.1 */ public Cursor getCursor() { return getCursor_NoClientCode(); } final Cursor getCursor_NoClientCode() { Cursor cursor = this.cursor; if (cursor != null) { return cursor; } Container parent = this.parent; if (parent != null) { return parent.getCursor_NoClientCode(); } else { return Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); } } /** * Returns whether the cursor has been explicitly set for this Component. * If this method returns false, this Component is inheriting * its cursor from an ancestor. * * @return true if the cursor has been explicitly set for this * Component; false otherwise. * @since 1.4 */ public boolean isCursorSet() { return (cursor != null); } /** * Paints this component. *

* This method is called when the contents of the component should * be painted; such as when the component is first being shown or * is damaged and in need of repair. The clip rectangle in the * Graphics parameter is set to the area * which needs to be painted. * Subclasses of Component that override this * method need not call super.paint(g). *

* For performance reasons, Components with zero width * or height aren't considered to need painting when they are first shown, * and also aren't considered to need repair. *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @param g the graphics context to use for painting * @see #update * @since JDK1.0 */ public void paint(Graphics g) { } /** * Updates this component. *

* If this component is not a lightweight component, the * AWT calls the update method in response to * a call to repaint. You can assume that * the background is not cleared. *

* The update method of Component * calls this component's paint method to redraw * this component. This method is commonly overridden by subclasses * which need to do additional work in response to a call to * repaint. * Subclasses of Component that override this method should either * call super.update(g), or call paint(g) * directly from their update method. *

* The origin of the graphics context, its * (00) coordinate point, is the * top-left corner of this component. The clipping region of the * graphics context is the bounding rectangle of this component. * *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @param g the specified context to use for updating * @see #paint * @see #repaint() * @since JDK1.0 */ public void update(Graphics g) { paint(g); } /** * Paints this component and all of its subcomponents. *

* The origin of the graphics context, its * (00) coordinate point, is the * top-left corner of this component. The clipping region of the * graphics context is the bounding rectangle of this component. * * @param g the graphics context to use for painting * @see #paint * @since JDK1.0 */ public void paintAll(Graphics g) { if (isShowing()) { GraphicsCallback.PeerPaintCallback.getInstance(). runOneComponent(this, new Rectangle(0, 0, width, height), g, g.getClip(), GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); } } /** * Simulates the peer callbacks into java.awt for painting of * lightweight Components. * @param g the graphics context to use for painting * @see #paintAll */ void lightweightPaint(Graphics g) { paint(g); } /** * Paints all the heavyweight subcomponents. */ void paintHeavyweightComponents(Graphics g) { } /** * Repaints this component. *

* If this component is a lightweight component, this method * causes a call to this component's paint * method as soon as possible. Otherwise, this method causes * a call to this component's update method as soon * as possible. *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @see #update(Graphics) * @since JDK1.0 */ public void repaint() { repaint(0, 0, 0, width, height); } /** * Repaints the component. If this component is a lightweight * component, this results in a call to paint * within tm milliseconds. *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @param tm maximum time in milliseconds before update * @see #paint * @see #update(Graphics) * @since JDK1.0 */ public void repaint(long tm) { repaint(tm, 0, 0, width, height); } /** * Repaints the specified rectangle of this component. *

* If this component is a lightweight component, this method * causes a call to this component's paint method * as soon as possible. Otherwise, this method causes a call to * this component's update method as soon as possible. *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @param x the x coordinate * @param y the y coordinate * @param width the width * @param height the height * @see #update(Graphics) * @since JDK1.0 */ public void repaint(int x, int y, int width, int height) { repaint(0, x, y, width, height); } /** * Repaints the specified rectangle of this component within * tm milliseconds. *

* If this component is a lightweight component, this method causes * a call to this component's paint method. * Otherwise, this method causes a call to this component's * update method. *

* Note: For more information on the paint mechanisms utilitized * by AWT and Swing, including information on how to write the most * efficient painting code, see * Painting in AWT and Swing. * * @param tm maximum time in milliseconds before update * @param x the x coordinate * @param y the y coordinate * @param width the width * @param height the height * @see #update(Graphics) * @since JDK1.0 */ public void repaint(long tm, int x, int y, int width, int height) { if (this.peer instanceof LightweightPeer) { // Needs to be translated to parent coordinates since // a parent native container provides the actual repaint // services. Additionally, the request is restricted to // the bounds of the component. if (parent != null) { if (x < 0) { width += x; x = 0; } if (y < 0) { height += y; y = 0; } int pwidth = (width > this.width) ? this.width : width; int pheight = (height > this.height) ? this.height : height; if (pwidth <= 0 || pheight <= 0) { return; } int px = this.x + x; int py = this.y + y; parent.repaint(tm, px, py, pwidth, pheight); } } else { if (isVisible() && (this.peer != null) && (width > 0) && (height > 0)) { PaintEvent e = new PaintEvent(this, PaintEvent.UPDATE, new Rectangle(x, y, width, height)); SunToolkit.postEvent(SunToolkit.targetToAppContext(this), e); } } } /** * Prints this component. Applications should override this method * for components that must do special processing before being * printed or should be printed differently than they are painted. *

* The default implementation of this method calls the * paint method. *

* The origin of the graphics context, its * (00) coordinate point, is the * top-left corner of this component. The clipping region of the * graphics context is the bounding rectangle of this component. * @param g the graphics context to use for printing * @see #paint(Graphics) * @since JDK1.0 */ public void print(Graphics g) { paint(g); } /** * Prints this component and all of its subcomponents. *

* The origin of the graphics context, its * (00) coordinate point, is the * top-left corner of this component. The clipping region of the * graphics context is the bounding rectangle of this component. * @param g the graphics context to use for printing * @see #print(Graphics) * @since JDK1.0 */ public void printAll(Graphics g) { if (isShowing()) { GraphicsCallback.PeerPrintCallback.getInstance(). runOneComponent(this, new Rectangle(0, 0, width, height), g, g.getClip(), GraphicsCallback.LIGHTWEIGHTS | GraphicsCallback.HEAVYWEIGHTS); } } /** * Simulates the peer callbacks into java.awt for printing of * lightweight Components. * @param g the graphics context to use for printing * @see #printAll */ void lightweightPrint(Graphics g) { print(g); } /** * Prints all the heavyweight subcomponents. */ void printHeavyweightComponents(Graphics g) { } private Insets getInsets_NoClientCode() { ComponentPeer peer = this.peer; if (peer instanceof ContainerPeer) { return (Insets)((ContainerPeer)peer).getInsets().clone(); } return new Insets(0, 0, 0, 0); } /** * Repaints the component when the image has changed. * This imageUpdate method of an ImageObserver * is called when more information about an * image which had been previously requested using an asynchronous * routine such as the drawImage method of * Graphics becomes available. * See the definition of imageUpdate for * more information on this method and its arguments. *

* The imageUpdate method of Component * incrementally draws an image on the component as more of the bits * of the image are available. *

* If the system property awt.image.incrementaldraw * is missing or has the value true, the image is * incrementally drawn. If the system property has any other value, * then the image is not drawn until it has been completely loaded. *

* Also, if incremental drawing is in effect, the value of the * system property awt.image.redrawrate is interpreted * as an integer to give the maximum redraw rate, in milliseconds. If * the system property is missing or cannot be interpreted as an * integer, the redraw rate is once every 100ms. *

* The interpretation of the x, y, * width, and height arguments depends on * the value of the infoflags argument. * * @param img the image being observed * @param infoflags see imageUpdate for more information * @param x the x coordinate * @param y the y coordinate * @param w the width * @param h the height * @return false if the infoflags indicate that the * image is completely loaded; true otherwise. * * @see java.awt.image.ImageObserver * @see Graphics#drawImage(Image, int, int, Color, java.awt.image.ImageObserver) * @see Graphics#drawImage(Image, int, int, java.awt.image.ImageObserver) * @see Graphics#drawImage(Image, int, int, int, int, Color, java.awt.image.ImageObserver) * @see Graphics#drawImage(Image, int, int, int, int, java.awt.image.ImageObserver) * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since JDK1.0 */ public boolean imageUpdate(Image img, int infoflags, int x, int y, int w, int h) { int rate = -1; if ((infoflags & (FRAMEBITS|ALLBITS)) != 0) { rate = 0; } else if ((infoflags & SOMEBITS) != 0) { if (isInc) { rate = incRate; if (rate < 0) { rate = 0; } } } if (rate >= 0) { repaint(rate, 0, 0, width, height); } return (infoflags & (ALLBITS|ABORT)) == 0; } /** * Creates an image from the specified image producer. * @param producer the image producer * @return the image produced * @since JDK1.0 */ public Image createImage(ImageProducer producer) { ComponentPeer peer = this.peer; if ((peer != null) && ! (peer instanceof LightweightPeer)) { return peer.createImage(producer); } return getToolkit().createImage(producer); } /** * Creates an off-screen drawable image * to be used for double buffering. * @param width the specified width * @param height the specified height * @return an off-screen drawable image, which can be used for double * buffering. The return value may be null if the * component is not displayable. This will always happen if * GraphicsEnvironment.isHeadless() returns * true. * @see #isDisplayable * @see GraphicsEnvironment#isHeadless * @since JDK1.0 */ public Image createImage(int width, int height) { ComponentPeer peer = this.peer; if (peer instanceof LightweightPeer) { if (parent != null) { return parent.createImage(width, height); } else { return null;} } else { return (peer != null) ? peer.createImage(width, height) : null; } } /** * Creates a volatile off-screen drawable image * to be used for double buffering. * @param width the specified width. * @param height the specified height. * @return an off-screen drawable image, which can be used for double * buffering. The return value may be null if the * component is not displayable. This will always happen if * GraphicsEnvironment.isHeadless() returns * true. * @see java.awt.image.VolatileImage * @see #isDisplayable * @see GraphicsEnvironment#isHeadless * @since 1.4 */ public VolatileImage createVolatileImage(int width, int height) { ComponentPeer peer = this.peer; if (peer instanceof LightweightPeer) { if (parent != null) { return parent.createVolatileImage(width, height); } else { return null;} } else { return (peer != null) ? peer.createVolatileImage(width, height) : null; } } /** * Creates a volatile off-screen drawable image, with the given capabilities. * The contents of this image may be lost at any time due * to operating system issues, so the image must be managed * via the VolatileImage interface. * @param width the specified width. * @param height the specified height. * @param caps the image capabilities * @exception AWTException if an image with the specified capabilities cannot * be created * @return a VolatileImage object, which can be used * to manage surface contents loss and capabilities. * @see java.awt.image.VolatileImage * @since 1.4 */ public VolatileImage createVolatileImage(int width, int height, ImageCapabilities caps) throws AWTException { // REMIND : check caps return createVolatileImage(width, height); } /** * Prepares an image for rendering on this component. The image * data is downloaded asynchronously in another thread and the * appropriate screen representation of the image is generated. * @param image the Image for which to * prepare a screen representation * @param observer the ImageObserver object * to be notified as the image is being prepared * @return true if the image has already been fully * prepared; false otherwise * @since JDK1.0 */ public boolean prepareImage(Image image, ImageObserver observer) { return prepareImage(image, -1, -1, observer); } /** * Prepares an image for rendering on this component at the * specified width and height. *

* The image data is downloaded asynchronously in another thread, * and an appropriately scaled screen representation of the image is * generated. * @param image the instance of Image * for which to prepare a screen representation * @param width the width of the desired screen representation * @param height the height of the desired screen representation * @param observer the ImageObserver object * to be notified as the image is being prepared * @return true if the image has already been fully * prepared; false otherwise * @see java.awt.image.ImageObserver * @since JDK1.0 */ public boolean prepareImage(Image image, int width, int height, ImageObserver observer) { ComponentPeer peer = this.peer; if (peer instanceof LightweightPeer) { return (parent != null) ? parent.prepareImage(image, width, height, observer) : getToolkit().prepareImage(image, width, height, observer); } else { return (peer != null) ? peer.prepareImage(image, width, height, observer) : getToolkit().prepareImage(image, width, height, observer); } } /** * Returns the status of the construction of a screen representation * of the specified image. *

* This method does not cause the image to begin loading. An * application must use the prepareImage method * to force the loading of an image. *

* Information on the flags returned by this method can be found * with the discussion of the ImageObserver interface. * @param image the Image object whose status * is being checked * @param observer the ImageObserver * object to be notified as the image is being prepared * @return the bitwise inclusive OR of * ImageObserver flags indicating what * information about the image is currently available * @see #prepareImage(Image, int, int, java.awt.image.ImageObserver) * @see Toolkit#checkImage(Image, int, int, java.awt.image.ImageObserver) * @see java.awt.image.ImageObserver * @since JDK1.0 */ public int checkImage(Image image, ImageObserver observer) { return checkImage(image, -1, -1, observer); } /** * Returns the status of the construction of a screen representation * of the specified image. *

* This method does not cause the image to begin loading. An * application must use the prepareImage method * to force the loading of an image. *

* The checkImage method of Component * calls its peer's checkImage method to calculate * the flags. If this component does not yet have a peer, the * component's toolkit's checkImage method is called * instead. *

* Information on the flags returned by this method can be found * with the discussion of the ImageObserver interface. * @param image the Image object whose status * is being checked * @param width the width of the scaled version * whose status is to be checked * @param height the height of the scaled version * whose status is to be checked * @param observer the ImageObserver object * to be notified as the image is being prepared * @return the bitwise inclusive OR of * ImageObserver flags indicating what * information about the image is currently available * @see #prepareImage(Image, int, int, java.awt.image.ImageObserver) * @see Toolkit#checkImage(Image, int, int, java.awt.image.ImageObserver) * @see java.awt.image.ImageObserver * @since JDK1.0 */ public int checkImage(Image image, int width, int height, ImageObserver observer) { ComponentPeer peer = this.peer; if (peer instanceof LightweightPeer) { return (parent != null) ? parent.checkImage(image, width, height, observer) : getToolkit().checkImage(image, width, height, observer); } else { return (peer != null) ? peer.checkImage(image, width, height, observer) : getToolkit().checkImage(image, width, height, observer); } } /** * Creates a new strategy for multi-buffering on this component. * Multi-buffering is useful for rendering performance. This method * attempts to create the best strategy available with the number of * buffers supplied. It will always create a BufferStrategy * with that number of buffers. * A page-flipping strategy is attempted first, then a blitting strategy * using accelerated buffers. Finally, an unaccelerated blitting * strategy is used. *

* Each time this method is called, * the existing buffer strategy for this component is discarded. * @param numBuffers number of buffers to create, including the front buffer * @exception IllegalArgumentException if numBuffers is less than 1. * @exception IllegalStateException if the component is not displayable * @see #isDisplayable * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() * @since 1.4 */ void createBufferStrategy(int numBuffers) { BufferCapabilities bufferCaps; if (numBuffers > 1) { // Try to create a page-flipping strategy bufferCaps = new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), BufferCapabilities.FlipContents.UNDEFINED); try { createBufferStrategy(numBuffers, bufferCaps); return; // Success } catch (AWTException e) { // Failed } } // Try a blitting (but still accelerated) strategy bufferCaps = new BufferCapabilities(new ImageCapabilities(true), new ImageCapabilities(true), null); try { createBufferStrategy(numBuffers, bufferCaps); return; // Success } catch (AWTException e) { // Failed } // Try an unaccelerated blitting strategy bufferCaps = new BufferCapabilities(new ImageCapabilities(false), new ImageCapabilities(false), null); try { createBufferStrategy(numBuffers, bufferCaps); return; // Success } catch (AWTException e) { // Code should never reach here (an unaccelerated blitting // strategy should always work) throw new InternalError("Could not create a buffer strategy", e); } } /** * Creates a new strategy for multi-buffering on this component with the * required buffer capabilities. This is useful, for example, if only * accelerated memory or page flipping is desired (as specified by the * buffer capabilities). *

* Each time this method * is called, dispose will be invoked on the existing * BufferStrategy. * @param numBuffers number of buffers to create * @param caps the required capabilities for creating the buffer strategy; * cannot be null * @exception AWTException if the capabilities supplied could not be * supported or met; this may happen, for example, if there is not enough * accelerated memory currently available, or if page flipping is specified * but not possible. * @exception IllegalArgumentException if numBuffers is less than 1, or if * caps is null * @see Window#getBufferStrategy() * @see Canvas#getBufferStrategy() * @since 1.4 */ void createBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { // Check arguments if (numBuffers < 1) { throw new IllegalArgumentException( "Number of buffers must be at least 1"); } if (caps == null) { throw new IllegalArgumentException("No capabilities specified"); } // Destroy old buffers if (bufferStrategy != null) { bufferStrategy.dispose(); } if (numBuffers == 1) { bufferStrategy = new SingleBufferStrategy(caps); } else { SunGraphicsEnvironment sge = (SunGraphicsEnvironment) GraphicsEnvironment.getLocalGraphicsEnvironment(); if (!caps.isPageFlipping() && sge.isFlipStrategyPreferred(peer)) { caps = new ProxyCapabilities(caps); } // assert numBuffers > 1; if (caps.isPageFlipping()) { bufferStrategy = new FlipSubRegionBufferStrategy(numBuffers, caps); } else { bufferStrategy = new BltSubRegionBufferStrategy(numBuffers, caps); } } } /** * This is a proxy capabilities class used when a FlipBufferStrategy * is created instead of the requested Blit strategy. * * @see sun.java2d.SunGraphicsEnvironment#isFlipStrategyPreferred(ComponentPeer) */ private class ProxyCapabilities extends ExtendedBufferCapabilities { private BufferCapabilities orig; private ProxyCapabilities(BufferCapabilities orig) { super(orig.getFrontBufferCapabilities(), orig.getBackBufferCapabilities(), orig.getFlipContents() == BufferCapabilities.FlipContents.BACKGROUND ? BufferCapabilities.FlipContents.BACKGROUND : BufferCapabilities.FlipContents.COPIED); this.orig = orig; } } /** * @return the buffer strategy used by this component * @see Window#createBufferStrategy * @see Canvas#createBufferStrategy * @since 1.4 */ BufferStrategy getBufferStrategy() { return bufferStrategy; } /** * @return the back buffer currently used by this component's * BufferStrategy. If there is no BufferStrategy or no * back buffer, this method returns null. */ Image getBackBuffer() { if (bufferStrategy != null) { if (bufferStrategy instanceof BltBufferStrategy) { BltBufferStrategy bltBS = (BltBufferStrategy)bufferStrategy; return bltBS.getBackBuffer(); } else if (bufferStrategy instanceof FlipBufferStrategy) { FlipBufferStrategy flipBS = (FlipBufferStrategy)bufferStrategy; return flipBS.getBackBuffer(); } } return null; } /** * Inner class for flipping buffers on a component. That component must * be a Canvas or Window. * @see Canvas * @see Window * @see java.awt.image.BufferStrategy * @author Michael Martak * @since 1.4 */ protected class FlipBufferStrategy extends BufferStrategy { /** * The number of buffers */ protected int numBuffers; // = 0 /** * The buffering capabilities */ protected BufferCapabilities caps; // = null /** * The drawing buffer */ protected Image drawBuffer; // = null /** * The drawing buffer as a volatile image */ protected VolatileImage drawVBuffer; // = null /** * Whether or not the drawing buffer has been recently restored from * a lost state. */ protected boolean validatedContents; // = false /** * Size of the back buffers. (Note: these fields were added in 6.0 * but kept package-private to avoid exposing them in the spec. * None of these fields/methods really should have been marked * protected when they were introduced in 1.4, but now we just have * to live with that decision.) */ int width; int height; /** * Creates a new flipping buffer strategy for this component. * The component must be a Canvas or Window. * @see Canvas * @see Window * @param numBuffers the number of buffers * @param caps the capabilities of the buffers * @exception AWTException if the capabilities supplied could not be * supported or met * @exception ClassCastException if the component is not a canvas or * window. * @exception IllegalStateException if the component has no peer * @exception IllegalArgumentException if {@code numBuffers} is less than two, * or if {@code BufferCapabilities.isPageFlipping} is not * {@code true}. * @see #createBuffers(int, BufferCapabilities) */ protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { if (!(Component.this instanceof Window) && !(Component.this instanceof Canvas)) { throw new ClassCastException( "Component must be a Canvas or Window"); } this.numBuffers = numBuffers; this.caps = caps; createBuffers(numBuffers, caps); } /** * Creates one or more complex, flipping buffers with the given * capabilities. * @param numBuffers number of buffers to create; must be greater than * one * @param caps the capabilities of the buffers. * BufferCapabilities.isPageFlipping must be * true. * @exception AWTException if the capabilities supplied could not be * supported or met * @exception IllegalStateException if the component has no peer * @exception IllegalArgumentException if numBuffers is less than two, * or if BufferCapabilities.isPageFlipping is not * true. * @see java.awt.BufferCapabilities#isPageFlipping() */ protected void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException { if (numBuffers < 2) { throw new IllegalArgumentException( "Number of buffers cannot be less than two"); } else if (peer == null) { throw new IllegalStateException( "Component must have a valid peer"); } else if (caps == null || !caps.isPageFlipping()) { throw new IllegalArgumentException( "Page flipping capabilities must be specified"); } // save the current bounds width = getWidth(); height = getHeight(); if (drawBuffer != null) { // dispose the existing backbuffers drawBuffer = null; drawVBuffer = null; destroyBuffers(); // ... then recreate the backbuffers } if (caps instanceof ExtendedBufferCapabilities) { ExtendedBufferCapabilities ebc = (ExtendedBufferCapabilities)caps; if (ebc.getVSync() == VSYNC_ON) { // if this buffer strategy is not allowed to be v-synced, // change the caps that we pass to the peer but keep on // trying to create v-synced buffers; // do not throw IAE here in case it is disallowed, see // ExtendedBufferCapabilities for more info if (!VSyncedBSManager.vsyncAllowed(this)) { caps = ebc.derive(VSYNC_DEFAULT); } } } peer.createBuffers(numBuffers, caps); updateInternalBuffers(); } /** * Updates internal buffers (both volatile and non-volatile) * by requesting the back-buffer from the peer. */ private void updateInternalBuffers() { // get the images associated with the draw buffer drawBuffer = getBackBuffer(); if (drawBuffer instanceof VolatileImage) { drawVBuffer = (VolatileImage)drawBuffer; } else { drawVBuffer = null; } } /** * @return direct access to the back buffer, as an image. * @exception IllegalStateException if the buffers have not yet * been created */ protected Image getBackBuffer() { if (peer != null) { return peer.getBackBuffer(); } else { throw new IllegalStateException( "Component must have a valid peer"); } } /** * Flipping moves the contents of the back buffer to the front buffer, * either by copying or by moving the video pointer. * @param flipAction an integer value describing the flipping action * for the contents of the back buffer. This should be one of the * values of the BufferCapabilities.FlipContents * property. * @exception IllegalStateException if the buffers have not yet * been created * @see java.awt.BufferCapabilities#getFlipContents() */ protected void flip(BufferCapabilities.FlipContents flipAction) { if (peer != null) { Image backBuffer = getBackBuffer(); if (backBuffer != null) { peer.flip(0, 0, backBuffer.getWidth(null), backBuffer.getHeight(null), flipAction); } } else { throw new IllegalStateException( "Component must have a valid peer"); } } void flipSubRegion(int x1, int y1, int x2, int y2, BufferCapabilities.FlipContents flipAction) { if (peer != null) { peer.flip(x1, y1, x2, y2, flipAction); } else { throw new IllegalStateException( "Component must have a valid peer"); } } /** * Destroys the buffers created through this object */ protected void destroyBuffers() { VSyncedBSManager.releaseVsync(this); if (peer != null) { peer.destroyBuffers(); } else { throw new IllegalStateException( "Component must have a valid peer"); } } /** * @return the buffering capabilities of this strategy */ public BufferCapabilities getCapabilities() { if (caps instanceof ProxyCapabilities) { return ((ProxyCapabilities)caps).orig; } else { return caps; } } /** * @return the graphics on the drawing buffer. This method may not * be synchronized for performance reasons; use of this method by multiple * threads should be handled at the application level. Disposal of the * graphics object must be handled by the application. */ public Graphics getDrawGraphics() { revalidate(); return drawBuffer.getGraphics(); } /** * Restore the drawing buffer if it has been lost */ protected void revalidate() { revalidate(true); } void revalidate(boolean checkSize) { validatedContents = false; if (checkSize && (getWidth() != width || getHeight() != height)) { // component has been resized; recreate the backbuffers try { createBuffers(numBuffers, caps); } catch (AWTException e) { // shouldn't be possible } validatedContents = true; } // get the buffers from the peer every time since they // might have been replaced in response to a display change event updateInternalBuffers(); // now validate the backbuffer if (drawVBuffer != null) { GraphicsConfiguration gc = getGraphicsConfiguration_NoClientCode(); int returnCode = drawVBuffer.validate(gc); if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) { try { createBuffers(numBuffers, caps); } catch (AWTException e) { // shouldn't be possible } if (drawVBuffer != null) { // backbuffers were recreated, so validate again drawVBuffer.validate(gc); } validatedContents = true; } else if (returnCode == VolatileImage.IMAGE_RESTORED) { validatedContents = true; } } } /** * @return whether the drawing buffer was lost since the last call to * getDrawGraphics */ public boolean contentsLost() { if (drawVBuffer == null) { return false; } return drawVBuffer.contentsLost(); } /** * @return whether the drawing buffer was recently restored from a lost * state and reinitialized to the default background color (white) */ public boolean contentsRestored() { return validatedContents; } /** * Makes the next available buffer visible by either blitting or * flipping. */ public void show() { flip(caps.getFlipContents()); } /** * Makes specified region of the the next available buffer visible * by either blitting or flipping. */ void showSubRegion(int x1, int y1, int x2, int y2) { flipSubRegion(x1, y1, x2, y2, caps.getFlipContents()); } /** * {@inheritDoc} * @since 1.6 */ public void dispose() { if (Component.this.bufferStrategy == this) { Component.this.bufferStrategy = null; if (peer != null) { destroyBuffers(); } } } } // Inner class FlipBufferStrategy /** * Inner class for blitting offscreen surfaces to a component. * * @author Michael Martak * @since 1.4 */ protected class BltBufferStrategy extends BufferStrategy { /** * The buffering capabilities */ protected BufferCapabilities caps; // = null /** * The back buffers */ protected VolatileImage[] backBuffers; // = null /** * Whether or not the drawing buffer has been recently restored from * a lost state. */ protected boolean validatedContents; // = false /** * Size of the back buffers */ protected int width; protected int height; /** * Insets for the hosting Component. The size of the back buffer * is constrained by these. */ private Insets insets; /** * Creates a new blt buffer strategy around a component * @param numBuffers number of buffers to create, including the * front buffer * @param caps the capabilities of the buffers */ protected BltBufferStrategy(int numBuffers, BufferCapabilities caps) { this.caps = caps; createBackBuffers(numBuffers - 1); } /** * {@inheritDoc} * @since 1.6 */ public void dispose() { if (backBuffers != null) { for (int counter = backBuffers.length - 1; counter >= 0; counter--) { if (backBuffers[counter] != null) { backBuffers[counter].flush(); backBuffers[counter] = null; } } } if (Component.this.bufferStrategy == this) { Component.this.bufferStrategy = null; } } /** * Creates the back buffers */ protected void createBackBuffers(int numBuffers) { if (numBuffers == 0) { backBuffers = null; } else { // save the current bounds width = getWidth(); height = getHeight(); insets = getInsets_NoClientCode(); int iWidth = width - insets.left - insets.right; int iHeight = height - insets.top - insets.bottom; // It is possible for the component's width and/or height // to be 0 here. Force the size of the backbuffers to // be > 0 so that creating the image won't fail. iWidth = Math.max(1, iWidth); iHeight = Math.max(1, iHeight); if (backBuffers == null) { backBuffers = new VolatileImage[numBuffers]; } else { // flush any existing backbuffers for (int i = 0; i < numBuffers; i++) { if (backBuffers[i] != null) { backBuffers[i].flush(); backBuffers[i] = null; } } } // create the backbuffers for (int i = 0; i < numBuffers; i++) { backBuffers[i] = createVolatileImage(iWidth, iHeight); } } } /** * @return the buffering capabilities of this strategy */ public BufferCapabilities getCapabilities() { return caps; } /** * @return the draw graphics */ public Graphics getDrawGraphics() { revalidate(); Image backBuffer = getBackBuffer(); if (backBuffer == null) { return getGraphics(); } SunGraphics2D g = (SunGraphics2D)backBuffer.getGraphics(); g.constrain(-insets.left, -insets.top, backBuffer.getWidth(null) + insets.left, backBuffer.getHeight(null) + insets.top); return g; } /** * @return direct access to the back buffer, as an image. * If there is no back buffer, returns null. */ Image getBackBuffer() { if (backBuffers != null) { return backBuffers[backBuffers.length - 1]; } else { return null; } } /** * Makes the next available buffer visible. */ public void show() { showSubRegion(insets.left, insets.top, width - insets.right, height - insets.bottom); } /** * Package-private method to present a specific rectangular area * of this buffer. This class currently shows only the entire * buffer, by calling showSubRegion() with the full dimensions of * the buffer. Subclasses (e.g., BltSubRegionBufferStrategy * and FlipSubRegionBufferStrategy) may have region-specific show * methods that call this method with actual sub regions of the * buffer. */ void showSubRegion(int x1, int y1, int x2, int y2) { if (backBuffers == null) { return; } // Adjust location to be relative to client area. x1 -= insets.left; x2 -= insets.left; y1 -= insets.top; y2 -= insets.top; Graphics g = getGraphics_NoClientCode(); if (g == null) { // Not showing, bail return; } try { // First image copy is in terms of Frame's coordinates, need // to translate to client area. g.translate(insets.left, insets.top); for (int i = 0; i < backBuffers.length; i++) { g.drawImage(backBuffers[i], x1, y1, x2, y2, x1, y1, x2, y2, null); g.dispose(); g = null; g = backBuffers[i].getGraphics(); } } finally { if (g != null) { g.dispose(); } } } /** * Restore the drawing buffer if it has been lost */ protected void revalidate() { revalidate(true); } void revalidate(boolean checkSize) { validatedContents = false; if (backBuffers == null) { return; } if (checkSize) { Insets insets = getInsets_NoClientCode(); if (getWidth() != width || getHeight() != height || !insets.equals(this.insets)) { // component has been resized; recreate the backbuffers createBackBuffers(backBuffers.length); validatedContents = true; } } // now validate the backbuffer GraphicsConfiguration gc = getGraphicsConfiguration_NoClientCode(); int returnCode = backBuffers[backBuffers.length - 1].validate(gc); if (returnCode == VolatileImage.IMAGE_INCOMPATIBLE) { if (checkSize) { createBackBuffers(backBuffers.length); // backbuffers were recreated, so validate again backBuffers[backBuffers.length - 1].validate(gc); } // else case means we're called from Swing on the toolkit // thread, don't recreate buffers as that'll deadlock // (creating VolatileImages invokes getting GraphicsConfig // which grabs treelock). validatedContents = true; } else if (returnCode == VolatileImage.IMAGE_RESTORED) { validatedContents = true; } } /** * @return whether the drawing buffer was lost since the last call to * getDrawGraphics */ public boolean contentsLost() { if (backBuffers == null) { return false; } else { return backBuffers[backBuffers.length - 1].contentsLost(); } } /** * @return whether the drawing buffer was recently restored from a lost * state and reinitialized to the default background color (white) */ public boolean contentsRestored() { return validatedContents; } } // Inner class BltBufferStrategy /** * Private class to perform sub-region flipping. */ private class FlipSubRegionBufferStrategy extends FlipBufferStrategy implements SubRegionShowable { protected FlipSubRegionBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { super(numBuffers, caps); } public void show(int x1, int y1, int x2, int y2) { showSubRegion(x1, y1, x2, y2); } // This is invoked by Swing on the toolkit thread. public boolean showIfNotLost(int x1, int y1, int x2, int y2) { if (!contentsLost()) { showSubRegion(x1, y1, x2, y2); return !contentsLost(); } return false; } } /** * Private class to perform sub-region blitting. Swing will use * this subclass via the SubRegionShowable interface in order to * copy only the area changed during a repaint. * See javax.swing.BufferStrategyPaintManager. */ private class BltSubRegionBufferStrategy extends BltBufferStrategy implements SubRegionShowable { protected BltSubRegionBufferStrategy(int numBuffers, BufferCapabilities caps) { super(numBuffers, caps); } public void show(int x1, int y1, int x2, int y2) { showSubRegion(x1, y1, x2, y2); } // This method is called by Swing on the toolkit thread. public boolean showIfNotLost(int x1, int y1, int x2, int y2) { if (!contentsLost()) { showSubRegion(x1, y1, x2, y2); return !contentsLost(); } return false; } } /** * Inner class for flipping buffers on a component. That component must * be a Canvas or Window. * @see Canvas * @see Window * @see java.awt.image.BufferStrategy * @author Michael Martak * @since 1.4 */ private class SingleBufferStrategy extends BufferStrategy { private BufferCapabilities caps; public SingleBufferStrategy(BufferCapabilities caps) { this.caps = caps; } public BufferCapabilities getCapabilities() { return caps; } public Graphics getDrawGraphics() { return getGraphics(); } public boolean contentsLost() { return false; } public boolean contentsRestored() { return false; } public void show() { // Do nothing } } // Inner class SingleBufferStrategy /** * Sets whether or not paint messages received from the operating system * should be ignored. This does not affect paint events generated in * software by the AWT, unless they are an immediate response to an * OS-level paint message. *

* This is useful, for example, if running under full-screen mode and * better performance is desired, or if page-flipping is used as the * buffer strategy. * * @since 1.4 * @see #getIgnoreRepaint * @see Canvas#createBufferStrategy * @see Window#createBufferStrategy * @see java.awt.image.BufferStrategy * @see GraphicsDevice#setFullScreenWindow */ public void setIgnoreRepaint(boolean ignoreRepaint) { this.ignoreRepaint = ignoreRepaint; } /** * @return whether or not paint messages received from the operating system * should be ignored. * * @since 1.4 * @see #setIgnoreRepaint */ public boolean getIgnoreRepaint() { return ignoreRepaint; } /** * Checks whether this component "contains" the specified point, * where x and y are defined to be * relative to the coordinate system of this component. * @param x the x coordinate of the point * @param y the y coordinate of the point * @see #getComponentAt(int, int) * @since JDK1.1 */ public boolean contains(int x, int y) { return inside(x, y); } /** * @deprecated As of JDK version 1.1, * replaced by contains(int, int). */ @Deprecated public boolean inside(int x, int y) { return (x >= 0) && (x < width) && (y >= 0) && (y < height); } /** * Checks whether this component "contains" the specified point, * where the point's x and y coordinates are defined * to be relative to the coordinate system of this component. * @param p the point * @throws NullPointerException if {@code p} is {@code null} * @see #getComponentAt(Point) * @since JDK1.1 */ public boolean contains(Point p) { return contains(p.x, p.y); } /** * Determines if this component or one of its immediate * subcomponents contains the (xy) location, * and if so, returns the containing component. This method only * looks one level deep. If the point (xy) is * inside a subcomponent that itself has subcomponents, it does not * go looking down the subcomponent tree. *

* The locate method of Component simply * returns the component itself if the (xy) * coordinate location is inside its bounding box, and null * otherwise. * @param x the x coordinate * @param y the y coordinate * @return the component or subcomponent that contains the * (xy) location; * null if the location * is outside this component * @see #contains(int, int) * @since JDK1.0 */ public Component getComponentAt(int x, int y) { return locate(x, y); } /** * @deprecated As of JDK version 1.1, * replaced by getComponentAt(int, int). */ @Deprecated public Component locate(int x, int y) { return contains(x, y) ? this : null; } /** * Returns the component or subcomponent that contains the * specified point. * @param p the point * @see java.awt.Component#contains * @since JDK1.1 */ public Component getComponentAt(Point p) { return getComponentAt(p.x, p.y); } /** * @deprecated As of JDK version 1.1, * replaced by dispatchEvent(AWTEvent e). */ @Deprecated public void deliverEvent(Event e) { postEvent(e); } /** * Dispatches an event to this component or one of its sub components. * Calls processEvent before returning for 1.1-style * events which have been enabled for the Component. * @param e the event */ public final void dispatchEvent(AWTEvent e) { dispatchEventImpl(e); } @SuppressWarnings("deprecation") void dispatchEventImpl(AWTEvent e) { int id = e.getID(); // Check that this component belongs to this app-context AppContext compContext = appContext; if (compContext != null && !compContext.equals(AppContext.getAppContext())) { if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { eventLog.fine("Event " + e + " is being dispatched on the wrong AppContext"); } } if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { eventLog.finest("{0}", e); } /* * 0. Set timestamp and modifiers of current event. */ if (!(e instanceof KeyEvent)) { // Timestamp of a key event is set later in DKFM.preDispatchKeyEvent(KeyEvent). EventQueue.setCurrentEventAndMostRecentTime(e); } /* * 1. Pre-dispatchers. Do any necessary retargeting/reordering here * before we notify AWTEventListeners. */ if (e instanceof SunDropTargetEvent) { ((SunDropTargetEvent)e).dispatch(); return; } if (!e.focusManagerIsDispatching) { // Invoke the private focus retargeting method which provides // lightweight Component support if (e.isPosted) { e = KeyboardFocusManager.retargetFocusEvent(e); e.isPosted = true; } // Now, with the event properly targeted to a lightweight // descendant if necessary, invoke the public focus retargeting // and dispatching function if (KeyboardFocusManager.getCurrentKeyboardFocusManager(). dispatchEvent(e)) { return; } } if ((e instanceof FocusEvent) && focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("" + e); } // MouseWheel may need to be retargeted here so that // AWTEventListener sees the event go to the correct // Component. If the MouseWheelEvent needs to go to an ancestor, // the event is dispatched to the ancestor, and dispatching here // stops. if (id == MouseEvent.MOUSE_WHEEL && (!eventTypeEnabled(id)) && (peer != null && !peer.handlesWheelScrolling()) && (dispatchMouseWheelToAncestor((MouseWheelEvent)e))) { return; } /* * 2. Allow the Toolkit to pass this to AWTEventListeners. */ Toolkit toolkit = Toolkit.getDefaultToolkit(); toolkit.notifyAWTEventListeners(e); /* * 3. If no one has consumed a key event, allow the * KeyboardFocusManager to process it. */ if (!e.isConsumed()) { if (e instanceof java.awt.event.KeyEvent) { KeyboardFocusManager.getCurrentKeyboardFocusManager(). processKeyEvent(this, (KeyEvent)e); if (e.isConsumed()) { return; } } } /* * 4. Allow input methods to process the event */ if (areInputMethodsEnabled()) { // We need to pass on InputMethodEvents since some host // input method adapters send them through the Java // event queue instead of directly to the component, // and the input context also handles the Java composition window if(((e instanceof InputMethodEvent) && !(this instanceof CompositionArea)) || // Otherwise, we only pass on input and focus events, because // a) input methods shouldn't know about semantic or component-level events // b) passing on the events takes time // c) isConsumed() is always true for semantic events. (e instanceof InputEvent) || (e instanceof FocusEvent)) { InputContext inputContext = getInputContext(); if (inputContext != null) { inputContext.dispatchEvent(e); if (e.isConsumed()) { if ((e instanceof FocusEvent) && focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("3579: Skipping " + e); } return; } } } } else { // When non-clients get focus, we need to explicitly disable the native // input method. The native input method is actually not disabled when // the active/passive/peered clients loose focus. if (id == FocusEvent.FOCUS_GAINED) { InputContext inputContext = getInputContext(); if (inputContext != null && inputContext instanceof sun.awt.im.InputContext) { ((sun.awt.im.InputContext)inputContext).disableNativeIM(); } } } /* * 5. Pre-process any special events before delivery */ switch(id) { // Handling of the PAINT and UPDATE events is now done in the // peer's handleEvent() method so the background can be cleared // selectively for non-native components on Windows only. // - Fred.Ecks@Eng.sun.com, 5-8-98 case KeyEvent.KEY_PRESSED: case KeyEvent.KEY_RELEASED: Container p = (Container)((this instanceof Container) ? this : parent); if (p != null) { p.preProcessKeyEvent((KeyEvent)e); if (e.isConsumed()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Pre-process consumed event"); } return; } } break; case WindowEvent.WINDOW_CLOSING: if (toolkit instanceof WindowClosingListener) { windowClosingException = ((WindowClosingListener) toolkit).windowClosingNotify((WindowEvent)e); if (checkWindowClosingException()) { return; } } break; default: break; } /* * 6. Deliver event for normal processing */ if (newEventsOnly) { // Filtering needs to really be moved to happen at a lower // level in order to get maximum performance gain; it is // here temporarily to ensure the API spec is honored. // if (eventEnabled(e)) { processEvent(e); } } else if (id == MouseEvent.MOUSE_WHEEL) { // newEventsOnly will be false for a listenerless ScrollPane, but // MouseWheelEvents still need to be dispatched to it so scrolling // can be done. autoProcessMouseWheel((MouseWheelEvent)e); } else if (!(e instanceof MouseEvent && !postsOldMouseEvents())) { // // backward compatibility // Event olde = e.convertToOld(); if (olde != null) { int key = olde.key; int modifiers = olde.modifiers; postEvent(olde); if (olde.isConsumed()) { e.consume(); } // if target changed key or modifier values, copy them // back to original event // switch(olde.id) { case Event.KEY_PRESS: case Event.KEY_RELEASE: case Event.KEY_ACTION: case Event.KEY_ACTION_RELEASE: if (olde.key != key) { ((KeyEvent)e).setKeyChar(olde.getKeyEventChar()); } if (olde.modifiers != modifiers) { ((KeyEvent)e).setModifiers(olde.modifiers); } break; default: break; } } } /* * 8. Special handling for 4061116 : Hook for browser to close modal * dialogs. */ if (id == WindowEvent.WINDOW_CLOSING && !e.isConsumed()) { if (toolkit instanceof WindowClosingListener) { windowClosingException = ((WindowClosingListener)toolkit). windowClosingDelivered((WindowEvent)e); if (checkWindowClosingException()) { return; } } } /* * 9. Allow the peer to process the event. * Except KeyEvents, they will be processed by peer after * all KeyEventPostProcessors * (see DefaultKeyboardFocusManager.dispatchKeyEvent()) */ if (!(e instanceof KeyEvent)) { ComponentPeer tpeer = peer; if (e instanceof FocusEvent && (tpeer == null || tpeer instanceof LightweightPeer)) { // if focus owner is lightweight then its native container // processes event Component source = (Component)e.getSource(); if (source != null) { Container target = source.getNativeContainer(); if (target != null) { tpeer = target.getPeer(); } } } if (tpeer != null) { tpeer.handleEvent(e); } } if (SunToolkit.isTouchKeyboardAutoShowEnabled() && (toolkit instanceof SunToolkit) && ((e instanceof MouseEvent) || (e instanceof FocusEvent))) { ((SunToolkit)toolkit).showOrHideTouchKeyboard(this, e); } } // dispatchEventImpl() /* * If newEventsOnly is false, method is called so that ScrollPane can * override it and handle common-case mouse wheel scrolling. NOP * for Component. */ void autoProcessMouseWheel(MouseWheelEvent e) {} /* * Dispatch given MouseWheelEvent to the first ancestor for which * MouseWheelEvents are enabled. * * Returns whether or not event was dispatched to an ancestor */ boolean dispatchMouseWheelToAncestor(MouseWheelEvent e) { int newX, newY; newX = e.getX() + getX(); // Coordinates take into account at least newY = e.getY() + getY(); // the cursor's position relative to this // Component (e.getX()), and this Component's // position relative to its parent. MouseWheelEvent newMWE; if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { eventLog.finest("dispatchMouseWheelToAncestor"); eventLog.finest("orig event src is of " + e.getSource().getClass()); } /* parent field for Window refers to the owning Window. * MouseWheelEvents should NOT be propagated into owning Windows */ synchronized (getTreeLock()) { Container anc = getParent(); while (anc != null && !anc.eventEnabled(e)) { // fix coordinates to be relative to new event source newX += anc.getX(); newY += anc.getY(); if (!(anc instanceof Window)) { anc = anc.getParent(); } else { break; } } if (eventLog.isLoggable(PlatformLogger.Level.FINEST)) { eventLog.finest("new event src is " + anc.getClass()); } if (anc != null && anc.eventEnabled(e)) { // Change event to be from new source, with new x,y // For now, just create a new event - yucky newMWE = new MouseWheelEvent(anc, // new source e.getID(), e.getWhen(), e.getModifiers(), newX, // x relative to new source newY, // y relative to new source e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getScrollType(), e.getScrollAmount(), e.getWheelRotation(), e.getPreciseWheelRotation()); ((AWTEvent)e).copyPrivateDataInto(newMWE); // When dispatching a wheel event to // ancestor, there is no need trying to find descendant // lightweights to dispatch event to. // If we dispatch the event to toplevel ancestor, // this could encolse the loop: 6480024. anc.dispatchEventToSelf(newMWE); if (newMWE.isConsumed()) { e.consume(); } return true; } } return false; } boolean checkWindowClosingException() { if (windowClosingException != null) { if (this instanceof Dialog) { ((Dialog)this).interruptBlocking(); } else { windowClosingException.fillInStackTrace(); windowClosingException.printStackTrace(); windowClosingException = null; } return true; } return false; } boolean areInputMethodsEnabled() { // in 1.2, we assume input method support is required for all // components that handle key events, but components can turn off // input methods by calling enableInputMethods(false). return ((eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0) && ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 || keyListener != null); } // REMIND: remove when filtering is handled at lower level boolean eventEnabled(AWTEvent e) { return eventTypeEnabled(e.id); } boolean eventTypeEnabled(int type) { switch(type) { case ComponentEvent.COMPONENT_MOVED: case ComponentEvent.COMPONENT_RESIZED: case ComponentEvent.COMPONENT_SHOWN: case ComponentEvent.COMPONENT_HIDDEN: if ((eventMask & AWTEvent.COMPONENT_EVENT_MASK) != 0 || componentListener != null) { return true; } break; case FocusEvent.FOCUS_GAINED: case FocusEvent.FOCUS_LOST: if ((eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0 || focusListener != null) { return true; } break; case KeyEvent.KEY_PRESSED: case KeyEvent.KEY_RELEASED: case KeyEvent.KEY_TYPED: if ((eventMask & AWTEvent.KEY_EVENT_MASK) != 0 || keyListener != null) { return true; } break; case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: case MouseEvent.MOUSE_ENTERED: case MouseEvent.MOUSE_EXITED: case MouseEvent.MOUSE_CLICKED: if ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0 || mouseListener != null) { return true; } break; case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_DRAGGED: if ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0 || mouseMotionListener != null) { return true; } break; case MouseEvent.MOUSE_WHEEL: if ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0 || mouseWheelListener != null) { return true; } break; case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: case InputMethodEvent.CARET_POSITION_CHANGED: if ((eventMask & AWTEvent.INPUT_METHOD_EVENT_MASK) != 0 || inputMethodListener != null) { return true; } break; case HierarchyEvent.HIERARCHY_CHANGED: if ((eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 || hierarchyListener != null) { return true; } break; case HierarchyEvent.ANCESTOR_MOVED: case HierarchyEvent.ANCESTOR_RESIZED: if ((eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 || hierarchyBoundsListener != null) { return true; } break; case ActionEvent.ACTION_PERFORMED: if ((eventMask & AWTEvent.ACTION_EVENT_MASK) != 0) { return true; } break; case TextEvent.TEXT_VALUE_CHANGED: if ((eventMask & AWTEvent.TEXT_EVENT_MASK) != 0) { return true; } break; case ItemEvent.ITEM_STATE_CHANGED: if ((eventMask & AWTEvent.ITEM_EVENT_MASK) != 0) { return true; } break; case AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED: if ((eventMask & AWTEvent.ADJUSTMENT_EVENT_MASK) != 0) { return true; } break; default: break; } // // Always pass on events defined by external programs. // if (type > AWTEvent.RESERVED_ID_MAX) { return true; } return false; } /** * @deprecated As of JDK version 1.1, * replaced by dispatchEvent(AWTEvent). */ @Deprecated public boolean postEvent(Event e) { ComponentPeer peer = this.peer; if (handleEvent(e)) { e.consume(); return true; } Component parent = this.parent; int eventx = e.x; int eventy = e.y; if (parent != null) { e.translate(x, y); if (parent.postEvent(e)) { e.consume(); return true; } // restore coords e.x = eventx; e.y = eventy; } return false; } // Event source interfaces /** * Adds the specified component listener to receive component events from * this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the component listener * @see java.awt.event.ComponentEvent * @see java.awt.event.ComponentListener * @see #removeComponentListener * @see #getComponentListeners * @since JDK1.1 */ public synchronized void addComponentListener(ComponentListener l) { if (l == null) { return; } componentListener = AWTEventMulticaster.add(componentListener, l); newEventsOnly = true; } /** * Removes the specified component listener so that it no longer * receives component events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * @param l the component listener * @see java.awt.event.ComponentEvent * @see java.awt.event.ComponentListener * @see #addComponentListener * @see #getComponentListeners * @since JDK1.1 */ public synchronized void removeComponentListener(ComponentListener l) { if (l == null) { return; } componentListener = AWTEventMulticaster.remove(componentListener, l); } /** * Returns an array of all the component listeners * registered on this component. * * @return all ComponentListeners of this component * or an empty array if no component * listeners are currently registered * * @see #addComponentListener * @see #removeComponentListener * @since 1.4 */ public synchronized ComponentListener[] getComponentListeners() { return getListeners(ComponentListener.class); } /** * Adds the specified focus listener to receive focus events from * this component when this component gains input focus. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the focus listener * @see java.awt.event.FocusEvent * @see java.awt.event.FocusListener * @see #removeFocusListener * @see #getFocusListeners * @since JDK1.1 */ public synchronized void addFocusListener(FocusListener l) { if (l == null) { return; } focusListener = AWTEventMulticaster.add(focusListener, l); newEventsOnly = true; // if this is a lightweight component, enable focus events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(AWTEvent.FOCUS_EVENT_MASK); } } /** * Removes the specified focus listener so that it no longer * receives focus events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the focus listener * @see java.awt.event.FocusEvent * @see java.awt.event.FocusListener * @see #addFocusListener * @see #getFocusListeners * @since JDK1.1 */ public synchronized void removeFocusListener(FocusListener l) { if (l == null) { return; } focusListener = AWTEventMulticaster.remove(focusListener, l); } /** * Returns an array of all the focus listeners * registered on this component. * * @return all of this component's FocusListeners * or an empty array if no component * listeners are currently registered * * @see #addFocusListener * @see #removeFocusListener * @since 1.4 */ public synchronized FocusListener[] getFocusListeners() { return getListeners(FocusListener.class); } /** * Adds the specified hierarchy listener to receive hierarchy changed * events from this component when the hierarchy to which this container * belongs changes. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the hierarchy listener * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyListener * @see #removeHierarchyListener * @see #getHierarchyListeners * @since 1.3 */ public void addHierarchyListener(HierarchyListener l) { if (l == null) { return; } boolean notifyAncestors; synchronized (this) { notifyAncestors = (hierarchyListener == null && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0); hierarchyListener = AWTEventMulticaster.add(hierarchyListener, l); notifyAncestors = (notifyAncestors && hierarchyListener != null); newEventsOnly = true; } if (notifyAncestors) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent(AWTEvent.HIERARCHY_EVENT_MASK, 1); } } } /** * Removes the specified hierarchy listener so that it no longer * receives hierarchy changed events from this component. This method * performs no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the hierarchy listener * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyListener * @see #addHierarchyListener * @see #getHierarchyListeners * @since 1.3 */ public void removeHierarchyListener(HierarchyListener l) { if (l == null) { return; } boolean notifyAncestors; synchronized (this) { notifyAncestors = (hierarchyListener != null && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0); hierarchyListener = AWTEventMulticaster.remove(hierarchyListener, l); notifyAncestors = (notifyAncestors && hierarchyListener == null); } if (notifyAncestors) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent(AWTEvent.HIERARCHY_EVENT_MASK, -1); } } } /** * Returns an array of all the hierarchy listeners * registered on this component. * * @return all of this component's HierarchyListeners * or an empty array if no hierarchy * listeners are currently registered * * @see #addHierarchyListener * @see #removeHierarchyListener * @since 1.4 */ public synchronized HierarchyListener[] getHierarchyListeners() { return getListeners(HierarchyListener.class); } /** * Adds the specified hierarchy bounds listener to receive hierarchy * bounds events from this component when the hierarchy to which this * container belongs changes. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the hierarchy bounds listener * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyBoundsListener * @see #removeHierarchyBoundsListener * @see #getHierarchyBoundsListeners * @since 1.3 */ public void addHierarchyBoundsListener(HierarchyBoundsListener l) { if (l == null) { return; } boolean notifyAncestors; synchronized (this) { notifyAncestors = (hierarchyBoundsListener == null && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0); hierarchyBoundsListener = AWTEventMulticaster.add(hierarchyBoundsListener, l); notifyAncestors = (notifyAncestors && hierarchyBoundsListener != null); newEventsOnly = true; } if (notifyAncestors) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent( AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, 1); } } } /** * Removes the specified hierarchy bounds listener so that it no longer * receives hierarchy bounds events from this component. This method * performs no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the hierarchy bounds listener * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyBoundsListener * @see #addHierarchyBoundsListener * @see #getHierarchyBoundsListeners * @since 1.3 */ public void removeHierarchyBoundsListener(HierarchyBoundsListener l) { if (l == null) { return; } boolean notifyAncestors; synchronized (this) { notifyAncestors = (hierarchyBoundsListener != null && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0); hierarchyBoundsListener = AWTEventMulticaster.remove(hierarchyBoundsListener, l); notifyAncestors = (notifyAncestors && hierarchyBoundsListener == null); } if (notifyAncestors) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent( AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK, -1); } } } // Should only be called while holding the tree lock int numListening(long mask) { // One mask or the other, but not neither or both. if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { if ((mask != AWTEvent.HIERARCHY_EVENT_MASK) && (mask != AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)) { eventLog.fine("Assertion failed"); } } if ((mask == AWTEvent.HIERARCHY_EVENT_MASK && (hierarchyListener != null || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0)) || (mask == AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK && (hierarchyBoundsListener != null || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0))) { return 1; } else { return 0; } } // Should only be called while holding tree lock int countHierarchyMembers() { return 1; } // Should only be called while holding the tree lock int createHierarchyEvents(int id, Component changed, Container changedParent, long changeFlags, boolean enabledOnToolkit) { switch (id) { case HierarchyEvent.HIERARCHY_CHANGED: if (hierarchyListener != null || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 || enabledOnToolkit) { HierarchyEvent e = new HierarchyEvent(this, id, changed, changedParent, changeFlags); dispatchEvent(e); return 1; } break; case HierarchyEvent.ANCESTOR_MOVED: case HierarchyEvent.ANCESTOR_RESIZED: if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { if (changeFlags != 0) { eventLog.fine("Assertion (changeFlags == 0) failed"); } } if (hierarchyBoundsListener != null || (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 || enabledOnToolkit) { HierarchyEvent e = new HierarchyEvent(this, id, changed, changedParent); dispatchEvent(e); return 1; } break; default: // assert false if (eventLog.isLoggable(PlatformLogger.Level.FINE)) { eventLog.fine("This code must never be reached"); } break; } return 0; } /** * Returns an array of all the hierarchy bounds listeners * registered on this component. * * @return all of this component's HierarchyBoundsListeners * or an empty array if no hierarchy bounds * listeners are currently registered * * @see #addHierarchyBoundsListener * @see #removeHierarchyBoundsListener * @since 1.4 */ public synchronized HierarchyBoundsListener[] getHierarchyBoundsListeners() { return getListeners(HierarchyBoundsListener.class); } /* * Should only be called while holding the tree lock. * It's added only for overriding in java.awt.Window * because parent in Window is owner. */ void adjustListeningChildrenOnParent(long mask, int num) { if (parent != null) { parent.adjustListeningChildren(mask, num); } } /** * Adds the specified key listener to receive key events from * this component. * If l is null, no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the key listener. * @see java.awt.event.KeyEvent * @see java.awt.event.KeyListener * @see #removeKeyListener * @see #getKeyListeners * @since JDK1.1 */ public synchronized void addKeyListener(KeyListener l) { if (l == null) { return; } keyListener = AWTEventMulticaster.add(keyListener, l); newEventsOnly = true; // if this is a lightweight component, enable key events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(AWTEvent.KEY_EVENT_MASK); } } /** * Removes the specified key listener so that it no longer * receives key events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the key listener * @see java.awt.event.KeyEvent * @see java.awt.event.KeyListener * @see #addKeyListener * @see #getKeyListeners * @since JDK1.1 */ public synchronized void removeKeyListener(KeyListener l) { if (l == null) { return; } keyListener = AWTEventMulticaster.remove(keyListener, l); } /** * Returns an array of all the key listeners * registered on this component. * * @return all of this component's KeyListeners * or an empty array if no key * listeners are currently registered * * @see #addKeyListener * @see #removeKeyListener * @since 1.4 */ public synchronized KeyListener[] getKeyListeners() { return getListeners(KeyListener.class); } /** * Adds the specified mouse listener to receive mouse events from * this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse listener * @see java.awt.event.MouseEvent * @see java.awt.event.MouseListener * @see #removeMouseListener * @see #getMouseListeners * @since JDK1.1 */ public synchronized void addMouseListener(MouseListener l) { if (l == null) { return; } mouseListener = AWTEventMulticaster.add(mouseListener,l); newEventsOnly = true; // if this is a lightweight component, enable mouse events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(AWTEvent.MOUSE_EVENT_MASK); } } /** * Removes the specified mouse listener so that it no longer * receives mouse events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse listener * @see java.awt.event.MouseEvent * @see java.awt.event.MouseListener * @see #addMouseListener * @see #getMouseListeners * @since JDK1.1 */ public synchronized void removeMouseListener(MouseListener l) { if (l == null) { return; } mouseListener = AWTEventMulticaster.remove(mouseListener, l); } /** * Returns an array of all the mouse listeners * registered on this component. * * @return all of this component's MouseListeners * or an empty array if no mouse * listeners are currently registered * * @see #addMouseListener * @see #removeMouseListener * @since 1.4 */ public synchronized MouseListener[] getMouseListeners() { return getListeners(MouseListener.class); } /** * Adds the specified mouse motion listener to receive mouse motion * events from this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse motion listener * @see java.awt.event.MouseEvent * @see java.awt.event.MouseMotionListener * @see #removeMouseMotionListener * @see #getMouseMotionListeners * @since JDK1.1 */ public synchronized void addMouseMotionListener(MouseMotionListener l) { if (l == null) { return; } mouseMotionListener = AWTEventMulticaster.add(mouseMotionListener,l); newEventsOnly = true; // if this is a lightweight component, enable mouse events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK); } } /** * Removes the specified mouse motion listener so that it no longer * receives mouse motion events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse motion listener * @see java.awt.event.MouseEvent * @see java.awt.event.MouseMotionListener * @see #addMouseMotionListener * @see #getMouseMotionListeners * @since JDK1.1 */ public synchronized void removeMouseMotionListener(MouseMotionListener l) { if (l == null) { return; } mouseMotionListener = AWTEventMulticaster.remove(mouseMotionListener, l); } /** * Returns an array of all the mouse motion listeners * registered on this component. * * @return all of this component's MouseMotionListeners * or an empty array if no mouse motion * listeners are currently registered * * @see #addMouseMotionListener * @see #removeMouseMotionListener * @since 1.4 */ public synchronized MouseMotionListener[] getMouseMotionListeners() { return getListeners(MouseMotionListener.class); } /** * Adds the specified mouse wheel listener to receive mouse wheel events * from this component. Containers also receive mouse wheel events from * sub-components. *

* For information on how mouse wheel events are dispatched, see * the class description for {@link MouseWheelEvent}. *

* If l is null, no exception is thrown and no * action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse wheel listener * @see java.awt.event.MouseWheelEvent * @see java.awt.event.MouseWheelListener * @see #removeMouseWheelListener * @see #getMouseWheelListeners * @since 1.4 */ public synchronized void addMouseWheelListener(MouseWheelListener l) { if (l == null) { return; } mouseWheelListener = AWTEventMulticaster.add(mouseWheelListener,l); newEventsOnly = true; // if this is a lightweight component, enable mouse events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(AWTEvent.MOUSE_WHEEL_EVENT_MASK); } } /** * Removes the specified mouse wheel listener so that it no longer * receives mouse wheel events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If l is null, no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the mouse wheel listener. * @see java.awt.event.MouseWheelEvent * @see java.awt.event.MouseWheelListener * @see #addMouseWheelListener * @see #getMouseWheelListeners * @since 1.4 */ public synchronized void removeMouseWheelListener(MouseWheelListener l) { if (l == null) { return; } mouseWheelListener = AWTEventMulticaster.remove(mouseWheelListener, l); } /** * Returns an array of all the mouse wheel listeners * registered on this component. * * @return all of this component's MouseWheelListeners * or an empty array if no mouse wheel * listeners are currently registered * * @see #addMouseWheelListener * @see #removeMouseWheelListener * @since 1.4 */ public synchronized MouseWheelListener[] getMouseWheelListeners() { return getListeners(MouseWheelListener.class); } /** * Adds the specified input method listener to receive * input method events from this component. A component will * only receive input method events from input methods * if it also overrides getInputMethodRequests to return an * InputMethodRequests instance. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the input method listener * @see java.awt.event.InputMethodEvent * @see java.awt.event.InputMethodListener * @see #removeInputMethodListener * @see #getInputMethodListeners * @see #getInputMethodRequests * @since 1.2 */ public synchronized void addInputMethodListener(InputMethodListener l) { if (l == null) { return; } inputMethodListener = AWTEventMulticaster.add(inputMethodListener, l); newEventsOnly = true; } /** * Removes the specified input method listener so that it no longer * receives input method events from this component. This method performs * no function, nor does it throw an exception, if the listener * specified by the argument was not previously added to this component. * If listener l is null, * no exception is thrown and no action is performed. *

Refer to AWT Threading Issues for details on AWT's threading model. * * @param l the input method listener * @see java.awt.event.InputMethodEvent * @see java.awt.event.InputMethodListener * @see #addInputMethodListener * @see #getInputMethodListeners * @since 1.2 */ public synchronized void removeInputMethodListener(InputMethodListener l) { if (l == null) { return; } inputMethodListener = AWTEventMulticaster.remove(inputMethodListener, l); } /** * Returns an array of all the input method listeners * registered on this component. * * @return all of this component's InputMethodListeners * or an empty array if no input method * listeners are currently registered * * @see #addInputMethodListener * @see #removeInputMethodListener * @since 1.4 */ public synchronized InputMethodListener[] getInputMethodListeners() { return getListeners(InputMethodListener.class); } /** * Returns an array of all the objects currently registered * as FooListeners * upon this Component. * FooListeners are registered using the * addFooListener method. * *

* You can specify the listenerType argument * with a class literal, such as * FooListener.class. * For example, you can query a * Component c * for its mouse listeners with the following code: * *

MouseListener[] mls = (MouseListener[])(c.getListeners(MouseListener.class));
* * If no such listeners exist, this method returns an empty array. * * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from * java.util.EventListener * @return an array of all objects registered as * FooListeners on this component, * or an empty array if no such listeners have been added * @exception ClassCastException if listenerType * doesn't specify a class or interface that implements * java.util.EventListener * @throws NullPointerException if {@code listenerType} is {@code null} * @see #getComponentListeners * @see #getFocusListeners * @see #getHierarchyListeners * @see #getHierarchyBoundsListeners * @see #getKeyListeners * @see #getMouseListeners * @see #getMouseMotionListeners * @see #getMouseWheelListeners * @see #getInputMethodListeners * @see #getPropertyChangeListeners * * @since 1.3 */ @SuppressWarnings("unchecked") public T[] getListeners(Class listenerType) { EventListener l = null; if (listenerType == ComponentListener.class) { l = componentListener; } else if (listenerType == FocusListener.class) { l = focusListener; } else if (listenerType == HierarchyListener.class) { l = hierarchyListener; } else if (listenerType == HierarchyBoundsListener.class) { l = hierarchyBoundsListener; } else if (listenerType == KeyListener.class) { l = keyListener; } else if (listenerType == MouseListener.class) { l = mouseListener; } else if (listenerType == MouseMotionListener.class) { l = mouseMotionListener; } else if (listenerType == MouseWheelListener.class) { l = mouseWheelListener; } else if (listenerType == InputMethodListener.class) { l = inputMethodListener; } else if (listenerType == PropertyChangeListener.class) { return (T[])getPropertyChangeListeners(); } return AWTEventMulticaster.getListeners(l, listenerType); } /** * Gets the input method request handler which supports * requests from input methods for this component. A component * that supports on-the-spot text input must override this * method to return an InputMethodRequests instance. * At the same time, it also has to handle input method events. * * @return the input method request handler for this component, * null by default * @see #addInputMethodListener * @since 1.2 */ public InputMethodRequests getInputMethodRequests() { return null; } /** * Gets the input context used by this component for handling * the communication with input methods when text is entered * in this component. By default, the input context used for * the parent component is returned. Components may * override this to return a private input context. * * @return the input context used by this component; * null if no context can be determined * @since 1.2 */ public InputContext getInputContext() { Container parent = this.parent; if (parent == null) { return null; } else { return parent.getInputContext(); } } /** * Enables the events defined by the specified event mask parameter * to be delivered to this component. *

* Event types are automatically enabled when a listener for * that event type is added to the component. *

* This method only needs to be invoked by subclasses of * Component which desire to have the specified event * types delivered to processEvent regardless of whether * or not a listener is registered. * @param eventsToEnable the event mask defining the event types * @see #processEvent * @see #disableEvents * @see AWTEvent * @since JDK1.1 */ protected final void enableEvents(long eventsToEnable) { long notifyAncestors = 0; synchronized (this) { if ((eventsToEnable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 && hierarchyListener == null && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) == 0) { notifyAncestors |= AWTEvent.HIERARCHY_EVENT_MASK; } if ((eventsToEnable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0 && hierarchyBoundsListener == null && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) == 0) { notifyAncestors |= AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; } eventMask |= eventsToEnable; newEventsOnly = true; } // if this is a lightweight component, enable mouse events // in the native container. if (peer instanceof LightweightPeer) { parent.proxyEnableEvents(eventMask); } if (notifyAncestors != 0) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent(notifyAncestors, 1); } } } /** * Disables the events defined by the specified event mask parameter * from being delivered to this component. * @param eventsToDisable the event mask defining the event types * @see #enableEvents * @since JDK1.1 */ protected final void disableEvents(long eventsToDisable) { long notifyAncestors = 0; synchronized (this) { if ((eventsToDisable & AWTEvent.HIERARCHY_EVENT_MASK) != 0 && hierarchyListener == null && (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0) { notifyAncestors |= AWTEvent.HIERARCHY_EVENT_MASK; } if ((eventsToDisable & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK)!=0 && hierarchyBoundsListener == null && (eventMask & AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK) != 0) { notifyAncestors |= AWTEvent.HIERARCHY_BOUNDS_EVENT_MASK; } eventMask &= ~eventsToDisable; } if (notifyAncestors != 0) { synchronized (getTreeLock()) { adjustListeningChildrenOnParent(notifyAncestors, -1); } } } transient sun.awt.EventQueueItem[] eventCache; /** * @see #isCoalescingEnabled * @see #checkCoalescing */ transient private boolean coalescingEnabled = checkCoalescing(); /** * Weak map of known coalesceEvent overriders. * Value indicates whether overriden. * Bootstrap classes are not included. */ private static final Map, Boolean> coalesceMap = new java.util.WeakHashMap, Boolean>(); /** * Indicates whether this class overrides coalesceEvents. * It is assumed that all classes that are loaded from the bootstrap * do not. * The boostrap class loader is assumed to be represented by null. * We do not check that the method really overrides * (it might be static, private or package private). */ private boolean checkCoalescing() { if (getClass().getClassLoader()==null) { return false; } final Class clazz = getClass(); synchronized (coalesceMap) { // Check cache. Boolean value = coalesceMap.get(clazz); if (value != null) { return value; } // Need to check non-bootstraps. Boolean enabled = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Boolean run() { return isCoalesceEventsOverriden(clazz); } } ); coalesceMap.put(clazz, enabled); return enabled; } } /** * Parameter types of coalesceEvents(AWTEvent,AWTEVent). */ private static final Class[] coalesceEventsParams = { AWTEvent.class, AWTEvent.class }; /** * Indicates whether a class or its superclasses override coalesceEvents. * Must be called with lock on coalesceMap and privileged. * @see checkCoalescing */ private static boolean isCoalesceEventsOverriden(Class clazz) { assert Thread.holdsLock(coalesceMap); // First check superclass - we may not need to bother ourselves. Class superclass = clazz.getSuperclass(); if (superclass == null) { // Only occurs on implementations that // do not use null to represent the bootsrap class loader. return false; } if (superclass.getClassLoader() != null) { Boolean value = coalesceMap.get(superclass); if (value == null) { // Not done already - recurse. if (isCoalesceEventsOverriden(superclass)) { coalesceMap.put(superclass, true); return true; } } else if (value) { return true; } } try { // Throws if not overriden. clazz.getDeclaredMethod( "coalesceEvents", coalesceEventsParams ); return true; } catch (NoSuchMethodException e) { // Not present in this class. return false; } } /** * Indicates whether coalesceEvents may do something. */ final boolean isCoalescingEnabled() { return coalescingEnabled; } /** * Potentially coalesce an event being posted with an existing * event. This method is called by EventQueue.postEvent * if an event with the same ID as the event to be posted is found in * the queue (both events must have this component as their source). * This method either returns a coalesced event which replaces * the existing event (and the new event is then discarded), or * null to indicate that no combining should be done * (add the second event to the end of the queue). Either event * parameter may be modified and returned, as the other one is discarded * unless null is returned. *

* This implementation of coalesceEvents coalesces * two event types: mouse move (and drag) events, * and paint (and update) events. * For mouse move events the last event is always returned, causing * intermediate moves to be discarded. For paint events, the new * event is coalesced into a complex RepaintArea in the peer. * The new AWTEvent is always returned. * * @param existingEvent the event already on the EventQueue * @param newEvent the event being posted to the * EventQueue * @return a coalesced event, or null indicating that no * coalescing was done */ protected AWTEvent coalesceEvents(AWTEvent existingEvent, AWTEvent newEvent) { return null; } /** * Processes events occurring on this component. By default this * method calls the appropriate * process<event type>Event * method for the given class of event. *

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the event * @see #processComponentEvent * @see #processFocusEvent * @see #processKeyEvent * @see #processMouseEvent * @see #processMouseMotionEvent * @see #processInputMethodEvent * @see #processHierarchyEvent * @see #processMouseWheelEvent * @since JDK1.1 */ protected void processEvent(AWTEvent e) { if (e instanceof FocusEvent) { processFocusEvent((FocusEvent)e); } else if (e instanceof MouseEvent) { switch(e.getID()) { case MouseEvent.MOUSE_PRESSED: case MouseEvent.MOUSE_RELEASED: case MouseEvent.MOUSE_CLICKED: case MouseEvent.MOUSE_ENTERED: case MouseEvent.MOUSE_EXITED: processMouseEvent((MouseEvent)e); break; case MouseEvent.MOUSE_MOVED: case MouseEvent.MOUSE_DRAGGED: processMouseMotionEvent((MouseEvent)e); break; case MouseEvent.MOUSE_WHEEL: processMouseWheelEvent((MouseWheelEvent)e); break; } } else if (e instanceof KeyEvent) { processKeyEvent((KeyEvent)e); } else if (e instanceof ComponentEvent) { processComponentEvent((ComponentEvent)e); } else if (e instanceof InputMethodEvent) { processInputMethodEvent((InputMethodEvent)e); } else if (e instanceof HierarchyEvent) { switch (e.getID()) { case HierarchyEvent.HIERARCHY_CHANGED: processHierarchyEvent((HierarchyEvent)e); break; case HierarchyEvent.ANCESTOR_MOVED: case HierarchyEvent.ANCESTOR_RESIZED: processHierarchyBoundsEvent((HierarchyEvent)e); break; } } } /** * Processes component events occurring on this component by * dispatching them to any registered * ComponentListener objects. *

* This method is not called unless component events are * enabled for this component. Component events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the component event * @see java.awt.event.ComponentEvent * @see java.awt.event.ComponentListener * @see #addComponentListener * @see #enableEvents * @since JDK1.1 */ protected void processComponentEvent(ComponentEvent e) { ComponentListener listener = componentListener; if (listener != null) { int id = e.getID(); switch(id) { case ComponentEvent.COMPONENT_RESIZED: listener.componentResized(e); break; case ComponentEvent.COMPONENT_MOVED: listener.componentMoved(e); break; case ComponentEvent.COMPONENT_SHOWN: listener.componentShown(e); break; case ComponentEvent.COMPONENT_HIDDEN: listener.componentHidden(e); break; } } } /** * Processes focus events occurring on this component by * dispatching them to any registered * FocusListener objects. *

* This method is not called unless focus events are * enabled for this component. Focus events are enabled * when one of the following occurs: *

*

* If focus events are enabled for a Component, * the current KeyboardFocusManager determines * whether or not a focus event should be dispatched to * registered FocusListener objects. If the * events are to be dispatched, the KeyboardFocusManager * calls the Component's dispatchEvent * method, which results in a call to the Component's * processFocusEvent method. *

* If focus events are enabled for a Component, calling * the Component's dispatchEvent method * with a FocusEvent as the argument will result in a * call to the Component's processFocusEvent * method regardless of the current KeyboardFocusManager. * *

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the focus event * @see java.awt.event.FocusEvent * @see java.awt.event.FocusListener * @see java.awt.KeyboardFocusManager * @see #addFocusListener * @see #enableEvents * @see #dispatchEvent * @since JDK1.1 */ protected void processFocusEvent(FocusEvent e) { FocusListener listener = focusListener; if (listener != null) { int id = e.getID(); switch(id) { case FocusEvent.FOCUS_GAINED: listener.focusGained(e); break; case FocusEvent.FOCUS_LOST: listener.focusLost(e); break; } } } /** * Processes key events occurring on this component by * dispatching them to any registered * KeyListener objects. *

* This method is not called unless key events are * enabled for this component. Key events are enabled * when one of the following occurs: *

* *

* If key events are enabled for a Component, * the current KeyboardFocusManager determines * whether or not a key event should be dispatched to * registered KeyListener objects. The * DefaultKeyboardFocusManager will not dispatch * key events to a Component that is not the focus * owner or is not showing. *

* As of J2SE 1.4, KeyEvents are redirected to * the focus owner. Please see the * Focus Specification * for further information. *

* Calling a Component's dispatchEvent * method with a KeyEvent as the argument will * result in a call to the Component's * processKeyEvent method regardless of the * current KeyboardFocusManager as long as the * component is showing, focused, and enabled, and key events * are enabled on it. *

If the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the key event * @see java.awt.event.KeyEvent * @see java.awt.event.KeyListener * @see java.awt.KeyboardFocusManager * @see java.awt.DefaultKeyboardFocusManager * @see #processEvent * @see #dispatchEvent * @see #addKeyListener * @see #enableEvents * @see #isShowing * @since JDK1.1 */ protected void processKeyEvent(KeyEvent e) { KeyListener listener = keyListener; if (listener != null) { int id = e.getID(); switch(id) { case KeyEvent.KEY_TYPED: listener.keyTyped(e); break; case KeyEvent.KEY_PRESSED: listener.keyPressed(e); break; case KeyEvent.KEY_RELEASED: listener.keyReleased(e); break; } } } /** * Processes mouse events occurring on this component by * dispatching them to any registered * MouseListener objects. *

* This method is not called unless mouse events are * enabled for this component. Mouse events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the mouse event * @see java.awt.event.MouseEvent * @see java.awt.event.MouseListener * @see #addMouseListener * @see #enableEvents * @since JDK1.1 */ protected void processMouseEvent(MouseEvent e) { MouseListener listener = mouseListener; if (listener != null) { int id = e.getID(); switch(id) { case MouseEvent.MOUSE_PRESSED: listener.mousePressed(e); break; case MouseEvent.MOUSE_RELEASED: listener.mouseReleased(e); break; case MouseEvent.MOUSE_CLICKED: listener.mouseClicked(e); break; case MouseEvent.MOUSE_EXITED: listener.mouseExited(e); break; case MouseEvent.MOUSE_ENTERED: listener.mouseEntered(e); break; } } } /** * Processes mouse motion events occurring on this component by * dispatching them to any registered * MouseMotionListener objects. *

* This method is not called unless mouse motion events are * enabled for this component. Mouse motion events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the mouse motion event * @see java.awt.event.MouseEvent * @see java.awt.event.MouseMotionListener * @see #addMouseMotionListener * @see #enableEvents * @since JDK1.1 */ protected void processMouseMotionEvent(MouseEvent e) { MouseMotionListener listener = mouseMotionListener; if (listener != null) { int id = e.getID(); switch(id) { case MouseEvent.MOUSE_MOVED: listener.mouseMoved(e); break; case MouseEvent.MOUSE_DRAGGED: listener.mouseDragged(e); break; } } } /** * Processes mouse wheel events occurring on this component by * dispatching them to any registered * MouseWheelListener objects. *

* This method is not called unless mouse wheel events are * enabled for this component. Mouse wheel events are enabled * when one of the following occurs: *

*

* For information on how mouse wheel events are dispatched, see * the class description for {@link MouseWheelEvent}. *

* Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the mouse wheel event * @see java.awt.event.MouseWheelEvent * @see java.awt.event.MouseWheelListener * @see #addMouseWheelListener * @see #enableEvents * @since 1.4 */ protected void processMouseWheelEvent(MouseWheelEvent e) { MouseWheelListener listener = mouseWheelListener; if (listener != null) { int id = e.getID(); switch(id) { case MouseEvent.MOUSE_WHEEL: listener.mouseWheelMoved(e); break; } } } boolean postsOldMouseEvents() { return false; } /** * Processes input method events occurring on this component by * dispatching them to any registered * InputMethodListener objects. *

* This method is not called unless input method events * are enabled for this component. Input method events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the input method event * @see java.awt.event.InputMethodEvent * @see java.awt.event.InputMethodListener * @see #addInputMethodListener * @see #enableEvents * @since 1.2 */ protected void processInputMethodEvent(InputMethodEvent e) { InputMethodListener listener = inputMethodListener; if (listener != null) { int id = e.getID(); switch (id) { case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: listener.inputMethodTextChanged(e); break; case InputMethodEvent.CARET_POSITION_CHANGED: listener.caretPositionChanged(e); break; } } } /** * Processes hierarchy events occurring on this component by * dispatching them to any registered * HierarchyListener objects. *

* This method is not called unless hierarchy events * are enabled for this component. Hierarchy events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the hierarchy event * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyListener * @see #addHierarchyListener * @see #enableEvents * @since 1.3 */ protected void processHierarchyEvent(HierarchyEvent e) { HierarchyListener listener = hierarchyListener; if (listener != null) { int id = e.getID(); switch (id) { case HierarchyEvent.HIERARCHY_CHANGED: listener.hierarchyChanged(e); break; } } } /** * Processes hierarchy bounds events occurring on this component by * dispatching them to any registered * HierarchyBoundsListener objects. *

* This method is not called unless hierarchy bounds events * are enabled for this component. Hierarchy bounds events are enabled * when one of the following occurs: *

*

Note that if the event parameter is null * the behavior is unspecified and may result in an * exception. * * @param e the hierarchy event * @see java.awt.event.HierarchyEvent * @see java.awt.event.HierarchyBoundsListener * @see #addHierarchyBoundsListener * @see #enableEvents * @since 1.3 */ protected void processHierarchyBoundsEvent(HierarchyEvent e) { HierarchyBoundsListener listener = hierarchyBoundsListener; if (listener != null) { int id = e.getID(); switch (id) { case HierarchyEvent.ANCESTOR_MOVED: listener.ancestorMoved(e); break; case HierarchyEvent.ANCESTOR_RESIZED: listener.ancestorResized(e); break; } } } /** * @deprecated As of JDK version 1.1 * replaced by processEvent(AWTEvent). */ @Deprecated public boolean handleEvent(Event evt) { switch (evt.id) { case Event.MOUSE_ENTER: return mouseEnter(evt, evt.x, evt.y); case Event.MOUSE_EXIT: return mouseExit(evt, evt.x, evt.y); case Event.MOUSE_MOVE: return mouseMove(evt, evt.x, evt.y); case Event.MOUSE_DOWN: return mouseDown(evt, evt.x, evt.y); case Event.MOUSE_DRAG: return mouseDrag(evt, evt.x, evt.y); case Event.MOUSE_UP: return mouseUp(evt, evt.x, evt.y); case Event.KEY_PRESS: case Event.KEY_ACTION: return keyDown(evt, evt.key); case Event.KEY_RELEASE: case Event.KEY_ACTION_RELEASE: return keyUp(evt, evt.key); case Event.ACTION_EVENT: return action(evt, evt.arg); case Event.GOT_FOCUS: return gotFocus(evt, evt.arg); case Event.LOST_FOCUS: return lostFocus(evt, evt.arg); } return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseEvent(MouseEvent). */ @Deprecated public boolean mouseDown(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseMotionEvent(MouseEvent). */ @Deprecated public boolean mouseDrag(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseEvent(MouseEvent). */ @Deprecated public boolean mouseUp(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseMotionEvent(MouseEvent). */ @Deprecated public boolean mouseMove(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseEvent(MouseEvent). */ @Deprecated public boolean mouseEnter(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processMouseEvent(MouseEvent). */ @Deprecated public boolean mouseExit(Event evt, int x, int y) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processKeyEvent(KeyEvent). */ @Deprecated public boolean keyDown(Event evt, int key) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processKeyEvent(KeyEvent). */ @Deprecated public boolean keyUp(Event evt, int key) { return false; } /** * @deprecated As of JDK version 1.1, * should register this component as ActionListener on component * which fires action events. */ @Deprecated public boolean action(Event evt, Object what) { return false; } /** * Makes this Component displayable by connecting it to a * native screen resource. * This method is called internally by the toolkit and should * not be called directly by programs. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * @see #isDisplayable * @see #removeNotify * @see #invalidate * @since JDK1.0 */ public void addNotify() { synchronized (getTreeLock()) { ComponentPeer peer = this.peer; if (peer == null || peer instanceof LightweightPeer){ if (peer == null) { // Update both the Component's peer variable and the local // variable we use for thread safety. this.peer = peer = getToolkit().createComponent(this); } // This is a lightweight component which means it won't be // able to get window-related events by itself. If any // have been enabled, then the nearest native container must // be enabled. if (parent != null) { long mask = 0; if ((mouseListener != null) || ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0)) { mask |= AWTEvent.MOUSE_EVENT_MASK; } if ((mouseMotionListener != null) || ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0)) { mask |= AWTEvent.MOUSE_MOTION_EVENT_MASK; } if ((mouseWheelListener != null ) || ((eventMask & AWTEvent.MOUSE_WHEEL_EVENT_MASK) != 0)) { mask |= AWTEvent.MOUSE_WHEEL_EVENT_MASK; } if (focusListener != null || (eventMask & AWTEvent.FOCUS_EVENT_MASK) != 0) { mask |= AWTEvent.FOCUS_EVENT_MASK; } if (keyListener != null || (eventMask & AWTEvent.KEY_EVENT_MASK) != 0) { mask |= AWTEvent.KEY_EVENT_MASK; } if (mask != 0) { parent.proxyEnableEvents(mask); } } } else { // It's native. If the parent is lightweight it will need some // help. Container parent = getContainer(); if (parent != null && parent.isLightweight()) { relocateComponent(); if (!parent.isRecursivelyVisibleUpToHeavyweightContainer()) { peer.setVisible(false); } } } invalidate(); int npopups = (popups != null? popups.size() : 0); for (int i = 0 ; i < npopups ; i++) { PopupMenu popup = popups.elementAt(i); popup.addNotify(); } if (dropTarget != null) dropTarget.addNotify(peer); peerFont = getFont(); if (getContainer() != null && !isAddNotifyComplete) { getContainer().increaseComponentCount(this); } // Update stacking order updateZOrder(); if (!isAddNotifyComplete) { mixOnShowing(); } isAddNotifyComplete = true; if (hierarchyListener != null || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)) { HierarchyEvent e = new HierarchyEvent(this, HierarchyEvent.HIERARCHY_CHANGED, this, parent, HierarchyEvent.DISPLAYABILITY_CHANGED | ((isRecursivelyVisible()) ? HierarchyEvent.SHOWING_CHANGED : 0)); dispatchEvent(e); } } } /** * Makes this Component undisplayable by destroying it native * screen resource. *

* This method is called by the toolkit internally and should * not be called directly by programs. Code overriding * this method should call super.removeNotify as * the first line of the overriding method. * * @see #isDisplayable * @see #addNotify * @since JDK1.0 */ public void removeNotify() { KeyboardFocusManager.clearMostRecentFocusOwner(this); if (KeyboardFocusManager.getCurrentKeyboardFocusManager(). getPermanentFocusOwner() == this) { KeyboardFocusManager.getCurrentKeyboardFocusManager(). setGlobalPermanentFocusOwner(null); } synchronized (getTreeLock()) { if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) { transferFocus(true); } if (getContainer() != null && isAddNotifyComplete) { getContainer().decreaseComponentCount(this); } int npopups = (popups != null? popups.size() : 0); for (int i = 0 ; i < npopups ; i++) { PopupMenu popup = popups.elementAt(i); popup.removeNotify(); } // If there is any input context for this component, notify // that this component is being removed. (This has to be done // before hiding peer.) if ((eventMask & AWTEvent.INPUT_METHODS_ENABLED_MASK) != 0) { InputContext inputContext = getInputContext(); if (inputContext != null) { inputContext.removeNotify(this); } } ComponentPeer p = peer; if (p != null) { boolean isLightweight = isLightweight(); if (bufferStrategy instanceof FlipBufferStrategy) { ((FlipBufferStrategy)bufferStrategy).destroyBuffers(); } if (dropTarget != null) dropTarget.removeNotify(peer); // Hide peer first to stop system events such as cursor moves. if (visible) { p.setVisible(false); } peer = null; // Stop peer updates. peerFont = null; Toolkit.getEventQueue().removeSourceEvents(this, false); KeyboardFocusManager.getCurrentKeyboardFocusManager(). discardKeyEvents(this); p.dispose(); mixOnHiding(isLightweight); isAddNotifyComplete = false; // Nullifying compoundShape means that the component has normal shape // (or has no shape at all). this.compoundShape = null; } if (hierarchyListener != null || (eventMask & AWTEvent.HIERARCHY_EVENT_MASK) != 0 || Toolkit.enabledOnToolkit(AWTEvent.HIERARCHY_EVENT_MASK)) { HierarchyEvent e = new HierarchyEvent(this, HierarchyEvent.HIERARCHY_CHANGED, this, parent, HierarchyEvent.DISPLAYABILITY_CHANGED | ((isRecursivelyVisible()) ? HierarchyEvent.SHOWING_CHANGED : 0)); dispatchEvent(e); } } } /** * @deprecated As of JDK version 1.1, * replaced by processFocusEvent(FocusEvent). */ @Deprecated public boolean gotFocus(Event evt, Object what) { return false; } /** * @deprecated As of JDK version 1.1, * replaced by processFocusEvent(FocusEvent). */ @Deprecated public boolean lostFocus(Event evt, Object what) { return false; } /** * Returns whether this Component can become the focus * owner. * * @return true if this Component is * focusable; false otherwise * @see #setFocusable * @since JDK1.1 * @deprecated As of 1.4, replaced by isFocusable(). */ @Deprecated public boolean isFocusTraversable() { if (isFocusTraversableOverridden == FOCUS_TRAVERSABLE_UNKNOWN) { isFocusTraversableOverridden = FOCUS_TRAVERSABLE_DEFAULT; } return focusable; } /** * Returns whether this Component can be focused. * * @return true if this Component is focusable; * false otherwise. * @see #setFocusable * @since 1.4 */ public boolean isFocusable() { return isFocusTraversable(); } /** * Sets the focusable state of this Component to the specified value. This * value overrides the Component's default focusability. * * @param focusable indicates whether this Component is focusable * @see #isFocusable * @since 1.4 * @beaninfo * bound: true */ public void setFocusable(boolean focusable) { boolean oldFocusable; synchronized (this) { oldFocusable = this.focusable; this.focusable = focusable; } isFocusTraversableOverridden = FOCUS_TRAVERSABLE_SET; firePropertyChange("focusable", oldFocusable, focusable); if (oldFocusable && !focusable) { if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabled()) { transferFocus(true); } KeyboardFocusManager.clearMostRecentFocusOwner(this); } } final boolean isFocusTraversableOverridden() { return (isFocusTraversableOverridden != FOCUS_TRAVERSABLE_DEFAULT); } /** * Sets the focus traversal keys for a given traversal operation for this * Component. *

* The default values for a Component's focus traversal keys are * implementation-dependent. Sun recommends that all implementations for a * particular native platform use the same default values. The * recommendations for Windows and Unix are listed below. These * recommendations are used in the Sun AWT implementations. * * * * * * * * * * * * * * * * * * * * * * *
IdentifierMeaningDefault
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYSNormal forward keyboard traversalTAB on KEY_PRESSED, CTRL-TAB on KEY_PRESSED
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYSNormal reverse keyboard traversalSHIFT-TAB on KEY_PRESSED, CTRL-SHIFT-TAB on KEY_PRESSED
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYSGo up one focus traversal cyclenone
* * To disable a traversal key, use an empty Set; Collections.EMPTY_SET is * recommended. *

* Using the AWTKeyStroke API, client code can specify on which of two * specific KeyEvents, KEY_PRESSED or KEY_RELEASED, the focus traversal * operation will occur. Regardless of which KeyEvent is specified, * however, all KeyEvents related to the focus traversal key, including the * associated KEY_TYPED event, will be consumed, and will not be dispatched * to any Component. It is a runtime error to specify a KEY_TYPED event as * mapping to a focus traversal operation, or to map the same event to * multiple default focus traversal operations. *

* If a value of null is specified for the Set, this Component inherits the * Set from its parent. If all ancestors of this Component have null * specified for the Set, then the current KeyboardFocusManager's default * Set is used. *

* This method may throw a {@code ClassCastException} if any {@code Object} * in {@code keystrokes} is not an {@code AWTKeyStroke}. * * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS * @param keystrokes the Set of AWTKeyStroke for the specified operation * @see #getFocusTraversalKeys * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS * @throws IllegalArgumentException if id is not one of * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, or if keystrokes * contains null, or if any keystroke represents a KEY_TYPED event, * or if any keystroke already maps to another focus traversal * operation for this Component * @since 1.4 * @beaninfo * bound: true */ public void setFocusTraversalKeys(int id, Set keystrokes) { if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH - 1) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } setFocusTraversalKeys_NoIDCheck(id, keystrokes); } /** * Returns the Set of focus traversal keys for a given traversal operation * for this Component. (See * setFocusTraversalKeys for a full description of each key.) *

* If a Set of traversal keys has not been explicitly defined for this * Component, then this Component's parent's Set is returned. If no Set * has been explicitly defined for any of this Component's ancestors, then * the current KeyboardFocusManager's default Set is returned. * * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS * @return the Set of AWTKeyStrokes for the specified operation. The Set * will be unmodifiable, and may be empty. null will never be * returned. * @see #setFocusTraversalKeys * @see KeyboardFocusManager#FORWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#BACKWARD_TRAVERSAL_KEYS * @see KeyboardFocusManager#UP_CYCLE_TRAVERSAL_KEYS * @throws IllegalArgumentException if id is not one of * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS * @since 1.4 */ public Set getFocusTraversalKeys(int id) { if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH - 1) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } return getFocusTraversalKeys_NoIDCheck(id); } // We define these methods so that Container does not need to repeat this // code. Container cannot call super. because Container allows // DOWN_CYCLE_TRAVERSAL_KEY while Component does not. The Component method // would erroneously generate an IllegalArgumentException for // DOWN_CYCLE_TRAVERSAL_KEY. final void setFocusTraversalKeys_NoIDCheck(int id, Set keystrokes) { Set oldKeys; synchronized (this) { if (focusTraversalKeys == null) { initializeFocusTraversalKeys(); } if (keystrokes != null) { for (AWTKeyStroke keystroke : keystrokes ) { if (keystroke == null) { throw new IllegalArgumentException("cannot set null focus traversal key"); } if (keystroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED) { throw new IllegalArgumentException("focus traversal keys cannot map to KEY_TYPED events"); } for (int i = 0; i < focusTraversalKeys.length; i++) { if (i == id) { continue; } if (getFocusTraversalKeys_NoIDCheck(i).contains(keystroke)) { throw new IllegalArgumentException("focus traversal keys must be unique for a Component"); } } } } oldKeys = focusTraversalKeys[id]; focusTraversalKeys[id] = (keystrokes != null) ? Collections.unmodifiableSet(new HashSet(keystrokes)) : null; } firePropertyChange(focusTraversalKeyPropertyNames[id], oldKeys, keystrokes); } final Set getFocusTraversalKeys_NoIDCheck(int id) { // Okay to return Set directly because it is an unmodifiable view @SuppressWarnings("unchecked") Set keystrokes = (focusTraversalKeys != null) ? focusTraversalKeys[id] : null; if (keystrokes != null) { return keystrokes; } else { Container parent = this.parent; if (parent != null) { return parent.getFocusTraversalKeys(id); } else { return KeyboardFocusManager.getCurrentKeyboardFocusManager(). getDefaultFocusTraversalKeys(id); } } } /** * Returns whether the Set of focus traversal keys for the given focus * traversal operation has been explicitly defined for this Component. If * this method returns false, this Component is inheriting the * Set from an ancestor, or from the current KeyboardFocusManager. * * @param id one of KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS * @return true if the the Set of focus traversal keys for the * given focus traversal operation has been explicitly defined for * this Component; false otherwise. * @throws IllegalArgumentException if id is not one of * KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, * KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, or * KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS * @since 1.4 */ public boolean areFocusTraversalKeysSet(int id) { if (id < 0 || id >= KeyboardFocusManager.TRAVERSAL_KEY_LENGTH - 1) { throw new IllegalArgumentException("invalid focus traversal key identifier"); } return (focusTraversalKeys != null && focusTraversalKeys[id] != null); } /** * Sets whether focus traversal keys are enabled for this Component. * Components for which focus traversal keys are disabled receive key * events for focus traversal keys. Components for which focus traversal * keys are enabled do not see these events; instead, the events are * automatically converted to traversal operations. * * @param focusTraversalKeysEnabled whether focus traversal keys are * enabled for this Component * @see #getFocusTraversalKeysEnabled * @see #setFocusTraversalKeys * @see #getFocusTraversalKeys * @since 1.4 * @beaninfo * bound: true */ public void setFocusTraversalKeysEnabled(boolean focusTraversalKeysEnabled) { boolean oldFocusTraversalKeysEnabled; synchronized (this) { oldFocusTraversalKeysEnabled = this.focusTraversalKeysEnabled; this.focusTraversalKeysEnabled = focusTraversalKeysEnabled; } firePropertyChange("focusTraversalKeysEnabled", oldFocusTraversalKeysEnabled, focusTraversalKeysEnabled); } /** * Returns whether focus traversal keys are enabled for this Component. * Components for which focus traversal keys are disabled receive key * events for focus traversal keys. Components for which focus traversal * keys are enabled do not see these events; instead, the events are * automatically converted to traversal operations. * * @return whether focus traversal keys are enabled for this Component * @see #setFocusTraversalKeysEnabled * @see #setFocusTraversalKeys * @see #getFocusTraversalKeys * @since 1.4 */ public boolean getFocusTraversalKeysEnabled() { return focusTraversalKeysEnabled; } /** * Requests that this Component get the input focus, and that this * Component's top-level ancestor become the focused Window. This * component must be displayable, focusable, visible and all of * its ancestors (with the exception of the top-level Window) must * be visible for the request to be granted. Every effort will be * made to honor the request; however, in some cases it may be * impossible to do so. Developers must never assume that this * Component is the focus owner until this Component receives a * FOCUS_GAINED event. If this request is denied because this * Component's top-level Window cannot become the focused Window, * the request will be remembered and will be granted when the * Window is later focused by the user. *

* This method cannot be used to set the focus owner to no Component at * all. Use KeyboardFocusManager.clearGlobalFocusOwner() * instead. *

* Because the focus behavior of this method is platform-dependent, * developers are strongly encouraged to use * requestFocusInWindow when possible. * *

Note: Not all focus transfers result from invoking this method. As * such, a component may receive focus without this or any of the other * {@code requestFocus} methods of {@code Component} being invoked. * * @see #requestFocusInWindow * @see java.awt.event.FocusEvent * @see #addFocusListener * @see #isFocusable * @see #isDisplayable * @see KeyboardFocusManager#clearGlobalFocusOwner * @since JDK1.0 */ public void requestFocus() { requestFocusHelper(false, true); } boolean requestFocus(CausedFocusEvent.Cause cause) { return requestFocusHelper(false, true, cause); } /** * Requests that this Component get the input focus, * and that this Component's top-level ancestor * become the focused Window. This component must be * displayable, focusable, visible and all of its ancestors (with * the exception of the top-level Window) must be visible for the * request to be granted. Every effort will be made to honor the * request; however, in some cases it may be impossible to do * so. Developers must never assume that this component is the * focus owner until this component receives a FOCUS_GAINED * event. If this request is denied because this component's * top-level window cannot become the focused window, the request * will be remembered and will be granted when the window is later * focused by the user. *

* This method returns a boolean value. If false is returned, * the request is guaranteed to fail. If true is * returned, the request will succeed unless it is vetoed, or an * extraordinary event, such as disposal of the component's peer, occurs * before the request can be granted by the native windowing system. Again, * while a return value of true indicates that the request is * likely to succeed, developers must never assume that this component is * the focus owner until this component receives a FOCUS_GAINED event. *

* This method cannot be used to set the focus owner to no component at * all. Use KeyboardFocusManager.clearGlobalFocusOwner * instead. *

* Because the focus behavior of this method is platform-dependent, * developers are strongly encouraged to use * requestFocusInWindow when possible. *

* Every effort will be made to ensure that FocusEvents * generated as a * result of this request will have the specified temporary value. However, * because specifying an arbitrary temporary state may not be implementable * on all native windowing systems, correct behavior for this method can be * guaranteed only for lightweight Components. * This method is not intended * for general use, but exists instead as a hook for lightweight component * libraries, such as Swing. * *

Note: Not all focus transfers result from invoking this method. As * such, a component may receive focus without this or any of the other * {@code requestFocus} methods of {@code Component} being invoked. * * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the *Focus Specification * @return false if the focus change request is guaranteed to * fail; true if it is likely to succeed * @see java.awt.event.FocusEvent * @see #addFocusListener * @see #isFocusable * @see #isDisplayable * @see KeyboardFocusManager#clearGlobalFocusOwner * @since 1.4 */ protected boolean requestFocus(boolean temporary) { return requestFocusHelper(temporary, true); } boolean requestFocus(boolean temporary, CausedFocusEvent.Cause cause) { return requestFocusHelper(temporary, true, cause); } /** * Requests that this Component get the input focus, if this * Component's top-level ancestor is already the focused * Window. This component must be displayable, focusable, visible * and all of its ancestors (with the exception of the top-level * Window) must be visible for the request to be granted. Every * effort will be made to honor the request; however, in some * cases it may be impossible to do so. Developers must never * assume that this Component is the focus owner until this * Component receives a FOCUS_GAINED event. *

* This method returns a boolean value. If false is returned, * the request is guaranteed to fail. If true is * returned, the request will succeed unless it is vetoed, or an * extraordinary event, such as disposal of the Component's peer, occurs * before the request can be granted by the native windowing system. Again, * while a return value of true indicates that the request is * likely to succeed, developers must never assume that this Component is * the focus owner until this Component receives a FOCUS_GAINED event. *

* This method cannot be used to set the focus owner to no Component at * all. Use KeyboardFocusManager.clearGlobalFocusOwner() * instead. *

* The focus behavior of this method can be implemented uniformly across * platforms, and thus developers are strongly encouraged to use this * method over requestFocus when possible. Code which relies * on requestFocus may exhibit different focus behavior on * different platforms. * *

Note: Not all focus transfers result from invoking this method. As * such, a component may receive focus without this or any of the other * {@code requestFocus} methods of {@code Component} being invoked. * * @return false if the focus change request is guaranteed to * fail; true if it is likely to succeed * @see #requestFocus * @see java.awt.event.FocusEvent * @see #addFocusListener * @see #isFocusable * @see #isDisplayable * @see KeyboardFocusManager#clearGlobalFocusOwner * @since 1.4 */ public boolean requestFocusInWindow() { return requestFocusHelper(false, false); } boolean requestFocusInWindow(CausedFocusEvent.Cause cause) { return requestFocusHelper(false, false, cause); } /** * Requests that this Component get the input focus, * if this Component's top-level ancestor is already * the focused Window. This component must be * displayable, focusable, visible and all of its ancestors (with * the exception of the top-level Window) must be visible for the * request to be granted. Every effort will be made to honor the * request; however, in some cases it may be impossible to do * so. Developers must never assume that this component is the * focus owner until this component receives a FOCUS_GAINED event. *

* This method returns a boolean value. If false is returned, * the request is guaranteed to fail. If true is * returned, the request will succeed unless it is vetoed, or an * extraordinary event, such as disposal of the component's peer, occurs * before the request can be granted by the native windowing system. Again, * while a return value of true indicates that the request is * likely to succeed, developers must never assume that this component is * the focus owner until this component receives a FOCUS_GAINED event. *

* This method cannot be used to set the focus owner to no component at * all. Use KeyboardFocusManager.clearGlobalFocusOwner * instead. *

* The focus behavior of this method can be implemented uniformly across * platforms, and thus developers are strongly encouraged to use this * method over requestFocus when possible. Code which relies * on requestFocus may exhibit different focus behavior on * different platforms. *

* Every effort will be made to ensure that FocusEvents * generated as a * result of this request will have the specified temporary value. However, * because specifying an arbitrary temporary state may not be implementable * on all native windowing systems, correct behavior for this method can be * guaranteed only for lightweight components. This method is not intended * for general use, but exists instead as a hook for lightweight component * libraries, such as Swing. * *

Note: Not all focus transfers result from invoking this method. As * such, a component may receive focus without this or any of the other * {@code requestFocus} methods of {@code Component} being invoked. * * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the *Focus Specification * @return false if the focus change request is guaranteed to * fail; true if it is likely to succeed * @see #requestFocus * @see java.awt.event.FocusEvent * @see #addFocusListener * @see #isFocusable * @see #isDisplayable * @see KeyboardFocusManager#clearGlobalFocusOwner * @since 1.4 */ protected boolean requestFocusInWindow(boolean temporary) { return requestFocusHelper(temporary, false); } boolean requestFocusInWindow(boolean temporary, CausedFocusEvent.Cause cause) { return requestFocusHelper(temporary, false, cause); } final boolean requestFocusHelper(boolean temporary, boolean focusedWindowChangeAllowed) { return requestFocusHelper(temporary, focusedWindowChangeAllowed, CausedFocusEvent.Cause.UNKNOWN); } final boolean requestFocusHelper(boolean temporary, boolean focusedWindowChangeAllowed, CausedFocusEvent.Cause cause) { // 1) Check if the event being dispatched is a system-generated mouse event. AWTEvent currentEvent = EventQueue.getCurrentEvent(); if (currentEvent instanceof MouseEvent && SunToolkit.isSystemGenerated(currentEvent)) { // 2) Sanity check: if the mouse event component source belongs to the same containing window. Component source = ((MouseEvent)currentEvent).getComponent(); if (source == null || source.getContainingWindow() == getContainingWindow()) { focusLog.finest("requesting focus by mouse event \"in window\""); // If both the conditions are fulfilled the focus request should be strictly // bounded by the toplevel window. It's assumed that the mouse event activates // the window (if it wasn't active) and this makes it possible for a focus // request with a strong in-window requirement to change focus in the bounds // of the toplevel. If, by any means, due to asynchronous nature of the event // dispatching mechanism, the window happens to be natively inactive by the time // this focus request is eventually handled, it should not re-activate the // toplevel. Otherwise the result may not meet user expectations. See 6981400. focusedWindowChangeAllowed = false; } } if (!isRequestFocusAccepted(temporary, focusedWindowChangeAllowed, cause)) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("requestFocus is not accepted"); } return false; } // Update most-recent map KeyboardFocusManager.setMostRecentFocusOwner(this); Component window = this; while ( (window != null) && !(window instanceof Window)) { if (!window.isVisible()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("component is recurively invisible"); } return false; } window = window.parent; } ComponentPeer peer = this.peer; Component heavyweight = (peer instanceof LightweightPeer) ? getNativeContainer() : this; if (heavyweight == null || !heavyweight.isVisible()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Component is not a part of visible hierarchy"); } return false; } peer = heavyweight.peer; if (peer == null) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Peer is null"); } return false; } // Focus this Component long time = 0; if (EventQueue.isDispatchThread()) { time = Toolkit.getEventQueue().getMostRecentKeyEventTime(); } else { // A focus request made from outside EDT should not be associated with any event // and so its time stamp is simply set to the current time. time = System.currentTimeMillis(); } boolean success = peer.requestFocus (this, temporary, focusedWindowChangeAllowed, time, cause); if (!success) { KeyboardFocusManager.getCurrentKeyboardFocusManager (appContext).dequeueKeyEvents(time, this); if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Peer request failed"); } } else { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Pass for " + this); } } return success; } private boolean isRequestFocusAccepted(boolean temporary, boolean focusedWindowChangeAllowed, CausedFocusEvent.Cause cause) { if (!isFocusable() || !isVisible()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Not focusable or not visible"); } return false; } ComponentPeer peer = this.peer; if (peer == null) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("peer is null"); } return false; } Window window = getContainingWindow(); if (window == null || !window.isFocusableWindow()) { if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("Component doesn't have toplevel"); } return false; } // We have passed all regular checks for focus request, // now let's call RequestFocusController and see what it says. Component focusOwner = KeyboardFocusManager.getMostRecentFocusOwner(window); if (focusOwner == null) { // sometimes most recent focus owner may be null, but focus owner is not // e.g. we reset most recent focus owner if user removes focus owner focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); if (focusOwner != null && focusOwner.getContainingWindow() != window) { focusOwner = null; } } if (focusOwner == this || focusOwner == null) { // Controller is supposed to verify focus transfers and for this it // should know both from and to components. And it shouldn't verify // transfers from when these components are equal. if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("focus owner is null or this"); } return true; } if (CausedFocusEvent.Cause.ACTIVATION == cause) { // we shouldn't call RequestFocusController in case we are // in activation. We do request focus on component which // has got temporary focus lost and then on component which is // most recent focus owner. But most recent focus owner can be // changed by requestFocsuXXX() call only, so this transfer has // been already approved. if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("cause is activation"); } return true; } boolean ret = Component.requestFocusController.acceptRequestFocus(focusOwner, this, temporary, focusedWindowChangeAllowed, cause); if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) { focusLog.finest("RequestFocusController returns {0}", ret); } return ret; } private static RequestFocusController requestFocusController = new DummyRequestFocusController(); // Swing access this method through reflection to implement InputVerifier's functionality. // Perhaps, we should make this method public (later ;) private static class DummyRequestFocusController implements RequestFocusController { public boolean acceptRequestFocus(Component from, Component to, boolean temporary, boolean focusedWindowChangeAllowed, CausedFocusEvent.Cause cause) { return true; } }; synchronized static void setRequestFocusController(RequestFocusController requestController) { if (requestController == null) { requestFocusController = new DummyRequestFocusController(); } else { requestFocusController = requestController; } } /** * Returns the Container which is the focus cycle root of this Component's * focus traversal cycle. Each focus traversal cycle has only a single * focus cycle root and each Component which is not a Container belongs to * only a single focus traversal cycle. Containers which are focus cycle * roots belong to two cycles: one rooted at the Container itself, and one * rooted at the Container's nearest focus-cycle-root ancestor. For such * Containers, this method will return the Container's nearest focus-cycle- * root ancestor. * * @return this Component's nearest focus-cycle-root ancestor * @see Container#isFocusCycleRoot() * @since 1.4 */ public Container getFocusCycleRootAncestor() { Container rootAncestor = this.parent; while (rootAncestor != null && !rootAncestor.isFocusCycleRoot()) { rootAncestor = rootAncestor.parent; } return rootAncestor; } /** * Returns whether the specified Container is the focus cycle root of this * Component's focus traversal cycle. Each focus traversal cycle has only * a single focus cycle root and each Component which is not a Container * belongs to only a single focus traversal cycle. * * @param container the Container to be tested * @return true if the specified Container is a focus-cycle- * root of this Component; false otherwise * @see Container#isFocusCycleRoot() * @since 1.4 */ public boolean isFocusCycleRoot(Container container) { Container rootAncestor = getFocusCycleRootAncestor(); return (rootAncestor == container); } Container getTraversalRoot() { return getFocusCycleRootAncestor(); } /** * Transfers the focus to the next component, as though this Component were * the focus owner. * @see #requestFocus() * @since JDK1.1 */ public void transferFocus() { nextFocus(); } /** * @deprecated As of JDK version 1.1, * replaced by transferFocus(). */ @Deprecated public void nextFocus() { transferFocus(false); } boolean transferFocus(boolean clearOnFailure) { if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("clearOnFailure = " + clearOnFailure); } Component toFocus = getNextFocusCandidate(); boolean res = false; if (toFocus != null && !toFocus.isFocusOwner() && toFocus != this) { res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_FORWARD); } if (clearOnFailure && !res) { if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("clear global focus owner"); } KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwnerPriv(); } if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("returning result: " + res); } return res; } final Component getNextFocusCandidate() { Container rootAncestor = getTraversalRoot(); Component comp = this; while (rootAncestor != null && !(rootAncestor.isShowing() && rootAncestor.canBeFocusOwner())) { comp = rootAncestor; rootAncestor = comp.getFocusCycleRootAncestor(); } if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("comp = " + comp + ", root = " + rootAncestor); } Component candidate = null; if (rootAncestor != null) { FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy(); Component toFocus = policy.getComponentAfter(rootAncestor, comp); if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("component after is " + toFocus); } if (toFocus == null) { toFocus = policy.getDefaultComponent(rootAncestor); if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("default component is " + toFocus); } } if (toFocus == null) { Applet applet = EmbeddedFrame.getAppletIfAncestorOf(this); if (applet != null) { toFocus = applet; } } candidate = toFocus; } if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("Focus transfer candidate: " + candidate); } return candidate; } /** * Transfers the focus to the previous component, as though this Component * were the focus owner. * @see #requestFocus() * @since 1.4 */ public void transferFocusBackward() { transferFocusBackward(false); } boolean transferFocusBackward(boolean clearOnFailure) { Container rootAncestor = getTraversalRoot(); Component comp = this; while (rootAncestor != null && !(rootAncestor.isShowing() && rootAncestor.canBeFocusOwner())) { comp = rootAncestor; rootAncestor = comp.getFocusCycleRootAncestor(); } boolean res = false; if (rootAncestor != null) { FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy(); Component toFocus = policy.getComponentBefore(rootAncestor, comp); if (toFocus == null) { toFocus = policy.getDefaultComponent(rootAncestor); } if (toFocus != null) { res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_BACKWARD); } } if (clearOnFailure && !res) { if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("clear global focus owner"); } KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwnerPriv(); } if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { focusLog.finer("returning result: " + res); } return res; } /** * Transfers the focus up one focus traversal cycle. Typically, the focus * owner is set to this Component's focus cycle root, and the current focus * cycle root is set to the new focus owner's focus cycle root. If, * however, this Component's focus cycle root is a Window, then the focus * owner is set to the focus cycle root's default Component to focus, and * the current focus cycle root is unchanged. * * @see #requestFocus() * @see Container#isFocusCycleRoot() * @see Container#setFocusCycleRoot(boolean) * @since 1.4 */ public void transferFocusUpCycle() { Container rootAncestor; for (rootAncestor = getFocusCycleRootAncestor(); rootAncestor != null && !(rootAncestor.isShowing() && rootAncestor.isFocusable() && rootAncestor.isEnabled()); rootAncestor = rootAncestor.getFocusCycleRootAncestor()) { } if (rootAncestor != null) { Container rootAncestorRootAncestor = rootAncestor.getFocusCycleRootAncestor(); Container fcr = (rootAncestorRootAncestor != null) ? rootAncestorRootAncestor : rootAncestor; KeyboardFocusManager.getCurrentKeyboardFocusManager(). setGlobalCurrentFocusCycleRootPriv(fcr); rootAncestor.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_UP); } else { Window window = getContainingWindow(); if (window != null) { Component toFocus = window.getFocusTraversalPolicy(). getDefaultComponent(window); if (toFocus != null) { KeyboardFocusManager.getCurrentKeyboardFocusManager(). setGlobalCurrentFocusCycleRootPriv(window); toFocus.requestFocus(CausedFocusEvent.Cause.TRAVERSAL_UP); } } } } /** * Returns true if this Component is the * focus owner. This method is obsolete, and has been replaced by * isFocusOwner(). * * @return true if this Component is the * focus owner; false otherwise * @since 1.2 */ public boolean hasFocus() { return (KeyboardFocusManager.getCurrentKeyboardFocusManager(). getFocusOwner() == this); } /** * Returns true if this Component is the * focus owner. * * @return true if this Component is the * focus owner; false otherwise * @since 1.4 */ public boolean isFocusOwner() { return hasFocus(); } /* * Used to disallow auto-focus-transfer on disposal of the focus owner * in the process of disposing its parent container. */ private boolean autoFocusTransferOnDisposal = true; void setAutoFocusTransferOnDisposal(boolean value) { autoFocusTransferOnDisposal = value; } boolean isAutoFocusTransferOnDisposal() { return autoFocusTransferOnDisposal; } /** * Adds the specified popup menu to the component. * @param popup the popup menu to be added to the component. * @see #remove(MenuComponent) * @exception NullPointerException if {@code popup} is {@code null} * @since JDK1.1 */ public void add(PopupMenu popup) { synchronized (getTreeLock()) { if (popup.parent != null) { popup.parent.remove(popup); } if (popups == null) { popups = new Vector(); } popups.addElement(popup); popup.parent = this; if (peer != null) { if (popup.peer == null) { popup.addNotify(); } } } } /** * Removes the specified popup menu from the component. * @param popup the popup menu to be removed * @see #add(PopupMenu) * @since JDK1.1 */ @SuppressWarnings("unchecked") public void remove(MenuComponent popup) { synchronized (getTreeLock()) { if (popups == null) { return; } int index = popups.indexOf(popup); if (index >= 0) { PopupMenu pmenu = (PopupMenu)popup; if (pmenu.peer != null) { pmenu.removeNotify(); } pmenu.parent = null; popups.removeElementAt(index); if (popups.size() == 0) { popups = null; } } } } /** * Returns a string representing the state of this component. This * method is intended to be used only for debugging purposes, and the * content and format of the returned string may vary between * implementations. The returned string may be empty but may not be * null. * * @return a string representation of this component's state * @since JDK1.0 */ protected String paramString() { final String thisName = Objects.toString(getName(), ""); final String invalid = isValid() ? "" : ",invalid"; final String hidden = visible ? "" : ",hidden"; final String disabled = enabled ? "" : ",disabled"; return thisName + ',' + x + ',' + y + ',' + width + 'x' + height + invalid + hidden + disabled; } /** * Returns a string representation of this component and its values. * @return a string representation of this component * @since JDK1.0 */ public String toString() { return getClass().getName() + '[' + paramString() + ']'; } /** * Prints a listing of this component to the standard system output * stream System.out. * @see java.lang.System#out * @since JDK1.0 */ public void list() { list(System.out, 0); } /** * Prints a listing of this component to the specified output * stream. * @param out a print stream * @throws NullPointerException if {@code out} is {@code null} * @since JDK1.0 */ public void list(PrintStream out) { list(out, 0); } /** * Prints out a list, starting at the specified indentation, to the * specified print stream. * @param out a print stream * @param indent number of spaces to indent * @see java.io.PrintStream#println(java.lang.Object) * @throws NullPointerException if {@code out} is {@code null} * @since JDK1.0 */ public void list(PrintStream out, int indent) { for (int i = 0 ; i < indent ; i++) { out.print(" "); } out.println(this); } /** * Prints a listing to the specified print writer. * @param out the print writer to print to * @throws NullPointerException if {@code out} is {@code null} * @since JDK1.1 */ public void list(PrintWriter out) { list(out, 0); } /** * Prints out a list, starting at the specified indentation, to * the specified print writer. * @param out the print writer to print to * @param indent the number of spaces to indent * @throws NullPointerException if {@code out} is {@code null} * @see java.io.PrintStream#println(java.lang.Object) * @since JDK1.1 */ public void list(PrintWriter out, int indent) { for (int i = 0 ; i < indent ; i++) { out.print(" "); } out.println(this); } /* * Fetches the native container somewhere higher up in the component * tree that contains this component. */ final Container getNativeContainer() { Container p = getContainer(); while (p != null && p.peer instanceof LightweightPeer) { p = p.getContainer(); } return p; } /** * Adds a PropertyChangeListener to the listener list. The listener is * registered for all bound properties of this class, including the * following: *

* Note that if this Component is inheriting a bound property, then no * event will be fired in response to a change in the inherited property. *

* If listener is null, * no exception is thrown and no action is performed. * * @param listener the property change listener to be added * * @see #removePropertyChangeListener * @see #getPropertyChangeListeners * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) */ public void addPropertyChangeListener( PropertyChangeListener listener) { synchronized (getObjectLock()) { if (listener == null) { return; } if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(listener); } } /** * Removes a PropertyChangeListener from the listener list. This method * should be used to remove PropertyChangeListeners that were registered * for all bound properties of this class. *

* If listener is null, no exception is thrown and no action is performed. * * @param listener the PropertyChangeListener to be removed * * @see #addPropertyChangeListener * @see #getPropertyChangeListeners * @see #removePropertyChangeListener(java.lang.String,java.beans.PropertyChangeListener) */ public void removePropertyChangeListener( PropertyChangeListener listener) { synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } changeSupport.removePropertyChangeListener(listener); } } /** * Returns an array of all the property change listeners * registered on this component. * * @return all of this component's PropertyChangeListeners * or an empty array if no property change * listeners are currently registered * * @see #addPropertyChangeListener * @see #removePropertyChangeListener * @see #getPropertyChangeListeners(java.lang.String) * @see java.beans.PropertyChangeSupport#getPropertyChangeListeners * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners() { synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } return changeSupport.getPropertyChangeListeners(); } } /** * Adds a PropertyChangeListener to the listener list for a specific * property. The specified property may be user-defined, or one of the * following: *

* Note that if this Component is inheriting a bound property, then no * event will be fired in response to a change in the inherited property. *

* If propertyName or listener is null, * no exception is thrown and no action is taken. * * @param propertyName one of the property names listed above * @param listener the property change listener to be added * * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) * @see #getPropertyChangeListeners(java.lang.String) * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) */ public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener) { synchronized (getObjectLock()) { if (listener == null) { return; } if (changeSupport == null) { changeSupport = new PropertyChangeSupport(this); } changeSupport.addPropertyChangeListener(propertyName, listener); } } /** * Removes a PropertyChangeListener from the listener * list for a specific property. This method should be used to remove * PropertyChangeListeners * that were registered for a specific bound property. *

* If propertyName or listener is null, * no exception is thrown and no action is taken. * * @param propertyName a valid property name * @param listener the PropertyChangeListener to be removed * * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) * @see #getPropertyChangeListeners(java.lang.String) * @see #removePropertyChangeListener(java.beans.PropertyChangeListener) */ public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener) { synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } changeSupport.removePropertyChangeListener(propertyName, listener); } } /** * Returns an array of all the listeners which have been associated * with the named property. * * @return all of the PropertyChangeListeners associated with * the named property; if no such listeners have been added or * if propertyName is null, an empty * array is returned * * @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) * @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener) * @see #getPropertyChangeListeners * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } return changeSupport.getPropertyChangeListeners(propertyName); } } /** * Support for reporting bound property changes for Object properties. * This method can be called when a bound property has changed and it will * send the appropriate PropertyChangeEvent to any registered * PropertyChangeListeners. * * @param propertyName the property whose value has changed * @param oldValue the property's previous value * @param newValue the property's new value */ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { PropertyChangeSupport changeSupport; synchronized (getObjectLock()) { changeSupport = this.changeSupport; } if (changeSupport == null || (oldValue != null && newValue != null && oldValue.equals(newValue))) { return; } changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** * Support for reporting bound property changes for boolean properties. * This method can be called when a bound property has changed and it will * send the appropriate PropertyChangeEvent to any registered * PropertyChangeListeners. * * @param propertyName the property whose value has changed * @param oldValue the property's previous value * @param newValue the property's new value * @since 1.4 */ protected void firePropertyChange(String propertyName, boolean oldValue, boolean newValue) { PropertyChangeSupport changeSupport = this.changeSupport; if (changeSupport == null || oldValue == newValue) { return; } changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** * Support for reporting bound property changes for integer properties. * This method can be called when a bound property has changed and it will * send the appropriate PropertyChangeEvent to any registered * PropertyChangeListeners. * * @param propertyName the property whose value has changed * @param oldValue the property's previous value * @param newValue the property's new value * @since 1.4 */ protected void firePropertyChange(String propertyName, int oldValue, int newValue) { PropertyChangeSupport changeSupport = this.changeSupport; if (changeSupport == null || oldValue == newValue) { return; } changeSupport.firePropertyChange(propertyName, oldValue, newValue); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a byte) * @param newValue the new value of the property (as a byte) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, byte oldValue, byte newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, Byte.valueOf(oldValue), Byte.valueOf(newValue)); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a char) * @param newValue the new value of the property (as a char) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, char oldValue, char newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, new Character(oldValue), new Character(newValue)); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a short) * @param newValue the old value of the property (as a short) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, short oldValue, short newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, Short.valueOf(oldValue), Short.valueOf(newValue)); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a long) * @param newValue the new value of the property (as a long) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, long oldValue, long newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, Long.valueOf(oldValue), Long.valueOf(newValue)); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a float) * @param newValue the new value of the property (as a float) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, float oldValue, float newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, Float.valueOf(oldValue), Float.valueOf(newValue)); } /** * Reports a bound property change. * * @param propertyName the programmatic name of the property * that was changed * @param oldValue the old value of the property (as a double) * @param newValue the new value of the property (as a double) * @see #firePropertyChange(java.lang.String, java.lang.Object, * java.lang.Object) * @since 1.5 */ public void firePropertyChange(String propertyName, double oldValue, double newValue) { if (changeSupport == null || oldValue == newValue) { return; } firePropertyChange(propertyName, Double.valueOf(oldValue), Double.valueOf(newValue)); } // Serialization support. /** * Component Serialized Data Version. * * @serial */ private int componentSerializedDataVersion = 4; /** * This hack is for Swing serialization. It will invoke * the Swing package private method compWriteObjectNotify. */ private void doSwingSerialization() { Package swingPackage = Package.getPackage("javax.swing"); // For Swing serialization to correctly work Swing needs to // be notified before Component does it's serialization. This // hack accomodates this. // // Swing classes MUST be loaded by the bootstrap class loader, // otherwise we don't consider them. for (Class klass = Component.this.getClass(); klass != null; klass = klass.getSuperclass()) { if (klass.getPackage() == swingPackage && klass.getClassLoader() == null) { final Class swingClass = klass; // Find the first override of the compWriteObjectNotify method Method[] methods = AccessController.doPrivileged( new PrivilegedAction() { public Method[] run() { return swingClass.getDeclaredMethods(); } }); for (int counter = methods.length - 1; counter >= 0; counter--) { final Method method = methods[counter]; if (method.getName().equals("compWriteObjectNotify")){ // We found it, use doPrivileged to make it accessible // to use. AccessController.doPrivileged(new PrivilegedAction() { public Void run() { method.setAccessible(true); return null; } }); // Invoke the method try { method.invoke(this, (Object[]) null); } catch (IllegalAccessException iae) { } catch (InvocationTargetException ite) { } // We're done, bail. return; } } } } } /** * Writes default serializable fields to stream. Writes * a variety of serializable listeners as optional data. * The non-serializable listeners are detected and * no attempt is made to serialize them. * * @param s the ObjectOutputStream to write * @serialData null terminated sequence of * 0 or more pairs; the pair consists of a String * and an Object; the String indicates * the type of object and is one of the following (as of 1.4): * componentListenerK indicating an * ComponentListener object; * focusListenerK indicating an * FocusListener object; * keyListenerK indicating an * KeyListener object; * mouseListenerK indicating an * MouseListener object; * mouseMotionListenerK indicating an * MouseMotionListener object; * inputMethodListenerK indicating an * InputMethodListener object; * hierarchyListenerK indicating an * HierarchyListener object; * hierarchyBoundsListenerK indicating an * HierarchyBoundsListener object; * mouseWheelListenerK indicating an * MouseWheelListener object * @serialData an optional ComponentOrientation * (after inputMethodListener, as of 1.2) * * @see AWTEventMulticaster#save(java.io.ObjectOutputStream, java.lang.String, java.util.EventListener) * @see #componentListenerK * @see #focusListenerK * @see #keyListenerK * @see #mouseListenerK * @see #mouseMotionListenerK * @see #inputMethodListenerK * @see #hierarchyListenerK * @see #hierarchyBoundsListenerK * @see #mouseWheelListenerK * @see #readObject(ObjectInputStream) */ private void writeObject(ObjectOutputStream s) throws IOException { doSwingSerialization(); s.defaultWriteObject(); AWTEventMulticaster.save(s, componentListenerK, componentListener); AWTEventMulticaster.save(s, focusListenerK, focusListener); AWTEventMulticaster.save(s, keyListenerK, keyListener); AWTEventMulticaster.save(s, mouseListenerK, mouseListener); AWTEventMulticaster.save(s, mouseMotionListenerK, mouseMotionListener); AWTEventMulticaster.save(s, inputMethodListenerK, inputMethodListener); s.writeObject(null); s.writeObject(componentOrientation); AWTEventMulticaster.save(s, hierarchyListenerK, hierarchyListener); AWTEventMulticaster.save(s, hierarchyBoundsListenerK, hierarchyBoundsListener); s.writeObject(null); AWTEventMulticaster.save(s, mouseWheelListenerK, mouseWheelListener); s.writeObject(null); } /** * Reads the ObjectInputStream and if it isn't * null adds a listener to receive a variety * of events fired by the component. * Unrecognized keys or values will be ignored. * * @param s the ObjectInputStream to read * @see #writeObject(ObjectOutputStream) */ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { objectLock = new Object(); acc = AccessController.getContext(); s.defaultReadObject(); appContext = AppContext.getAppContext(); coalescingEnabled = checkCoalescing(); if (componentSerializedDataVersion < 4) { // These fields are non-transient and rely on default // serialization. However, the default values are insufficient, // so we need to set them explicitly for object data streams prior // to 1.4. focusable = true; isFocusTraversableOverridden = FOCUS_TRAVERSABLE_UNKNOWN; initializeFocusTraversalKeys(); focusTraversalKeysEnabled = true; } Object keyOrNull; while(null != (keyOrNull = s.readObject())) { String key = ((String)keyOrNull).intern(); if (componentListenerK == key) addComponentListener((ComponentListener)(s.readObject())); else if (focusListenerK == key) addFocusListener((FocusListener)(s.readObject())); else if (keyListenerK == key) addKeyListener((KeyListener)(s.readObject())); else if (mouseListenerK == key) addMouseListener((MouseListener)(s.readObject())); else if (mouseMotionListenerK == key) addMouseMotionListener((MouseMotionListener)(s.readObject())); else if (inputMethodListenerK == key) addInputMethodListener((InputMethodListener)(s.readObject())); else // skip value for unrecognized key s.readObject(); } // Read the component's orientation if it's present Object orient = null; try { orient = s.readObject(); } catch (java.io.OptionalDataException e) { // JDK 1.1 instances will not have this optional data. // e.eof will be true to indicate that there is no more // data available for this object. // If e.eof is not true, throw the exception as it // might have been caused by reasons unrelated to // componentOrientation. if (!e.eof) { throw (e); } } if (orient != null) { componentOrientation = (ComponentOrientation)orient; } else { componentOrientation = ComponentOrientation.UNKNOWN; } try { while(null != (keyOrNull = s.readObject())) { String key = ((String)keyOrNull).intern(); if (hierarchyListenerK == key) { addHierarchyListener((HierarchyListener)(s.readObject())); } else if (hierarchyBoundsListenerK == key) { addHierarchyBoundsListener((HierarchyBoundsListener) (s.readObject())); } else { // skip value for unrecognized key s.readObject(); } } } catch (java.io.OptionalDataException e) { // JDK 1.1/1.2 instances will not have this optional data. // e.eof will be true to indicate that there is no more // data available for this object. // If e.eof is not true, throw the exception as it // might have been caused by reasons unrelated to // hierarchy and hierarchyBounds listeners. if (!e.eof) { throw (e); } } try { while (null != (keyOrNull = s.readObject())) { String key = ((String)keyOrNull).intern(); if (mouseWheelListenerK == key) { addMouseWheelListener((MouseWheelListener)(s.readObject())); } else { // skip value for unrecognized key s.readObject(); } } } catch (java.io.OptionalDataException e) { // pre-1.3 instances will not have this optional data. // e.eof will be true to indicate that there is no more // data available for this object. // If e.eof is not true, throw the exception as it // might have been caused by reasons unrelated to // mouse wheel listeners if (!e.eof) { throw (e); } } if (popups != null) { int npopups = popups.size(); for (int i = 0 ; i < npopups ; i++) { PopupMenu popup = popups.elementAt(i); popup.parent = this; } } } /** * Sets the language-sensitive orientation that is to be used to order * the elements or text within this component. Language-sensitive * LayoutManager and Component * subclasses will use this property to * determine how to lay out and draw components. *

* At construction time, a component's orientation is set to * ComponentOrientation.UNKNOWN, * indicating that it has not been specified * explicitly. The UNKNOWN orientation behaves the same as * ComponentOrientation.LEFT_TO_RIGHT. *

* To set the orientation of a single component, use this method. * To set the orientation of an entire component * hierarchy, use * {@link #applyComponentOrientation applyComponentOrientation}. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * * @see ComponentOrientation * @see #invalidate * * @author Laura Werner, IBM * @beaninfo * bound: true */ public void setComponentOrientation(ComponentOrientation o) { ComponentOrientation oldValue = componentOrientation; componentOrientation = o; // This is a bound property, so report the change to // any registered listeners. (Cheap if there are none.) firePropertyChange("componentOrientation", oldValue, o); // This could change the preferred size of the Component. invalidateIfValid(); } /** * Retrieves the language-sensitive orientation that is to be used to order * the elements or text within this component. LayoutManager * and Component * subclasses that wish to respect orientation should call this method to * get the component's orientation before performing layout or drawing. * * @see ComponentOrientation * * @author Laura Werner, IBM */ public ComponentOrientation getComponentOrientation() { return componentOrientation; } /** * Sets the ComponentOrientation property of this component * and all components contained within it. *

* This method changes layout-related information, and therefore, * invalidates the component hierarchy. * * * @param orientation the new component orientation of this component and * the components contained within it. * @exception NullPointerException if orientation is null. * @see #setComponentOrientation * @see #getComponentOrientation * @see #invalidate * @since 1.4 */ public void applyComponentOrientation(ComponentOrientation orientation) { if (orientation == null) { throw new NullPointerException(); } setComponentOrientation(orientation); } final boolean canBeFocusOwner() { // It is enabled, visible, focusable. if (isEnabled() && isDisplayable() && isVisible() && isFocusable()) { return true; } return false; } /** * Checks that this component meets the prerequesites to be focus owner: * - it is enabled, visible, focusable * - it's parents are all enabled and showing * - top-level window is focusable * - if focus cycle root has DefaultFocusTraversalPolicy then it also checks that this policy accepts * this component as focus owner * @since 1.5 */ final boolean canBeFocusOwnerRecursively() { // - it is enabled, visible, focusable if (!canBeFocusOwner()) { return false; } // - it's parents are all enabled and showing synchronized(getTreeLock()) { if (parent != null) { return parent.canContainFocusOwner(this); } } return true; } /** * Fix the location of the HW component in a LW container hierarchy. */ final void relocateComponent() { synchronized (getTreeLock()) { if (peer == null) { return; } int nativeX = x; int nativeY = y; for (Component cont = getContainer(); cont != null && cont.isLightweight(); cont = cont.getContainer()) { nativeX += cont.x; nativeY += cont.y; } peer.setBounds(nativeX, nativeY, width, height, ComponentPeer.SET_LOCATION); } } /** * Returns the Window ancestor of the component. * @return Window ancestor of the component or component by itself if it is Window; * null, if component is not a part of window hierarchy */ Window getContainingWindow() { return SunToolkit.getContainingWindow(this); } /** * Initialize JNI field and method IDs */ private static native void initIDs(); /* * --- Accessibility Support --- * * Component will contain all of the methods in interface Accessible, * though it won't actually implement the interface - that will be up * to the individual objects which extend Component. */ /** * The {@code AccessibleContext} associated with this {@code Component}. */ protected AccessibleContext accessibleContext = null; /** * Gets the AccessibleContext associated * with this Component. * The method implemented by this base * class returns null. Classes that extend Component * should implement this method to return the * AccessibleContext associated with the subclass. * * * @return the AccessibleContext of this * Component * @since 1.3 */ public AccessibleContext getAccessibleContext() { return accessibleContext; } /** * Inner class of Component used to provide default support for * accessibility. This class is not meant to be used directly by * application developers, but is instead meant only to be * subclassed by component developers. *

* The class used to obtain the accessible role for this object. * @since 1.3 */ protected abstract class AccessibleAWTComponent extends AccessibleContext implements Serializable, AccessibleComponent { private static final long serialVersionUID = 642321655757800191L; /** * Though the class is abstract, this should be called by * all sub-classes. */ protected AccessibleAWTComponent() { } /** * Number of PropertyChangeListener objects registered. It's used * to add/remove ComponentListener and FocusListener to track * target Component's state. */ private volatile transient int propertyListenersCount = 0; protected ComponentListener accessibleAWTComponentHandler = null; protected FocusListener accessibleAWTFocusHandler = null; /** * Fire PropertyChange listener, if one is registered, * when shown/hidden.. * @since 1.3 */ protected class AccessibleAWTComponentHandler implements ComponentListener { public void componentHidden(ComponentEvent e) { if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, AccessibleState.VISIBLE, null); } } public void componentShown(ComponentEvent e) { if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.VISIBLE); } } public void componentMoved(ComponentEvent e) { } public void componentResized(ComponentEvent e) { } } // inner class AccessibleAWTComponentHandler /** * Fire PropertyChange listener, if one is registered, * when focus events happen * @since 1.3 */ protected class AccessibleAWTFocusHandler implements FocusListener { public void focusGained(FocusEvent event) { if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.FOCUSED); } } public void focusLost(FocusEvent event) { if (accessibleContext != null) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, AccessibleState.FOCUSED, null); } } } // inner class AccessibleAWTFocusHandler /** * Adds a PropertyChangeListener to the listener list. * * @param listener the property change listener to be added */ public void addPropertyChangeListener(PropertyChangeListener listener) { if (accessibleAWTComponentHandler == null) { accessibleAWTComponentHandler = new AccessibleAWTComponentHandler(); } if (accessibleAWTFocusHandler == null) { accessibleAWTFocusHandler = new AccessibleAWTFocusHandler(); } if (propertyListenersCount++ == 0) { Component.this.addComponentListener(accessibleAWTComponentHandler); Component.this.addFocusListener(accessibleAWTFocusHandler); } super.addPropertyChangeListener(listener); } /** * Remove a PropertyChangeListener from the listener list. * This removes a PropertyChangeListener that was registered * for all properties. * * @param listener The PropertyChangeListener to be removed */ public void removePropertyChangeListener(PropertyChangeListener listener) { if (--propertyListenersCount == 0) { Component.this.removeComponentListener(accessibleAWTComponentHandler); Component.this.removeFocusListener(accessibleAWTFocusHandler); } super.removePropertyChangeListener(listener); } // AccessibleContext methods // /** * Gets the accessible name of this object. This should almost never * return java.awt.Component.getName(), * as that generally isn't a localized name, * and doesn't have meaning for the user. If the * object is fundamentally a text object (e.g. a menu item), the * accessible name should be the text of the object (e.g. "save"). * If the object has a tooltip, the tooltip text may also be an * appropriate String to return. * * @return the localized name of the object -- can be * null if this * object does not have a name * @see javax.accessibility.AccessibleContext#setAccessibleName */ public String getAccessibleName() { return accessibleName; } /** * Gets the accessible description of this object. This should be * a concise, localized description of what this object is - what * is its meaning to the user. If the object has a tooltip, the * tooltip text may be an appropriate string to return, assuming * it contains a concise description of the object (instead of just * the name of the object - e.g. a "Save" icon on a toolbar that * had "save" as the tooltip text shouldn't return the tooltip * text as the description, but something like "Saves the current * text document" instead). * * @return the localized description of the object -- can be * null if this object does not have a description * @see javax.accessibility.AccessibleContext#setAccessibleDescription */ public String getAccessibleDescription() { return accessibleDescription; } /** * Gets the role of this object. * * @return an instance of AccessibleRole * describing the role of the object * @see javax.accessibility.AccessibleRole */ public AccessibleRole getAccessibleRole() { return AccessibleRole.AWT_COMPONENT; } /** * Gets the state of this object. * * @return an instance of AccessibleStateSet * containing the current state set of the object * @see javax.accessibility.AccessibleState */ public AccessibleStateSet getAccessibleStateSet() { return Component.this.getAccessibleStateSet(); } /** * Gets the Accessible parent of this object. * If the parent of this object implements Accessible, * this method should simply return getParent. * * @return the Accessible parent of this * object -- can be null if this * object does not have an Accessible parent */ public Accessible getAccessibleParent() { if (accessibleParent != null) { return accessibleParent; } else { Container parent = getParent(); if (parent instanceof Accessible) { return (Accessible) parent; } } return null; } /** * Gets the index of this object in its accessible parent. * * @return the index of this object in its parent; or -1 if this * object does not have an accessible parent * @see #getAccessibleParent */ public int getAccessibleIndexInParent() { return Component.this.getAccessibleIndexInParent(); } /** * Returns the number of accessible children in the object. If all * of the children of this object implement Accessible, * then this method should return the number of children of this object. * * @return the number of accessible children in the object */ public int getAccessibleChildrenCount() { return 0; // Components don't have children } /** * Returns the nth Accessible child of the object. * * @param i zero-based index of child * @return the nth Accessible child of the object */ public Accessible getAccessibleChild(int i) { return null; // Components don't have children } /** * Returns the locale of this object. * * @return the locale of this object */ public Locale getLocale() { return Component.this.getLocale(); } /** * Gets the AccessibleComponent associated * with this object if one exists. * Otherwise return null. * * @return the component */ public AccessibleComponent getAccessibleComponent() { return this; } // AccessibleComponent methods // /** * Gets the background color of this object. * * @return the background color, if supported, of the object; * otherwise, null */ public Color getBackground() { return Component.this.getBackground(); } /** * Sets the background color of this object. * (For transparency, see isOpaque.) * * @param c the new Color for the background * @see Component#isOpaque */ public void setBackground(Color c) { Component.this.setBackground(c); } /** * Gets the foreground color of this object. * * @return the foreground color, if supported, of the object; * otherwise, null */ public Color getForeground() { return Component.this.getForeground(); } /** * Sets the foreground color of this object. * * @param c the new Color for the foreground */ public void setForeground(Color c) { Component.this.setForeground(c); } /** * Gets the Cursor of this object. * * @return the Cursor, if supported, * of the object; otherwise, null */ public Cursor getCursor() { return Component.this.getCursor(); } /** * Sets the Cursor of this object. *

* The method may have no visual effect if the Java platform * implementation and/or the native system do not support * changing the mouse cursor shape. * @param cursor the new Cursor for the object */ public void setCursor(Cursor cursor) { Component.this.setCursor(cursor); } /** * Gets the Font of this object. * * @return the Font, if supported, * for the object; otherwise, null */ public Font getFont() { return Component.this.getFont(); } /** * Sets the Font of this object. * * @param f the new Font for the object */ public void setFont(Font f) { Component.this.setFont(f); } /** * Gets the FontMetrics of this object. * * @param f the Font * @return the FontMetrics, if supported, * the object; otherwise, null * @see #getFont */ public FontMetrics getFontMetrics(Font f) { if (f == null) { return null; } else { return Component.this.getFontMetrics(f); } } /** * Determines if the object is enabled. * * @return true if object is enabled; otherwise, false */ public boolean isEnabled() { return Component.this.isEnabled(); } /** * Sets the enabled state of the object. * * @param b if true, enables this object; otherwise, disables it */ public void setEnabled(boolean b) { boolean old = Component.this.isEnabled(); Component.this.setEnabled(b); if (b != old) { if (accessibleContext != null) { if (b) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.ENABLED); } else { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, AccessibleState.ENABLED, null); } } } } /** * Determines if the object is visible. Note: this means that the * object intends to be visible; however, it may not in fact be * showing on the screen because one of the objects that this object * is contained by is not visible. To determine if an object is * showing on the screen, use isShowing. * * @return true if object is visible; otherwise, false */ public boolean isVisible() { return Component.this.isVisible(); } /** * Sets the visible state of the object. * * @param b if true, shows this object; otherwise, hides it */ public void setVisible(boolean b) { boolean old = Component.this.isVisible(); Component.this.setVisible(b); if (b != old) { if (accessibleContext != null) { if (b) { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, null, AccessibleState.VISIBLE); } else { accessibleContext.firePropertyChange( AccessibleContext.ACCESSIBLE_STATE_PROPERTY, AccessibleState.VISIBLE, null); } } } } /** * Determines if the object is showing. This is determined by checking * the visibility of the object and ancestors of the object. Note: * this will return true even if the object is obscured by another * (for example, it happens to be underneath a menu that was pulled * down). * * @return true if object is showing; otherwise, false */ public boolean isShowing() { return Component.this.isShowing(); } /** * Checks whether the specified point is within this object's bounds, * where the point's x and y coordinates are defined to be relative to * the coordinate system of the object. * * @param p the Point relative to the * coordinate system of the object * @return true if object contains Point; otherwise false */ public boolean contains(Point p) { return Component.this.contains(p); } /** * Returns the location of the object on the screen. * * @return location of object on screen -- can be * null if this object is not on the screen */ public Point getLocationOnScreen() { synchronized (Component.this.getTreeLock()) { if (Component.this.isShowing()) { return Component.this.getLocationOnScreen(); } else { return null; } } } /** * Gets the location of the object relative to the parent in the form * of a point specifying the object's top-left corner in the screen's * coordinate space. * * @return an instance of Point representing the top-left corner of * the object's bounds in the coordinate space of the screen; * null if this object or its parent are not on the screen */ public Point getLocation() { return Component.this.getLocation(); } /** * Sets the location of the object relative to the parent. * @param p the coordinates of the object */ public void setLocation(Point p) { Component.this.setLocation(p); } /** * Gets the bounds of this object in the form of a Rectangle object. * The bounds specify this object's width, height, and location * relative to its parent. * * @return a rectangle indicating this component's bounds; * null if this object is not on the screen */ public Rectangle getBounds() { return Component.this.getBounds(); } /** * Sets the bounds of this object in the form of a * Rectangle object. * The bounds specify this object's width, height, and location * relative to its parent. * * @param r a rectangle indicating this component's bounds */ public void setBounds(Rectangle r) { Component.this.setBounds(r); } /** * Returns the size of this object in the form of a * Dimension object. The height field of the * Dimension object contains this objects's * height, and the width field of the Dimension * object contains this object's width. * * @return a Dimension object that indicates * the size of this component; null if * this object is not on the screen */ public Dimension getSize() { return Component.this.getSize(); } /** * Resizes this object so that it has width and height. * * @param d - the dimension specifying the new size of the object */ public void setSize(Dimension d) { Component.this.setSize(d); } /** * Returns the Accessible child, * if one exists, contained at the local * coordinate Point. Otherwise returns * null. * * @param p the point defining the top-left corner of * the Accessible, given in the * coordinate space of the object's parent * @return the Accessible, if it exists, * at the specified location; else null */ public Accessible getAccessibleAt(Point p) { return null; // Components don't have children } /** * Returns whether this object can accept focus or not. * * @return true if object can accept focus; otherwise false */ public boolean isFocusTraversable() { return Component.this.isFocusTraversable(); } /** * Requests focus for this object. */ public void requestFocus() { Component.this.requestFocus(); } /** * Adds the specified focus listener to receive focus events from this * component. * * @param l the focus listener */ public void addFocusListener(FocusListener l) { Component.this.addFocusListener(l); } /** * Removes the specified focus listener so it no longer receives focus * events from this component. * * @param l the focus listener */ public void removeFocusListener(FocusListener l) { Component.this.removeFocusListener(l); } } // inner class AccessibleAWTComponent /** * Gets the index of this object in its accessible parent. * If this object does not have an accessible parent, returns * -1. * * @return the index of this object in its accessible parent */ int getAccessibleIndexInParent() { synchronized (getTreeLock()) { int index = -1; Container parent = this.getParent(); if (parent != null && parent instanceof Accessible) { Component ca[] = parent.getComponents(); for (int i = 0; i < ca.length; i++) { if (ca[i] instanceof Accessible) { index++; } if (this.equals(ca[i])) { return index; } } } return -1; } } /** * Gets the current state set of this object. * * @return an instance of AccessibleStateSet * containing the current state set of the object * @see AccessibleState */ AccessibleStateSet getAccessibleStateSet() { synchronized (getTreeLock()) { AccessibleStateSet states = new AccessibleStateSet(); if (this.isEnabled()) { states.add(AccessibleState.ENABLED); } if (this.isFocusTraversable()) { states.add(AccessibleState.FOCUSABLE); } if (this.isVisible()) { states.add(AccessibleState.VISIBLE); } if (this.isShowing()) { states.add(AccessibleState.SHOWING); } if (this.isFocusOwner()) { states.add(AccessibleState.FOCUSED); } if (this instanceof Accessible) { AccessibleContext ac = ((Accessible) this).getAccessibleContext(); if (ac != null) { Accessible ap = ac.getAccessibleParent(); if (ap != null) { AccessibleContext pac = ap.getAccessibleContext(); if (pac != null) { AccessibleSelection as = pac.getAccessibleSelection(); if (as != null) { states.add(AccessibleState.SELECTABLE); int i = ac.getAccessibleIndexInParent(); if (i >= 0) { if (as.isAccessibleChildSelected(i)) { states.add(AccessibleState.SELECTED); } } } } } } } if (Component.isInstanceOf(this, "javax.swing.JComponent")) { if (((javax.swing.JComponent) this).isOpaque()) { states.add(AccessibleState.OPAQUE); } } return states; } } /** * Checks that the given object is instance of the given class. * @param obj Object to be checked * @param className The name of the class. Must be fully-qualified class name. * @return true, if this object is instanceof given class, * false, otherwise, or if obj or className is null */ static boolean isInstanceOf(Object obj, String className) { if (obj == null) return false; if (className == null) return false; Class cls = obj.getClass(); while (cls != null) { if (cls.getName().equals(className)) { return true; } cls = cls.getSuperclass(); } return false; } // ************************** MIXING CODE ******************************* /** * Check whether we can trust the current bounds of the component. * The return value of false indicates that the container of the * component is invalid, and therefore needs to be layed out, which would * probably mean changing the bounds of its children. * Null-layout of the container or absence of the container mean * the bounds of the component are final and can be trusted. */ final boolean areBoundsValid() { Container cont = getContainer(); return cont == null || cont.isValid() || cont.getLayout() == null; } /** * Applies the shape to the component * @param shape Shape to be applied to the component */ void applyCompoundShape(Region shape) { checkTreeLock(); if (!areBoundsValid()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; areBoundsValid = " + areBoundsValid()); } return; } if (!isLightweight()) { ComponentPeer peer = getPeer(); if (peer != null) { // The Region class has some optimizations. That's why // we should manually check whether it's empty and // substitute the object ourselves. Otherwise we end up // with some incorrect Region object with loX being // greater than the hiX for instance. if (shape.isEmpty()) { shape = Region.EMPTY_REGION; } // Note: the shape is not really copied/cloned. We create // the Region object ourselves, so there's no any possibility // to modify the object outside of the mixing code. // Nullifying compoundShape means that the component has normal shape // (or has no shape at all). if (shape.equals(getNormalShape())) { if (this.compoundShape == null) { return; } this.compoundShape = null; peer.applyShape(null); } else { if (shape.equals(getAppliedShape())) { return; } this.compoundShape = shape; Point compAbsolute = getLocationOnWindow(); if (mixingLog.isLoggable(PlatformLogger.Level.FINER)) { mixingLog.fine("this = " + this + "; compAbsolute=" + compAbsolute + "; shape=" + shape); } peer.applyShape(shape.getTranslatedRegion(-compAbsolute.x, -compAbsolute.y)); } } } } /** * Returns the shape previously set with applyCompoundShape(). * If the component is LW or no shape was applied yet, * the method returns the normal shape. */ private Region getAppliedShape() { checkTreeLock(); //XXX: if we allow LW components to have a shape, this must be changed return (this.compoundShape == null || isLightweight()) ? getNormalShape() : this.compoundShape; } Point getLocationOnWindow() { checkTreeLock(); Point curLocation = getLocation(); for (Container parent = getContainer(); parent != null && !(parent instanceof Window); parent = parent.getContainer()) { curLocation.x += parent.getX(); curLocation.y += parent.getY(); } return curLocation; } /** * Returns the full shape of the component located in window coordinates */ final Region getNormalShape() { checkTreeLock(); //XXX: we may take into account a user-specified shape for this component Point compAbsolute = getLocationOnWindow(); return Region.getInstanceXYWH( compAbsolute.x, compAbsolute.y, getWidth(), getHeight() ); } /** * Returns the "opaque shape" of the component. * * The opaque shape of a lightweight components is the actual shape that * needs to be cut off of the heavyweight components in order to mix this * lightweight component correctly with them. * * The method is overriden in the java.awt.Container to handle non-opaque * containers containing opaque children. * * See 6637655 for details. */ Region getOpaqueShape() { checkTreeLock(); if (mixingCutoutRegion != null) { return mixingCutoutRegion; } else { return getNormalShape(); } } final int getSiblingIndexAbove() { checkTreeLock(); Container parent = getContainer(); if (parent == null) { return -1; } int nextAbove = parent.getComponentZOrder(this) - 1; return nextAbove < 0 ? -1 : nextAbove; } final ComponentPeer getHWPeerAboveMe() { checkTreeLock(); Container cont = getContainer(); int indexAbove = getSiblingIndexAbove(); while (cont != null) { for (int i = indexAbove; i > -1; i--) { Component comp = cont.getComponent(i); if (comp != null && comp.isDisplayable() && !comp.isLightweight()) { return comp.getPeer(); } } // traversing the hierarchy up to the closest HW container; // further traversing may return a component that is not actually // a native sibling of this component and this kind of z-order // request may not be allowed by the underlying system (6852051). if (!cont.isLightweight()) { break; } indexAbove = cont.getSiblingIndexAbove(); cont = cont.getContainer(); } return null; } final int getSiblingIndexBelow() { checkTreeLock(); Container parent = getContainer(); if (parent == null) { return -1; } int nextBelow = parent.getComponentZOrder(this) + 1; return nextBelow >= parent.getComponentCount() ? -1 : nextBelow; } final boolean isNonOpaqueForMixing() { return mixingCutoutRegion != null && mixingCutoutRegion.isEmpty(); } private Region calculateCurrentShape() { checkTreeLock(); Region s = getNormalShape(); if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; normalShape=" + s); } if (getContainer() != null) { Component comp = this; Container cont = comp.getContainer(); while (cont != null) { for (int index = comp.getSiblingIndexAbove(); index != -1; --index) { /* It is assumed that: * * getComponent(getContainer().getComponentZOrder(comp)) == comp * * The assumption has been made according to the current * implementation of the Container class. */ Component c = cont.getComponent(index); if (c.isLightweight() && c.isShowing()) { s = s.getDifference(c.getOpaqueShape()); } } if (cont.isLightweight()) { s = s.getIntersection(cont.getNormalShape()); } else { break; } comp = cont; cont = cont.getContainer(); } } if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("currentShape=" + s); } return s; } void applyCurrentShape() { checkTreeLock(); if (!areBoundsValid()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; areBoundsValid = " + areBoundsValid()); } return; // Because applyCompoundShape() ignores such components anyway } if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this); } applyCompoundShape(calculateCurrentShape()); } final void subtractAndApplyShape(Region s) { checkTreeLock(); if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; s=" + s); } applyCompoundShape(getAppliedShape().getDifference(s)); } private final void applyCurrentShapeBelowMe() { checkTreeLock(); Container parent = getContainer(); if (parent != null && parent.isShowing()) { // First, reapply shapes of my siblings parent.recursiveApplyCurrentShape(getSiblingIndexBelow()); // Second, if my container is non-opaque, reapply shapes of siblings of my container Container parent2 = parent.getContainer(); while (!parent.isOpaque() && parent2 != null) { parent2.recursiveApplyCurrentShape(parent.getSiblingIndexBelow()); parent = parent2; parent2 = parent.getContainer(); } } } final void subtractAndApplyShapeBelowMe() { checkTreeLock(); Container parent = getContainer(); if (parent != null && isShowing()) { Region opaqueShape = getOpaqueShape(); // First, cut my siblings parent.recursiveSubtractAndApplyShape(opaqueShape, getSiblingIndexBelow()); // Second, if my container is non-opaque, cut siblings of my container Container parent2 = parent.getContainer(); while (!parent.isOpaque() && parent2 != null) { parent2.recursiveSubtractAndApplyShape(opaqueShape, parent.getSiblingIndexBelow()); parent = parent2; parent2 = parent.getContainer(); } } } void mixOnShowing() { synchronized (getTreeLock()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this); } if (!isMixingNeeded()) { return; } if (isLightweight()) { subtractAndApplyShapeBelowMe(); } else { applyCurrentShape(); } } } void mixOnHiding(boolean isLightweight) { // We cannot be sure that the peer exists at this point, so we need the argument // to find out whether the hiding component is (well, actually was) a LW or a HW. synchronized (getTreeLock()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; isLightweight = " + isLightweight); } if (!isMixingNeeded()) { return; } if (isLightweight) { applyCurrentShapeBelowMe(); } } } void mixOnReshaping() { synchronized (getTreeLock()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this); } if (!isMixingNeeded()) { return; } if (isLightweight()) { applyCurrentShapeBelowMe(); } else { applyCurrentShape(); } } } void mixOnZOrderChanging(int oldZorder, int newZorder) { synchronized (getTreeLock()) { boolean becameHigher = newZorder < oldZorder; Container parent = getContainer(); if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; oldZorder=" + oldZorder + "; newZorder=" + newZorder + "; parent=" + parent); } if (!isMixingNeeded()) { return; } if (isLightweight()) { if (becameHigher) { if (parent != null && isShowing()) { parent.recursiveSubtractAndApplyShape(getOpaqueShape(), getSiblingIndexBelow(), oldZorder); } } else { if (parent != null) { parent.recursiveApplyCurrentShape(oldZorder, newZorder); } } } else { if (becameHigher) { applyCurrentShape(); } else { if (parent != null) { Region shape = getAppliedShape(); for (int index = oldZorder; index < newZorder; index++) { Component c = parent.getComponent(index); if (c.isLightweight() && c.isShowing()) { shape = shape.getDifference(c.getOpaqueShape()); } } applyCompoundShape(shape); } } } } } void mixOnValidating() { // This method gets overriden in the Container. Obviously, a plain // non-container components don't need to handle validation. } final boolean isMixingNeeded() { if (SunToolkit.getSunAwtDisableMixing()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINEST)) { mixingLog.finest("this = " + this + "; Mixing disabled via sun.awt.disableMixing"); } return false; } if (!areBoundsValid()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; areBoundsValid = " + areBoundsValid()); } return false; } Window window = getContainingWindow(); if (window != null) { if (!window.hasHeavyweightDescendants() || !window.hasLightweightDescendants() || window.isDisposing()) { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("containing window = " + window + "; has h/w descendants = " + window.hasHeavyweightDescendants() + "; has l/w descendants = " + window.hasLightweightDescendants() + "; disposing = " + window.isDisposing()); } return false; } } else { if (mixingLog.isLoggable(PlatformLogger.Level.FINE)) { mixingLog.fine("this = " + this + "; containing window is null"); } return false; } return true; } // ****************** END OF MIXING CODE ******************************** // Note that the method is overriden in the Window class, // a window doesn't need to be updated in the Z-order. void updateZOrder() { peer.setZOrder(getHWPeerAboveMe()); } }