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