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