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