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