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