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