1 /* 2 * Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 22 * CA 95054 USA or visit www.sun.com if you need additional information or 23 * have any questions. 24 */ 25 package sun.awt.X11; 26 27 import java.awt.*; 28 29 import java.awt.event.ComponentEvent; 30 import java.awt.event.InvocationEvent; 31 import java.awt.event.WindowEvent; 32 33 import java.util.logging.Level; 34 import java.util.logging.Logger; 35 36 import sun.awt.ComponentAccessor; 37 import sun.awt.SunToolkit; 38 39 abstract class XDecoratedPeer extends XWindowPeer { 40 private static final Logger log = Logger.getLogger("sun.awt.X11.XDecoratedPeer"); 41 private static final Logger insLog = Logger.getLogger("sun.awt.X11.insets.XDecoratedPeer"); 42 private static final Logger focusLog = Logger.getLogger("sun.awt.X11.focus.XDecoratedPeer"); 43 private static final Logger iconLog = Logger.getLogger("sun.awt.X11.icon.XDecoratedPeer"); 44 45 // Set to true when we get the first ConfigureNotify after being 46 // reparented - indicates that WM has adopted the top-level. 47 boolean configure_seen; 48 boolean insets_corrected; 49 50 XIconWindow iconWindow; 51 WindowDimensions dimensions; 52 XContentWindow content; 53 Insets currentInsets; 54 XFocusProxyWindow focusProxy; 55 56 XDecoratedPeer(Window target) { 57 super(target); 58 } 59 60 XDecoratedPeer(XCreateWindowParams params) { 61 super(params); 62 } 63 64 public long getShell() { 65 return window; 66 } 67 68 public long getContentWindow() { 69 return (content == null) ? window : content.getWindow(); 70 } 71 72 void preInit(XCreateWindowParams params) { 73 super.preInit(params); 74 winAttr.initialFocus = true; 75 76 currentInsets = new Insets(0,0,0,0); 77 applyGuessedInsets(); 78 79 Rectangle bounds = (Rectangle)params.get(BOUNDS); 80 dimensions = new WindowDimensions(bounds, getRealInsets(), false); 81 params.put(BOUNDS, dimensions.getClientRect()); 82 insLog.log(Level.FINE, "Initial dimensions {0}", new Object[] { dimensions }); 83 84 // Deny default processing of these events on the shell - proxy will take care of 85 // them instead 86 Long eventMask = (Long)params.get(EVENT_MASK); 87 params.add(EVENT_MASK, Long.valueOf(eventMask.longValue() & ~(XConstants.FocusChangeMask | XConstants.KeyPressMask | XConstants.KeyReleaseMask))); 88 } 89 90 void postInit(XCreateWindowParams params) { 91 super.postInit(params); 92 // The lines that follow need to be in a postInit, so they 93 // happen after the X window is created. 94 initResizability(); 95 updateSizeHints(dimensions); 96 XWM.requestWMExtents(getWindow()); 97 98 content = XContentWindow.createContent(this); 99 100 if (warningWindow != null) { 101 warningWindow.toFront(); 102 } 103 focusProxy = createFocusProxy(); 104 } 105 106 void setIconHints(java.util.List<XIconInfo> icons) { 107 if (!XWM.getWM().setNetWMIcon(this, icons)) { 108 if (icons.size() > 0) { 109 if (iconWindow == null) { 110 iconWindow = new XIconWindow(this); 111 } 112 iconWindow.setIconImages(icons); 113 } 114 } 115 } 116 117 public void updateMinimumSize() { 118 super.updateMinimumSize(); 119 updateMinSizeHints(); 120 } 121 122 private void updateMinSizeHints() { 123 if (isResizable()) { 124 Dimension minimumSize = getTargetMinimumSize(); 125 if (minimumSize != null) { 126 Insets insets = getRealInsets(); 127 int minWidth = minimumSize.width - insets.left - insets.right; 128 int minHeight = minimumSize.height - insets.top - insets.bottom; 129 if (minWidth < 0) minWidth = 0; 130 if (minHeight < 0) minHeight = 0; 131 setSizeHints(XUtilConstants.PMinSize | (isLocationByPlatform()?0:(XUtilConstants.PPosition | XUtilConstants.USPosition)), 132 getX(), getY(), minWidth, minHeight); 133 if (isVisible()) { 134 Rectangle bounds = getShellBounds(); 135 int nw = (bounds.width < minWidth) ? minWidth : bounds.width; 136 int nh = (bounds.height < minHeight) ? minHeight : bounds.height; 137 if (nw != bounds.width || nh != bounds.height) { 138 setShellSize(new Rectangle(0, 0, nw, nh)); 139 } 140 } 141 } else { 142 boolean isMinSizeSet = isMinSizeSet(); 143 XWM.removeSizeHints(this, XUtilConstants.PMinSize); 144 /* Some WMs need remap to redecorate the window */ 145 if (isMinSizeSet && isShowing() && XWM.needRemap(this)) { 146 /* 147 * Do the re/mapping at the Xlib level. Since we essentially 148 * work around a WM bug we don't want this hack to be exposed 149 * to Intrinsics (i.e. don't mess with grabs, callbacks etc). 150 */ 151 xSetVisible(false); 152 XToolkit.XSync(); 153 xSetVisible(true); 154 } 155 } 156 } 157 } 158 159 XFocusProxyWindow createFocusProxy() { 160 return new XFocusProxyWindow(this); 161 } 162 163 protected XAtomList getWMProtocols() { 164 XAtomList protocols = super.getWMProtocols(); 165 protocols.add(wm_delete_window); 166 protocols.add(wm_take_focus); 167 return protocols; 168 } 169 170 public Graphics getGraphics() { 171 return getGraphics(content.surfaceData, 172 ComponentAccessor.getForeground(target), 173 ComponentAccessor.getBackground(target), 174 ComponentAccessor.getFont_NoClientCode(target)); 175 } 176 177 public void setTitle(String title) { 178 if (log.isLoggable(Level.FINE)) log.fine("Title is " + title); 179 winAttr.title = title; 180 updateWMName(); 181 } 182 183 protected String getWMName() { 184 if (winAttr.title == null || winAttr.title.trim().equals("")) { 185 return " "; 186 } else { 187 return winAttr.title; 188 } 189 } 190 191 void updateWMName() { 192 super.updateWMName(); 193 String name = getWMName(); 194 XToolkit.awtLock(); 195 try { 196 if (name == null || name.trim().equals("")) { 197 name = "Java"; 198 } 199 XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME); 200 iconNameAtom.setProperty(getWindow(), name); 201 XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME"); 202 netIconNameAtom.setPropertyUTF8(getWindow(), name); 203 } finally { 204 XToolkit.awtUnlock(); 205 } 206 } 207 208 // NOTE: This method may be called by privileged threads. 209 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 210 public void handleIconify() { 211 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); 212 } 213 214 // NOTE: This method may be called by privileged threads. 215 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 216 public void handleDeiconify() { 217 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); 218 } 219 220 public void handleFocusEvent(XEvent xev) { 221 super.handleFocusEvent(xev); 222 XFocusChangeEvent xfe = xev.get_xfocus(); 223 224 // If we somehow received focus events forward it instead to proxy 225 // FIXME: Shouldn't we instead check for inferrior? 226 focusLog.finer("Received focus event on shell: " + xfe); 227 // focusProxy.xRequestFocus(); 228 } 229 230 /*************************************************************************************** 231 * I N S E T S C O D E 232 **************************************************************************************/ 233 234 protected boolean isInitialReshape() { 235 return false; 236 } 237 238 private static Insets difference(Insets i1, Insets i2) { 239 return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right); 240 } 241 242 private static boolean isNull(Insets i) { 243 return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0); 244 } 245 246 private static Insets copy(Insets i) { 247 return new Insets(i.top, i.left, i.bottom, i.right); 248 } 249 250 // insets which we get from WM (e.g from _NET_FRAME_EXTENTS) 251 private Insets wm_set_insets; 252 253 private Insets getWMSetInsets(XAtom changedAtom) { 254 if (isEmbedded()) { 255 return null; 256 } 257 258 if (wm_set_insets != null) { 259 return wm_set_insets; 260 } 261 262 if (changedAtom == null) { 263 wm_set_insets = XWM.getInsetsFromExtents(getWindow()); 264 } else { 265 wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom); 266 } 267 268 insLog.log(Level.FINER, "FRAME_EXTENTS: {0}", new Object[]{wm_set_insets}); 269 270 if (wm_set_insets != null) { 271 wm_set_insets = copy(wm_set_insets); 272 } 273 return wm_set_insets; 274 } 275 276 private void resetWMSetInsets() { 277 wm_set_insets = null; 278 } 279 280 public void handlePropertyNotify(XEvent xev) { 281 super.handlePropertyNotify(xev); 282 283 XPropertyEvent ev = xev.get_xproperty(); 284 if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom() 285 || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom()) 286 { 287 getWMSetInsets(XAtom.get(ev.get_atom())); 288 } 289 } 290 291 long reparent_serial = 0; 292 293 public void handleReparentNotifyEvent(XEvent xev) { 294 XReparentEvent xe = xev.get_xreparent(); 295 if (insLog.isLoggable(Level.FINE)) insLog.fine(xe.toString()); 296 reparent_serial = xe.get_serial(); 297 XToolkit.awtLock(); 298 try { 299 long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); 300 301 if (isEmbedded()) { 302 setReparented(true); 303 insets_corrected = true; 304 return; 305 } 306 Component t = (Component)target; 307 if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { 308 setReparented(true); 309 insets_corrected = true; 310 reshape(dimensions, SET_SIZE, false); 311 } else if (xe.get_parent() == root) { 312 configure_seen = false; 313 insets_corrected = false; 314 315 /* 316 * We can be repareted to root for two reasons: 317 * . setVisible(false) 318 * . WM exited 319 */ 320 if (isVisible()) { /* WM exited */ 321 /* Work around 4775545 */ 322 XWM.getWM().unshadeKludge(this); 323 insLog.fine("- WM exited"); 324 } else { 325 insLog.fine(" - reparent due to hide"); 326 } 327 } else { /* reparented to WM frame, figure out our insets */ 328 setReparented(true); 329 insets_corrected = false; 330 331 // Check if we have insets provided by the WM 332 Insets correctWM = getWMSetInsets(null); 333 if (correctWM != null) { 334 insLog.log(Level.FINER, "wm-provided insets {0}", new Object[]{correctWM}); 335 // If these insets are equal to our current insets - no actions are necessary 336 Insets dimInsets = dimensions.getInsets(); 337 if (correctWM.equals(dimInsets)) { 338 insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); 339 no_reparent_artifacts = true; 340 insets_corrected = true; 341 applyGuessedInsets(); 342 return; 343 } 344 } else { 345 correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); 346 347 if (correctWM != null) { 348 insLog.log(Level.FINER, "correctWM {0}", new Object[] {correctWM}); 349 } else { 350 insLog.log(Level.FINER, "correctWM insets are not available, waiting for configureNotify"); 351 } 352 } 353 354 if (correctWM != null) { 355 handleCorrectInsets(correctWM); 356 } 357 } 358 } finally { 359 XToolkit.awtUnlock(); 360 } 361 } 362 363 protected void handleCorrectInsets(Insets correctWM) { 364 XToolkit.awtLock(); 365 try { 366 /* 367 * Ok, now see if we need adjust window size because 368 * initial insets were wrong (most likely they were). 369 */ 370 Insets correction = difference(correctWM, currentInsets); 371 insLog.log(Level.FINEST, "Corrention {0}", new Object[] {correction}); 372 if (!isNull(correction)) { 373 currentInsets = copy(correctWM); 374 applyGuessedInsets(); 375 376 //Fix for 6318109: PIT: Min Size is not honored properly when a 377 //smaller size is specified in setSize(), XToolkit 378 //update minimum size hints 379 updateMinSizeHints(); 380 } 381 if (insLog.isLoggable(Level.FINER)) insLog.finer("Dimensions before reparent: " + dimensions); 382 383 dimensions.setInsets(getRealInsets()); 384 insets_corrected = true; 385 386 if (isMaximized()) { 387 return; 388 } 389 390 /* 391 * If this window has been sized by a pack() we need 392 * to keep the interior geometry intact. Since pack() 393 * computed width and height with wrong insets, we 394 * must adjust the target dimensions appropriately. 395 */ 396 if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { 397 reshape(dimensions, SET_BOUNDS, false); 398 } else { 399 reshape(dimensions, SET_SIZE, false); 400 } 401 } finally { 402 XToolkit.awtUnlock(); 403 } 404 } 405 406 public void handleMoved(WindowDimensions dims) { 407 Point loc = dims.getLocation(); 408 ComponentAccessor.setX((Component)target, loc.x); 409 ComponentAccessor.setY((Component)target, loc.y); 410 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); 411 } 412 413 414 protected Insets guessInsets() { 415 if (isEmbedded() || isTargetUndecorated()) { 416 return new Insets(0, 0, 0, 0); 417 } else { 418 if (!isNull(currentInsets)) { 419 /* insets were set on wdata by System Properties */ 420 return copy(currentInsets); 421 } else { 422 Insets res = getWMSetInsets(null); 423 if (res == null) { 424 res = XWM.getWM().guessInsets(this); 425 } 426 return res; 427 } 428 } 429 } 430 431 private void applyGuessedInsets() { 432 Insets guessed = guessInsets(); 433 currentInsets = copy(guessed); 434 } 435 436 public void revalidate() { 437 XToolkit.executeOnEventHandlerThread(target, new Runnable() { 438 public void run() { 439 target.invalidate(); 440 target.validate(); 441 } 442 }); 443 } 444 445 Insets getRealInsets() { 446 if (isNull(currentInsets)) { 447 applyGuessedInsets(); 448 } 449 return currentInsets; 450 } 451 452 public Insets getInsets() { 453 Insets in = copy(getRealInsets()); 454 in.top += getMenuBarHeight(); 455 if (insLog.isLoggable(Level.FINEST)) { 456 insLog.log(Level.FINEST, "Get insets returns {0}", new Object[] {in}); 457 } 458 return in; 459 } 460 461 boolean gravityBug() { 462 return XWM.configureGravityBuggy(); 463 } 464 465 // The height of area used to display current active input method 466 int getInputMethodHeight() { 467 return 0; 468 } 469 470 void updateSizeHints(WindowDimensions dims) { 471 Rectangle rec = dims.getClientRect(); 472 checkShellRect(rec); 473 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 474 } 475 476 void updateSizeHints() { 477 updateSizeHints(dimensions); 478 } 479 480 // Coordinates are that of the target 481 // Called only on Toolkit thread 482 public void reshape(WindowDimensions newDimensions, int op, 483 boolean userReshape) 484 { 485 if (insLog.isLoggable(Level.FINE)) { 486 insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape); 487 } 488 if (userReshape) { 489 // We handle only userReshape == true cases. It means that 490 // if the window manager or any other part of the windowing 491 // system sets inappropriate size for this window, we can 492 // do nothing but accept it. 493 Rectangle newBounds = newDimensions.getBounds(); 494 Insets insets = newDimensions.getInsets(); 495 // Inherit isClientSizeSet from newDimensions 496 if (newDimensions.isClientSizeSet()) { 497 newBounds = new Rectangle(newBounds.x, newBounds.y, 498 newBounds.width - insets.left - insets.right, 499 newBounds.height - insets.top - insets.bottom); 500 } 501 newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet()); 502 } 503 XToolkit.awtLock(); 504 try { 505 if (!isReparented() || !isVisible()) { 506 insLog.log(Level.FINE, "- not reparented({0}) or not visible({1}), default reshape", 507 new Object[] {Boolean.valueOf(isReparented()), Boolean.valueOf(visible)}); 508 509 // Fix for 6323293. 510 // This actually is needed to preserve compatibility with previous releases - 511 // some of licensees are expecting componentMoved event on invisible one while 512 // its location changes. 513 Point oldLocation = getLocation(); 514 515 Point newLocation = new Point(ComponentAccessor.getX((Component)target), 516 ComponentAccessor.getY((Component)target)); 517 518 if (!newLocation.equals(oldLocation)) { 519 handleMoved(newDimensions); 520 } 521 522 dimensions = new WindowDimensions(newDimensions); 523 updateSizeHints(dimensions); 524 Rectangle client = dimensions.getClientRect(); 525 checkShellRect(client); 526 setShellBounds(client); 527 if (content != null && 528 !content.getSize().equals(newDimensions.getSize())) 529 { 530 reconfigureContentWindow(newDimensions); 531 } 532 return; 533 } 534 535 int wm = XWM.getWMID(); 536 updateChildrenSizes(); 537 applyGuessedInsets(); 538 539 Rectangle shellRect = newDimensions.getClientRect(); 540 541 if (gravityBug()) { 542 Insets in = newDimensions.getInsets(); 543 shellRect.translate(in.left, in.top); 544 } 545 546 if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { 547 shellRect.setLocation(0, 0); 548 } 549 550 checkShellRectSize(shellRect); 551 if (!isEmbedded()) { 552 checkShellRectPos(shellRect); 553 } 554 555 op = op & ~NO_EMBEDDED_CHECK; 556 557 if (op == SET_LOCATION) { 558 setShellPosition(shellRect); 559 } else if (isResizable()) { 560 if (op == SET_BOUNDS) { 561 setShellBounds(shellRect); 562 } else { 563 setShellSize(shellRect); 564 } 565 } else { 566 XWM.setShellNotResizable(this, newDimensions, shellRect, true); 567 if (op == SET_BOUNDS) { 568 setShellPosition(shellRect); 569 } 570 } 571 572 reconfigureContentWindow(newDimensions); 573 } finally { 574 XToolkit.awtUnlock(); 575 } 576 } 577 578 /** 579 * @param x, y, width, heith - dimensions of the window with insets 580 */ 581 private void reshape(int x, int y, int width, int height, int operation, 582 boolean userReshape) 583 { 584 Rectangle newRec; 585 boolean setClient = false; 586 WindowDimensions dims = new WindowDimensions(dimensions); 587 switch (operation & (~NO_EMBEDDED_CHECK)) { 588 case SET_LOCATION: 589 // Set location always sets bounds location. However, until the window is mapped we 590 // should use client coordinates 591 dims.setLocation(x, y); 592 break; 593 case SET_SIZE: 594 // Set size sets bounds size. However, until the window is mapped we 595 // should use client coordinates 596 dims.setSize(width, height); 597 break; 598 case SET_CLIENT_SIZE: { 599 // Sets client rect size. Width and height contain insets. 600 Insets in = currentInsets; 601 width -= in.left+in.right; 602 height -= in.top+in.bottom; 603 dims.setClientSize(width, height); 604 break; 605 } 606 case SET_BOUNDS: 607 default: 608 dims.setLocation(x, y); 609 dims.setSize(width, height); 610 break; 611 } 612 if (insLog.isLoggable(Level.FINE)) insLog.log(Level.FINE, "For the operation {0} new dimensions are {1}", 613 new Object[] {operationToString(operation), dims}); 614 615 reshape(dims, operation, userReshape); 616 } 617 618 // This method gets overriden in XFramePeer & XDialogPeer. 619 abstract boolean isTargetUndecorated(); 620 621 /** 622 * @see java.awt.peer.ComponentPeer#setBounds 623 */ 624 public void setBounds(int x, int y, int width, int height, int op) { 625 // TODO: Rewrite with WindowDimensions 626 reshape(x, y, width, height, op, true); 627 validateSurface(); 628 } 629 630 // Coordinates are that of the shell 631 void reconfigureContentWindow(WindowDimensions dims) { 632 if (content == null) { 633 insLog.fine("WARNING: Content window is null"); 634 return; 635 } 636 content.setContentBounds(dims); 637 } 638 639 boolean no_reparent_artifacts = false; 640 public void handleConfigureNotifyEvent(XEvent xev) { 641 assert (SunToolkit.isAWTLockHeldByCurrentThread()); 642 XConfigureEvent xe = xev.get_xconfigure(); 643 insLog.log(Level.FINE, "Configure notify {0}", new Object[] {xe}); 644 645 // XXX: should really only consider synthetic events, but 646 if (isReparented()) { 647 configure_seen = true; 648 } 649 650 if (!isMaximized() 651 && (xe.get_serial() == reparent_serial || xe.get_window() != getShell()) 652 && !no_reparent_artifacts) 653 { 654 insLog.fine("- reparent artifact, skipping"); 655 return; 656 } 657 no_reparent_artifacts = false; 658 659 /** 660 * When there is a WM we receive some CN before being visible and after. 661 * We should skip all CN which are before being visible, because we assume 662 * the gravity is in action while it is not yet. 663 * 664 * When there is no WM we receive CN only _before_ being visible. 665 * We should process these CNs. 666 */ 667 if (!isVisible() && XWM.getWMID() != XWM.NO_WM) { 668 insLog.fine(" - not visible, skipping"); 669 return; 670 } 671 672 /* 673 * Some window managers configure before we are reparented and 674 * the send event flag is set! ugh... (Enlighetenment for one, 675 * possibly MWM as well). If we haven't been reparented yet 676 * this is just the WM shuffling us into position. Ignore 677 * it!!!! or we wind up in a bogus location. 678 */ 679 int runningWM = XWM.getWMID(); 680 if (insLog.isLoggable(Level.FINE)) { 681 insLog.log(Level.FINE, "reparented={0}, visible={1}, WM={2}, decorations={3}", 682 new Object[] {isReparented(), isVisible(), runningWM, getDecorations()}); 683 } 684 if (!isReparented() && isVisible() && runningWM != XWM.NO_WM 685 && !XWM.isNonReparentingWM() 686 && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 687 insLog.fine("- visible but not reparented, skipping"); 688 return; 689 } 690 //Last chance to correct insets 691 if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 692 long parent = XlibUtil.getParentWindow(window); 693 Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null; 694 if (insLog.isLoggable(Level.FINER)) { 695 if (correctWM != null) { 696 insLog.finer("Configure notify - insets : " + correctWM); 697 } else { 698 insLog.finer("Configure notify - insets are still not available"); 699 } 700 } 701 if (correctWM != null) { 702 handleCorrectInsets(correctWM); 703 } else { 704 //Only one attempt to correct insets is made (to lower risk) 705 //if insets are still not available we simply set the flag 706 insets_corrected = true; 707 } 708 } 709 710 updateChildrenSizes(); 711 712 // Bounds of the window 713 Rectangle targetBounds = new Rectangle(ComponentAccessor.getX((Component)target), 714 ComponentAccessor.getY((Component)target), 715 ComponentAccessor.getWidth((Component)target), 716 ComponentAccessor.getHeight((Component)target)); 717 718 Point newLocation = targetBounds.getLocation(); 719 if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { 720 // Location, Client size + insets 721 newLocation = new Point(xe.get_x() - currentInsets.left, xe.get_y() - currentInsets.top); 722 } else { 723 // CDE/MWM/Metacity/Sawfish bug: if shell is resized using 724 // top or left border, we don't receive synthetic 725 // ConfigureNotify, only the one from X with zero 726 // coordinates. This is the workaround to get real 727 // location, 6261336 728 switch (XWM.getWMID()) { 729 case XWM.CDE_WM: 730 case XWM.MOTIF_WM: 731 case XWM.METACITY_WM: 732 case XWM.SAWFISH_WM: 733 { 734 Point xlocation = queryXLocation(); 735 if (log.isLoggable(Level.FINE)) log.log(Level.FINE, "New X location: {0}", new Object[]{xlocation}); 736 if (xlocation != null) { 737 newLocation = xlocation; 738 } 739 break; 740 } 741 default: 742 break; 743 } 744 } 745 746 WindowDimensions newDimensions = 747 new WindowDimensions(newLocation, 748 new Dimension(xe.get_width(), xe.get_height()), 749 copy(currentInsets), 750 true); 751 752 insLog.log(Level.FINER, "Insets are {0}, new dimensions {1}", 753 new Object[] {currentInsets, newDimensions}); 754 755 checkIfOnNewScreen(newDimensions.getBounds()); 756 757 Point oldLocation = getLocation(); 758 dimensions = newDimensions; 759 if (!newLocation.equals(oldLocation)) { 760 handleMoved(newDimensions); 761 } 762 reconfigureContentWindow(newDimensions); 763 updateChildrenSizes(); 764 765 repositionSecurityWarning(); 766 } 767 768 private void checkShellRectSize(Rectangle shellRect) { 769 if (shellRect.width < 0) { 770 shellRect.width = 1; 771 } 772 if (shellRect.height < 0) { 773 shellRect.height = 1; 774 } 775 } 776 777 private void checkShellRectPos(Rectangle shellRect) { 778 int wm = XWM.getWMID(); 779 if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) { 780 if (shellRect.x == 0 && shellRect.y == 0) { 781 shellRect.x = shellRect.y = 1; 782 } 783 } 784 } 785 786 private void checkShellRect(Rectangle shellRect) { 787 checkShellRectSize(shellRect); 788 checkShellRectPos(shellRect); 789 } 790 791 public void setShellBounds(Rectangle rec) { 792 if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell bounds on " + 793 this + " to " + rec); 794 XToolkit.awtLock(); 795 try { 796 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 797 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); 798 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); 799 } 800 finally { 801 XToolkit.awtUnlock(); 802 } 803 } 804 public void setShellSize(Rectangle rec) { 805 if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell size on " + 806 this + " to " + rec); 807 XToolkit.awtLock(); 808 try { 809 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 810 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); 811 } 812 finally { 813 XToolkit.awtUnlock(); 814 } 815 } 816 public void setShellPosition(Rectangle rec) { 817 if (insLog.isLoggable(Level.FINE)) insLog.fine("Setting shell position on " + 818 this + " to " + rec); 819 XToolkit.awtLock(); 820 try { 821 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 822 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); 823 } 824 finally { 825 XToolkit.awtUnlock(); 826 } 827 } 828 829 void initResizability() { 830 setResizable(winAttr.initialResizability); 831 } 832 public void setResizable(boolean resizable) { 833 int fs = winAttr.functions; 834 if (!isResizable() && resizable) { 835 currentInsets = new Insets(0, 0, 0, 0); 836 resetWMSetInsets(); 837 if (!isEmbedded()) { 838 setReparented(false); 839 } 840 winAttr.isResizable = resizable; 841 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 842 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 843 } else { 844 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 845 } 846 winAttr.functions = fs; 847 XWM.setShellResizable(this); 848 } else if (isResizable() && !resizable) { 849 currentInsets = new Insets(0, 0, 0, 0); 850 resetWMSetInsets(); 851 if (!isEmbedded()) { 852 setReparented(false); 853 } 854 winAttr.isResizable = resizable; 855 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 856 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 857 } else { 858 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 859 } 860 winAttr.functions = fs; 861 XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false); 862 } 863 } 864 865 Rectangle getShellBounds() { 866 return dimensions.getClientRect(); 867 } 868 869 public Rectangle getBounds() { 870 return dimensions.getBounds(); 871 } 872 873 public Dimension getSize() { 874 return dimensions.getSize(); 875 } 876 877 public int getX() { 878 return dimensions.getLocation().x; 879 } 880 881 public int getY() { 882 return dimensions.getLocation().y; 883 } 884 885 public Point getLocation() { 886 return dimensions.getLocation(); 887 } 888 889 public int getAbsoluteX() { 890 // NOTE: returning this peer's location which is shell location 891 return dimensions.getScreenBounds().x; 892 } 893 894 public int getAbsoluteY() { 895 // NOTE: returning this peer's location which is shell location 896 return dimensions.getScreenBounds().y; 897 } 898 899 public int getWidth() { 900 return getSize().width; 901 } 902 903 public int getHeight() { 904 return getSize().height; 905 } 906 907 final public WindowDimensions getDimensions() { 908 return dimensions; 909 } 910 911 public Point getLocationOnScreen() { 912 XToolkit.awtLock(); 913 try { 914 if (configure_seen) { 915 return toGlobal(0,0); 916 } else { 917 Point location = target.getLocation(); 918 if (insLog.isLoggable(Level.FINE)) 919 insLog.log(Level.FINE, "getLocationOnScreen {0} not reparented: {1} ", 920 new Object[] {this, location}); 921 return location; 922 } 923 } finally { 924 XToolkit.awtUnlock(); 925 } 926 } 927 928 929 /*************************************************************************************** 930 * END OF I N S E T S C O D E 931 **************************************************************************************/ 932 933 protected boolean isEventDisabled(XEvent e) { 934 switch (e.get_type()) { 935 // Do not generate MOVED/RESIZED events since we generate them by ourselves 936 case XConstants.ConfigureNotify: 937 return true; 938 case XConstants.EnterNotify: 939 case XConstants.LeaveNotify: 940 // Disable crossing event on outer borders of Frame so 941 // we receive only one set of cross notifications(first set is from content window) 942 return true; 943 default: 944 return super.isEventDisabled(e); 945 } 946 } 947 948 int getDecorations() { 949 return winAttr.decorations; 950 } 951 952 int getFunctions() { 953 return winAttr.functions; 954 } 955 956 public void setVisible(boolean vis) { 957 log.log(Level.FINER, "Setting {0} to visible {1}", new Object[] {this, Boolean.valueOf(vis)}); 958 if (vis && !isVisible()) { 959 XWM.setShellDecor(this); 960 super.setVisible(vis); 961 if (winAttr.isResizable) { 962 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. 963 //We need to update frame's minimum size, not to reset it 964 XWM.removeSizeHints(this, XUtilConstants.PMaxSize); 965 updateMinimumSize(); 966 } 967 } else { 968 super.setVisible(vis); 969 } 970 } 971 972 protected void suppressWmTakeFocus(boolean doSuppress) { 973 XAtomList protocols = getWMProtocols(); 974 if (doSuppress) { 975 protocols.remove(wm_take_focus); 976 } else { 977 protocols.add(wm_take_focus); 978 } 979 wm_protocols.setAtomListProperty(this, protocols); 980 } 981 982 public void dispose() { 983 if (content != null) { 984 content.destroy(); 985 } 986 focusProxy.destroy(); 987 988 if (iconWindow != null) { 989 iconWindow.destroy(); 990 } 991 992 super.dispose(); 993 } 994 995 public void handleClientMessage(XEvent xev) { 996 super.handleClientMessage(xev); 997 XClientMessageEvent cl = xev.get_xclient(); 998 if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) { 999 if (cl.get_data(0) == wm_delete_window.getAtom()) { 1000 handleQuit(); 1001 } else if (cl.get_data(0) == wm_take_focus.getAtom()) { 1002 handleWmTakeFocus(cl); 1003 } 1004 } 1005 } 1006 1007 private void handleWmTakeFocus(XClientMessageEvent cl) { 1008 focusLog.log(Level.FINE, "WM_TAKE_FOCUS on {0}", new Object[]{this}); 1009 requestWindowFocus(cl.get_data(1), true); 1010 } 1011 1012 /** 1013 * Requests focus to this decorated top-level by requesting X input focus 1014 * to the shell window. 1015 */ 1016 protected void requestXFocus(long time, boolean timeProvided) { 1017 // We have proxied focus mechanism - instead of shell the focus is held 1018 // by "proxy" - invisible mapped window. When we want to set X input focus to 1019 // toplevel set it on proxy instead. 1020 if (focusProxy == null) { 1021 if (focusLog.isLoggable(Level.FINE)) focusLog.warning("Focus proxy is null for " + this); 1022 } else { 1023 if (focusLog.isLoggable(Level.FINE)) focusLog.fine("Requesting focus to proxy: " + focusProxy); 1024 if (timeProvided) { 1025 focusProxy.xRequestFocus(time); 1026 } else { 1027 focusProxy.xRequestFocus(); 1028 } 1029 } 1030 } 1031 1032 XFocusProxyWindow getFocusProxy() { 1033 return focusProxy; 1034 } 1035 1036 public void handleQuit() { 1037 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 1038 } 1039 1040 final void dumpMe() { 1041 System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height); 1042 } 1043 1044 final void dumpTarget() { 1045 int getWidth = ComponentAccessor.getWidth((Component)target); 1046 int getHeight = ComponentAccessor.getHeight((Component)target); 1047 int getTargetX = ComponentAccessor.getX((Component)target); 1048 int getTargetY = ComponentAccessor.getY((Component)target); 1049 System.err.println(">>> Target: " + getTargetX + ", " + getTargetY + ", " + getWidth + ", " + getHeight); 1050 } 1051 1052 final void dumpShell() { 1053 dumpWindow("Shell", getShell()); 1054 } 1055 final void dumpContent() { 1056 dumpWindow("Content", getContentWindow()); 1057 } 1058 final void dumpParent() { 1059 long parent = XlibUtil.getParentWindow(getShell()); 1060 if (parent != 0) 1061 { 1062 dumpWindow("Parent", parent); 1063 } 1064 else 1065 { 1066 System.err.println(">>> NO PARENT"); 1067 } 1068 } 1069 1070 final void dumpWindow(String id, long window) { 1071 XWindowAttributes pattr = new XWindowAttributes(); 1072 try { 1073 XToolkit.awtLock(); 1074 try { 1075 int status = 1076 XlibWrapper.XGetWindowAttributes(XToolkit.getDisplay(), 1077 window, pattr.pData); 1078 } 1079 finally { 1080 XToolkit.awtUnlock(); 1081 } 1082 System.err.println(">>>> " + id + ": " + pattr.get_x() 1083 + ", " + pattr.get_y() + ", " + pattr.get_width() 1084 + ", " + pattr.get_height()); 1085 } finally { 1086 pattr.dispose(); 1087 } 1088 } 1089 1090 final void dumpAll() { 1091 dumpTarget(); 1092 dumpMe(); 1093 dumpParent(); 1094 dumpShell(); 1095 dumpContent(); 1096 } 1097 1098 boolean isMaximized() { 1099 return false; 1100 } 1101 1102 @Override 1103 boolean isOverrideRedirect() { 1104 return Window.Type.POPUP.equals(getWindowType()); 1105 } 1106 1107 public boolean requestWindowFocus(long time, boolean timeProvided) { 1108 focusLog.fine("Request for decorated window focus"); 1109 // If this is Frame or Dialog we can't assure focus request success - but we still can try 1110 // If this is Window and its owner Frame is active we can be sure request succedded. 1111 Window focusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow(); 1112 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow); 1113 1114 focusLog.log(Level.FINER, "Current window is: active={0}, focused={1}", 1115 new Object[]{ Boolean.valueOf(target == activeWindow), 1116 Boolean.valueOf(target == focusedWindow)}); 1117 1118 XWindowPeer toFocus = this; 1119 while (toFocus.nextTransientFor != null) { 1120 toFocus = toFocus.nextTransientFor; 1121 } 1122 if (toFocus == null || !toFocus.focusAllowedFor()) { 1123 // This might change when WM will have property to determine focus policy. 1124 // Right now, because policy is unknown we can't be sure we succedded 1125 return false; 1126 } 1127 if (this == toFocus) { 1128 if (isWMStateNetHidden()) { 1129 focusLog.fine("The window is unmapped, so rejecting the request"); 1130 return false; 1131 } 1132 if (target == activeWindow && target != focusedWindow) { 1133 // Happens when an owned window is currently focused 1134 focusLog.fine("Focus is on child window - transfering it back to the owner"); 1135 handleWindowFocusInSync(-1); 1136 return true; 1137 } 1138 Window realNativeFocusedWindow = XWindowPeer.getNativeFocusedWindow(); 1139 focusLog.finest("Real native focused window: " + realNativeFocusedWindow + 1140 "\nKFM's focused window: " + focusedWindow); 1141 1142 // See 6522725, 6613426. 1143 if (target == realNativeFocusedWindow) { 1144 focusLog.fine("The window is already natively focused."); 1145 return true; 1146 } 1147 } 1148 focusLog.fine("Requesting focus to " + (this == toFocus ? "this window" : toFocus)); 1149 1150 if (timeProvided) { 1151 toFocus.requestXFocus(time); 1152 } else { 1153 toFocus.requestXFocus(); 1154 } 1155 return (this == toFocus); 1156 } 1157 1158 XWindowPeer actualFocusedWindow = null; 1159 void setActualFocusedWindow(XWindowPeer actualFocusedWindow) { 1160 synchronized(getStateLock()) { 1161 this.actualFocusedWindow = actualFocusedWindow; 1162 } 1163 } 1164 1165 boolean requestWindowFocus(XWindowPeer actualFocusedWindow, 1166 long time, boolean timeProvided) 1167 { 1168 setActualFocusedWindow(actualFocusedWindow); 1169 return requestWindowFocus(time, timeProvided); 1170 } 1171 public void handleWindowFocusIn(long serial) { 1172 if (null == actualFocusedWindow) { 1173 super.handleWindowFocusIn(serial); 1174 } else { 1175 /* 1176 * Fix for 6314575. 1177 * If this is a result of clicking on one of the Frame's component 1178 * then 'actualFocusedWindow' shouldn't be focused. A decision of focusing 1179 * it or not should be made after the appropriate Java mouse event (if any) 1180 * is handled by the component where 'actualFocusedWindow' value may be reset. 1181 * 1182 * The fix is based on the empiric fact consisting in that the component 1183 * receives native mouse event nearly at the same time the Frame receives 1184 * WM_TAKE_FOCUS (when FocusIn is generated via XSetInputFocus call) but 1185 * definetely before the Frame gets FocusIn event (when this method is called). 1186 */ 1187 postEvent(new InvocationEvent(target, new Runnable() { 1188 public void run() { 1189 XWindowPeer fw = null; 1190 synchronized (getStateLock()) { 1191 fw = actualFocusedWindow; 1192 actualFocusedWindow = null; 1193 if (null == fw || !fw.isVisible() || !fw.isFocusableWindow()) { 1194 fw = XDecoratedPeer.this; 1195 } 1196 } 1197 fw.handleWindowFocusIn_Dispatch(); 1198 } 1199 })); 1200 } 1201 } 1202 1203 public void handleWindowFocusOut(Window oppositeWindow, long serial) { 1204 Window actualFocusedWindow = XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow(); 1205 1206 // If the actual focused window is not this decorated window then retain it. 1207 if (actualFocusedWindow != null && actualFocusedWindow != target) { 1208 Window owner = XWindowPeer.getDecoratedOwner(actualFocusedWindow); 1209 1210 if (owner != null && owner == target) { 1211 setActualFocusedWindow((XWindowPeer) ComponentAccessor.getPeer(actualFocusedWindow)); 1212 } 1213 } 1214 super.handleWindowFocusOut(oppositeWindow, serial); 1215 } 1216 1217 private Point queryXLocation() 1218 { 1219 return XlibUtil.translateCoordinates( 1220 getContentWindow(), 1221 XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()), 1222 new Point(0, 0)); 1223 } 1224 }