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