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