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