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