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