1 /*
   2  * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.lwawt;
  27 
  28 import java.awt.AWTEvent;
  29 import java.awt.AWTException;
  30 import java.awt.BufferCapabilities;
  31 import java.awt.Color;
  32 import java.awt.Component;
  33 import java.awt.Container;
  34 import java.awt.Cursor;
  35 import java.awt.Dimension;
  36 import java.awt.Font;
  37 import java.awt.FontMetrics;
  38 import java.awt.Graphics;
  39 import java.awt.GraphicsConfiguration;
  40 import java.awt.Image;
  41 import java.awt.Point;
  42 import java.awt.Rectangle;
  43 import java.awt.Toolkit;
  44 import java.awt.Window;
  45 import java.awt.dnd.DropTarget;
  46 import java.awt.dnd.peer.DropTargetPeer;
  47 import java.awt.event.AWTEventListener;
  48 import java.awt.event.ComponentEvent;
  49 import java.awt.event.FocusEvent;
  50 import java.awt.event.InputEvent;
  51 import java.awt.event.KeyEvent;
  52 import java.awt.event.MouseEvent;
  53 import java.awt.event.MouseWheelEvent;
  54 import java.awt.event.PaintEvent;
  55 import java.awt.image.ColorModel;
  56 import java.awt.image.ImageObserver;
  57 import java.awt.image.ImageProducer;
  58 import java.awt.image.VolatileImage;
  59 import java.awt.peer.ComponentPeer;
  60 import java.awt.peer.ContainerPeer;
  61 import java.awt.peer.KeyboardFocusManagerPeer;
  62 import java.lang.reflect.Field;
  63 import java.security.AccessController;
  64 import java.security.PrivilegedAction;
  65 import java.util.concurrent.atomic.AtomicBoolean;
  66 
  67 import javax.swing.JComponent;
  68 import javax.swing.RepaintManager;
  69 import javax.swing.SwingUtilities;
  70 
  71 import com.sun.java.swing.SwingUtilities3;
  72 import sun.awt.AWTAccessor;
  73 import sun.awt.PaintEventDispatcher;
  74 import sun.awt.RepaintArea;
  75 import sun.awt.SunToolkit;
  76 import sun.awt.event.IgnorePaintEvent;
  77 import sun.awt.image.SunVolatileImage;
  78 import sun.awt.image.ToolkitImage;
  79 import sun.java2d.SunGraphics2D;
  80 import sun.java2d.opengl.OGLRenderQueue;
  81 import sun.java2d.pipe.Region;
  82 import sun.util.logging.PlatformLogger;
  83 
  84 public abstract class LWComponentPeer<T extends Component, D extends JComponent>
  85     implements ComponentPeer, DropTargetPeer
  86 {
  87     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.lwawt.focus.LWComponentPeer");
  88 
  89     /**
  90      * State lock is to be used for modifications to this peer's fields (e.g.
  91      * bounds, background, font, etc.) It should be the last lock in the lock
  92      * chain
  93      */
  94     private final Object stateLock = new Object();
  95 
  96     /**
  97      * The lock to operate with the peers hierarchy. AWT tree lock is not used
  98      * as there are many peers related ops to be done on the toolkit thread, and
  99      * we don't want to depend on a public lock on this thread
 100      */
 101     private static final Object peerTreeLock = new Object();
 102 
 103     /**
 104      * The associated AWT object.
 105      */
 106     private final T target;
 107 
 108     /**
 109      * Container peer. It may not be the peer of the target's direct parent, for
 110      * example, in the case of hw/lw mixing. However, let's skip this scenario
 111      * for the time being. We also assume the container peer is not null, which
 112      * might also be false if addNotify() is called for a component outside of
 113      * the hierarchy. The exception is LWWindowPeers: their containers are
 114      * always null
 115      */
 116     private final LWContainerPeer<?, ?> containerPeer;
 117 
 118     /**
 119      * Handy reference to the top-level window peer. Window peer is borrowed
 120      * from the containerPeer in constructor, and should also be updated when
 121      * the component is reparented to another container
 122      */
 123     private final LWWindowPeer windowPeer;
 124 
 125     private final AtomicBoolean disposed = new AtomicBoolean(false);
 126 
 127     // Bounds are relative to parent peer
 128     private final Rectangle bounds = new Rectangle();
 129     private Region region;
 130 
 131     // Component state. Should be accessed under the state lock
 132     private boolean visible = false;
 133     private boolean enabled = true;
 134 
 135     private Color background;
 136     private Color foreground;
 137     private Font font;
 138 
 139     /**
 140      * Paint area to coalesce all the paint events and store the target dirty
 141      * area.
 142      */
 143     private final RepaintArea targetPaintArea;
 144 
 145     //   private volatile boolean paintPending;
 146     private volatile boolean isLayouting;
 147 
 148     private final D delegate;
 149     private Container delegateContainer;
 150     private Component delegateDropTarget;
 151     private final Object dropTargetLock = new Object();
 152 
 153     private int fNumDropTargets = 0;
 154     private PlatformDropTarget fDropTarget = null;
 155 
 156     private final PlatformComponent platformComponent;
 157 
 158     /**
 159      * Character with reasonable value between the minimum width and maximum.
 160      */
 161     static final char WIDE_CHAR = '0';
 162 
 163     /**
 164      * The back buffer provide user with a BufferStrategy.
 165      */
 166     private Image backBuffer;
 167 
 168     /**
 169      * All Swing delegates use delegateContainer as a parent. This container
 170      * intentionally do not use parent of the peer.
 171      */
 172     @SuppressWarnings("serial")// Safe: outer class is non-serializable.
 173     private final class DelegateContainer extends Container {
 174         {
 175             enableEvents(0xFFFFFFFF);
 176         }
 177 
 178         @Override
 179         public boolean isLightweight() {
 180             return false;
 181         }
 182 
 183         @Override
 184         public Point getLocation() {
 185             return getLocationOnScreen();
 186         }
 187 
 188         @Override
 189         public Point getLocationOnScreen() {
 190             return LWComponentPeer.this.getLocationOnScreen();
 191         }
 192 
 193         @Override
 194         public int getX() {
 195             return getLocation().x;
 196         }
 197 
 198         @Override
 199         public int getY() {
 200             return getLocation().y;
 201         }
 202     }
 203 
 204     LWComponentPeer(final T target, final PlatformComponent platformComponent) {
 205         targetPaintArea = new LWRepaintArea();
 206         this.target = target;
 207         this.platformComponent = platformComponent;
 208 
 209         // Container peer is always null for LWWindowPeers, so
 210         // windowPeer is always null for them as well. On the other
 211         // hand, LWWindowPeer shouldn't use windowPeer at all
 212         final Container container = SunToolkit.getNativeContainer(target);
 213         containerPeer = (LWContainerPeer) LWToolkit.targetToPeer(container);
 214         windowPeer = containerPeer != null ? containerPeer.getWindowPeerOrSelf()
 215                                            : null;
 216         // don't bother about z-order here as updateZOrder()
 217         // will be called from addNotify() later anyway
 218         if (containerPeer != null) {
 219             containerPeer.addChildPeer(this);
 220         }
 221 
 222         // the delegate must be created after the target is set
 223         AWTEventListener toolkitListener = null;
 224         synchronized (Toolkit.getDefaultToolkit()) {
 225             try {
 226                 toolkitListener = getToolkitAWTEventListener();
 227                 setToolkitAWTEventListener(null);
 228 
 229                 synchronized (getDelegateLock()) {
 230                     delegate = createDelegate();
 231                     if (delegate != null) {
 232                         delegate.setVisible(false);
 233                         delegateContainer = new DelegateContainer();
 234                         delegateContainer.add(delegate);
 235                         delegateContainer.addNotify();
 236                         delegate.addNotify();
 237                         resetColorsAndFont(delegate);
 238                         delegate.setOpaque(true);
 239                     } else {
 240                         return;
 241                     }
 242                 }
 243 
 244             } finally {
 245                 setToolkitAWTEventListener(toolkitListener);
 246             }
 247 
 248             // todo swing: later on we will probably have one global RM
 249             SwingUtilities3.setDelegateRepaintManager(delegate, new RepaintManager() {
 250                 @Override
 251                 public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) {
 252                     repaintPeer(SwingUtilities.convertRectangle(
 253                             c, new Rectangle(x, y, w, h), getDelegate()));
 254                 }
 255             });
 256         }
 257     }
 258 
 259     /**
 260      * This method must be called under Toolkit.getDefaultToolkit() lock
 261      * and followed by setToolkitAWTEventListener()
 262      */
 263     protected final AWTEventListener getToolkitAWTEventListener() {
 264         return AccessController.doPrivileged(new PrivilegedAction<AWTEventListener>() {
 265             public AWTEventListener run() {
 266                 Toolkit toolkit = Toolkit.getDefaultToolkit();
 267                 try {
 268                     Field field = Toolkit.class.getDeclaredField("eventListener");
 269                     field.setAccessible(true);
 270                     return (AWTEventListener) field.get(toolkit);
 271                 } catch (Exception e) {
 272                     throw new InternalError(e.toString());
 273                 }
 274             }
 275         });
 276     }
 277 
 278     protected final void setToolkitAWTEventListener(final AWTEventListener listener) {
 279         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 280             public Void run() {
 281                 Toolkit toolkit = Toolkit.getDefaultToolkit();
 282                 try {
 283                     Field field = Toolkit.class.getDeclaredField("eventListener");
 284                     field.setAccessible(true);
 285                     field.set(toolkit, listener);
 286                 } catch (Exception e) {
 287                     throw new InternalError(e.toString());
 288                 }
 289                 return null;
 290             }
 291         });
 292     }
 293 
 294     /**
 295      * This method is called under getDelegateLock().
 296      * Overridden in subclasses.
 297      */
 298     D createDelegate() {
 299         return null;
 300     }
 301 
 302     final D getDelegate() {
 303         return delegate;
 304     }
 305 
 306     /**
 307      * This method should be called under getDelegateLock().
 308      */
 309     Component getDelegateFocusOwner() {
 310         return getDelegate();
 311     }
 312 
 313     /**
 314      * Initializes this peer. The call to initialize() is not placed to
 315      * LWComponentPeer ctor to let the subclass ctor to finish completely first.
 316      * Instead, it's the LWToolkit object who is responsible for initialization.
 317      * Note that we call setVisible() at the end of initialization.
 318      */
 319     public final void initialize() {
 320         platformComponent.initialize(getPlatformWindow());
 321         initializeImpl();
 322         setVisible(target.isVisible());
 323     }
 324 
 325     /**
 326      * Fetching general properties from the target. Should be overridden in
 327      * subclasses to initialize specific peers properties.
 328      */
 329     void initializeImpl() {
 330         // note that these methods can be overridden by the user and
 331         // can return some strange values like null.
 332         setBackground(target.getBackground());
 333         setForeground(target.getForeground());
 334         setFont(target.getFont());
 335         setBounds(target.getBounds());
 336         setEnabled(target.isEnabled());
 337     }
 338 
 339     private static void resetColorsAndFont(final Container c) {
 340         c.setBackground(null);
 341         c.setForeground(null);
 342         c.setFont(null);
 343         for (int i = 0; i < c.getComponentCount(); i++) {
 344             resetColorsAndFont((Container) c.getComponent(i));
 345         }
 346     }
 347 
 348     final Object getStateLock() {
 349         return stateLock;
 350     }
 351 
 352     /**
 353      * Synchronize all operations with the Swing delegates under AWT tree lock,
 354      * using a new separate lock to synchronize access to delegates may lead
 355      * deadlocks. Think of it as a 'virtual EDT'.
 356      *
 357      * @return DelegateLock
 358      */
 359     final Object getDelegateLock() {
 360         return getTarget().getTreeLock();
 361     }
 362 
 363     protected static final Object getPeerTreeLock() {
 364         return peerTreeLock;
 365     }
 366 
 367     public final T getTarget() {
 368         return target;
 369     }
 370 
 371     // Just a helper method
 372     // Returns the window peer or null if this is a window peer
 373     protected final LWWindowPeer getWindowPeer() {
 374         return windowPeer;
 375     }
 376 
 377     // Returns the window peer or 'this' if this is a window peer
 378     protected LWWindowPeer getWindowPeerOrSelf() {
 379         return getWindowPeer();
 380     }
 381 
 382     // Just a helper method
 383     protected final LWContainerPeer<?, ?> getContainerPeer() {
 384         return containerPeer;
 385     }
 386 
 387     public PlatformWindow getPlatformWindow() {
 388         LWWindowPeer windowPeer = getWindowPeer();
 389         return windowPeer.getPlatformWindow();
 390     }
 391 
 392     // ---- PEER METHODS ---- //
 393 
 394     // Just a helper method
 395     public LWToolkit getLWToolkit() {
 396         return LWToolkit.getLWToolkit();
 397     }
 398 
 399     @Override
 400     public final void dispose() {
 401         if (disposed.compareAndSet(false, true)) {
 402             disposeImpl();
 403         }
 404     }
 405 
 406     protected void disposeImpl() {
 407         destroyBuffers();
 408         LWContainerPeer<?, ?> cp = getContainerPeer();
 409         if (cp != null) {
 410             cp.removeChildPeer(this);
 411         }
 412         platformComponent.dispose();
 413         LWToolkit.targetDisposedPeer(getTarget(), this);
 414     }
 415 
 416     public final boolean isDisposed() {
 417         return disposed.get();
 418     }
 419 
 420     /*
 421      * GraphicsConfiguration is borrowed from the parent peer. The
 422      * return value must not be null.
 423      *
 424      * Overridden in LWWindowPeer.
 425      */
 426     @Override
 427     public GraphicsConfiguration getGraphicsConfiguration() {
 428         // Don't check windowPeer for null as it can only happen
 429         // for windows, but this method is overridden in
 430         // LWWindowPeer and doesn't call super()
 431         return getWindowPeer().getGraphicsConfiguration();
 432     }
 433 
 434 
 435     // Just a helper method
 436     public final LWGraphicsConfig getLWGC() {
 437         return (LWGraphicsConfig) getGraphicsConfiguration();
 438     }
 439 
 440     /*
 441      * Overridden in LWWindowPeer to replace its surface
 442      * data and back buffer.
 443      */
 444     @Override
 445     public boolean updateGraphicsData(GraphicsConfiguration gc) {
 446         // TODO: not implemented
 447 //        throw new RuntimeException("Has not been implemented yet.");
 448         return false;
 449     }
 450 
 451     @Override
 452     public Graphics getGraphics() {
 453         final Graphics g = getOnscreenGraphics();
 454         if (g != null) {
 455             synchronized (getPeerTreeLock()){
 456                 applyConstrain(g);
 457             }
 458         }
 459         return g;
 460     }
 461 
 462     /*
 463      * Peer Graphics is borrowed from the parent peer, while
 464      * foreground and background colors and font are specific to
 465      * this peer.
 466      */
 467     public final Graphics getOnscreenGraphics() {
 468         final LWWindowPeer wp = getWindowPeerOrSelf();
 469         return wp.getOnscreenGraphics(getForeground(), getBackground(),
 470                                       getFont());
 471 
 472     }
 473 
 474     private void applyConstrain(final Graphics g) {
 475         final SunGraphics2D sg2d = (SunGraphics2D) g;
 476         final Rectangle size = localToWindow(getSize());
 477         sg2d.constrain(size.x, size.y, size.width, size.height, getVisibleRegion());
 478     }
 479 
 480     Region getVisibleRegion() {
 481         return computeVisibleRect(this, getRegion());
 482     }
 483 
 484     static final Region computeVisibleRect(final LWComponentPeer<?, ?> c,
 485                                            Region region) {
 486         final LWContainerPeer<?, ?> p = c.getContainerPeer();
 487         if (p != null) {
 488             final Rectangle r = c.getBounds();
 489             region = region.getTranslatedRegion(r.x, r.y);
 490             region = region.getIntersection(p.getRegion());
 491             region = region.getIntersection(p.getContentSize());
 492             region = p.cutChildren(region, c);
 493             region = computeVisibleRect(p, region);
 494             region = region.getTranslatedRegion(-r.x, -r.y);
 495         }
 496         return region;
 497     }
 498 
 499     @Override
 500     public ColorModel getColorModel() {
 501         // Is it a correct implementation?
 502         return getGraphicsConfiguration().getColorModel();
 503     }
 504 
 505     public boolean isTranslucent() {
 506         // Translucent windows of the top level are supported only
 507         return false;
 508     }
 509 
 510     @Override
 511     public final void createBuffers(int numBuffers, BufferCapabilities caps)
 512             throws AWTException {
 513         getLWGC().assertOperationSupported(numBuffers, caps);
 514         final Image buffer = getLWGC().createBackBuffer(this);
 515         synchronized (getStateLock()) {
 516             backBuffer = buffer;
 517         }
 518     }
 519 
 520     @Override
 521     public final Image getBackBuffer() {
 522         synchronized (getStateLock()) {
 523             if (backBuffer != null) {
 524                 return backBuffer;
 525             }
 526         }
 527         throw new IllegalStateException("Buffers have not been created");
 528     }
 529 
 530     @Override
 531     public final void flip(int x1, int y1, int x2, int y2,
 532                      BufferCapabilities.FlipContents flipAction) {
 533         getLWGC().flip(this, getBackBuffer(), x1, y1, x2, y2, flipAction);
 534     }
 535 
 536     @Override
 537     public final void destroyBuffers() {
 538         final Image oldBB;
 539         synchronized (getStateLock()) {
 540             oldBB = backBuffer;
 541             backBuffer = null;
 542         }
 543         getLWGC().destroyBackBuffer(oldBB);
 544     }
 545 
 546     // Helper method
 547     public void setBounds(Rectangle r) {
 548         setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS);
 549     }
 550 
 551     /**
 552      * This method could be called on the toolkit thread.
 553      */
 554     @Override
 555     public void setBounds(int x, int y, int w, int h, int op) {
 556         setBounds(x, y, w, h, op, true, false);
 557     }
 558 
 559     protected void setBounds(int x, int y, int w, int h, int op, boolean notify,
 560                              final boolean updateTarget) {
 561         Rectangle oldBounds;
 562         synchronized (getStateLock()) {
 563             oldBounds = new Rectangle(bounds);
 564             if ((op & (SET_LOCATION | SET_BOUNDS)) != 0) {
 565                 bounds.x = x;
 566                 bounds.y = y;
 567             }
 568             if ((op & (SET_SIZE | SET_BOUNDS)) != 0) {
 569                 bounds.width = w;
 570                 bounds.height = h;
 571             }
 572         }
 573         boolean moved = (oldBounds.x != x) || (oldBounds.y != y);
 574         boolean resized = (oldBounds.width != w) || (oldBounds.height != h);
 575         if (!moved && !resized) {
 576             return;
 577         }
 578         final D delegate = getDelegate();
 579         if (delegate != null) {
 580             synchronized (getDelegateLock()) {
 581                 delegateContainer.setBounds(0, 0, w, h);
 582                 delegate.setBounds(delegateContainer.getBounds());
 583                 // TODO: the following means that the delegateContainer NEVER gets validated. That's WRONG!
 584                 delegate.validate();
 585             }
 586         }
 587 
 588         final Point locationInWindow = localToWindow(0, 0);
 589         platformComponent.setBounds(locationInWindow.x, locationInWindow.y, w,
 590                                     h);
 591         if (notify) {
 592             repaintOldNewBounds(oldBounds);
 593             if (resized) {
 594                 handleResize(w, h, updateTarget);
 595             }
 596             if (moved) {
 597                 handleMove(x, y, updateTarget);
 598             }
 599         }
 600     }
 601 
 602     public final Rectangle getBounds() {
 603         synchronized (getStateLock()) {
 604             // Return a copy to prevent subsequent modifications
 605             return bounds.getBounds();
 606         }
 607     }
 608 
 609     public final Rectangle getSize() {
 610         synchronized (getStateLock()) {
 611             // Return a copy to prevent subsequent modifications
 612             return new Rectangle(bounds.width, bounds.height);
 613         }
 614     }
 615 
 616     @Override
 617     public Point getLocationOnScreen() {
 618         Point windowLocation = getWindowPeer().getLocationOnScreen();
 619         Point locationInWindow = localToWindow(0, 0);
 620         return new Point(windowLocation.x + locationInWindow.x,
 621                 windowLocation.y + locationInWindow.y);
 622     }
 623 
 624     /**
 625      * Returns the cursor of the peer, which is cursor of the target by default,
 626      * but peer can override this behavior.
 627      *
 628      * @param p Point relative to the peer.
 629      * @return Cursor of the peer or null if default cursor should be used.
 630      */
 631     Cursor getCursor(final Point p) {
 632         return getTarget().getCursor();
 633     }
 634 
 635     @Override
 636     public void setBackground(final Color c) {
 637         final Color oldBg = getBackground();
 638         if (oldBg == c || (oldBg != null && oldBg.equals(c))) {
 639             return;
 640         }
 641         synchronized (getStateLock()) {
 642             background = c;
 643         }
 644         final D delegate = getDelegate();
 645         if (delegate != null) {
 646             synchronized (getDelegateLock()) {
 647                 // delegate will repaint the target
 648                 delegate.setBackground(c);
 649             }
 650         } else {
 651             repaintPeer();
 652         }
 653     }
 654 
 655     public final Color getBackground() {
 656         synchronized (getStateLock()) {
 657             return background;
 658         }
 659     }
 660 
 661     @Override
 662     public void setForeground(final Color c) {
 663         final Color oldFg = getForeground();
 664         if (oldFg == c || (oldFg != null && oldFg.equals(c))) {
 665             return;
 666         }
 667         synchronized (getStateLock()) {
 668             foreground = c;
 669         }
 670         final D delegate = getDelegate();
 671         if (delegate != null) {
 672             synchronized (getDelegateLock()) {
 673                 // delegate will repaint the target
 674                 delegate.setForeground(c);
 675             }
 676         } else {
 677             repaintPeer();
 678         }
 679     }
 680 
 681     protected final Color getForeground() {
 682         synchronized (getStateLock()) {
 683             return foreground;
 684         }
 685     }
 686 
 687     @Override
 688     public void setFont(final Font f) {
 689         final Font oldF = getFont();
 690         if (oldF == f || (oldF != null && oldF.equals(f))) {
 691             return;
 692         }
 693         synchronized (getStateLock()) {
 694             font = f;
 695         }
 696         final D delegate = getDelegate();
 697         if (delegate != null) {
 698             synchronized (getDelegateLock()) {
 699                 // delegate will repaint the target
 700                 delegate.setFont(f);
 701             }
 702         } else {
 703             repaintPeer();
 704         }
 705     }
 706 
 707     protected final Font getFont() {
 708         synchronized (getStateLock()) {
 709             return font;
 710         }
 711     }
 712 
 713     @Override
 714     public FontMetrics getFontMetrics(final Font f) {
 715         // Borrow the metrics from the top-level window
 716 //        return getWindowPeer().getFontMetrics(f);
 717         // Obtain the metrics from the offscreen window where this peer is
 718         // mostly drawn to.
 719         // TODO: check for "use platform metrics" settings
 720         final Graphics g = getOnscreenGraphics();
 721         if (g != null) {
 722             try {
 723                 return g.getFontMetrics(f);
 724             } finally {
 725                 g.dispose();
 726             }
 727         }
 728         synchronized (getDelegateLock()) {
 729             return delegateContainer.getFontMetrics(f);
 730         }
 731     }
 732 
 733     @Override
 734     public void setEnabled(final boolean e) {
 735         boolean status = e;
 736         final LWComponentPeer<?, ?> cp = getContainerPeer();
 737         if (cp != null) {
 738             status &= cp.isEnabled();
 739         }
 740         synchronized (getStateLock()) {
 741             if (enabled == status) {
 742                 return;
 743             }
 744             enabled = status;
 745         }
 746 
 747         final D delegate = getDelegate();
 748 
 749         if (delegate != null) {
 750             synchronized (getDelegateLock()) {
 751                 delegate.setEnabled(status);
 752             }
 753         } else {
 754             repaintPeer();
 755         }
 756     }
 757 
 758     // Helper method
 759     public final boolean isEnabled() {
 760         synchronized (getStateLock()) {
 761             return enabled;
 762         }
 763     }
 764 
 765     @Override
 766     public void setVisible(final boolean v) {
 767         synchronized (getStateLock()) {
 768             if (visible == v) {
 769                 return;
 770             }
 771             visible = v;
 772         }
 773         setVisibleImpl(v);
 774     }
 775 
 776     protected void setVisibleImpl(final boolean v) {
 777         final D delegate = getDelegate();
 778 
 779         if (delegate != null) {
 780             synchronized (getDelegateLock()) {
 781                 delegate.setVisible(v);
 782             }
 783         }
 784         if (visible) {
 785             repaintPeer();
 786         } else {
 787             repaintParent(getBounds());
 788         }
 789     }
 790 
 791     // Helper method
 792     public final boolean isVisible() {
 793         synchronized (getStateLock()) {
 794             return visible;
 795         }
 796     }
 797 
 798     @Override
 799     public void paint(final Graphics g) {
 800         getTarget().paint(g);
 801     }
 802 
 803     @Override
 804     public void print(final Graphics g) {
 805         getTarget().print(g);
 806     }
 807 
 808     @Override
 809     public void reparent(ContainerPeer newContainer) {
 810         // TODO: not implemented
 811         throw new UnsupportedOperationException("ComponentPeer.reparent()");
 812     }
 813 
 814     @Override
 815     public boolean isReparentSupported() {
 816         // TODO: not implemented
 817         return false;
 818     }
 819 
 820     @Override
 821     public void setZOrder(final ComponentPeer above) {
 822         LWContainerPeer<?, ?> cp = getContainerPeer();
 823         // Don't check containerPeer for null as it can only happen
 824         // for windows, but this method is overridden in
 825         // LWWindowPeer and doesn't call super()
 826         cp.setChildPeerZOrder(this, (LWComponentPeer<?, ?>) above);
 827     }
 828 
 829     @Override
 830     public void coalescePaintEvent(PaintEvent e) {
 831         if (!(e instanceof IgnorePaintEvent)) {
 832             Rectangle r = e.getUpdateRect();
 833             if ((r != null) && !r.isEmpty()) {
 834                 targetPaintArea.add(r, e.getID());
 835             }
 836         }
 837     }
 838 
 839     /*
 840      * Should be overridden in subclasses which use complex Swing components.
 841      */
 842     @Override
 843     public void layout() {
 844         // TODO: not implemented
 845     }
 846 
 847     @Override
 848     public boolean isObscured() {
 849         // TODO: not implemented
 850         return false;
 851     }
 852 
 853     @Override
 854     public boolean canDetermineObscurity() {
 855         // TODO: not implemented
 856         return false;
 857     }
 858 
 859     /**
 860      * Determines the preferred size of the component. By default forwards the
 861      * request to the Swing helper component. Should be overridden in subclasses
 862      * if required.
 863      */
 864     @Override
 865     public Dimension getPreferredSize() {
 866         final Dimension size;
 867         synchronized (getDelegateLock()) {
 868             size = getDelegate().getPreferredSize();
 869         }
 870         return validateSize(size);
 871     }
 872 
 873     /**
 874      * Determines the minimum size of the component. By default forwards the
 875      * request to the Swing helper component. Should be overridden in subclasses
 876      * if required.
 877      */
 878     @Override
 879     public Dimension getMinimumSize() {
 880         final Dimension size;
 881         synchronized (getDelegateLock()) {
 882             size = getDelegate().getMinimumSize();
 883         }
 884         return validateSize(size);
 885     }
 886 
 887     /**
 888      * In some situations delegates can return empty minimum/preferred size.
 889      * (For example: empty JLabel, etc), but awt components never should be
 890      * empty. In the XPeers or WPeers we use some magic constants, but here we
 891      * try to use something more useful,
 892      */
 893     private Dimension validateSize(final Dimension size) {
 894         if (size.width == 0 || size.height == 0) {
 895             final FontMetrics fm = getFontMetrics(getFont());
 896             size.width = fm.charWidth(WIDE_CHAR);
 897             size.height = fm.getHeight();
 898         }
 899         return size;
 900     }
 901 
 902     @Override
 903     public void updateCursorImmediately() {
 904         getLWToolkit().getCursorManager().updateCursor();
 905     }
 906 
 907     @Override
 908     public boolean isFocusable() {
 909         // Overridden in focusable subclasses like buttons
 910         return false;
 911     }
 912 
 913     @Override
 914     public boolean requestFocus(Component lightweightChild, boolean temporary,
 915                                 boolean focusedWindowChangeAllowed, long time,
 916                                 FocusEvent.Cause cause)
 917     {
 918         if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
 919             focusLog.finest("lightweightChild=" + lightweightChild + ", temporary=" + temporary +
 920                             ", focusedWindowChangeAllowed=" + focusedWindowChangeAllowed +
 921                             ", time= " + time + ", cause=" + cause);
 922         }
 923         if (LWKeyboardFocusManagerPeer.processSynchronousLightweightTransfer(
 924                 getTarget(), lightweightChild, temporary,
 925                 focusedWindowChangeAllowed, time)) {
 926             return true;
 927         }
 928 
 929         int result = LWKeyboardFocusManagerPeer.shouldNativelyFocusHeavyweight(
 930                 getTarget(), lightweightChild, temporary,
 931                 focusedWindowChangeAllowed, time, cause);
 932         switch (result) {
 933             case LWKeyboardFocusManagerPeer.SNFH_FAILURE:
 934                 return false;
 935             case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:
 936                 Window parentWindow = SunToolkit.getContainingWindow(getTarget());
 937                 if (parentWindow == null) {
 938                     focusLog.fine("request rejected, parentWindow is null");
 939                     LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
 940                     return false;
 941                 }
 942                 final LWWindowPeer parentPeer =
 943                         AWTAccessor.getComponentAccessor()
 944                                    .getPeer(parentWindow);
 945                 if (parentPeer == null) {
 946                     focusLog.fine("request rejected, parentPeer is null");
 947                     LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
 948                     return false;
 949                 }
 950 
 951                 // A fix for 7145768. Ensure the parent window is currently natively focused.
 952                 // The more evident place to perform this check is in KFM.shouldNativelyFocusHeavyweight,
 953                 // however that is the shared code and this particular problem's reproducibility has
 954                 // platform specifics. So, it was decided to narrow down the fix to lwawt (OSX) in
 955                 // current release. TODO: consider fixing it in the shared code.
 956                 if (!focusedWindowChangeAllowed) {
 957                     LWWindowPeer decoratedPeer = parentPeer.isSimpleWindow() ?
 958                         LWWindowPeer.getOwnerFrameDialog(parentPeer) : parentPeer;
 959 
 960                     if (decoratedPeer == null || !decoratedPeer.getPlatformWindow().isActive()) {
 961                         if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
 962                             focusLog.fine("request rejected, focusedWindowChangeAllowed==false, " +
 963                                           "decoratedPeer is inactive: " + decoratedPeer);
 964                         }
 965                         LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
 966                         return false;
 967                     }
 968                 }
 969 
 970                 boolean res = parentPeer.requestWindowFocus(cause);
 971                 // If parent window can be made focused and has been made focused (synchronously)
 972                 // then we can proceed with children, otherwise we retreat
 973                 if (!res || !parentWindow.isFocused()) {
 974                     if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
 975                         focusLog.fine("request rejected, res= " + res + ", parentWindow.isFocused()=" +
 976                                       parentWindow.isFocused());
 977                     }
 978                     LWKeyboardFocusManagerPeer.removeLastFocusRequest(getTarget());
 979                     return false;
 980                 }
 981 
 982                 KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
 983                 Component focusOwner = kfmPeer.getCurrentFocusOwner();
 984                 return LWKeyboardFocusManagerPeer.deliverFocus(lightweightChild,
 985                         getTarget(), temporary,
 986                         focusedWindowChangeAllowed,
 987                         time, cause, focusOwner);
 988 
 989             case LWKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:
 990                 return true;
 991         }
 992 
 993         return false;
 994     }
 995 
 996     @Override
 997     public final Image createImage(final ImageProducer producer) {
 998         return new ToolkitImage(producer);
 999     }
1000 
1001     @Override
1002     public final Image createImage(final int width, final int height) {
1003         return getLWGC().createAcceleratedImage(getTarget(), width, height);
1004     }
1005 
1006     @Override
1007     public final VolatileImage createVolatileImage(final int w, final int h) {
1008         return new SunVolatileImage(getTarget(), w, h);
1009     }
1010 
1011     @Override
1012     public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
1013         // TODO: is it a right/complete implementation?
1014         return Toolkit.getDefaultToolkit().prepareImage(img, w, h, o);
1015     }
1016 
1017     @Override
1018     public int checkImage(Image img, int w, int h, ImageObserver o) {
1019         // TODO: is it a right/complete implementation?
1020         return Toolkit.getDefaultToolkit().checkImage(img, w, h, o);
1021     }
1022 
1023     @Override
1024     public boolean handlesWheelScrolling() {
1025         // TODO: not implemented
1026         return false;
1027     }
1028 
1029     @Override
1030     public final void applyShape(final Region shape) {
1031         synchronized (getStateLock()) {
1032             if (region == shape || (region != null && region.equals(shape))) {
1033                 return;
1034             }
1035         }
1036         applyShapeImpl(shape);
1037     }
1038 
1039     void applyShapeImpl(final Region shape) {
1040         synchronized (getStateLock()) {
1041             if (shape != null) {
1042                 region = Region.WHOLE_REGION.getIntersection(shape);
1043             } else {
1044                 region = null;
1045             }
1046         }
1047         repaintParent(getBounds());
1048     }
1049 
1050     protected final Region getRegion() {
1051         synchronized (getStateLock()) {
1052             return isShaped() ? region : Region.getInstance(getSize());
1053         }
1054     }
1055 
1056     public boolean isShaped() {
1057         synchronized (getStateLock()) {
1058             return region != null;
1059         }
1060     }
1061 
1062     // DropTargetPeer Method
1063     @Override
1064     public void addDropTarget(DropTarget dt) {
1065         LWWindowPeer winPeer = getWindowPeerOrSelf();
1066         if (winPeer != null && winPeer != this) {
1067             // We need to register the DropTarget in the
1068             // peer of the window ancestor of the component
1069             winPeer.addDropTarget(dt);
1070         } else {
1071             synchronized (dropTargetLock) {
1072                 // 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only
1073                 // if it's the first (or last) one for the component. Otherwise this call is a no-op.
1074                 if (++fNumDropTargets == 1) {
1075                     // Having a non-null drop target would be an error but let's check just in case:
1076                     if (fDropTarget != null) {
1077                         throw new IllegalStateException("Current drop target is not null");
1078                     }
1079                     // Create a new drop target:
1080                     fDropTarget = LWToolkit.getLWToolkit().createDropTarget(dt, target, this);
1081                 }
1082             }
1083         }
1084     }
1085 
1086     // DropTargetPeer Method
1087     @Override
1088     public void removeDropTarget(DropTarget dt) {
1089         LWWindowPeer winPeer = getWindowPeerOrSelf();
1090         if (winPeer != null && winPeer != this) {
1091             // We need to unregister the DropTarget in the
1092             // peer of the window ancestor of the component
1093             winPeer.removeDropTarget(dt);
1094         } else {
1095             synchronized (dropTargetLock){
1096                 // 10-14-02 VL: Windows WComponentPeer would add (or remove) the drop target only
1097                 // if it's the first (or last) one for the component. Otherwise this call is a no-op.
1098                 if (--fNumDropTargets == 0) {
1099                     // Having a null drop target would be an error but let's check just in case:
1100                     if (fDropTarget != null) {
1101                         // Dispose of the drop target:
1102                         fDropTarget.dispose();
1103                         fDropTarget = null;
1104                     } else
1105                         System.err.println("CComponent.removeDropTarget(): current drop target is null.");
1106                 }
1107             }
1108         }
1109     }
1110 
1111     // ---- PEER NOTIFICATIONS ---- //
1112 
1113     /**
1114      * Called when this peer's location has been changed either as a result
1115      * of target.setLocation() or as a result of user actions (window is
1116      * dragged with mouse).
1117      *
1118      * This method could be called on the toolkit thread.
1119      */
1120     protected final void handleMove(final int x, final int y,
1121                                     final boolean updateTarget) {
1122         if (updateTarget) {
1123             AWTAccessor.getComponentAccessor().setLocation(getTarget(), x, y);
1124             postEvent(new ComponentEvent(getTarget(),
1125                                          ComponentEvent.COMPONENT_MOVED));
1126         }
1127     }
1128 
1129     /**
1130      * Called when this peer's size has been changed either as a result of
1131      * target.setSize() or as a result of user actions (window is resized).
1132      *
1133      * This method could be called on the toolkit thread.
1134      */
1135     protected final void handleResize(final int w, final int h,
1136                                       final boolean updateTarget) {
1137         Image oldBB = null;
1138         synchronized (getStateLock()) {
1139             if (backBuffer != null) {
1140                 oldBB = backBuffer;
1141                 backBuffer = getLWGC().createBackBuffer(this);
1142             }
1143         }
1144         getLWGC().destroyBackBuffer(oldBB);
1145 
1146         if (updateTarget) {
1147             AWTAccessor.getComponentAccessor().setSize(getTarget(), w, h);
1148             postEvent(new ComponentEvent(getTarget(),
1149                                          ComponentEvent.COMPONENT_RESIZED));
1150         }
1151     }
1152 
1153     protected final void repaintOldNewBounds(final Rectangle oldB) {
1154         repaintParent(oldB);
1155         repaintPeer(getSize());
1156     }
1157 
1158     protected final void repaintParent(final Rectangle oldB) {
1159         final LWContainerPeer<?, ?> cp = getContainerPeer();
1160         if (cp != null) {
1161             // Repaint unobscured part of the parent
1162             cp.repaintPeer(cp.getContentSize().intersection(oldB));
1163         }
1164     }
1165 
1166     // ---- EVENTS ---- //
1167 
1168     /**
1169      * Post an event to the proper Java EDT.
1170      */
1171     public void postEvent(final AWTEvent event) {
1172         LWToolkit.postEvent(event);
1173     }
1174 
1175     protected void postPaintEvent(int x, int y, int w, int h) {
1176         // TODO: call getIgnoreRepaint() directly with the right ACC
1177         if (AWTAccessor.getComponentAccessor().getIgnoreRepaint(target)) {
1178             return;
1179         }
1180         PaintEvent event = PaintEventDispatcher.getPaintEventDispatcher().
1181                 createPaintEvent(getTarget(), x, y, w, h);
1182         if (event != null) {
1183             postEvent(event);
1184         }
1185     }
1186 
1187     /*
1188      * Gives a chance for the peer to handle the event after it's been
1189      * processed by the target.
1190      */
1191     @Override
1192     public void handleEvent(AWTEvent e) {
1193         if ((e instanceof InputEvent) && ((InputEvent) e).isConsumed()) {
1194             return;
1195         }
1196         switch (e.getID()) {
1197             case FocusEvent.FOCUS_GAINED:
1198             case FocusEvent.FOCUS_LOST:
1199                 handleJavaFocusEvent((FocusEvent) e);
1200                 break;
1201             case PaintEvent.PAINT:
1202                 // Got a native paint event
1203 //                paintPending = false;
1204                 // fall through to the next statement
1205             case PaintEvent.UPDATE:
1206                 handleJavaPaintEvent();
1207                 break;
1208             case MouseEvent.MOUSE_PRESSED:
1209                 handleJavaMouseEvent((MouseEvent)e);
1210         }
1211 
1212         sendEventToDelegate(e);
1213     }
1214 
1215     protected void sendEventToDelegate(final AWTEvent e) {
1216         if (getDelegate() == null || !isShowing() || !isEnabled()) {
1217             return;
1218         }
1219         synchronized (getDelegateLock()) {
1220             AWTEvent delegateEvent = createDelegateEvent(e);
1221             if (delegateEvent != null) {
1222                 AWTAccessor.getComponentAccessor()
1223                         .processEvent((Component) delegateEvent.getSource(),
1224                                 delegateEvent);
1225                 if (delegateEvent instanceof KeyEvent) {
1226                     KeyEvent ke = (KeyEvent) delegateEvent;
1227                     SwingUtilities.processKeyBindings(ke);
1228                 }
1229             }
1230         }
1231     }
1232 
1233     /**
1234      * Changes the target of the AWTEvent from awt component to appropriate
1235      * swing delegate.
1236      */
1237     @SuppressWarnings("deprecation")
1238     private AWTEvent createDelegateEvent(final AWTEvent e) {
1239         // TODO modifiers should be changed to getModifiers()|getModifiersEx()?
1240         AWTEvent delegateEvent = null;
1241         if (e instanceof MouseWheelEvent) {
1242             MouseWheelEvent me = (MouseWheelEvent) e;
1243             delegateEvent = new MouseWheelEvent(
1244                     delegate, me.getID(), me.getWhen(),
1245                     me.getModifiers(),
1246                     me.getX(), me.getY(),
1247                     me.getXOnScreen(), me.getYOnScreen(),
1248                     me.getClickCount(),
1249                     me.isPopupTrigger(),
1250                     me.getScrollType(),
1251                     me.getScrollAmount(),
1252                     me.getWheelRotation(),
1253                     me.getPreciseWheelRotation());
1254         } else if (e instanceof MouseEvent) {
1255             MouseEvent me = (MouseEvent) e;
1256 
1257             Component eventTarget = SwingUtilities.getDeepestComponentAt(delegate, me.getX(), me.getY());
1258 
1259             if (me.getID() == MouseEvent.MOUSE_DRAGGED) {
1260                 if (delegateDropTarget == null) {
1261                     delegateDropTarget = eventTarget;
1262                 } else {
1263                     eventTarget = delegateDropTarget;
1264                 }
1265             }
1266             if (me.getID() == MouseEvent.MOUSE_RELEASED && delegateDropTarget != null) {
1267                 eventTarget = delegateDropTarget;
1268                 delegateDropTarget = null;
1269             }
1270             if (eventTarget == null) {
1271                 eventTarget = delegate;
1272             }
1273             delegateEvent = SwingUtilities.convertMouseEvent(getTarget(), me, eventTarget);
1274         } else if (e instanceof KeyEvent) {
1275             KeyEvent ke = (KeyEvent) e;
1276             delegateEvent = new KeyEvent(getDelegateFocusOwner(), ke.getID(), ke.getWhen(),
1277                     ke.getModifiers(), ke.getKeyCode(), ke.getKeyChar(), ke.getKeyLocation());
1278             AWTAccessor.getKeyEventAccessor().setExtendedKeyCode((KeyEvent) delegateEvent,
1279                     ke.getExtendedKeyCode());
1280         } else if (e instanceof FocusEvent) {
1281             FocusEvent fe = (FocusEvent) e;
1282             delegateEvent = new FocusEvent(getDelegateFocusOwner(), fe.getID(), fe.isTemporary());
1283         }
1284         return delegateEvent;
1285     }
1286 
1287     protected void handleJavaMouseEvent(MouseEvent e) {
1288         Component target = getTarget();
1289         assert (e.getSource() == target);
1290 
1291         if (!target.isFocusOwner() && LWKeyboardFocusManagerPeer.shouldFocusOnClick(target)) {
1292             LWKeyboardFocusManagerPeer.requestFocusFor(target, FocusEvent.Cause.MOUSE_EVENT);
1293         }
1294     }
1295 
1296     /**
1297      * Handler for FocusEvents.
1298      */
1299     void handleJavaFocusEvent(final FocusEvent e) {
1300         // Note that the peer receives all the FocusEvents from
1301         // its lightweight children as well
1302         KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance();
1303         kfmPeer.setCurrentFocusOwner(e.getID() == FocusEvent.FOCUS_GAINED ? getTarget() : null);
1304     }
1305 
1306     /**
1307      * All peers should clear background before paint.
1308      *
1309      * @return false on components that DO NOT require a clearRect() before
1310      *         painting.
1311      */
1312     protected final boolean shouldClearRectBeforePaint() {
1313         // TODO: sun.awt.noerasebackground
1314         return true;
1315     }
1316 
1317     /**
1318      * Handler for PAINT and UPDATE PaintEvents.
1319      */
1320     private void handleJavaPaintEvent() {
1321         // Skip all painting while layouting and all UPDATEs
1322         // while waiting for native paint
1323 //        if (!isLayouting && !paintPending) {
1324         if (!isLayouting()) {
1325             targetPaintArea.paint(getTarget(), shouldClearRectBeforePaint());
1326         }
1327     }
1328 
1329     // ---- UTILITY METHODS ---- //
1330 
1331     /**
1332      * Finds a top-most visible component for the given point. The location is
1333      * specified relative to the peer's parent.
1334      */
1335     LWComponentPeer<?, ?> findPeerAt(final int x, final int y) {
1336         final Rectangle r = getBounds();
1337         final Region sh = getRegion();
1338         final boolean found = isVisible() && sh.contains(x - r.x, y - r.y);
1339         return found ? this : null;
1340     }
1341 
1342     /*
1343      * Translated the given point in Window coordinates to the point in
1344      * coordinates local to this component. The given window peer must be
1345      * the window where this component is in.
1346      */
1347     public Point windowToLocal(int x, int y, LWWindowPeer wp) {
1348         return windowToLocal(new Point(x, y), wp);
1349     }
1350 
1351     public Point windowToLocal(Point p, LWWindowPeer wp) {
1352         LWComponentPeer<?, ?> cp = this;
1353         while (cp != wp) {
1354             Rectangle cpb = cp.getBounds();
1355             p.x -= cpb.x;
1356             p.y -= cpb.y;
1357             cp = cp.getContainerPeer();
1358         }
1359         // Return a copy to prevent subsequent modifications
1360         return new Point(p);
1361     }
1362 
1363     public Rectangle windowToLocal(Rectangle r, LWWindowPeer wp) {
1364         Point p = windowToLocal(r.getLocation(), wp);
1365         return new Rectangle(p, r.getSize());
1366     }
1367 
1368     public Point localToWindow(int x, int y) {
1369         return localToWindow(new Point(x, y));
1370     }
1371 
1372     public Point localToWindow(Point p) {
1373         LWComponentPeer<?, ?> cp = getContainerPeer();
1374         Rectangle r = getBounds();
1375         while (cp != null) {
1376             p.x += r.x;
1377             p.y += r.y;
1378             r = cp.getBounds();
1379             cp = cp.getContainerPeer();
1380         }
1381         // Return a copy to prevent subsequent modifications
1382         return new Point(p);
1383     }
1384 
1385     public Rectangle localToWindow(Rectangle r) {
1386         Point p = localToWindow(r.getLocation());
1387         return new Rectangle(p, r.getSize());
1388     }
1389 
1390     public final void repaintPeer() {
1391         repaintPeer(getSize());
1392     }
1393 
1394     void repaintPeer(final Rectangle r) {
1395         final Rectangle toPaint = getSize().intersection(r);
1396         if (!isShowing() || toPaint.isEmpty()) {
1397             return;
1398         }
1399 
1400         postPaintEvent(toPaint.x, toPaint.y, toPaint.width, toPaint.height);
1401     }
1402 
1403     /**
1404      * Determines whether this peer is showing on screen. This means that the
1405      * peer must be visible, and it must be in a container that is visible and
1406      * showing.
1407      *
1408      * @see #isVisible()
1409      */
1410     protected final boolean isShowing() {
1411         synchronized (getPeerTreeLock()) {
1412             if (isVisible()) {
1413                 final LWContainerPeer<?, ?> container = getContainerPeer();
1414                 return (container == null) || container.isShowing();
1415             }
1416         }
1417         return false;
1418     }
1419 
1420     /**
1421      * Paints the peer. Delegate the actual painting to Swing components.
1422      */
1423     protected final void paintPeer(final Graphics g) {
1424         final D delegate = getDelegate();
1425         if (delegate != null) {
1426             if (!SwingUtilities.isEventDispatchThread()) {
1427                 throw new InternalError("Painting must be done on EDT");
1428             }
1429             synchronized (getDelegateLock()) {
1430                 // JComponent.print() is guaranteed to not affect the double buffer
1431                 getDelegate().print(g);
1432             }
1433         }
1434     }
1435 
1436     protected static final void flushOnscreenGraphics(){
1437         final OGLRenderQueue rq = OGLRenderQueue.getInstance();
1438         rq.lock();
1439         try {
1440             rq.flushNow();
1441         } finally {
1442             rq.unlock();
1443         }
1444     }
1445 
1446     /**
1447      * Used by ContainerPeer to skip all the paint events during layout.
1448      *
1449      * @param isLayouting layouting state.
1450      */
1451     protected final void setLayouting(final boolean isLayouting) {
1452         this.isLayouting = isLayouting;
1453     }
1454 
1455     /**
1456      * Returns layouting state. Used by ComponentPeer to skip all the paint
1457      * events during layout.
1458      *
1459      * @return true during layout, false otherwise.
1460      */
1461     private boolean isLayouting() {
1462         return isLayouting;
1463     }
1464 }