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