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