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