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