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