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