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