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