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