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