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)) log.fine("Title is " + title); 183 winAttr.title = title; 184 updateWMName(); 185 } 186 187 protected String getWMName() { 188 if (winAttr.title == null || winAttr.title.trim().equals("")) { 189 return " "; 190 } else { 191 return winAttr.title; 192 } 193 } 194 195 void updateWMName() { 196 super.updateWMName(); 197 String name = getWMName(); 198 XToolkit.awtLock(); 199 try { 200 if (name == null || name.trim().equals("")) { 201 name = "Java"; 202 } 203 XAtom iconNameAtom = XAtom.get(XAtom.XA_WM_ICON_NAME); 204 iconNameAtom.setProperty(getWindow(), name); 205 XAtom netIconNameAtom = XAtom.get("_NET_WM_ICON_NAME"); 206 netIconNameAtom.setPropertyUTF8(getWindow(), name); 207 } finally { 208 XToolkit.awtUnlock(); 209 } 210 } 211 212 // NOTE: This method may be called by privileged threads. 213 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 214 public void handleIconify() { 215 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); 216 } 217 218 // NOTE: This method may be called by privileged threads. 219 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 220 public void handleDeiconify() { 221 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); 222 } 223 224 public void handleFocusEvent(XEvent xev) { 225 super.handleFocusEvent(xev); 226 XFocusChangeEvent xfe = xev.get_xfocus(); 227 228 // If we somehow received focus events forward it instead to proxy 229 // FIXME: Shouldn't we instead check for inferrior? 230 focusLog.finer("Received focus event on shell: " + xfe); 231 // focusProxy.xRequestFocus(); 232 } 233 234 /*************************************************************************************** 235 * I N S E T S C O D E 236 **************************************************************************************/ 237 238 protected boolean isInitialReshape() { 239 return false; 240 } 241 242 private static Insets difference(Insets i1, Insets i2) { 243 return new Insets(i1.top-i2.top, i1.left - i2.left, i1.bottom-i2.bottom, i1.right-i2.right); 244 } 245 246 private static boolean isNull(Insets i) { 247 return (i == null) || ((i.left | i.top | i.right | i.bottom) == 0); 248 } 249 250 private static Insets copy(Insets i) { 251 return new Insets(i.top, i.left, i.bottom, i.right); 252 } 253 254 // insets which we get from WM (e.g from _NET_FRAME_EXTENTS) 255 private Insets wm_set_insets; 256 257 private Insets getWMSetInsets(XAtom changedAtom) { 258 if (isEmbedded()) { 259 return null; 260 } 261 262 if (wm_set_insets != null) { 263 return wm_set_insets; 264 } 265 266 if (changedAtom == null) { 267 wm_set_insets = XWM.getInsetsFromExtents(getWindow()); 268 } else { 269 wm_set_insets = XWM.getInsetsFromProp(getWindow(), changedAtom); 270 } 271 272 insLog.finer("FRAME_EXTENTS: {0}", wm_set_insets); 273 274 if (wm_set_insets != null) { 275 wm_set_insets = copy(wm_set_insets); 276 } 277 return wm_set_insets; 278 } 279 280 private void resetWMSetInsets() { 281 wm_set_insets = null; 282 } 283 284 public void handlePropertyNotify(XEvent xev) { 285 super.handlePropertyNotify(xev); 286 287 XPropertyEvent ev = xev.get_xproperty(); 288 if (ev.get_atom() == XWM.XA_KDE_NET_WM_FRAME_STRUT.getAtom() 289 || ev.get_atom() == XWM.XA_NET_FRAME_EXTENTS.getAtom()) 290 { 291 getWMSetInsets(XAtom.get(ev.get_atom())); 292 } 293 } 294 295 long reparent_serial = 0; 296 297 public void handleReparentNotifyEvent(XEvent xev) { 298 XReparentEvent xe = xev.get_xreparent(); 299 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine(xe.toString()); 300 reparent_serial = xe.get_serial(); 301 XToolkit.awtLock(); 302 try { 303 long root = XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()); 304 305 if (isEmbedded()) { 306 setReparented(true); 307 insets_corrected = true; 308 return; 309 } 310 Component t = (Component)target; 311 if (getDecorations() == XWindowAttributesData.AWT_DECOR_NONE) { 312 setReparented(true); 313 insets_corrected = true; 314 reshape(dimensions, SET_SIZE, false); 315 } else if (xe.get_parent() == root) { 316 configure_seen = false; 317 insets_corrected = false; 318 319 /* 320 * We can be repareted to root for two reasons: 321 * . setVisible(false) 322 * . WM exited 323 */ 324 if (isVisible()) { /* WM exited */ 325 /* Work around 4775545 */ 326 XWM.getWM().unshadeKludge(this); 327 insLog.fine("- WM exited"); 328 } else { 329 insLog.fine(" - reparent due to hide"); 330 } 331 } else { /* reparented to WM frame, figure out our insets */ 332 setReparented(true); 333 insets_corrected = false; 334 335 // Check if we have insets provided by the WM 336 Insets correctWM = getWMSetInsets(null); 337 if (correctWM != null) { 338 insLog.finer("wm-provided insets {0}", correctWM); 339 // If these insets are equal to our current insets - no actions are necessary 340 Insets dimInsets = dimensions.getInsets(); 341 if (correctWM.equals(dimInsets)) { 342 insLog.finer("Insets are the same as estimated - no additional reshapes necessary"); 343 no_reparent_artifacts = true; 344 insets_corrected = true; 345 applyGuessedInsets(); 346 return; 347 } 348 } else { 349 correctWM = XWM.getWM().getInsets(this, xe.get_window(), xe.get_parent()); 350 351 if (correctWM != null) { 352 insLog.finer("correctWM {0}", correctWM); 353 } else { 354 insLog.finer("correctWM insets are not available, waiting for configureNotify"); 355 } 356 } 357 358 if (correctWM != null) { 359 handleCorrectInsets(correctWM); 360 } 361 } 362 } finally { 363 XToolkit.awtUnlock(); 364 } 365 } 366 367 protected void handleCorrectInsets(Insets correctWM) { 368 XToolkit.awtLock(); 369 try { 370 /* 371 * Ok, now see if we need adjust window size because 372 * initial insets were wrong (most likely they were). 373 */ 374 Insets correction = difference(correctWM, currentInsets); 375 insLog.finest("Corrention {0}", correction); 376 if (!isNull(correction)) { 377 currentInsets = copy(correctWM); 378 applyGuessedInsets(); 379 380 //Fix for 6318109: PIT: Min Size is not honored properly when a 381 //smaller size is specified in setSize(), XToolkit 382 //update minimum size hints 383 updateMinSizeHints(); 384 } 385 if (insLog.isLoggable(PlatformLogger.FINER)) insLog.finer("Dimensions before reparent: " + dimensions); 386 387 dimensions.setInsets(getRealInsets()); 388 insets_corrected = true; 389 390 if (isMaximized()) { 391 return; 392 } 393 394 /* 395 * If this window has been sized by a pack() we need 396 * to keep the interior geometry intact. Since pack() 397 * computed width and height with wrong insets, we 398 * must adjust the target dimensions appropriately. 399 */ 400 if ((getHints().get_flags() & (XUtilConstants.USPosition | XUtilConstants.PPosition)) != 0) { 401 reshape(dimensions, SET_BOUNDS, false); 402 } else { 403 reshape(dimensions, SET_SIZE, false); 404 } 405 } finally { 406 XToolkit.awtUnlock(); 407 } 408 } 409 410 public void handleMoved(WindowDimensions dims) { 411 Point loc = dims.getLocation(); 412 AWTAccessor.getComponentAccessor().setLocation((Component)target, loc.x, loc.y); 413 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); 414 } 415 416 417 protected Insets guessInsets() { 418 if (isEmbedded() || isTargetUndecorated()) { 419 return new Insets(0, 0, 0, 0); 420 } else { 421 if (!isNull(currentInsets)) { 422 /* insets were set on wdata by System Properties */ 423 return copy(currentInsets); 424 } else { 425 Insets res = getWMSetInsets(null); 426 if (res == null) { 427 res = XWM.getWM().guessInsets(this); 428 } 429 return res; 430 } 431 } 432 } 433 434 private void applyGuessedInsets() { 435 Insets guessed = guessInsets(); 436 currentInsets = copy(guessed); 437 } 438 439 public void revalidate() { 440 XToolkit.executeOnEventHandlerThread(target, new Runnable() { 441 public void run() { 442 target.invalidate(); 443 target.validate(); 444 } 445 }); 446 } 447 448 Insets getRealInsets() { 449 if (isNull(currentInsets)) { 450 applyGuessedInsets(); 451 } 452 return currentInsets; 453 } 454 455 public Insets getInsets() { 456 Insets in = copy(getRealInsets()); 457 in.top += getMenuBarHeight(); 458 if (insLog.isLoggable(PlatformLogger.FINEST)) { 459 insLog.finest("Get insets returns {0}", in); 460 } 461 return in; 462 } 463 464 boolean gravityBug() { 465 return XWM.configureGravityBuggy(); 466 } 467 468 // The height of area used to display current active input method 469 int getInputMethodHeight() { 470 return 0; 471 } 472 473 void updateSizeHints(WindowDimensions dims) { 474 Rectangle rec = dims.getClientRect(); 475 checkShellRect(rec); 476 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 477 } 478 479 void updateSizeHints() { 480 updateSizeHints(dimensions); 481 } 482 483 // Coordinates are that of the target 484 // Called only on Toolkit thread 485 public void reshape(WindowDimensions newDimensions, int op, 486 boolean userReshape) 487 { 488 if (insLog.isLoggable(PlatformLogger.FINE)) { 489 insLog.fine("Reshaping " + this + " to " + newDimensions + " op " + op + " user reshape " + userReshape); 490 } 491 if (userReshape) { 492 // We handle only userReshape == true cases. It means that 493 // if the window manager or any other part of the windowing 494 // system sets inappropriate size for this window, we can 495 // do nothing but accept it. 496 Rectangle newBounds = newDimensions.getBounds(); 497 Insets insets = newDimensions.getInsets(); 498 // Inherit isClientSizeSet from newDimensions 499 if (newDimensions.isClientSizeSet()) { 500 newBounds = new Rectangle(newBounds.x, newBounds.y, 501 newBounds.width - insets.left - insets.right, 502 newBounds.height - insets.top - insets.bottom); 503 } 504 newDimensions = new WindowDimensions(newBounds, insets, newDimensions.isClientSizeSet()); 505 } 506 XToolkit.awtLock(); 507 try { 508 if (!isReparented() || !isVisible()) { 509 insLog.fine("- not reparented({0}) or not visible({1}), default reshape", 510 Boolean.valueOf(isReparented()), Boolean.valueOf(visible)); 511 512 // Fix for 6323293. 513 // This actually is needed to preserve compatibility with previous releases - 514 // some of licensees are expecting componentMoved event on invisible one while 515 // its location changes. 516 Point oldLocation = getLocation(); 517 518 Point newLocation = new Point(AWTAccessor.getComponentAccessor().getX((Component)target), 519 AWTAccessor.getComponentAccessor().getY((Component)target)); 520 521 if (!newLocation.equals(oldLocation)) { 522 handleMoved(newDimensions); 523 } 524 525 dimensions = new WindowDimensions(newDimensions); 526 updateSizeHints(dimensions); 527 Rectangle client = dimensions.getClientRect(); 528 checkShellRect(client); 529 setShellBounds(client); 530 if (content != null && 531 !content.getSize().equals(newDimensions.getSize())) 532 { 533 reconfigureContentWindow(newDimensions); 534 } 535 return; 536 } 537 538 int wm = XWM.getWMID(); 539 updateChildrenSizes(); 540 applyGuessedInsets(); 541 542 Rectangle shellRect = newDimensions.getClientRect(); 543 544 if (gravityBug()) { 545 Insets in = newDimensions.getInsets(); 546 shellRect.translate(in.left, in.top); 547 } 548 549 if ((op & NO_EMBEDDED_CHECK) == 0 && isEmbedded()) { 550 shellRect.setLocation(0, 0); 551 } 552 553 checkShellRectSize(shellRect); 554 if (!isEmbedded()) { 555 checkShellRectPos(shellRect); 556 } 557 558 op = op & ~NO_EMBEDDED_CHECK; 559 560 if (op == SET_LOCATION) { 561 setShellPosition(shellRect); 562 } else if (isResizable()) { 563 if (op == SET_BOUNDS) { 564 setShellBounds(shellRect); 565 } else { 566 setShellSize(shellRect); 567 } 568 } else { 569 XWM.setShellNotResizable(this, newDimensions, shellRect, true); 570 if (op == SET_BOUNDS) { 571 setShellPosition(shellRect); 572 } 573 } 574 575 reconfigureContentWindow(newDimensions); 576 } finally { 577 XToolkit.awtUnlock(); 578 } 579 } 580 581 /** 582 * @param x, y, width, heith - dimensions of the window with insets 583 */ 584 private void reshape(int x, int y, int width, int height, int operation, 585 boolean userReshape) 586 { 587 Rectangle newRec; 588 boolean setClient = false; 589 WindowDimensions dims = new WindowDimensions(dimensions); 590 switch (operation & (~NO_EMBEDDED_CHECK)) { 591 case SET_LOCATION: 592 // Set location always sets bounds location. However, until the window is mapped we 593 // should use client coordinates 594 dims.setLocation(x, y); 595 break; 596 case SET_SIZE: 597 // Set size sets bounds size. However, until the window is mapped we 598 // should use client coordinates 599 dims.setSize(width, height); 600 break; 601 case SET_CLIENT_SIZE: { 602 // Sets client rect size. Width and height contain insets. 603 Insets in = currentInsets; 604 width -= in.left+in.right; 605 height -= in.top+in.bottom; 606 dims.setClientSize(width, height); 607 break; 608 } 609 case SET_BOUNDS: 610 default: 611 dims.setLocation(x, y); 612 dims.setSize(width, height); 613 break; 614 } 615 if (insLog.isLoggable(PlatformLogger.FINE)) 616 insLog.fine("For the operation {0} new dimensions are {1}", 617 operationToString(operation), dims); 618 619 reshape(dims, operation, userReshape); 620 } 621 622 // This method gets overriden in XFramePeer & XDialogPeer. 623 abstract boolean isTargetUndecorated(); 624 625 /** 626 * @see java.awt.peer.ComponentPeer#setBounds 627 */ 628 public void setBounds(int x, int y, int width, int height, int op) { 629 // TODO: Rewrite with WindowDimensions 630 reshape(x, y, width, height, op, true); 631 validateSurface(); 632 } 633 634 // Coordinates are that of the shell 635 void reconfigureContentWindow(WindowDimensions dims) { 636 if (content == null) { 637 insLog.fine("WARNING: Content window is null"); 638 return; 639 } 640 content.setContentBounds(dims); 641 } 642 643 boolean no_reparent_artifacts = false; 644 public void handleConfigureNotifyEvent(XEvent xev) { 645 assert (SunToolkit.isAWTLockHeldByCurrentThread()); 646 XConfigureEvent xe = xev.get_xconfigure(); 647 insLog.fine("Configure notify {0}", xe); 648 649 // XXX: should really only consider synthetic events, but 650 if (isReparented()) { 651 configure_seen = true; 652 } 653 654 if (!isMaximized() 655 && (xe.get_serial() == reparent_serial || xe.get_window() != getShell()) 656 && !no_reparent_artifacts) 657 { 658 insLog.fine("- reparent artifact, skipping"); 659 return; 660 } 661 no_reparent_artifacts = false; 662 663 /** 664 * When there is a WM we receive some CN before being visible and after. 665 * We should skip all CN which are before being visible, because we assume 666 * the gravity is in action while it is not yet. 667 * 668 * When there is no WM we receive CN only _before_ being visible. 669 * We should process these CNs. 670 */ 671 if (!isVisible() && XWM.getWMID() != XWM.NO_WM) { 672 insLog.fine(" - not visible, skipping"); 673 return; 674 } 675 676 /* 677 * Some window managers configure before we are reparented and 678 * the send event flag is set! ugh... (Enlighetenment for one, 679 * possibly MWM as well). If we haven't been reparented yet 680 * this is just the WM shuffling us into position. Ignore 681 * it!!!! or we wind up in a bogus location. 682 */ 683 int runningWM = XWM.getWMID(); 684 if (insLog.isLoggable(PlatformLogger.FINE)) { 685 insLog.fine("reparented={0}, visible={1}, WM={2}, decorations={3}", 686 isReparented(), isVisible(), runningWM, getDecorations()); 687 } 688 if (!isReparented() && isVisible() && runningWM != XWM.NO_WM 689 && !XWM.isNonReparentingWM() 690 && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 691 insLog.fine("- visible but not reparented, skipping"); 692 return; 693 } 694 //Last chance to correct insets 695 if (!insets_corrected && getDecorations() != XWindowAttributesData.AWT_DECOR_NONE) { 696 long parent = XlibUtil.getParentWindow(window); 697 Insets correctWM = (parent != -1) ? XWM.getWM().getInsets(this, window, parent) : null; 698 if (insLog.isLoggable(PlatformLogger.FINER)) { 699 if (correctWM != null) { 700 insLog.finer("Configure notify - insets : " + correctWM); 701 } else { 702 insLog.finer("Configure notify - insets are still not available"); 703 } 704 } 705 if (correctWM != null) { 706 handleCorrectInsets(correctWM); 707 } else { 708 //Only one attempt to correct insets is made (to lower risk) 709 //if insets are still not available we simply set the flag 710 insets_corrected = true; 711 } 712 } 713 714 updateChildrenSizes(); 715 716 // Bounds of the window 717 Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds((Component)target); 718 719 Point newLocation = targetBounds.getLocation(); 720 if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { 721 // Location, Client size + insets 722 newLocation = new Point(xe.get_x() - currentInsets.left, xe.get_y() - currentInsets.top); 723 } else { 724 // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when 725 // a window is resized but the client can not tell if the window was 726 // moved or not. The client should consider the position as unkown 727 // and use TranslateCoordinates to find the actual position. 728 // 729 // TODO this should be the default for every case. 730 switch (XWM.getWMID()) { 731 case XWM.CDE_WM: 732 case XWM.MOTIF_WM: 733 case XWM.METACITY_WM: 734 case XWM.MUTTER_WM: 735 case XWM.SAWFISH_WM: 736 { 737 Point xlocation = queryXLocation(); 738 if (log.isLoggable(PlatformLogger.FINE)) log.fine("New X location: {0}", xlocation); 739 if (xlocation != null) { 740 newLocation = xlocation; 741 } 742 break; 743 } 744 default: 745 break; 746 } 747 } 748 749 WindowDimensions newDimensions = 750 new WindowDimensions(newLocation, 751 new Dimension(xe.get_width(), xe.get_height()), 752 copy(currentInsets), 753 true); 754 755 insLog.finer("Insets are {0}, new dimensions {1}", 756 currentInsets, newDimensions); 757 758 checkIfOnNewScreen(newDimensions.getBounds()); 759 760 Point oldLocation = getLocation(); 761 dimensions = newDimensions; 762 if (!newLocation.equals(oldLocation)) { 763 handleMoved(newDimensions); 764 } 765 reconfigureContentWindow(newDimensions); 766 updateChildrenSizes(); 767 768 repositionSecurityWarning(); 769 } 770 771 private void checkShellRectSize(Rectangle shellRect) { 772 shellRect.width = Math.max(MIN_SIZE, shellRect.width); 773 shellRect.height = Math.max(MIN_SIZE, shellRect.height); 774 } 775 776 private void checkShellRectPos(Rectangle shellRect) { 777 int wm = XWM.getWMID(); 778 if (wm == XWM.MOTIF_WM || wm == XWM.CDE_WM) { 779 if (shellRect.x == 0 && shellRect.y == 0) { 780 shellRect.x = shellRect.y = 1; 781 } 782 } 783 } 784 785 private void checkShellRect(Rectangle shellRect) { 786 checkShellRectSize(shellRect); 787 checkShellRectPos(shellRect); 788 } 789 790 public void setShellBounds(Rectangle rec) { 791 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell bounds on " + 792 this + " to " + rec); 793 XToolkit.awtLock(); 794 try { 795 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 796 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); 797 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); 798 } 799 finally { 800 XToolkit.awtUnlock(); 801 } 802 } 803 public void setShellSize(Rectangle rec) { 804 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell size on " + 805 this + " to " + rec); 806 XToolkit.awtLock(); 807 try { 808 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 809 XlibWrapper.XResizeWindow(XToolkit.getDisplay(), getShell(), rec.width, rec.height); 810 } 811 finally { 812 XToolkit.awtUnlock(); 813 } 814 } 815 public void setShellPosition(Rectangle rec) { 816 if (insLog.isLoggable(PlatformLogger.FINE)) insLog.fine("Setting shell position on " + 817 this + " to " + rec); 818 XToolkit.awtLock(); 819 try { 820 updateSizeHints(rec.x, rec.y, rec.width, rec.height); 821 XlibWrapper.XMoveWindow(XToolkit.getDisplay(), getShell(), rec.x, rec.y); 822 } 823 finally { 824 XToolkit.awtUnlock(); 825 } 826 } 827 828 void initResizability() { 829 setResizable(winAttr.initialResizability); 830 } 831 public void setResizable(boolean resizable) { 832 int fs = winAttr.functions; 833 if (!isResizable() && resizable) { 834 currentInsets = new Insets(0, 0, 0, 0); 835 resetWMSetInsets(); 836 if (!isEmbedded()) { 837 setReparented(false); 838 } 839 winAttr.isResizable = resizable; 840 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 841 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 842 } else { 843 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 844 } 845 winAttr.functions = fs; 846 XWM.setShellResizable(this); 847 } else if (isResizable() && !resizable) { 848 currentInsets = new Insets(0, 0, 0, 0); 849 resetWMSetInsets(); 850 if (!isEmbedded()) { 851 setReparented(false); 852 } 853 winAttr.isResizable = resizable; 854 if ((fs & MWMConstants.MWM_FUNC_ALL) != 0) { 855 fs |= (MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 856 } else { 857 fs &= ~(MWMConstants.MWM_FUNC_RESIZE | MWMConstants.MWM_FUNC_MAXIMIZE); 858 } 859 winAttr.functions = fs; 860 XWM.setShellNotResizable(this, dimensions, dimensions.getBounds(), false); 861 } 862 } 863 864 Rectangle getShellBounds() { 865 return dimensions.getClientRect(); 866 } 867 868 public Rectangle getBounds() { 869 return dimensions.getBounds(); 870 } 871 872 public Dimension getSize() { 873 return dimensions.getSize(); 874 } 875 876 public int getX() { 877 return dimensions.getLocation().x; 878 } 879 880 public int getY() { 881 return dimensions.getLocation().y; 882 } 883 884 public Point getLocation() { 885 return dimensions.getLocation(); 886 } 887 888 public int getAbsoluteX() { 889 // NOTE: returning this peer's location which is shell location 890 return dimensions.getScreenBounds().x; 891 } 892 893 public int getAbsoluteY() { 894 // NOTE: returning this peer's location which is shell location 895 return dimensions.getScreenBounds().y; 896 } 897 898 public int getWidth() { 899 return getSize().width; 900 } 901 902 public int getHeight() { 903 return getSize().height; 904 } 905 906 final public WindowDimensions getDimensions() { 907 return dimensions; 908 } 909 910 public Point getLocationOnScreen() { 911 XToolkit.awtLock(); 912 try { 913 if (configure_seen) { 914 return toGlobal(0,0); 915 } else { 916 Point location = target.getLocation(); 917 if (insLog.isLoggable(PlatformLogger.FINE)) 918 insLog.fine("getLocationOnScreen {0} not reparented: {1} ", 919 this, location); 920 return location; 921 } 922 } finally { 923 XToolkit.awtUnlock(); 924 } 925 } 926 927 928 /*************************************************************************************** 929 * END OF I N S E T S C O D E 930 **************************************************************************************/ 931 932 protected boolean isEventDisabled(XEvent e) { 933 switch (e.get_type()) { 934 // Do not generate MOVED/RESIZED events since we generate them by ourselves 935 case XConstants.ConfigureNotify: 936 return true; 937 case XConstants.EnterNotify: 938 case XConstants.LeaveNotify: 939 // Disable crossing event on outer borders of Frame so 940 // we receive only one set of cross notifications(first set is from content window) 941 return true; 942 default: 943 return super.isEventDisabled(e); 944 } 945 } 946 947 int getDecorations() { 948 return winAttr.decorations; 949 } 950 951 int getFunctions() { 952 return winAttr.functions; 953 } 954 955 public void setVisible(boolean vis) { 956 log.finer("Setting {0} to visible {1}", this, Boolean.valueOf(vis)); 957 if (vis && !isVisible()) { 958 XWM.setShellDecor(this); 959 super.setVisible(vis); 960 if (winAttr.isResizable) { 961 //Fix for 4320050: Minimum size for java.awt.Frame is not being enforced. 962 //We need to update frame's minimum size, not to reset it 963 XWM.removeSizeHints(this, XUtilConstants.PMaxSize); 964 updateMinimumSize(); 965 } 966 } else { 967 super.setVisible(vis); 968 } 969 } 970 971 protected void suppressWmTakeFocus(boolean doSuppress) { 972 XAtomList protocols = getWMProtocols(); 973 if (doSuppress) { 974 protocols.remove(wm_take_focus); 975 } else { 976 protocols.add(wm_take_focus); 977 } 978 wm_protocols.setAtomListProperty(this, protocols); 979 } 980 981 public void dispose() { 982 if (content != null) { 983 content.destroy(); 984 } 985 focusProxy.destroy(); 986 987 if (iconWindow != null) { 988 iconWindow.destroy(); 989 } 990 991 super.dispose(); 992 } 993 994 public void handleClientMessage(XEvent xev) { 995 super.handleClientMessage(xev); 996 XClientMessageEvent cl = xev.get_xclient(); 997 if ((wm_protocols != null) && (cl.get_message_type() == wm_protocols.getAtom())) { 998 if (cl.get_data(0) == wm_delete_window.getAtom()) { 999 handleQuit(); 1000 } else if (cl.get_data(0) == wm_take_focus.getAtom()) { 1001 handleWmTakeFocus(cl); 1002 } 1003 } 1004 } 1005 1006 private void handleWmTakeFocus(XClientMessageEvent cl) { 1007 focusLog.fine("WM_TAKE_FOCUS on {0}", this); 1008 requestWindowFocus(cl.get_data(1), true); 1009 } 1010 1011 /** 1012 * Requests focus to this decorated top-level by requesting X input focus 1013 * to the shell window. 1014 */ 1015 protected void requestXFocus(long time, boolean timeProvided) { 1016 // We have proxied focus mechanism - instead of shell the focus is held 1017 // by "proxy" - invisible mapped window. When we want to set X input focus to 1018 // toplevel set it on proxy instead. 1019 if (focusProxy == null) { 1020 if (focusLog.isLoggable(PlatformLogger.FINE)) focusLog.warning("Focus proxy is null for " + this); 1021 } else { 1022 if (focusLog.isLoggable(PlatformLogger.FINE)) focusLog.fine("Requesting focus to proxy: " + focusProxy); 1023 if (timeProvided) { 1024 focusProxy.xRequestFocus(time); 1025 } else { 1026 focusProxy.xRequestFocus(); 1027 } 1028 } 1029 } 1030 1031 XFocusProxyWindow getFocusProxy() { 1032 return focusProxy; 1033 } 1034 1035 public void handleQuit() { 1036 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_CLOSING)); 1037 } 1038 1039 final void dumpMe() { 1040 System.err.println(">>> Peer: " + x + ", " + y + ", " + width + ", " + height); 1041 } 1042 1043 final void dumpTarget() { 1044 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 1045 int getWidth = compAccessor.getWidth((Component)target); 1046 int getHeight = compAccessor.getHeight((Component)target); 1047 int getTargetX = compAccessor.getX((Component)target); 1048 int getTargetY = compAccessor.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.finer("Current window is: active={0}, focused={1}", 1115 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) AWTAccessor.getComponentAccessor().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 }