1 /*
   2  * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package sun.awt.X11;
  26 
  27 import java.awt.AWTEvent;
  28 import java.awt.AWTException;
  29 import java.awt.BufferCapabilities;
  30 import java.awt.Color;
  31 import java.awt.Component;
  32 import java.awt.Container;
  33 import java.awt.Cursor;
  34 import java.awt.Dimension;
  35 import java.awt.Font;
  36 import java.awt.FontMetrics;
  37 import java.awt.Graphics;
  38 import java.awt.GraphicsConfiguration;
  39 import java.awt.Image;
  40 import java.awt.Insets;
  41 import java.awt.Rectangle;
  42 import java.awt.SystemColor;
  43 import java.awt.Toolkit;
  44 import java.awt.Window;
  45 import java.awt.dnd.DropTarget;
  46 import java.awt.dnd.peer.DropTargetPeer;
  47 import java.awt.event.FocusEvent;
  48 import java.awt.event.InputEvent;
  49 import java.awt.event.InputMethodEvent;
  50 import java.awt.event.KeyEvent;
  51 import java.awt.event.MouseEvent;
  52 import java.awt.event.MouseWheelEvent;
  53 import java.awt.event.PaintEvent;
  54 import java.awt.event.WindowEvent;
  55 import java.awt.event.InvocationEvent;
  56 import java.awt.image.ImageObserver;
  57 import java.awt.image.ImageProducer;
  58 import java.awt.image.VolatileImage;
  59 import java.awt.peer.ComponentPeer;
  60 import java.awt.peer.ContainerPeer;
  61 import java.lang.reflect.*;
  62 import java.security.*;
  63 import java.util.Collection;
  64 import java.util.Set;
  65 import sun.util.logging.PlatformLogger;
  66 import sun.awt.*;
  67 import sun.awt.event.IgnorePaintEvent;
  68 import sun.awt.image.SunVolatileImage;
  69 import sun.awt.image.ToolkitImage;
  70 import sun.java2d.BackBufferCapsProvider;
  71 import sun.java2d.pipe.Region;
  72 
  73 
  74 public class XComponentPeer extends XWindow implements ComponentPeer, DropTargetPeer,
  75     BackBufferCapsProvider
  76 {
  77     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer");
  78     private static final PlatformLogger buffersLog = PlatformLogger.getLogger("sun.awt.X11.XComponentPeer.multibuffer");
  79     private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XComponentPeer");
  80     private static final PlatformLogger fontLog = PlatformLogger.getLogger("sun.awt.X11.font.XComponentPeer");
  81     private static final PlatformLogger enableLog = PlatformLogger.getLogger("sun.awt.X11.enable.XComponentPeer");
  82     private static final PlatformLogger shapeLog = PlatformLogger.getLogger("sun.awt.X11.shape.XComponentPeer");
  83 
  84     boolean paintPending = false;
  85     boolean isLayouting = false;
  86     private boolean enabled;
  87 
  88     // Actually used only by XDecoratedPeer
  89     protected int boundsOperation;
  90 
  91     Color foreground;
  92     Color background;
  93 
  94     // Colors calculated as on Motif using MotifColorUtilties.
  95     // If you use these, call updateMotifColors() in the peer's Constructor and
  96     // setBackground().  Examples are XCheckboxPeer and XButtonPeer.
  97     Color darkShadow;
  98     Color lightShadow;
  99     Color selectColor;
 100 
 101     Font font;
 102     private long backBuffer = 0;
 103     private VolatileImage xBackBuffer = null;
 104 
 105     static Color[] systemColors;
 106 
 107     XComponentPeer() {
 108     }
 109 
 110     XComponentPeer (XCreateWindowParams params) {
 111         super(params);
 112     }
 113 
 114     XComponentPeer(Component target, long parentWindow, Rectangle bounds) {
 115         super(target, parentWindow, bounds);
 116     }
 117 
 118     /**
 119      * Standard peer constructor, with corresponding Component
 120      */
 121     XComponentPeer(Component target) {
 122         super(target);
 123     }
 124 
 125 
 126     void preInit(XCreateWindowParams params) {
 127         super.preInit(params);
 128         boundsOperation = DEFAULT_OPERATION;
 129     }
 130     void postInit(XCreateWindowParams params) {
 131         super.postInit(params);
 132 
 133         pSetCursor(target.getCursor());
 134 
 135         foreground = target.getForeground();
 136         background = target.getBackground();
 137         font = target.getFont();
 138 
 139         if (isInitialReshape()) {
 140             Rectangle r = target.getBounds();
 141             reshape(r.x, r.y, r.width, r.height);
 142         }
 143 
 144         setEnabled(target.isEnabled());
 145 
 146         if (target.isVisible()) {
 147             setVisible(true);
 148         }
 149     }
 150 
 151     protected boolean isInitialReshape() {
 152         return true;
 153     }
 154 
 155     public void reparent(ContainerPeer newNativeParent) {
 156         XComponentPeer newPeer = (XComponentPeer)newNativeParent;
 157         XToolkit.awtLock();
 158         try {
 159             XlibWrapper.XReparentWindow(XToolkit.getDisplay(), getWindow(), newPeer.getContentWindow(), x, y);
 160             parentWindow = newPeer;
 161         } finally {
 162             XToolkit.awtUnlock();
 163         }
 164     }
 165     public boolean isReparentSupported() {
 166         return System.getProperty("sun.awt.X11.XComponentPeer.reparentNotSupported", "false").equals("false");
 167     }
 168 
 169     public boolean isObscured() {
 170         Container container  = (target instanceof Container) ?
 171             (Container)target : target.getParent();
 172 
 173         if (container == null) {
 174             return true;
 175         }
 176 
 177         Container parent;
 178         while ((parent = container.getParent()) != null) {
 179             container = parent;
 180         }
 181 
 182         if (container instanceof Window) {
 183             XWindowPeer wpeer = (XWindowPeer)(container.getPeer());
 184             if (wpeer != null) {
 185                 return (wpeer.winAttr.visibilityState !=
 186                         wpeer.winAttr.AWT_UNOBSCURED);
 187             }
 188         }
 189         return true;
 190     }
 191 
 192     public boolean canDetermineObscurity() {
 193         return true;
 194     }
 195 
 196     /*************************************************
 197      * FOCUS STUFF
 198      *************************************************/
 199 
 200     /**
 201      * Keeps the track of focused state of the _NATIVE_ window
 202      */
 203     boolean bHasFocus = false;
 204 
 205     /**
 206      * Descendants should use this method to determine whether or not native window
 207      * has focus.
 208      */
 209     final public boolean hasFocus() {
 210         return bHasFocus;
 211     }
 212 
 213     /**
 214      * Called when component receives focus
 215      */
 216     public void focusGained(FocusEvent e) {
 217         focusLog.fine("{0}", e);
 218         bHasFocus = true;
 219     }
 220 
 221     /**
 222      * Called when component loses focus
 223      */
 224     public void focusLost(FocusEvent e) {
 225         focusLog.fine("{0}", e);
 226         bHasFocus = false;
 227     }
 228 
 229     public boolean isFocusable() {
 230         /* should be implemented by other sub-classes */
 231         return false;
 232     }
 233 
 234     private static Class seClass;
 235     private static Constructor seCtor;
 236 
 237     final static AWTEvent wrapInSequenced(AWTEvent event) {
 238         try {
 239             if (seClass == null) {
 240                 seClass = Class.forName("java.awt.SequencedEvent");
 241             }
 242 
 243             if (seCtor == null) {
 244                 seCtor = (Constructor) AccessController.doPrivileged(new PrivilegedExceptionAction() {
 245                         public Object run() throws Exception {
 246                             Constructor ctor = seClass.getConstructor(new Class[] { AWTEvent.class });
 247                             ctor.setAccessible(true);
 248                             return ctor;
 249                         }
 250                     });
 251             }
 252 
 253             return (AWTEvent) seCtor.newInstance(new Object[] { event });
 254         }
 255         catch (ClassNotFoundException e) {
 256             throw new NoClassDefFoundError("java.awt.SequencedEvent.");
 257         }
 258         catch (PrivilegedActionException ex) {
 259             throw new NoClassDefFoundError("java.awt.SequencedEvent.");
 260         }
 261         catch (InstantiationException e) {
 262             assert false;
 263         }
 264         catch (IllegalAccessException e) {
 265             assert false;
 266         }
 267         catch (InvocationTargetException e) {
 268             assert false;
 269         }
 270 
 271         return null;
 272     }
 273 
 274     // TODO: consider moving it to KeyboardFocusManagerPeerImpl
 275     final public boolean requestFocus(Component lightweightChild, boolean temporary,
 276                                       boolean focusedWindowChangeAllowed, long time,
 277                                       CausedFocusEvent.Cause cause)
 278     {
 279         if (XKeyboardFocusManagerPeer.
 280             processSynchronousLightweightTransfer(target, lightweightChild, temporary,
 281                                                   focusedWindowChangeAllowed, time))
 282         {
 283             return true;
 284         }
 285 
 286         int result = XKeyboardFocusManagerPeer.
 287             shouldNativelyFocusHeavyweight(target, lightweightChild,
 288                                            temporary, focusedWindowChangeAllowed,
 289                                            time, cause);
 290 
 291         switch (result) {
 292           case XKeyboardFocusManagerPeer.SNFH_FAILURE:
 293               return false;
 294           case XKeyboardFocusManagerPeer.SNFH_SUCCESS_PROCEED:
 295               // Currently we just generate focus events like we deal with lightweight instead of calling
 296               // XSetInputFocus on native window
 297               if (focusLog.isLoggable(PlatformLogger.FINER)) focusLog.finer("Proceeding with request to " +
 298                   lightweightChild + " in " + target);
 299               /**
 300                * The problems with requests in non-focused window arise because shouldNativelyFocusHeavyweight
 301                * checks that native window is focused while appropriate WINDOW_GAINED_FOCUS has not yet
 302                * been processed - it is in EventQueue. Thus, SNFH allows native request and stores request record
 303                * in requests list - and it breaks our requests sequence as first record on WGF should be the last
 304                * focus owner which had focus before WLF. So, we should not add request record for such requests
 305                * but store this component in mostRecent - and return true as before for compatibility.
 306                */
 307               Window parentWindow = SunToolkit.getContainingWindow(target);
 308               if (parentWindow == null) {
 309                   return rejectFocusRequestHelper("WARNING: Parent window is null");
 310               }
 311               XWindowPeer wpeer = (XWindowPeer)parentWindow.getPeer();
 312               if (wpeer == null) {
 313                   return rejectFocusRequestHelper("WARNING: Parent window's peer is null");
 314               }
 315               /*
 316                * Passing null 'actualFocusedWindow' as we don't want to restore focus on it
 317                * when a component inside a Frame is requesting focus.
 318                * See 6314575 for details.
 319                */
 320               boolean res = wpeer.requestWindowFocus(null);
 321 
 322               if (focusLog.isLoggable(PlatformLogger.FINER)) focusLog.finer("Requested window focus: " + res);
 323               // If parent window can be made focused and has been made focused(synchronously)
 324               // then we can proceed with children, otherwise we retreat.
 325               if (!(res && parentWindow.isFocused())) {
 326                   return rejectFocusRequestHelper("Waiting for asynchronous processing of the request");
 327               }
 328               return XKeyboardFocusManagerPeer.deliverFocus(lightweightChild,
 329                                                             (Component)target,
 330                                                             temporary,
 331                                                             focusedWindowChangeAllowed,
 332                                                             time, cause);
 333               // Motif compatibility code
 334           case XKeyboardFocusManagerPeer.SNFH_SUCCESS_HANDLED:
 335               // Either lightweight or excessive request - all events are generated.
 336               return true;
 337         }
 338         return false;
 339     }
 340 
 341     private boolean rejectFocusRequestHelper(String logMsg) {
 342         if (focusLog.isLoggable(PlatformLogger.FINER)) focusLog.finer(logMsg);
 343         XKeyboardFocusManagerPeer.removeLastFocusRequest(target);
 344         return false;
 345     }
 346 
 347     void handleJavaFocusEvent(AWTEvent e) {
 348         if (focusLog.isLoggable(PlatformLogger.FINER)) focusLog.finer(e.toString());
 349         if (e.getID() == FocusEvent.FOCUS_GAINED) {
 350             focusGained((FocusEvent)e);
 351         } else {
 352             focusLost((FocusEvent)e);
 353         }
 354     }
 355 
 356     void handleJavaWindowFocusEvent(AWTEvent e) {
 357     }
 358 
 359     /*************************************************
 360      * END OF FOCUS STUFF
 361      *************************************************/
 362 
 363 
 364 
 365     public void setVisible(boolean b) {
 366         xSetVisible(b);
 367     }
 368 
 369     public void hide() {
 370         setVisible(false);
 371     }
 372 
 373     /**
 374      * @see java.awt.peer.ComponentPeer
 375      */
 376     public void setEnabled(final boolean value) {
 377         if (enableLog.isLoggable(PlatformLogger.FINE)) {
 378             enableLog.fine("{0}ing {1}", (value ? "Enabl" : "Disabl"), this);
 379         }
 380         boolean status = value;
 381         // If any of our heavyweight ancestors are disable, we should be too
 382         // See 6176875 for more information
 383         final Container cp = SunToolkit.getNativeContainer(target);
 384         if (cp != null) {
 385             status &= ((XComponentPeer) cp.getPeer()).isEnabled();
 386         }
 387         synchronized (getStateLock()) {
 388             if (enabled == status) {
 389                 return;
 390             }
 391             enabled = status;
 392         }
 393 
 394         if (target instanceof Container) {
 395             final Component[] list = ((Container) target).getComponents();
 396             for (final Component child : list) {
 397                 final ComponentPeer p = child.getPeer();
 398                 if (p != null) {
 399                     p.setEnabled(status && child.isEnabled());
 400                 }
 401             }
 402         }
 403         repaint();
 404     }
 405 
 406     //
 407     // public so aw/Window can call it
 408     //
 409     public final boolean isEnabled() {
 410         synchronized (getStateLock()) {
 411             return enabled;
 412         }
 413     }
 414 
 415     @Override
 416     public void paint(final Graphics g) {
 417         super.paint(g);
 418         // allow target to change the picture
 419         target.paint(g);
 420     }
 421 
 422     public Graphics getGraphics() {
 423         return getGraphics(surfaceData, getPeerForeground(), getPeerBackground(), getPeerFont());
 424     }
 425     public void print(Graphics g) {
 426         // clear rect here to emulate X clears rect before Expose
 427         g.setColor(target.getBackground());
 428         g.fillRect(0, 0, target.getWidth(), target.getHeight());
 429         g.setColor(target.getForeground());
 430         // paint peer
 431         paintPeer(g);
 432         // allow target to change the picture
 433         target.print(g);
 434     }
 435 
 436     public void setBounds(int x, int y, int width, int height, int op) {
 437         this.x = x;
 438         this.y = y;
 439         this.width = width;
 440         this.height = height;
 441         xSetBounds(x,y,width,height);
 442         validateSurface();
 443         layout();
 444     }
 445 
 446     public void reshape(int x, int y, int width, int height) {
 447         setBounds(x, y, width, height, SET_BOUNDS);
 448     }
 449 
 450     public void coalescePaintEvent(PaintEvent e) {
 451         Rectangle r = e.getUpdateRect();
 452         if (!(e instanceof IgnorePaintEvent)) {
 453             paintArea.add(r, e.getID());
 454         }
 455         if (true) {
 456             switch(e.getID()) {
 457               case PaintEvent.UPDATE:
 458                   if (log.isLoggable(PlatformLogger.FINER)) {
 459                       log.finer("XCP coalescePaintEvent : UPDATE : add : x = " +
 460                             r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
 461                   }
 462                   return;
 463               case PaintEvent.PAINT:
 464                   if (log.isLoggable(PlatformLogger.FINER)) {
 465                       log.finer("XCP coalescePaintEvent : PAINT : add : x = " +
 466                             r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height);
 467                   }
 468                   return;
 469             }
 470         }
 471     }
 472 
 473     XWindowPeer getParentTopLevel() {
 474         AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
 475         Container parent = (target instanceof Container) ? ((Container)target) : (compAccessor.getParent(target));
 476         // Search for parent window
 477         while (parent != null && !(parent instanceof Window)) {
 478             parent = compAccessor.getParent(parent);
 479         }
 480         if (parent != null) {
 481             return (XWindowPeer)compAccessor.getPeer(parent);
 482         } else {
 483             return null;
 484         }
 485     }
 486 
 487     /* This method is intended to be over-ridden by peers to perform user interaction */
 488     void handleJavaMouseEvent(MouseEvent e) {
 489         switch (e.getID()) {
 490           case MouseEvent.MOUSE_PRESSED:
 491               if (target == e.getSource() &&
 492                   !target.isFocusOwner() &&
 493                   XKeyboardFocusManagerPeer.shouldFocusOnClick(target))
 494               {
 495                   XWindowPeer parentXWindow = getParentTopLevel();
 496                   Window parentWindow = ((Window)parentXWindow.getTarget());
 497                   // Simple windows are non-focusable in X terms but focusable in Java terms.
 498                   // As X-non-focusable they don't receive any focus events - we should generate them
 499                   // by ourselfves.
 500 //                   if (parentXWindow.isFocusableWindow() /*&& parentXWindow.isSimpleWindow()*/ &&
 501 //                       !(getCurrentNativeFocusedWindow() == parentWindow))
 502 //                   {
 503 //                       setCurrentNativeFocusedWindow(parentWindow);
 504 //                       WindowEvent wfg = new WindowEvent(parentWindow, WindowEvent.WINDOW_GAINED_FOCUS);
 505 //                       parentWindow.dispatchEvent(wfg);
 506 //                   }
 507                   XKeyboardFocusManagerPeer.requestFocusFor(target, CausedFocusEvent.Cause.MOUSE_EVENT);
 508               }
 509               break;
 510         }
 511     }
 512 
 513     /* This method is intended to be over-ridden by peers to perform user interaction */
 514     void handleJavaKeyEvent(KeyEvent e) {
 515     }
 516 
 517     /* This method is intended to be over-ridden by peers to perform user interaction */
 518     void handleJavaMouseWheelEvent(MouseWheelEvent e) {
 519     }
 520 
 521 
 522     /* This method is intended to be over-ridden by peers to perform user interaction */
 523     void handleJavaInputMethodEvent(InputMethodEvent e) {
 524     }
 525 
 526     void handleF10JavaKeyEvent(KeyEvent e) {
 527         if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_F10) {
 528             XWindowPeer winPeer = this.getToplevelXWindow();
 529             if (winPeer instanceof XFramePeer) {
 530                 XMenuBarPeer mPeer = ((XFramePeer)winPeer).getMenubarPeer();
 531                 if (mPeer != null) {
 532                     mPeer.handleF10KeyPress(e);
 533                 }
 534             }
 535         }
 536     }
 537 
 538     public void handleEvent(java.awt.AWTEvent e) {
 539         if ((e instanceof InputEvent) && !((InputEvent)e).isConsumed() && target.isEnabled())  {
 540             if (e instanceof MouseEvent) {
 541                 if (e instanceof MouseWheelEvent) {
 542                     handleJavaMouseWheelEvent((MouseWheelEvent) e);
 543                 }
 544                 else
 545                     handleJavaMouseEvent((MouseEvent) e);
 546             }
 547             else if (e instanceof KeyEvent) {
 548                 handleF10JavaKeyEvent((KeyEvent)e);
 549                 handleJavaKeyEvent((KeyEvent)e);
 550             }
 551         }
 552         else if (e instanceof KeyEvent && !((InputEvent)e).isConsumed()) {
 553             // even if target is disabled.
 554             handleF10JavaKeyEvent((KeyEvent)e);
 555         }
 556         else if (e instanceof InputMethodEvent) {
 557             handleJavaInputMethodEvent((InputMethodEvent) e);
 558         }
 559 
 560         int id = e.getID();
 561 
 562         switch(id) {
 563           case PaintEvent.PAINT:
 564               // Got native painting
 565               paintPending = false;
 566               // Fallthrough to next statement
 567           case PaintEvent.UPDATE:
 568               // Skip all painting while layouting and all UPDATEs
 569               // while waiting for native paint
 570               if (!isLayouting && !paintPending) {
 571                   paintArea.paint(target,false);
 572               }
 573               return;
 574           case FocusEvent.FOCUS_LOST:
 575           case FocusEvent.FOCUS_GAINED:
 576               handleJavaFocusEvent(e);
 577               break;
 578           case WindowEvent.WINDOW_LOST_FOCUS:
 579           case WindowEvent.WINDOW_GAINED_FOCUS:
 580               handleJavaWindowFocusEvent(e);
 581               break;
 582           default:
 583               break;
 584         }
 585 
 586     }
 587 
 588     public Dimension getMinimumSize() {
 589         return target.getSize();
 590     }
 591 
 592     public Dimension getPreferredSize() {
 593         return getMinimumSize();
 594     }
 595 
 596     public void layout() {}
 597 
 598     public java.awt.Toolkit getToolkit() {
 599         return Toolkit.getDefaultToolkit();
 600     }
 601 
 602     void updateMotifColors(Color bg) {
 603         int red = bg.getRed();
 604         int green = bg.getGreen();
 605         int blue = bg.getBlue();
 606 
 607         darkShadow = new Color(MotifColorUtilities.calculateBottomShadowFromBackground(red,green,blue));
 608         lightShadow = new Color(MotifColorUtilities.calculateTopShadowFromBackground(red,green,blue));
 609         selectColor= new Color(MotifColorUtilities.calculateSelectFromBackground(red,green,blue));
 610     }
 611 
 612     /*
 613      * Draw a 3D rectangle using the Motif colors.
 614      * "Normal" rectangles have shadows on the bottom.
 615      * "Depressed" rectangles (such as pressed buttons) have shadows on the top,
 616      * in which case true should be passed for topShadow.
 617      */
 618     public void drawMotif3DRect(Graphics g,
 619                                           int x, int y, int width, int height,
 620                                           boolean topShadow) {
 621         g.setColor(topShadow ? darkShadow : lightShadow);
 622         g.drawLine(x, y, x+width, y);       // top
 623         g.drawLine(x, y+height, x, y);      // left
 624 
 625         g.setColor(topShadow ? lightShadow : darkShadow );
 626         g.drawLine(x+1, y+height, x+width, y+height); // bottom
 627         g.drawLine(x+width, y+height, x+width, y+1);  // right
 628     }
 629 
 630     public void setBackground(Color c) {
 631         if (log.isLoggable(PlatformLogger.FINE)) log.fine("Set background to " + c);
 632         synchronized (getStateLock()) {
 633             background = c;
 634         }
 635         super.setBackground(c);
 636         repaint();
 637     }
 638 
 639     public void setForeground(Color c) {
 640         if (log.isLoggable(PlatformLogger.FINE)) log.fine("Set foreground to " + c);
 641         synchronized (getStateLock()) {
 642             foreground = c;
 643         }
 644         repaint();
 645     }
 646 
 647     /**
 648      * Gets the font metrics for the specified font.
 649      * @param font the font for which font metrics is to be
 650      *      obtained
 651      * @return the font metrics for <code>font</code>
 652      * @see       #getFont
 653      * @see       #getPeer
 654      * @see       java.awt.peer.ComponentPeer#getFontMetrics(Font)
 655      * @see       Toolkit#getFontMetrics(Font)
 656      * @since     JDK1.0
 657      */
 658     public FontMetrics getFontMetrics(Font font) {
 659         if (fontLog.isLoggable(PlatformLogger.FINE)) fontLog.fine("Getting font metrics for " + font);
 660         return sun.font.FontDesignMetrics.getMetrics(font);
 661     }
 662 
 663     public void setFont(Font f) {
 664         synchronized (getStateLock()) {
 665             if (f == null) {
 666                 f = XWindow.getDefaultFont();
 667             }
 668             font = f;
 669         }
 670         // as it stands currently we dont need to do layout or repaint since
 671         // layout is done in the Component upon setFont.
 672         //layout();
 673         // target.repaint();
 674         //repaint()?
 675     }
 676 
 677     public Font getFont() {
 678         return font;
 679     }
 680 
 681     public void updateCursorImmediately() {
 682         XGlobalCursorManager.getCursorManager().updateCursorImmediately();
 683     }
 684 
 685     public final void pSetCursor(Cursor cursor) {
 686         this.pSetCursor(cursor, true);
 687     }
 688 
 689     /*
 690      * The method changes the cursor.
 691      * @param cursor - a new cursor to change to.
 692      * @param ignoreSubComponents - if {@code true} is passed then
 693      *                              the new cursor will be installed on window.
 694      *                              if {@code false} is passed then
 695      *                              subsequent components will try to handle
 696      *                              this request and install their cursor.
 697      */
 698     //ignoreSubComponents not used here
 699     public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) {
 700         XToolkit.awtLock();
 701         try {
 702             long xcursor = XGlobalCursorManager.getCursor(cursor);
 703 
 704             XSetWindowAttributes xwa = new XSetWindowAttributes();
 705             xwa.set_cursor(xcursor);
 706 
 707             long valuemask = XConstants.CWCursor;
 708 
 709             XlibWrapper.XChangeWindowAttributes(XToolkit.getDisplay(),getWindow(),valuemask,xwa.pData);
 710             XlibWrapper.XFlush(XToolkit.getDisplay());
 711             xwa.dispose();
 712         } finally {
 713             XToolkit.awtUnlock();
 714         }
 715     }
 716 
 717     public Image createImage(ImageProducer producer) {
 718         return new ToolkitImage(producer);
 719     }
 720 
 721     public Image createImage(int width, int height) {
 722         return graphicsConfig.createAcceleratedImage(target, width, height);
 723     }
 724 
 725     public VolatileImage createVolatileImage(int width, int height) {
 726         return new SunVolatileImage(target, width, height);
 727     }
 728 
 729     public boolean prepareImage(Image img, int w, int h, ImageObserver o) {
 730         return getToolkit().prepareImage(img, w, h, o);
 731     }
 732 
 733     public int checkImage(Image img, int w, int h, ImageObserver o) {
 734         return getToolkit().checkImage(img, w, h, o);
 735     }
 736 
 737     public Dimension preferredSize() {
 738         return getPreferredSize();
 739     }
 740 
 741     public Dimension minimumSize() {
 742         return getMinimumSize();
 743     }
 744 
 745     public Insets getInsets() {
 746         return new Insets(0, 0, 0, 0);
 747     }
 748 
 749     public void beginValidate() {
 750     }
 751 
 752     public void endValidate() {
 753     }
 754 
 755 
 756     /**
 757      * DEPRECATED:  Replaced by getInsets().
 758      */
 759 
 760     public Insets insets() {
 761         return getInsets();
 762     }
 763 
 764     // Returns true if we are inside begin/endLayout and
 765     // are waiting for native painting
 766     public boolean isPaintPending() {
 767         return paintPending && isLayouting;
 768     }
 769 
 770     public boolean handlesWheelScrolling() {
 771         return false;
 772     }
 773 
 774     public void beginLayout() {
 775         // Skip all painting till endLayout
 776         isLayouting = true;
 777 
 778     }
 779 
 780     public void endLayout() {
 781         if (!paintPending && !paintArea.isEmpty()
 782             && !AWTAccessor.getComponentAccessor().getIgnoreRepaint(target))
 783         {
 784             // if not waiting for native painting repaint damaged area
 785             postEvent(new PaintEvent(target, PaintEvent.PAINT,
 786                                      new Rectangle()));
 787         }
 788         isLayouting = false;
 789     }
 790 
 791     public Color getWinBackground() {
 792         return getPeerBackground();
 793     }
 794 
 795     static int[] getRGBvals(Color c) {
 796 
 797         int rgbvals[] = new int[3];
 798 
 799         rgbvals[0] = c.getRed();
 800         rgbvals[1] = c.getGreen();
 801         rgbvals[2] = c.getBlue();
 802 
 803         return rgbvals;
 804     }
 805 
 806     static final int BACKGROUND_COLOR = 0;
 807     static final int HIGHLIGHT_COLOR = 1;
 808     static final int SHADOW_COLOR = 2;
 809     static final int FOREGROUND_COLOR = 3;
 810 
 811     public Color[] getGUIcolors() {
 812         Color c[] = new Color[4];
 813         float backb, highb, shadowb, hue, saturation;
 814         c[BACKGROUND_COLOR] = getWinBackground();
 815         if (c[BACKGROUND_COLOR] == null) {
 816             c[BACKGROUND_COLOR] = super.getWinBackground();
 817         }
 818         if (c[BACKGROUND_COLOR] == null) {
 819             c[BACKGROUND_COLOR] = Color.lightGray;
 820         }
 821 
 822         int[] rgb = getRGBvals(c[BACKGROUND_COLOR]);
 823 
 824         float[] hsb = Color.RGBtoHSB(rgb[0],rgb[1],rgb[2],null);
 825 
 826         hue = hsb[0];
 827         saturation = hsb[1];
 828         backb = hsb[2];
 829 
 830 
 831 /*      Calculate Highlight Brightness  */
 832 
 833         highb = backb + 0.2f;
 834         shadowb = backb - 0.4f;
 835         if ((highb > 1.0) ) {
 836             if  ((1.0 - backb) < 0.05) {
 837                 highb = shadowb + 0.25f;
 838             } else {
 839                 highb = 1.0f;
 840             }
 841         } else {
 842             if (shadowb < 0.0) {
 843                 if ((backb - 0.0) < 0.25) {
 844                     highb = backb + 0.75f;
 845                     shadowb = highb - 0.2f;
 846                 } else {
 847                     shadowb = 0.0f;
 848                 }
 849             }
 850         }
 851         c[HIGHLIGHT_COLOR] = Color.getHSBColor(hue,saturation,highb);
 852         c[SHADOW_COLOR] = Color.getHSBColor(hue,saturation,shadowb);
 853 
 854 
 855 /*
 856   c[SHADOW_COLOR] = c[BACKGROUND_COLOR].darker();
 857   int r2 = c[SHADOW_COLOR].getRed();
 858   int g2 = c[SHADOW_COLOR].getGreen();
 859   int b2 = c[SHADOW_COLOR].getBlue();
 860 */
 861 
 862         c[FOREGROUND_COLOR] = getPeerForeground();
 863         if (c[FOREGROUND_COLOR] == null) {
 864             c[FOREGROUND_COLOR] = Color.black;
 865         }
 866 /*
 867   if ((c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR]))
 868   && (c[BACKGROUND_COLOR].equals(c[SHADOW_COLOR]))) {
 869   c[SHADOW_COLOR] = new Color(c[BACKGROUND_COLOR].getRed() + 75,
 870   c[BACKGROUND_COLOR].getGreen() + 75,
 871   c[BACKGROUND_COLOR].getBlue() + 75);
 872   c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR].brighter();
 873   } else if (c[BACKGROUND_COLOR].equals(c[HIGHLIGHT_COLOR])) {
 874   c[HIGHLIGHT_COLOR] = c[SHADOW_COLOR];
 875   c[SHADOW_COLOR] = c[SHADOW_COLOR].darker();
 876   }
 877 */
 878         if (! isEnabled()) {
 879             c[BACKGROUND_COLOR] = c[BACKGROUND_COLOR].darker();
 880             // Reduce the contrast
 881             // Calculate the NTSC gray (NB: REC709 L* might be better!)
 882             // for foreground and background; then multiply the foreground
 883             // by the average lightness
 884 
 885 
 886             Color tc = c[BACKGROUND_COLOR];
 887             int bg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;
 888 
 889             tc = c[FOREGROUND_COLOR];
 890             int fg = tc.getRed() * 30 + tc.getGreen() * 59 + tc.getBlue() * 11;
 891 
 892             float ave = (float) ((fg + bg) / 51000.0);
 893             // 255 * 100 * 2
 894 
 895             Color newForeground = new Color((int) (tc.getRed() * ave),
 896                                             (int) (tc.getGreen() * ave),
 897                                             (int) (tc.getBlue() * ave));
 898 
 899             if (newForeground.equals(c[FOREGROUND_COLOR])) {
 900                 // This probably means the foreground color is black or white
 901                 newForeground = new Color(ave, ave, ave);
 902             }
 903             c[FOREGROUND_COLOR] = newForeground;
 904 
 905         }
 906 
 907 
 908         return c;
 909     }
 910 
 911     /**
 912      * Returns an array of Colors similar to getGUIcolors(), but using the
 913      * System colors.  This is useful if pieces of a Component (such as
 914      * the integrated scrollbars of a List) should retain the System color
 915      * instead of the background color set by Component.setBackground().
 916      */
 917     static Color[] getSystemColors() {
 918         if (systemColors == null) {
 919             systemColors = new Color[4];
 920             systemColors[BACKGROUND_COLOR] = SystemColor.window;
 921             systemColors[HIGHLIGHT_COLOR] = SystemColor.controlLtHighlight;
 922             systemColors[SHADOW_COLOR] = SystemColor.controlShadow;
 923             systemColors[FOREGROUND_COLOR] = SystemColor.windowText;
 924         }
 925         return systemColors;
 926     }
 927 
 928     /**
 929      * Draw a 3D oval.
 930      */
 931     public void draw3DOval(Graphics g, Color colors[],
 932                            int x, int y, int w, int h, boolean raised)
 933         {
 934         Color c = g.getColor();
 935         g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);
 936         g.drawArc(x, y, w, h, 45, 180);
 937         g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);
 938         g.drawArc(x, y, w, h, 225, 180);
 939         g.setColor(c);
 940     }
 941 
 942     public void draw3DRect(Graphics g, Color colors[],
 943                            int x, int y, int width, int height, boolean raised)
 944         {
 945             Color c = g.getColor();
 946             g.setColor(raised ? colors[HIGHLIGHT_COLOR] : colors[SHADOW_COLOR]);
 947             g.drawLine(x, y, x, y + height);
 948             g.drawLine(x + 1, y, x + width - 1, y);
 949             g.setColor(raised ? colors[SHADOW_COLOR] : colors[HIGHLIGHT_COLOR]);
 950             g.drawLine(x + 1, y + height, x + width, y + height);
 951             g.drawLine(x + width, y, x + width, y + height - 1);
 952             g.setColor(c);
 953         }
 954 
 955     /*
 956      * drawXXX() methods are used to print the native components by
 957      * rendering the Motif look ourselves.
 958      * ToDo(aim): needs to query native motif for more accurate color
 959      * information.
 960      */
 961     void draw3DOval(Graphics g, Color bg,
 962                     int x, int y, int w, int h, boolean raised)
 963         {
 964             Color c = g.getColor();
 965             Color shadow = bg.darker();
 966             Color highlight = bg.brighter();
 967 
 968             g.setColor(raised ? highlight : shadow);
 969             g.drawArc(x, y, w, h, 45, 180);
 970             g.setColor(raised ? shadow : highlight);
 971             g.drawArc(x, y, w, h, 225, 180);
 972             g.setColor(c);
 973         }
 974 
 975     void draw3DRect(Graphics g, Color bg,
 976                     int x, int y, int width, int height,
 977                     boolean raised) {
 978         Color c = g.getColor();
 979         Color shadow = bg.darker();
 980         Color highlight = bg.brighter();
 981 
 982         g.setColor(raised ? highlight : shadow);
 983         g.drawLine(x, y, x, y + height);
 984         g.drawLine(x + 1, y, x + width - 1, y);
 985         g.setColor(raised ? shadow : highlight);
 986         g.drawLine(x + 1, y + height, x + width, y + height);
 987         g.drawLine(x + width, y, x + width, y + height - 1);
 988         g.setColor(c);
 989     }
 990 
 991     void drawScrollbar(Graphics g, Color bg, int thickness, int length,
 992                int min, int max, int val, int vis, boolean horizontal) {
 993         Color c = g.getColor();
 994         double f = (double)(length - 2*(thickness-1)) / Math.max(1, ((max - min) + vis));
 995         int v1 = thickness + (int)(f * (val - min));
 996         int v2 = (int)(f * vis);
 997         int w2 = thickness-4;
 998         int tpts_x[] = new int[3];
 999         int tpts_y[] = new int[3];
1000 
1001         if (length < 3*w2 ) {
1002             v1 = v2 = 0;
1003             if (length < 2*w2 + 2) {
1004                 w2 = (length-2)/2;
1005             }
1006         } else  if (v2 < 7) {
1007             // enforce a minimum handle size
1008             v1 = Math.max(0, v1 - ((7 - v2)>>1));
1009             v2 = 7;
1010         }
1011 
1012         int ctr   = thickness/2;
1013         int sbmin = ctr - w2/2;
1014         int sbmax = ctr + w2/2;
1015 
1016         // paint the background slightly darker
1017         {
1018             Color d = new Color((int) (bg.getRed()   * 0.85),
1019                                 (int) (bg.getGreen() * 0.85),
1020                                 (int) (bg.getBlue()  * 0.85));
1021 
1022             g.setColor(d);
1023             if (horizontal) {
1024                 g.fillRect(0, 0, length, thickness);
1025             } else {
1026                 g.fillRect(0, 0, thickness, length);
1027             }
1028         }
1029 
1030         // paint the thumb and arrows in the normal background color
1031         g.setColor(bg);
1032         if (v1 > 0) {
1033             if (horizontal) {
1034                 g.fillRect(v1, 3, v2, thickness-3);
1035             } else {
1036                 g.fillRect(3, v1, thickness-3, v2);
1037             }
1038         }
1039 
1040         tpts_x[0] = ctr;    tpts_y[0] = 2;
1041         tpts_x[1] = sbmin;  tpts_y[1] = w2;
1042         tpts_x[2] = sbmax;  tpts_y[2] = w2;
1043         if (horizontal) {
1044             g.fillPolygon(tpts_y, tpts_x, 3);
1045         } else {
1046             g.fillPolygon(tpts_x, tpts_y, 3);
1047         }
1048 
1049         tpts_y[0] = length-2;
1050         tpts_y[1] = length-w2;
1051         tpts_y[2] = length-w2;
1052         if (horizontal) {
1053             g.fillPolygon(tpts_y, tpts_x, 3);
1054         } else {
1055             g.fillPolygon(tpts_x, tpts_y, 3);
1056         }
1057 
1058         Color highlight = bg.brighter();
1059 
1060         // // // // draw the "highlighted" edges
1061         g.setColor(highlight);
1062 
1063         // outline & arrows
1064         if (horizontal) {
1065             g.drawLine(1, thickness, length - 1, thickness);
1066             g.drawLine(length - 1, 1, length - 1, thickness);
1067 
1068             // arrows
1069             g.drawLine(1, ctr, w2, sbmin);
1070             g.drawLine(length - w2, sbmin, length - w2, sbmax);
1071             g.drawLine(length - w2, sbmin, length - 2, ctr);
1072 
1073         } else {
1074             g.drawLine(thickness, 1, thickness, length - 1);
1075             g.drawLine(1, length - 1, thickness, length - 1);
1076 
1077             // arrows
1078             g.drawLine(ctr, 1, sbmin, w2);
1079             g.drawLine(sbmin, length - w2, sbmax, length - w2);
1080             g.drawLine(sbmin, length - w2, ctr, length - 2);
1081         }
1082 
1083         // thumb
1084         if (v1 > 0) {
1085             if (horizontal) {
1086                 g.drawLine(v1, 2, v1 + v2, 2);
1087                 g.drawLine(v1, 2, v1, thickness-3);
1088             } else {
1089                 g.drawLine(2, v1, 2, v1 + v2);
1090                 g.drawLine(2, v1, thickness-3, v1);
1091             }
1092         }
1093 
1094         Color shadow = bg.darker();
1095 
1096         // // // // draw the "shadowed" edges
1097         g.setColor(shadow);
1098 
1099         // outline && arrows
1100         if (horizontal) {
1101             g.drawLine(0, 0, 0, thickness);
1102             g.drawLine(0, 0, length - 1, 0);
1103 
1104             // arrows
1105             g.drawLine(w2, sbmin, w2, sbmax);
1106             g.drawLine(w2, sbmax, 1, ctr);
1107             g.drawLine(length-2, ctr, length-w2, sbmax);
1108 
1109         } else {
1110             g.drawLine(0, 0, thickness, 0);
1111             g.drawLine(0, 0, 0, length - 1);
1112 
1113             // arrows
1114             g.drawLine(sbmin, w2, sbmax, w2);
1115             g.drawLine(sbmax, w2, ctr, 1);
1116             g.drawLine(ctr, length-2, sbmax, length-w2);
1117         }
1118 
1119         // thumb
1120         if (v1 > 0) {
1121             if (horizontal) {
1122                 g.drawLine(v1 + v2, 2, v1 + v2, thickness-2);
1123                 g.drawLine(v1, thickness-2, v1 + v2, thickness-2);
1124             } else {
1125                 g.drawLine(2, v1 + v2, thickness-2, v1 + v2);
1126                 g.drawLine(thickness-2, v1, thickness-2, v1 + v2);
1127             }
1128         }
1129         g.setColor(c);
1130     }
1131 
1132     /**
1133      * The following multibuffering-related methods delegate to our
1134      * associated GraphicsConfig (X11 or GLX) to handle the appropriate
1135      * native windowing system specific actions.
1136      */
1137 
1138     private BufferCapabilities backBufferCaps;
1139 
1140     public void createBuffers(int numBuffers, BufferCapabilities caps)
1141       throws AWTException
1142     {
1143         if (buffersLog.isLoggable(PlatformLogger.FINE)) {
1144             buffersLog.fine("createBuffers(" + numBuffers + ", " + caps + ")");
1145         }
1146         // set the caps first, they're used when creating the bb
1147         backBufferCaps = caps;
1148         backBuffer = graphicsConfig.createBackBuffer(this, numBuffers, caps);
1149         xBackBuffer = graphicsConfig.createBackBufferImage(target,
1150                                                            backBuffer);
1151     }
1152 
1153     @Override
1154     public BufferCapabilities getBackBufferCaps() {
1155         return backBufferCaps;
1156     }
1157 
1158     public void flip(int x1, int y1, int x2, int y2,
1159                      BufferCapabilities.FlipContents flipAction)
1160     {
1161         if (buffersLog.isLoggable(PlatformLogger.FINE)) {
1162             buffersLog.fine("flip(" + flipAction + ")");
1163         }
1164         if (backBuffer == 0) {
1165             throw new IllegalStateException("Buffers have not been created");
1166         }
1167         graphicsConfig.flip(this, target, xBackBuffer,
1168                             x1, y1, x2, y2, flipAction);
1169     }
1170 
1171     public Image getBackBuffer() {
1172         if (buffersLog.isLoggable(PlatformLogger.FINE)) {
1173             buffersLog.fine("getBackBuffer()");
1174         }
1175         if (backBuffer == 0) {
1176             throw new IllegalStateException("Buffers have not been created");
1177         }
1178         return xBackBuffer;
1179     }
1180 
1181     public void destroyBuffers() {
1182         if (buffersLog.isLoggable(PlatformLogger.FINE)) {
1183             buffersLog.fine("destroyBuffers()");
1184         }
1185         graphicsConfig.destroyBackBuffer(backBuffer);
1186         backBuffer = 0;
1187         xBackBuffer = null;
1188     }
1189 
1190     // End of multi-buffering
1191 
1192     public void notifyTextComponentChange(boolean add){
1193         Container parent = AWTAccessor.getComponentAccessor().getParent(target);
1194         while(!(parent == null ||
1195                 parent instanceof java.awt.Frame ||
1196                 parent instanceof java.awt.Dialog)) {
1197             parent = AWTAccessor.getComponentAccessor().getParent(parent);
1198         }
1199 
1200 /*      FIX ME - FIX ME need to implement InputMethods
1201     if (parent instanceof java.awt.Frame ||
1202         parent instanceof java.awt.Dialog) {
1203         if (add)
1204         ((MInputMethodControl)parent.getPeer()).addTextComponent((MComponentPeer)this);
1205         else
1206         ((MInputMethodControl)parent.getPeer()).removeTextComponent((MComponentPeer)this);
1207     }
1208 */
1209     }
1210 
1211     /**
1212      * Returns true if this event is disabled and shouldn't be processed by window
1213      * Currently if target component is disabled the following event will be disabled on window:
1214      * ButtonPress, ButtonRelease, KeyPress, KeyRelease, EnterNotify, LeaveNotify, MotionNotify
1215      */
1216     protected boolean isEventDisabled(XEvent e) {
1217         if (enableLog.isLoggable(PlatformLogger.FINEST)) {
1218             enableLog.finest("Component is {1}, checking for disabled event {0}", e, (isEnabled()?"enabled":"disable"));
1219         }
1220         if (!isEnabled()) {
1221             switch (e.get_type()) {
1222               case XConstants.ButtonPress:
1223               case XConstants.ButtonRelease:
1224               case XConstants.KeyPress:
1225               case XConstants.KeyRelease:
1226               case XConstants.EnterNotify:
1227               case XConstants.LeaveNotify:
1228               case XConstants.MotionNotify:
1229                   if (enableLog.isLoggable(PlatformLogger.FINER)) {
1230                       enableLog.finer("Event {0} is disable", e);
1231                   }
1232                   return true;
1233             }
1234         }
1235         switch(e.get_type()) {
1236           case XConstants.MapNotify:
1237           case XConstants.UnmapNotify:
1238               return true;
1239         }
1240         return super.isEventDisabled(e);
1241     }
1242 
1243     Color getPeerBackground() {
1244         return background;
1245     }
1246 
1247     Color getPeerForeground() {
1248         return foreground;
1249     }
1250 
1251     Font getPeerFont() {
1252         return font;
1253     }
1254 
1255     Dimension getPeerSize() {
1256         return new Dimension(width,height);
1257     }
1258 
1259     public void setBoundsOperation(int operation) {
1260         synchronized(getStateLock()) {
1261             if (boundsOperation == DEFAULT_OPERATION) {
1262                 boundsOperation = operation;
1263             } else if (operation == RESET_OPERATION) {
1264                 boundsOperation = DEFAULT_OPERATION;
1265             }
1266         }
1267     }
1268 
1269     static String operationToString(int operation) {
1270         switch (operation) {
1271           case SET_LOCATION:
1272               return "SET_LOCATION";
1273           case SET_SIZE:
1274               return "SET_SIZE";
1275           case SET_CLIENT_SIZE:
1276               return "SET_CLIENT_SIZE";
1277           default:
1278           case SET_BOUNDS:
1279               return "SET_BOUNDS";
1280         }
1281     }
1282 
1283     /**
1284      * Lowers this component at the bottom of the above HW peer. If the above parameter
1285      * is null then the method places this component at the top of the Z-order.
1286      */
1287     public void setZOrder(ComponentPeer above) {
1288         long aboveWindow = (above != null) ? ((XComponentPeer)above).getWindow() : 0;
1289 
1290         XToolkit.awtLock();
1291         try{
1292             XlibWrapper.SetZOrder(XToolkit.getDisplay(), getWindow(), aboveWindow);
1293         }finally{
1294             XToolkit.awtUnlock();
1295         }
1296     }
1297 
1298     private void addTree(Collection order, Set set, Container cont) {
1299         for (int i = 0; i < cont.getComponentCount(); i++) {
1300             Component comp = cont.getComponent(i);
1301             ComponentPeer peer = comp.getPeer();
1302             if (peer instanceof XComponentPeer) {
1303                 Long window = Long.valueOf(((XComponentPeer)peer).getWindow());
1304                 if (!set.contains(window)) {
1305                     set.add(window);
1306                     order.add(window);
1307                 }
1308             } else if (comp instanceof Container) {
1309                 // It is lightweight container, it might contain heavyweight components attached to this
1310                 // peer
1311                 addTree(order, set, (Container)comp);
1312             }
1313         }
1314     }
1315 
1316     /****** DropTargetPeer implementation ********************/
1317 
1318     public void addDropTarget(DropTarget dt) {
1319         Component comp = target;
1320         while(!(comp == null || comp instanceof Window)) {
1321             comp = comp.getParent();
1322         }
1323 
1324         if (comp instanceof Window) {
1325             XWindowPeer wpeer = (XWindowPeer)(comp.getPeer());
1326             if (wpeer != null) {
1327                 wpeer.addDropTarget();
1328             }
1329         }
1330     }
1331 
1332     public void removeDropTarget(DropTarget dt) {
1333         Component comp = target;
1334         while(!(comp == null || comp instanceof Window)) {
1335             comp = comp.getParent();
1336         }
1337 
1338         if (comp instanceof Window) {
1339             XWindowPeer wpeer = (XWindowPeer)(comp.getPeer());
1340             if (wpeer != null) {
1341                 wpeer.removeDropTarget();
1342             }
1343         }
1344     }
1345 
1346     /**
1347      * Applies the shape to the X-window.
1348      * @since 1.7
1349      */
1350     public void applyShape(Region shape) {
1351         if (XlibUtil.isShapingSupported()) {
1352             if (shapeLog.isLoggable(PlatformLogger.FINER)) {
1353                 shapeLog.finer(
1354                         "*** INFO: Setting shape: PEER: " + this
1355                         + "; WINDOW: " + getWindow()
1356                         + "; TARGET: " + target
1357                         + "; SHAPE: " + shape);
1358             }
1359             XToolkit.awtLock();
1360             try {
1361                 if (shape != null) {
1362                     XlibWrapper.SetRectangularShape(
1363                             XToolkit.getDisplay(),
1364                             getWindow(),
1365                             shape.getLoX(), shape.getLoY(),
1366                             shape.getHiX(), shape.getHiY(),
1367                             (shape.isRectangular() ? null : shape)
1368                             );
1369                 } else {
1370                     XlibWrapper.SetRectangularShape(
1371                             XToolkit.getDisplay(),
1372                             getWindow(),
1373                             0, 0,
1374                             0, 0,
1375                             null
1376                             );
1377                 }
1378             } finally {
1379                 XToolkit.awtUnlock();
1380             }
1381         } else {
1382             if (shapeLog.isLoggable(PlatformLogger.FINER)) {
1383                 shapeLog.finer("*** WARNING: Shaping is NOT supported!");
1384             }
1385         }
1386     }
1387 
1388     public boolean updateGraphicsData(GraphicsConfiguration gc) {
1389         int oldVisual = -1, newVisual = -1;
1390 
1391         if (graphicsConfig != null) {
1392             oldVisual = graphicsConfig.getVisual();
1393         }
1394         if (gc != null && gc instanceof X11GraphicsConfig) {
1395             newVisual = ((X11GraphicsConfig)gc).getVisual();
1396         }
1397 
1398         // If the new visual differs from the old one, the peer must be
1399         // recreated because X11 does not allow changing the visual on the fly.
1400         // So we even skip the initGraphicsConfiguration() call.
1401         // The initial assignment should happen though, hence the != -1 thing.
1402         if (oldVisual != -1 && oldVisual != newVisual) {
1403             return true;
1404         }
1405 
1406         initGraphicsConfiguration();
1407         doValidateSurface();
1408         return false;
1409     }
1410 }