1 /*
   2  * Copyright (c) 2002, 2007, 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.util.Vector;
  28 import java.awt.*;
  29 import java.awt.peer.*;
  30 import java.awt.event.*;
  31 import sun.awt.im.*;
  32 import sun.awt.*;
  33 import java.util.logging.*;
  34 import java.lang.reflect.Field;
  35 import java.util.*;
  36 
  37 class XFramePeer extends XDecoratedPeer implements FramePeer, XConstants {
  38     private static Logger log = Logger.getLogger("sun.awt.X11.XFramePeer");
  39     private static Logger stateLog = Logger.getLogger("sun.awt.X11.states");
  40     private static Logger insLog = Logger.getLogger("sun.awt.X11.insets.XFramePeer");
  41 
  42     XMenuBarPeer menubarPeer;
  43     MenuBar menubar;
  44     int state;
  45     private Boolean undecorated;
  46 
  47     private static final int MENUBAR_HEIGHT_IF_NO_MENUBAR = 0;
  48     private int lastAppliedMenubarHeight = MENUBAR_HEIGHT_IF_NO_MENUBAR;
  49 
  50     XFramePeer(Frame target) {
  51         super(target);
  52     }
  53 
  54     XFramePeer(XCreateWindowParams params) {
  55         super(params);
  56     }
  57 
  58     void preInit(XCreateWindowParams params) {
  59         super.preInit(params);
  60         Frame target = (Frame)(this.target);
  61         // set the window attributes for this Frame
  62         winAttr.initialState = target.getExtendedState();
  63         state = 0;
  64         undecorated = Boolean.valueOf(target.isUndecorated());
  65         winAttr.nativeDecor = !target.isUndecorated();
  66         if (winAttr.nativeDecor) {
  67             winAttr.decorations = winAttr.AWT_DECOR_ALL;
  68         } else {
  69             winAttr.decorations = winAttr.AWT_DECOR_NONE;
  70         }
  71         winAttr.functions = MWM_FUNC_ALL;
  72         winAttr.isResizable = true; // target.isResizable();
  73         winAttr.title = target.getTitle();
  74         winAttr.initialResizability = target.isResizable();
  75         if (log.isLoggable(Level.FINE)) {
  76             log.log(Level.FINE, "Frame''s initial attributes: decor {0}, resizable {1}, undecorated {2}, initial state {3}",
  77                      new Object[] {Integer.valueOf(winAttr.decorations), Boolean.valueOf(winAttr.initialResizability),
  78                                    Boolean.valueOf(!winAttr.nativeDecor), Integer.valueOf(winAttr.initialState)});
  79         }
  80     }
  81 
  82     void postInit(XCreateWindowParams params) {
  83         super.postInit(params);
  84         setupState(true);
  85     }
  86 
  87     protected Insets guessInsets() {
  88         if (isTargetUndecorated()) {
  89             return new Insets(0, 0, 0, 0);
  90         } else {
  91             return super.guessInsets();
  92         }
  93     }
  94 
  95     @Override
  96     boolean isTargetUndecorated() {
  97         if (undecorated != null) {
  98             return undecorated.booleanValue();
  99         } else {
 100             return ((Frame)target).isUndecorated();
 101         }
 102     }
 103 
 104     void setupState(boolean onInit) {
 105         if (onInit) {
 106             state = winAttr.initialState;
 107         }
 108         if ((state & Frame.ICONIFIED) != 0) {
 109             setInitialState(IconicState);
 110         } else {
 111             setInitialState(NormalState);
 112         }
 113         setExtendedState(state);
 114     }
 115 
 116     public void setMenuBar(MenuBar mb) {
 117         // state_lock should always be the second after awt_lock
 118         XToolkit.awtLock();
 119         try {
 120             synchronized(getStateLock()) {
 121                 if (mb == menubar) return;
 122                 if (mb == null) {
 123                     if (menubar != null) {
 124                         menubarPeer.xSetVisible(false);
 125                         menubar = null;
 126                         menubarPeer.dispose();
 127                         menubarPeer = null;
 128                     }
 129                 } else {
 130                     menubar = mb;
 131                     menubarPeer = (XMenuBarPeer) mb.getPeer();
 132                     if (menubarPeer != null) {
 133                         menubarPeer.init((Frame)target);
 134                     }
 135                 }
 136             }
 137         } finally {
 138             XToolkit.awtUnlock();
 139         }
 140 
 141         reshapeMenubarPeer();
 142     }
 143 
 144     XMenuBarPeer getMenubarPeer() {
 145         return menubarPeer;
 146     }
 147 
 148     int getMenuBarHeight() {
 149         if (menubarPeer != null) {
 150             return menubarPeer.getDesiredHeight();
 151         } else {
 152             return MENUBAR_HEIGHT_IF_NO_MENUBAR;
 153         }
 154     }
 155 
 156     void updateChildrenSizes() {
 157         super.updateChildrenSizes();
 158         // XWindow.reshape calls XBaseWindow.xSetBounds, which acquires
 159         // the AWT lock, so we have to acquire the AWT lock here
 160         // before getStateLock() to avoid a deadlock with the Toolkit thread
 161         // when this method is called on the EDT.
 162         XToolkit.awtLock();
 163         try {
 164             synchronized(getStateLock()) {
 165                 int width = dimensions.getClientSize().width;
 166                 if (menubarPeer != null) {
 167                     menubarPeer.reshape(0, 0, width, getMenuBarHeight());
 168                 }
 169             }
 170         } finally {
 171             XToolkit.awtUnlock();
 172         }
 173     }
 174 
 175     /**
 176      * In addition to reshaping menubarPeer (by using 'updateChildrenSizes')
 177      * this method also performs some frame reaction on this (i.e. layouts
 178      * other frame children, if required)
 179      */
 180     final void reshapeMenubarPeer() {
 181         XToolkit.executeOnEventHandlerThread(
 182             target,
 183             new Runnable() {
 184                 public void run() {
 185                     updateChildrenSizes();
 186                     boolean heightChanged = false;
 187 
 188                     int height = getMenuBarHeight();
 189                         // Neither 'XToolkit.awtLock()' nor 'getStateLock()'
 190                         // is acquired under this call, and it looks to run
 191                         // thread-safely. I currently see no reason to move
 192                         // it under following 'synchronized' clause.
 193 
 194                     synchronized(getStateLock()) {
 195                         if (height != lastAppliedMenubarHeight) {
 196                             lastAppliedMenubarHeight = height;
 197                             heightChanged = true;
 198                         }
 199                     }
 200                     if (heightChanged) {
 201                         // To make frame contents be re-layout (copied from
 202                         // 'XDecoratedPeer.revalidate()'). These are not
 203                         // 'synchronized', because can recursively call client
 204                         // methods, which are not supposed to be called with locks
 205                         // acquired.
 206                         target.invalidate();
 207                         target.validate();
 208                     }
 209                 }
 210             }
 211         );
 212     }
 213 
 214     public void setMaximizedBounds(Rectangle b) {
 215         if (insLog.isLoggable(Level.FINE)) {
 216             insLog.fine("Setting maximized bounds to " + b);
 217         }
 218         if (b == null) return;
 219         maxBounds = new Rectangle(b);
 220         XToolkit.awtLock();
 221         try {
 222             XSizeHints hints = getHints();
 223             hints.set_flags(hints.get_flags() | (int)XlibWrapper.PMaxSize);
 224             if (b.width != Integer.MAX_VALUE) {
 225                 hints.set_max_width(b.width);
 226             } else {
 227                 hints.set_max_width((int)XlibWrapper.DisplayWidth(XToolkit.getDisplay(), XlibWrapper.DefaultScreen(XToolkit.getDisplay())));
 228             }
 229             if (b.height != Integer.MAX_VALUE) {
 230                 hints.set_max_height(b.height);
 231             } else {
 232                 hints.set_max_height((int)XlibWrapper.DisplayHeight(XToolkit.getDisplay(), XlibWrapper.DefaultScreen(XToolkit.getDisplay())));
 233             }
 234             if (insLog.isLoggable(Level.FINER)) {
 235                 insLog.finer("Setting hints, flags " + XlibWrapper.hintsToString(hints.get_flags()));
 236             }
 237             XlibWrapper.XSetWMNormalHints(XToolkit.getDisplay(), window, hints.pData);
 238         } finally {
 239             XToolkit.awtUnlock();
 240         }
 241     }
 242 
 243     public int getState() { return state; }
 244 
 245     public void setState(int newState) {
 246         if (!isShowing()) {
 247             if (stateLog.isLoggable(Level.FINER)) {
 248                 stateLog.finer("Frame is not showing");
 249             }
 250             state = newState;
 251             return;
 252         }
 253         changeState(newState);
 254     }
 255 
 256     void changeState(int newState) {
 257         int changed = state ^ newState;
 258         int changeIconic = changed & Frame.ICONIFIED;
 259         boolean iconic = (newState & Frame.ICONIFIED) != 0;
 260         if (stateLog.isLoggable(Level.FINER)) {
 261             stateLog.log(Level.FINER, "Changing state, old state {0}, new state {1}(iconic {2})",
 262                          new Object[] {Integer.valueOf(state), Integer.valueOf(newState), Boolean.valueOf(iconic)});
 263         }
 264         if (changeIconic != 0 && iconic) {
 265             if (stateLog.isLoggable(Level.FINER)) {
 266                 stateLog.finer("Iconifying shell " + getShell() + ", this " + this + ", screen " + getScreenNumber());
 267             }
 268             XToolkit.awtLock();
 269             try {
 270                 int res = XlibWrapper.XIconifyWindow(XToolkit.getDisplay(), getShell(), getScreenNumber());
 271                 if (stateLog.isLoggable(Level.FINER)) {
 272                     stateLog.finer("XIconifyWindow returned " + res);
 273                 }
 274             }
 275             finally {
 276                 XToolkit.awtUnlock();
 277             }
 278         }
 279         if ((changed & ~Frame.ICONIFIED) != 0) {
 280             setExtendedState(newState);
 281         }
 282         if (changeIconic != 0 && !iconic) {
 283             if (stateLog.isLoggable(Level.FINER)) {
 284                 stateLog.finer("DeIconifying " + this);
 285             }
 286             xSetVisible(true);
 287         }
 288     }
 289 
 290     void setExtendedState(int newState) {
 291         XWM.getWM().setExtendedState(this, newState);
 292     }
 293 
 294     public void handlePropertyNotify(XEvent xev) {
 295         super.handlePropertyNotify(xev);
 296         XPropertyEvent ev = xev.get_xproperty();
 297 
 298         if (log.isLoggable(Level.FINER)) {
 299             log.log(Level.FINER, "Property change {0}", new Object[] {String.valueOf(ev)});
 300         }
 301 
 302         /*
 303          * Let's see if this is a window state protocol message, and
 304          * if it is - decode a new state in terms of java constants.
 305          */
 306         Integer newState = XWM.getWM().isStateChange(this, ev);
 307         if (newState == null) {
 308             return;
 309         }
 310 
 311         int changed = state ^ newState.intValue();
 312         if (changed == 0) {
 313             if (stateLog.isLoggable(Level.FINER)) {
 314                 stateLog.finer("State is the same: " + state);
 315             }
 316             return;
 317         }
 318 
 319         int old_state = state;
 320         state = newState.intValue();
 321 
 322         if ((changed & Frame.ICONIFIED) != 0) {
 323             if ((state & Frame.ICONIFIED) != 0) {
 324                 if (stateLog.isLoggable(Level.FINER)) {
 325                     stateLog.finer("Iconified");
 326                 }
 327                 handleIconify();
 328             } else {
 329                 if (stateLog.isLoggable(Level.FINER)) {
 330                     stateLog.finer("DeIconified");
 331                 }
 332                 content.purgeIconifiedExposeEvents();
 333                 handleDeiconify();
 334             }
 335         }
 336         handleStateChange(old_state, state);
 337     }
 338 
 339     // NOTE: This method may be called by privileged threads.
 340     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
 341     public void handleStateChange(int oldState, int newState) {
 342         super.handleStateChange(oldState, newState);
 343         for (ToplevelStateListener topLevelListenerTmp : toplevelStateListeners) {
 344             topLevelListenerTmp.stateChangedJava(oldState, newState);
 345         }
 346     }
 347 
 348     public void setVisible(boolean vis) {
 349         if (vis) {
 350             setupState(false);
 351         } else {
 352             if ((state & Frame.MAXIMIZED_BOTH) != 0) {
 353                 XWM.getWM().setExtendedState(this, state & ~Frame.MAXIMIZED_BOTH);
 354             }
 355         }
 356         super.setVisible(vis);
 357         if (vis && maxBounds != null) {
 358             setMaximizedBounds(maxBounds);
 359         }
 360     }
 361 
 362     void setInitialState(int wm_state) {
 363         XToolkit.awtLock();
 364         try {
 365             XWMHints hints = getWMHints();
 366             hints.set_flags((int)XlibWrapper.StateHint | hints.get_flags());
 367             hints.set_initial_state(wm_state);
 368             if (stateLog.isLoggable(Level.FINE)) {
 369                 stateLog.fine("Setting initial WM state on " + this + " to " + wm_state);
 370             }
 371             XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData);
 372         }
 373         finally {
 374             XToolkit.awtUnlock();
 375         }
 376     }
 377 
 378     public void dispose() {
 379         if (menubarPeer != null) {
 380             menubarPeer.dispose();
 381         }
 382         super.dispose();
 383     }
 384 
 385     boolean isMaximized() {
 386         return (state & (Frame.MAXIMIZED_VERT  | Frame.MAXIMIZED_HORIZ)) != 0;
 387     }
 388 
 389 
 390 
 391 
 392     static final int CROSSHAIR_INSET = 5;
 393 
 394     static final int BUTTON_Y = CROSSHAIR_INSET + 1;
 395     static final int BUTTON_W = 17;
 396     static final int BUTTON_H = 17;
 397 
 398     static final int SYS_MENU_X = CROSSHAIR_INSET + 1;
 399     static final int SYS_MENU_CONTAINED_X = SYS_MENU_X + 5;
 400     static final int SYS_MENU_CONTAINED_Y = BUTTON_Y + 7;
 401     static final int SYS_MENU_CONTAINED_W = 8;
 402     static final int SYS_MENU_CONTAINED_H = 3;
 403 
 404     static final int MAXIMIZE_X_DIFF = CROSSHAIR_INSET + BUTTON_W;
 405     static final int MAXIMIZE_CONTAINED_X_DIFF = MAXIMIZE_X_DIFF - 5;
 406     static final int MAXIMIZE_CONTAINED_Y = BUTTON_Y + 5;
 407     static final int MAXIMIZE_CONTAINED_W = 8;
 408     static final int MAXIMIZE_CONTAINED_H = 8;
 409 
 410     static final int MINIMIZE_X_DIFF = MAXIMIZE_X_DIFF + BUTTON_W;
 411     static final int MINIMIZE_CONTAINED_X_DIFF = MINIMIZE_X_DIFF - 7;
 412     static final int MINIMIZE_CONTAINED_Y = BUTTON_Y + 7;
 413     static final int MINIMIZE_CONTAINED_W = 3;
 414     static final int MINIMIZE_CONTAINED_H = 3;
 415 
 416     static final int TITLE_X = SYS_MENU_X + BUTTON_W;
 417     static final int TITLE_W_DIFF = BUTTON_W * 3 + CROSSHAIR_INSET * 2 - 1;
 418     static final int TITLE_MID_Y = BUTTON_Y + (BUTTON_H / 2);
 419 
 420     static final int MENUBAR_X = CROSSHAIR_INSET + 1;
 421     static final int MENUBAR_Y = BUTTON_Y + BUTTON_H;
 422 
 423     static final int HORIZ_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_H;
 424     static final int VERT_RESIZE_INSET = CROSSHAIR_INSET + BUTTON_W;
 425 
 426 
 427     /*
 428      * Print the native component by rendering the Motif look ourselves.
 429      * We also explicitly print the MenuBar since a MenuBar isn't a subclass
 430      * of Component (and thus it has no "print" method which gets called by
 431      * default).
 432      */
 433     public void print(Graphics g) {
 434         super.print(g);
 435 
 436         Frame f = (Frame)target;
 437         Insets finsets = f.getInsets();
 438         Dimension fsize = f.getSize();
 439 
 440         Color bg = f.getBackground();
 441         Color fg = f.getForeground();
 442         Color highlight = bg.brighter();
 443         Color shadow = bg.darker();
 444 
 445         // Well, we could query for the currently running window manager
 446         // and base the look on that, or we could just always do dtwm.
 447         // aim, tball, and levenson all agree we'll just do dtwm.
 448 
 449         if (hasDecorations(XWindowAttributesData.AWT_DECOR_BORDER)) {
 450 
 451             // top outer -- because we'll most likely be drawing on white paper,
 452             // for aesthetic reasons, don't make any part of the outer border
 453             // pure white
 454             if (highlight.equals(Color.white)) {
 455                 g.setColor(new Color(230, 230, 230));
 456             }
 457             else {
 458                 g.setColor(highlight);
 459             }
 460             g.drawLine(0, 0, fsize.width, 0);
 461             g.drawLine(0, 1, fsize.width - 1, 1);
 462 
 463             // left outer
 464             // if (highlight.equals(Color.white)) {
 465             //     g.setColor(new Color(230, 230, 230));
 466             // }
 467             // else {
 468             //     g.setColor(highlight);
 469             // }
 470             g.drawLine(0, 0, 0, fsize.height);
 471             g.drawLine(1, 0, 1, fsize.height - 1);
 472 
 473             // bottom cross-hair
 474             g.setColor(highlight);
 475             g.drawLine(CROSSHAIR_INSET + 1, fsize.height - CROSSHAIR_INSET,
 476                        fsize.width - CROSSHAIR_INSET,
 477                        fsize.height - CROSSHAIR_INSET);
 478 
 479             // right cross-hair
 480             // g.setColor(highlight);
 481             g.drawLine(fsize.width - CROSSHAIR_INSET, CROSSHAIR_INSET + 1,
 482                        fsize.width - CROSSHAIR_INSET,
 483                        fsize.height - CROSSHAIR_INSET);
 484 
 485             // bottom outer
 486             g.setColor(shadow);
 487             g.drawLine(1, fsize.height, fsize.width, fsize.height);
 488             g.drawLine(2, fsize.height - 1, fsize.width, fsize.height - 1);
 489 
 490             // right outer
 491             // g.setColor(shadow);
 492             g.drawLine(fsize.width, 1, fsize.width, fsize.height);
 493             g.drawLine(fsize.width - 1, 2, fsize.width - 1, fsize.height);
 494 
 495             // top cross-hair
 496             // g.setColor(shadow);
 497             g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET,
 498                        fsize.width - CROSSHAIR_INSET, CROSSHAIR_INSET);
 499 
 500             // left cross-hair
 501             // g.setColor(shadow);
 502             g.drawLine(CROSSHAIR_INSET, CROSSHAIR_INSET, CROSSHAIR_INSET,
 503                        fsize.height - CROSSHAIR_INSET);
 504         }
 505 
 506         if (hasDecorations(XWindowAttributesData.AWT_DECOR_TITLE)) {
 507 
 508             if (hasDecorations(XWindowAttributesData.AWT_DECOR_MENU)) {
 509 
 510                 // system menu
 511                 g.setColor(bg);
 512                 g.fill3DRect(SYS_MENU_X, BUTTON_Y, BUTTON_W, BUTTON_H, true);
 513                 g.fill3DRect(SYS_MENU_CONTAINED_X, SYS_MENU_CONTAINED_Y,
 514                              SYS_MENU_CONTAINED_W, SYS_MENU_CONTAINED_H, true);
 515             }
 516 
 517             // title bar
 518             // g.setColor(bg);
 519             g.fill3DRect(TITLE_X, BUTTON_Y, fsize.width - TITLE_W_DIFF, BUTTON_H,
 520                          true);
 521 
 522             if (hasDecorations(XWindowAttributesData.AWT_DECOR_MINIMIZE)) {
 523 
 524                 // minimize button
 525                 // g.setColor(bg);
 526                 g.fill3DRect(fsize.width - MINIMIZE_X_DIFF, BUTTON_Y, BUTTON_W,
 527                              BUTTON_H, true);
 528                 g.fill3DRect(fsize.width - MINIMIZE_CONTAINED_X_DIFF,
 529                              MINIMIZE_CONTAINED_Y, MINIMIZE_CONTAINED_W,
 530                              MINIMIZE_CONTAINED_H, true);
 531             }
 532 
 533             if (hasDecorations(XWindowAttributesData.AWT_DECOR_MAXIMIZE)) {
 534 
 535                 // maximize button
 536                 // g.setColor(bg);
 537                 g.fill3DRect(fsize.width - MAXIMIZE_X_DIFF, BUTTON_Y, BUTTON_W,
 538                              BUTTON_H, true);
 539                 g.fill3DRect(fsize.width - MAXIMIZE_CONTAINED_X_DIFF,
 540                              MAXIMIZE_CONTAINED_Y, MAXIMIZE_CONTAINED_W,
 541                              MAXIMIZE_CONTAINED_H, true);
 542             }
 543 
 544             // title bar text
 545             g.setColor(fg);
 546             Font sysfont = new Font(Font.SANS_SERIF, Font.PLAIN, 10);
 547             g.setFont(sysfont);
 548             FontMetrics sysfm = g.getFontMetrics();
 549             String ftitle = f.getTitle();
 550             g.drawString(ftitle,
 551                          ((TITLE_X + TITLE_X + fsize.width - TITLE_W_DIFF) / 2) -
 552                          (sysfm.stringWidth(ftitle) / 2),
 553                          TITLE_MID_Y + sysfm.getMaxDescent());
 554         }
 555 
 556         if (f.isResizable() &&
 557             hasDecorations(XWindowAttributesData.AWT_DECOR_RESIZEH)) {
 558 
 559             // add resize cross hairs
 560 
 561             // upper-left horiz (shadow)
 562             g.setColor(shadow);
 563             g.drawLine(1, HORIZ_RESIZE_INSET, CROSSHAIR_INSET,
 564                        HORIZ_RESIZE_INSET);
 565             // upper-left vert (shadow)
 566             // g.setColor(shadow);
 567             g.drawLine(VERT_RESIZE_INSET, 1, VERT_RESIZE_INSET, CROSSHAIR_INSET);
 568             // upper-right horiz (shadow)
 569             // g.setColor(shadow);
 570             g.drawLine(fsize.width - CROSSHAIR_INSET + 1, HORIZ_RESIZE_INSET,
 571                        fsize.width, HORIZ_RESIZE_INSET);
 572             // upper-right vert (shadow)
 573             // g.setColor(shadow);
 574             g.drawLine(fsize.width - VERT_RESIZE_INSET - 1, 2,
 575                        fsize.width - VERT_RESIZE_INSET - 1, CROSSHAIR_INSET + 1);
 576             // lower-left horiz (shadow)
 577             // g.setColor(shadow);
 578             g.drawLine(1, fsize.height - HORIZ_RESIZE_INSET - 1,
 579                        CROSSHAIR_INSET, fsize.height - HORIZ_RESIZE_INSET - 1);
 580             // lower-left vert (shadow)
 581             // g.setColor(shadow);
 582             g.drawLine(VERT_RESIZE_INSET, fsize.height - CROSSHAIR_INSET + 1,
 583                        VERT_RESIZE_INSET, fsize.height);
 584             // lower-right horiz (shadow)
 585             // g.setColor(shadow);
 586             g.drawLine(fsize.width - CROSSHAIR_INSET + 1,
 587                        fsize.height - HORIZ_RESIZE_INSET - 1, fsize.width,
 588                        fsize.height - HORIZ_RESIZE_INSET - 1);
 589             // lower-right vert (shadow)
 590             // g.setColor(shadow);
 591             g.drawLine(fsize.width - VERT_RESIZE_INSET - 1,
 592                        fsize.height - CROSSHAIR_INSET + 1,
 593                        fsize.width - VERT_RESIZE_INSET - 1, fsize.height);
 594 
 595             // upper-left horiz (highlight)
 596             g.setColor(highlight);
 597             g.drawLine(2, HORIZ_RESIZE_INSET + 1, CROSSHAIR_INSET,
 598                        HORIZ_RESIZE_INSET + 1);
 599             // upper-left vert (highlight)
 600             // g.setColor(highlight);
 601             g.drawLine(VERT_RESIZE_INSET + 1, 2, VERT_RESIZE_INSET + 1,
 602                        CROSSHAIR_INSET);
 603             // upper-right horiz (highlight)
 604             // g.setColor(highlight);
 605             g.drawLine(fsize.width - CROSSHAIR_INSET + 1,
 606                        HORIZ_RESIZE_INSET + 1, fsize.width - 1,
 607                        HORIZ_RESIZE_INSET + 1);
 608             // upper-right vert (highlight)
 609             // g.setColor(highlight);
 610             g.drawLine(fsize.width - VERT_RESIZE_INSET, 2,
 611                        fsize.width - VERT_RESIZE_INSET, CROSSHAIR_INSET);
 612             // lower-left horiz (highlight)
 613             // g.setColor(highlight);
 614             g.drawLine(2, fsize.height - HORIZ_RESIZE_INSET, CROSSHAIR_INSET,
 615                        fsize.height - HORIZ_RESIZE_INSET);
 616             // lower-left vert (highlight)
 617             // g.setColor(highlight);
 618             g.drawLine(VERT_RESIZE_INSET + 1,
 619                        fsize.height - CROSSHAIR_INSET + 1,
 620                        VERT_RESIZE_INSET + 1, fsize.height - 1);
 621             // lower-right horiz (highlight)
 622             // g.setColor(highlight);
 623             g.drawLine(fsize.width - CROSSHAIR_INSET + 1,
 624                        fsize.height - HORIZ_RESIZE_INSET, fsize.width - 1,
 625                        fsize.height - HORIZ_RESIZE_INSET);
 626             // lower-right vert (highlight)
 627             // g.setColor(highlight);
 628             g.drawLine(fsize.width - VERT_RESIZE_INSET,
 629                        fsize.height - CROSSHAIR_INSET + 1,
 630                        fsize.width - VERT_RESIZE_INSET, fsize.height - 1);
 631         }
 632 
 633         XMenuBarPeer peer = menubarPeer;
 634         if (peer != null) {
 635             Insets insets = getInsets();
 636             Graphics ng = g.create();
 637             int menubarX = 0;
 638             int menubarY = 0;
 639             if (hasDecorations(XWindowAttributesData.AWT_DECOR_BORDER)) {
 640                 menubarX += CROSSHAIR_INSET + 1;
 641                     menubarY += CROSSHAIR_INSET + 1;
 642             }
 643             if (hasDecorations(XWindowAttributesData.AWT_DECOR_TITLE)) {
 644                 menubarY += BUTTON_H;
 645             }
 646             try {
 647                 ng.translate(menubarX, menubarY);
 648                 peer.print(ng);
 649             } finally {
 650                 ng.dispose();
 651             }
 652         }
 653     }
 654 
 655     public void setBoundsPrivate(int x, int y, int width, int height) {
 656         setBounds(x, y, width, height, SET_BOUNDS);
 657     }
 658 
 659     public Rectangle getBoundsPrivate() {
 660         return getBounds();
 661     }
 662 }