1 /* 2 * Copyright (c) 2002, 2017, 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.FocusEvent; 31 import java.awt.event.WindowEvent; 32 import java.awt.geom.AffineTransform; 33 34 import java.awt.peer.ComponentPeer; 35 import java.awt.peer.WindowPeer; 36 37 import java.io.UnsupportedEncodingException; 38 39 import java.security.AccessController; 40 import java.security.PrivilegedAction; 41 42 import java.util.ArrayList; 43 import java.util.HashSet; 44 import java.util.Iterator; 45 import java.util.Set; 46 import java.util.Vector; 47 48 import java.util.concurrent.atomic.AtomicBoolean; 49 50 import sun.awt.AWTAccessor.ComponentAccessor; 51 import sun.util.logging.PlatformLogger; 52 53 import sun.awt.AWTAccessor; 54 import sun.awt.DisplayChangedListener; 55 import sun.awt.SunToolkit; 56 import sun.awt.X11GraphicsDevice; 57 import sun.awt.X11GraphicsEnvironment; 58 import sun.awt.IconInfo; 59 60 import sun.java2d.pipe.Region; 61 62 class XWindowPeer extends XPanelPeer implements WindowPeer, 63 DisplayChangedListener { 64 65 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XWindowPeer"); 66 private static final PlatformLogger focusLog = PlatformLogger.getLogger("sun.awt.X11.focus.XWindowPeer"); 67 private static final PlatformLogger insLog = PlatformLogger.getLogger("sun.awt.X11.insets.XWindowPeer"); 68 private static final PlatformLogger grabLog = PlatformLogger.getLogger("sun.awt.X11.grab.XWindowPeer"); 69 private static final PlatformLogger iconLog = PlatformLogger.getLogger("sun.awt.X11.icon.XWindowPeer"); 70 71 // should be synchronized on awtLock 72 private static Set<XWindowPeer> windows = new HashSet<XWindowPeer>(); 73 74 75 private boolean cachedFocusableWindow; 76 XWarningWindow warningWindow; 77 78 private boolean alwaysOnTop; 79 private boolean locationByPlatform; 80 81 Dialog modalBlocker; 82 boolean delayedModalBlocking = false; 83 Dimension targetMinimumSize = null; 84 85 private XWindowPeer ownerPeer; 86 87 // used for modal blocking to keep existing z-order 88 protected XWindowPeer prevTransientFor, nextTransientFor; 89 // value of WM_TRANSIENT_FOR hint set on this window 90 private XBaseWindow curRealTransientFor; 91 92 private boolean grab = false; // Whether to do a grab during showing 93 94 private boolean isMapped = false; // Is this window mapped or not 95 private boolean mustControlStackPosition = false; // Am override-redirect not on top 96 private XEventDispatcher rootPropertyEventDispatcher = null; 97 98 private static final AtomicBoolean isStartupNotificationRemoved = new AtomicBoolean(); 99 100 /* 101 * Focus related flags 102 */ 103 private boolean isUnhiding = false; // Is the window unhiding. 104 private boolean isBeforeFirstMapNotify = false; // Is the window (being shown) between 105 // setVisible(true) & handleMapNotify(). 106 107 /** 108 * The type of the window. 109 * 110 * The type is supposed to be immutable while the peer object exists. 111 * The value gets initialized in the preInit() method. 112 */ 113 private Window.Type windowType = Window.Type.NORMAL; 114 115 public final Window.Type getWindowType() { 116 return windowType; 117 } 118 119 // It need to be accessed from XFramePeer. 120 protected Vector <ToplevelStateListener> toplevelStateListeners = new Vector<ToplevelStateListener>(); 121 XWindowPeer(XCreateWindowParams params) { 122 super(params.putIfNull(PARENT_WINDOW, Long.valueOf(0))); 123 } 124 125 XWindowPeer(Window target) { 126 super(new XCreateWindowParams(new Object[] { 127 TARGET, target, 128 PARENT_WINDOW, Long.valueOf(0)})); 129 } 130 131 /* 132 * This constant defines icon size recommended for using. 133 * Apparently, we should use XGetIconSizes which should 134 * return icon sizes would be most appreciated by the WM. 135 * However, XGetIconSizes always returns 0 for some reason. 136 * So the constant has been introduced. 137 */ 138 private static final int PREFERRED_SIZE_FOR_ICON = 128; 139 140 /* 141 * Sometimes XChangeProperty(_NET_WM_ICON) doesn't work if 142 * image buffer is too large. This constant holds maximum 143 * length of buffer which can be used with _NET_WM_ICON hint. 144 * It holds int's value. 145 */ 146 private static final int MAXIMUM_BUFFER_LENGTH_NET_WM_ICON = (2<<15) - 1; 147 148 void preInit(XCreateWindowParams params) { 149 target = (Component)params.get(TARGET); 150 windowType = ((Window)target).getType(); 151 params.put(REPARENTED, 152 Boolean.valueOf(isOverrideRedirect() || isSimpleWindow())); 153 super.preInit(params); 154 params.putIfNull(BIT_GRAVITY, Integer.valueOf(XConstants.NorthWestGravity)); 155 156 long eventMask = 0; 157 if (params.containsKey(EVENT_MASK)) { 158 eventMask = ((Long)params.get(EVENT_MASK)); 159 } 160 eventMask |= XConstants.VisibilityChangeMask; 161 params.put(EVENT_MASK, eventMask); 162 163 XA_NET_WM_STATE = XAtom.get("_NET_WM_STATE"); 164 165 166 params.put(OVERRIDE_REDIRECT, Boolean.valueOf(isOverrideRedirect())); 167 168 SunToolkit.awtLock(); 169 try { 170 windows.add(this); 171 } finally { 172 SunToolkit.awtUnlock(); 173 } 174 175 cachedFocusableWindow = isFocusableWindow(); 176 177 if (!target.isFontSet()) { 178 target.setFont(XWindow.getDefaultFont()); 179 // we should not call setFont because it will call a repaint 180 // which the peer may not be ready to do yet. 181 } 182 if (!target.isBackgroundSet()) { 183 target.setBackground(SystemColor.window); 184 // we should not call setBackGround because it will call a repaint 185 // which the peer may not be ready to do yet. 186 187 } 188 if (!target.isForegroundSet()) { 189 target.setForeground(SystemColor.windowText); 190 // we should not call setForeGround because it will call a repaint 191 // which the peer may not be ready to do yet. 192 } 193 194 195 alwaysOnTop = ((Window)target).isAlwaysOnTop() && ((Window)target).isAlwaysOnTopSupported(); 196 197 GraphicsConfiguration gc = getGraphicsConfiguration(); 198 ((X11GraphicsDevice)gc.getDevice()).addDisplayChangedListener(this); 199 } 200 201 protected String getWMName() { 202 String name = target.getName(); 203 if (name == null || name.trim().equals("")) { 204 name = " "; 205 } 206 return name; 207 } 208 209 private static native String getLocalHostname(); 210 private static native int getJvmPID(); 211 212 @SuppressWarnings("deprecation") 213 void postInit(XCreateWindowParams params) { 214 super.postInit(params); 215 216 // Init WM_PROTOCOLS atom 217 initWMProtocols(); 218 219 // Set _NET_WM_PID and WM_CLIENT_MACHINE using this JVM 220 XAtom.get("WM_CLIENT_MACHINE").setProperty(getWindow(), getLocalHostname()); 221 XAtom.get("_NET_WM_PID").setCard32Property(getWindow(), getJvmPID()); 222 223 // Set WM_TRANSIENT_FOR and group_leader 224 Window t_window = (Window)target; 225 Window owner = t_window.getOwner(); 226 if (owner != null) { 227 ownerPeer = AWTAccessor.getComponentAccessor().getPeer(owner); 228 if (focusLog.isLoggable(PlatformLogger.Level.FINER)) { 229 focusLog.finer("Owner is " + owner); 230 focusLog.finer("Owner peer is " + ownerPeer); 231 focusLog.finer("Owner X window " + Long.toHexString(ownerPeer.getWindow())); 232 focusLog.finer("Owner content X window " + Long.toHexString(ownerPeer.getContentWindow())); 233 } 234 // as owner window may be an embedded window, we must get a toplevel window 235 // to set as TRANSIENT_FOR hint 236 long ownerWindow = ownerPeer.getWindow(); 237 if (ownerWindow != 0) { 238 XToolkit.awtLock(); 239 try { 240 // Set WM_TRANSIENT_FOR 241 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 242 focusLog.fine("Setting transient on " + Long.toHexString(getWindow()) 243 + " for " + Long.toHexString(ownerWindow)); 244 } 245 setToplevelTransientFor(this, ownerPeer, false, true); 246 247 // Set group leader 248 XWMHints hints = getWMHints(); 249 hints.set_flags(hints.get_flags() | (int)XUtilConstants.WindowGroupHint); 250 hints.set_window_group(ownerWindow); 251 XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData); 252 } 253 finally { 254 XToolkit.awtUnlock(); 255 } 256 } 257 } 258 259 if (owner != null || isSimpleWindow()) { 260 XNETProtocol protocol = XWM.getWM().getNETProtocol(); 261 if (protocol != null && protocol.active()) { 262 XToolkit.awtLock(); 263 try { 264 XAtomList net_wm_state = getNETWMState(); 265 net_wm_state.add(protocol.XA_NET_WM_STATE_SKIP_TASKBAR); 266 setNETWMState(net_wm_state); 267 } finally { 268 XToolkit.awtUnlock(); 269 } 270 271 } 272 } 273 274 // Init warning window(for applets) 275 if (((Window)target).getWarningString() != null) { 276 // accessSystemTray permission allows to display TrayIcon, TrayIcon tooltip 277 // and TrayIcon balloon windows without a warning window. 278 if (!AWTAccessor.getWindowAccessor().isTrayIconWindow((Window)target)) { 279 warningWindow = new XWarningWindow((Window)target, getWindow(), this); 280 } 281 } 282 283 setSaveUnder(true); 284 285 updateIconImages(); 286 287 updateShape(); 288 updateOpacity(); 289 // no need in updateOpaque() as it is no-op 290 } 291 292 public void updateIconImages() { 293 Window target = (Window)this.target; 294 java.util.List<Image> iconImages = target.getIconImages(); 295 XWindowPeer ownerPeer = getOwnerPeer(); 296 winAttr.icons = new ArrayList<IconInfo>(); 297 if (iconImages.size() != 0) { 298 //read icon images from target 299 winAttr.iconsInherited = false; 300 for (Iterator<Image> i = iconImages.iterator(); i.hasNext(); ) { 301 Image image = i.next(); 302 if (image == null) { 303 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 304 log.finest("XWindowPeer.updateIconImages: Skipping the image passed into Java because it's null."); 305 } 306 continue; 307 } 308 IconInfo iconInfo; 309 try { 310 iconInfo = new IconInfo(image); 311 } catch (Exception e){ 312 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 313 log.finest("XWindowPeer.updateIconImages: Perhaps the image passed into Java is broken. Skipping this icon."); 314 } 315 continue; 316 } 317 if (iconInfo.isValid()) { 318 winAttr.icons.add(iconInfo); 319 } 320 } 321 } 322 323 // Fix for CR#6425089 324 winAttr.icons = normalizeIconImages(winAttr.icons); 325 326 if (winAttr.icons.size() == 0) { 327 //target.icons is empty or all icon images are broken 328 if (ownerPeer != null) { 329 //icon is inherited from parent 330 winAttr.iconsInherited = true; 331 winAttr.icons = ownerPeer.getIconInfo(); 332 } else { 333 //default icon is used 334 winAttr.iconsInherited = false; 335 winAttr.icons = getDefaultIconInfo(); 336 } 337 } 338 recursivelySetIcon(winAttr.icons); 339 } 340 341 /* 342 * Sometimes XChangeProperty(_NET_WM_ICON) doesn't work if 343 * image buffer is too large. This function help us accommodate 344 * initial list of the icon images to certainly-acceptable. 345 * It does scale some of these icons to appropriate size 346 * if it's necessary. 347 */ 348 static java.util.List<IconInfo> normalizeIconImages(java.util.List<IconInfo> icons) { 349 java.util.List<IconInfo> result = new ArrayList<IconInfo>(); 350 int totalLength = 0; 351 boolean haveLargeIcon = false; 352 353 for (IconInfo icon : icons) { 354 int width = icon.getWidth(); 355 int height = icon.getHeight(); 356 int length = icon.getRawLength(); 357 358 if (width > PREFERRED_SIZE_FOR_ICON || height > PREFERRED_SIZE_FOR_ICON) { 359 if (haveLargeIcon) { 360 continue; 361 } 362 int scaledWidth = width; 363 int scaledHeight = height; 364 while (scaledWidth > PREFERRED_SIZE_FOR_ICON || 365 scaledHeight > PREFERRED_SIZE_FOR_ICON) { 366 scaledWidth = scaledWidth / 2; 367 scaledHeight = scaledHeight / 2; 368 } 369 370 icon.setScaledSize(scaledWidth, scaledHeight); 371 length = icon.getRawLength(); 372 } 373 374 if (totalLength + length <= MAXIMUM_BUFFER_LENGTH_NET_WM_ICON) { 375 totalLength += length; 376 result.add(icon); 377 if (width > PREFERRED_SIZE_FOR_ICON || height > PREFERRED_SIZE_FOR_ICON) { 378 haveLargeIcon = true; 379 } 380 } 381 } 382 383 if (iconLog.isLoggable(PlatformLogger.Level.FINEST)) { 384 iconLog.finest(">>> Length_ of buffer of icons data: " + totalLength + 385 ", maximum length: " + MAXIMUM_BUFFER_LENGTH_NET_WM_ICON); 386 } 387 388 return result; 389 } 390 391 /* 392 * Dumps each icon from the list 393 */ 394 static void dumpIcons(java.util.List<IconInfo> icons) { 395 if (iconLog.isLoggable(PlatformLogger.Level.FINEST)) { 396 iconLog.finest(">>> Sizes of icon images:"); 397 for (Iterator<IconInfo> i = icons.iterator(); i.hasNext(); ) { 398 iconLog.finest(" {0}", i.next()); 399 } 400 } 401 } 402 403 public void recursivelySetIcon(java.util.List<IconInfo> icons) { 404 dumpIcons(winAttr.icons); 405 setIconHints(icons); 406 Window target = (Window)this.target; 407 Window[] children = target.getOwnedWindows(); 408 int cnt = children.length; 409 final ComponentAccessor acc = AWTAccessor.getComponentAccessor(); 410 for (int i = 0; i < cnt; i++) { 411 final ComponentPeer childPeer = acc.getPeer(children[i]); 412 if (childPeer != null && childPeer instanceof XWindowPeer) { 413 if (((XWindowPeer)childPeer).winAttr.iconsInherited) { 414 ((XWindowPeer)childPeer).winAttr.icons = icons; 415 ((XWindowPeer)childPeer).recursivelySetIcon(icons); 416 } 417 } 418 } 419 } 420 421 java.util.List<IconInfo> getIconInfo() { 422 return winAttr.icons; 423 } 424 void setIconHints(java.util.List<IconInfo> icons) { 425 //This does nothing for XWindowPeer, 426 //It's overriden in XDecoratedPeer 427 } 428 429 private static ArrayList<IconInfo> defaultIconInfo; 430 protected static synchronized java.util.List<IconInfo> getDefaultIconInfo() { 431 if (defaultIconInfo == null) { 432 defaultIconInfo = new ArrayList<IconInfo>(); 433 if (XlibWrapper.dataModel == 32) { 434 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon16_png.java_icon16_png)); 435 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon24_png.java_icon24_png)); 436 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon32_png.java_icon32_png)); 437 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon32_java_icon48_png.java_icon48_png)); 438 } else { 439 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon16_png.java_icon16_png)); 440 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon24_png.java_icon24_png)); 441 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon32_png.java_icon32_png)); 442 defaultIconInfo.add(new IconInfo(sun.awt.AWTIcon64_java_icon48_png.java_icon48_png)); 443 } 444 } 445 return defaultIconInfo; 446 } 447 448 private void updateShape() { 449 // Shape shape = ((Window)target).getShape(); 450 Shape shape = AWTAccessor.getWindowAccessor().getShape((Window)target); 451 if (shape != null) { 452 applyShape(Region.getInstance(shape, null)); 453 } 454 } 455 456 private void updateOpacity() { 457 // float opacity = ((Window)target).getOpacity(); 458 float opacity = AWTAccessor.getWindowAccessor().getOpacity((Window)target); 459 if (opacity < 1.0f) { 460 setOpacity(opacity); 461 } 462 } 463 464 public void updateMinimumSize() { 465 //This function only saves minimumSize value in XWindowPeer 466 //Setting WMSizeHints is implemented in XDecoratedPeer 467 targetMinimumSize = (target.isMinimumSizeSet()) ? 468 target.getMinimumSize() : null; 469 } 470 471 public Dimension getTargetMinimumSize() { 472 return (targetMinimumSize == null) ? null : new Dimension(targetMinimumSize); 473 } 474 475 public XWindowPeer getOwnerPeer() { 476 return ownerPeer; 477 } 478 479 //Fix for 6318144: PIT:Setting Min Size bigger than current size enlarges 480 //the window but fails to revalidate, Sol-CDE 481 //This bug is regression for 482 //5025858: Resizing a decorated frame triggers componentResized event twice. 483 //Since events are not posted from Component.setBounds we need to send them here. 484 //Note that this function is overriden in XDecoratedPeer so event 485 //posting is not changing for decorated peers 486 public void setBounds(int x, int y, int width, int height, int op) { 487 XToolkit.awtLock(); 488 try { 489 Rectangle oldBounds = getBounds(); 490 491 super.setBounds(x, y, width, height, op); 492 493 Rectangle bounds = getBounds(); 494 495 XSizeHints hints = getHints(); 496 setSizeHints(hints.get_flags() | XUtilConstants.PPosition | XUtilConstants.PSize, 497 bounds.x, bounds.y, bounds.width, bounds.height); 498 XWM.setMotifDecor(this, false, 0, 0); 499 500 boolean isResized = !bounds.getSize().equals(oldBounds.getSize()); 501 boolean isMoved = !bounds.getLocation().equals(oldBounds.getLocation()); 502 if (isMoved || isResized) { 503 repositionSecurityWarning(); 504 } 505 if (isResized) { 506 postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_RESIZED)); 507 } 508 if (isMoved) { 509 postEventToEventQueue(new ComponentEvent(getEventSource(), ComponentEvent.COMPONENT_MOVED)); 510 } 511 } finally { 512 XToolkit.awtUnlock(); 513 } 514 } 515 516 void updateFocusability() { 517 updateFocusableWindowState(); 518 XToolkit.awtLock(); 519 try { 520 XWMHints hints = getWMHints(); 521 hints.set_flags(hints.get_flags() | (int)XUtilConstants.InputHint); 522 hints.set_input(false/*isNativelyNonFocusableWindow() ? (0):(1)*/); 523 XlibWrapper.XSetWMHints(XToolkit.getDisplay(), getWindow(), hints.pData); 524 } 525 finally { 526 XToolkit.awtUnlock(); 527 } 528 } 529 530 public Insets getInsets() { 531 return new Insets(0, 0, 0, 0); 532 } 533 534 // NOTE: This method may be called by privileged threads. 535 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 536 public void handleIconify() { 537 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_ICONIFIED)); 538 } 539 540 // NOTE: This method may be called by privileged threads. 541 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 542 public void handleDeiconify() { 543 postEvent(new WindowEvent((Window)target, WindowEvent.WINDOW_DEICONIFIED)); 544 } 545 546 // NOTE: This method may be called by privileged threads. 547 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 548 public void handleStateChange(int oldState, int newState) { 549 postEvent(new WindowEvent((Window)target, 550 WindowEvent.WINDOW_STATE_CHANGED, 551 oldState, newState)); 552 } 553 554 /** 555 * DEPRECATED: Replaced by getInsets(). 556 */ 557 public Insets insets() { 558 return getInsets(); 559 } 560 561 boolean isAutoRequestFocus() { 562 if (XToolkit.isToolkitThread()) { 563 return AWTAccessor.getWindowAccessor().isAutoRequestFocus((Window)target); 564 } else { 565 return ((Window)target).isAutoRequestFocus(); 566 } 567 } 568 569 /* 570 * Retrives real native focused window and converts it into Java peer. 571 */ 572 static XWindowPeer getNativeFocusedWindowPeer() { 573 XBaseWindow baseWindow = XToolkit.windowToXWindow(xGetInputFocus()); 574 return (baseWindow instanceof XWindowPeer) ? (XWindowPeer)baseWindow : 575 (baseWindow instanceof XFocusProxyWindow) ? 576 ((XFocusProxyWindow)baseWindow).getOwner() : null; 577 } 578 579 /* 580 * Retrives real native focused window and converts it into Java window. 581 */ 582 static Window getNativeFocusedWindow() { 583 XWindowPeer peer = getNativeFocusedWindowPeer(); 584 return peer != null ? (Window)peer.target : null; 585 } 586 587 boolean isFocusableWindow() { 588 if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread()) 589 { 590 return cachedFocusableWindow; 591 } else { 592 return ((Window)target).isFocusableWindow(); 593 } 594 } 595 596 /* WARNING: don't call client code in this method! */ 597 boolean isFocusedWindowModalBlocker() { 598 return false; 599 } 600 601 long getFocusTargetWindow() { 602 return getContentWindow(); 603 } 604 605 /** 606 * Returns whether or not this window peer has native X window 607 * configured as non-focusable window. It might happen if: 608 * - Java window is non-focusable 609 * - Java window is simple Window(not Frame or Dialog) 610 */ 611 boolean isNativelyNonFocusableWindow() { 612 if (XToolkit.isToolkitThread() || SunToolkit.isAWTLockHeldByCurrentThread()) 613 { 614 return isSimpleWindow() || !cachedFocusableWindow; 615 } else { 616 return isSimpleWindow() || !(((Window)target).isFocusableWindow()); 617 } 618 } 619 620 public void handleWindowFocusIn_Dispatch() { 621 if (EventQueue.isDispatchThread()) { 622 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target); 623 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS); 624 SunToolkit.setSystemGenerated(we); 625 target.dispatchEvent(we); 626 } 627 } 628 629 public void handleWindowFocusInSync(long serial) { 630 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS); 631 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target); 632 sendEvent(we); 633 } 634 // NOTE: This method may be called by privileged threads. 635 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 636 public void handleWindowFocusIn(long serial) { 637 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_GAINED_FOCUS); 638 /* wrap in Sequenced, then post*/ 639 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow((Window) target); 640 postEvent(wrapInSequenced((AWTEvent) we)); 641 } 642 643 // NOTE: This method may be called by privileged threads. 644 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 645 public void handleWindowFocusOut(Window oppositeWindow, long serial) { 646 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, oppositeWindow); 647 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null); 648 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null); 649 /* wrap in Sequenced, then post*/ 650 postEvent(wrapInSequenced((AWTEvent) we)); 651 } 652 public void handleWindowFocusOutSync(Window oppositeWindow, long serial) { 653 WindowEvent we = new WindowEvent((Window)target, WindowEvent.WINDOW_LOST_FOCUS, oppositeWindow); 654 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusedWindow(null); 655 XKeyboardFocusManagerPeer.getInstance().setCurrentFocusOwner(null); 656 sendEvent(we); 657 } 658 659 /* --- DisplayChangedListener Stuff --- */ 660 661 /* Xinerama 662 * called to check if we've been moved onto a different screen 663 * Based on checkNewXineramaScreen() in awt_GraphicsEnv.c 664 */ 665 public void checkIfOnNewScreen(Rectangle newBounds) { 666 if (!XToolkit.localEnv.runningXinerama()) { 667 return; 668 } 669 670 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 671 log.finest("XWindowPeer: Check if we've been moved to a new screen since we're running in Xinerama mode"); 672 } 673 674 int area = newBounds.width * newBounds.height; 675 int intAmt, vertAmt, horizAmt; 676 int largestAmt = 0; 677 int curScreenNum = ((X11GraphicsDevice)getGraphicsConfiguration().getDevice()).getScreen(); 678 int newScreenNum = 0; 679 GraphicsDevice gds[] = XToolkit.localEnv.getScreenDevices(); 680 GraphicsConfiguration newGC = null; 681 Rectangle screenBounds; 682 683 XToolkit.awtUnlock(); 684 try { 685 for (int i = 0; i < gds.length; i++) { 686 screenBounds = gds[i].getDefaultConfiguration().getBounds(); 687 if (newBounds.intersects(screenBounds)) { 688 horizAmt = Math.min(newBounds.x + newBounds.width, 689 screenBounds.x + screenBounds.width) - 690 Math.max(newBounds.x, screenBounds.x); 691 vertAmt = Math.min(newBounds.y + newBounds.height, 692 screenBounds.y + screenBounds.height)- 693 Math.max(newBounds.y, screenBounds.y); 694 intAmt = horizAmt * vertAmt; 695 if (intAmt == area) { 696 // Completely on this screen - done! 697 newScreenNum = i; 698 newGC = gds[i].getDefaultConfiguration(); 699 break; 700 } 701 if (intAmt > largestAmt) { 702 largestAmt = intAmt; 703 newScreenNum = i; 704 newGC = gds[i].getDefaultConfiguration(); 705 } 706 } 707 } 708 } finally { 709 XToolkit.awtLock(); 710 } 711 if (newScreenNum != curScreenNum) { 712 if (log.isLoggable(PlatformLogger.Level.FINEST)) { 713 log.finest("XWindowPeer: Moved to a new screen"); 714 } 715 executeDisplayChangedOnEDT(newGC); 716 } 717 } 718 719 /** 720 * Helper method that executes the displayChanged(screen) method on 721 * the event dispatch thread. This method is used in the Xinerama case 722 * and after display mode change events. 723 */ 724 private void executeDisplayChangedOnEDT(final GraphicsConfiguration gc) { 725 Runnable dc = new Runnable() { 726 public void run() { 727 AWTAccessor.getComponentAccessor(). 728 setGraphicsConfiguration(target, gc); 729 } 730 }; 731 SunToolkit.executeOnEventHandlerThread(target, dc); 732 } 733 734 /** 735 * From the DisplayChangedListener interface; called from 736 * X11GraphicsDevice when the display mode has been changed. 737 */ 738 public void displayChanged() { 739 executeDisplayChangedOnEDT(getGraphicsConfiguration()); 740 } 741 742 /** 743 * From the DisplayChangedListener interface; top-levels do not need 744 * to react to this event. 745 */ 746 public void paletteChanged() { 747 } 748 749 private Point queryXLocation() 750 { 751 return XlibUtil.translateCoordinates(getContentWindow(), XlibWrapper 752 .RootWindow(XToolkit.getDisplay(), 753 getScreenNumber()), 754 new Point(0, 0), getScale()); 755 } 756 757 protected Point getNewLocation(XConfigureEvent xe, int leftInset, int topInset) { 758 // Bounds of the window 759 Rectangle targetBounds = AWTAccessor.getComponentAccessor().getBounds(target); 760 761 int runningWM = XWM.getWMID(); 762 Point newLocation = targetBounds.getLocation(); 763 if (xe.get_send_event() || runningWM == XWM.NO_WM || XWM.isNonReparentingWM()) { 764 // Location, Client size + insets 765 newLocation = new Point(scaleDown(xe.get_x()) - leftInset, 766 scaleDown(xe.get_y()) - topInset); 767 } else { 768 // ICCCM 4.1.5 states that a real ConfigureNotify will be sent when 769 // a window is resized but the client can not tell if the window was 770 // moved or not. The client should consider the position as unkown 771 // and use TranslateCoordinates to find the actual position. 772 // 773 // TODO this should be the default for every case. 774 switch (runningWM) { 775 case XWM.CDE_WM: 776 case XWM.MOTIF_WM: 777 case XWM.METACITY_WM: 778 case XWM.MUTTER_WM: 779 case XWM.SAWFISH_WM: 780 case XWM.UNITY_COMPIZ_WM: 781 { 782 Point xlocation = queryXLocation(); 783 if (log.isLoggable(PlatformLogger.Level.FINE)) { 784 log.fine("New X location: {0}", xlocation); 785 } 786 if (xlocation != null) { 787 newLocation = xlocation; 788 } 789 break; 790 } 791 default: 792 break; 793 } 794 } 795 return newLocation; 796 } 797 798 /* 799 * Overridden to check if we need to update our GraphicsDevice/Config 800 * Added for 4934052. 801 */ 802 @Override 803 public void handleConfigureNotifyEvent(XEvent xev) { 804 assert (SunToolkit.isAWTLockHeldByCurrentThread()); 805 XConfigureEvent xe = xev.get_xconfigure(); 806 if (insLog.isLoggable(PlatformLogger.Level.FINE)) { 807 insLog.fine(xe.toString()); 808 } 809 checkIfOnNewScreen(toGlobal(new Rectangle(scaleDown(xe.get_x()), 810 scaleDown(xe.get_y()), 811 scaleDown(xe.get_width()), 812 scaleDown(xe.get_height())))); 813 814 Rectangle oldBounds = getBounds(); 815 816 x = scaleDown(xe.get_x()); 817 y = scaleDown(xe.get_y()); 818 width = scaleDown(xe.get_width()); 819 height = scaleDown(xe.get_height()); 820 821 if (!getBounds().getSize().equals(oldBounds.getSize())) { 822 AWTAccessor.getComponentAccessor().setSize(target, width, height); 823 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_RESIZED)); 824 } 825 if (!getBounds().getLocation().equals(oldBounds.getLocation())) { 826 AWTAccessor.getComponentAccessor().setLocation(target, x, y); 827 postEvent(new ComponentEvent(target, ComponentEvent.COMPONENT_MOVED)); 828 } 829 repositionSecurityWarning(); 830 } 831 832 final void requestXFocus(long time) { 833 requestXFocus(time, true); 834 } 835 836 final void requestXFocus() { 837 requestXFocus(0, false); 838 } 839 840 /** 841 * Requests focus to this top-level. Descendants should override to provide 842 * implementations based on a class of top-level. 843 */ 844 protected void requestXFocus(long time, boolean timeProvided) { 845 // Since in XAWT focus is synthetic and all basic Windows are 846 // override_redirect all we can do is check whether our parent 847 // is active. If it is - we can freely synthesize focus transfer. 848 // Luckily, this logic is already implemented in requestWindowFocus. 849 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 850 focusLog.fine("Requesting window focus"); 851 } 852 requestWindowFocus(time, timeProvided); 853 } 854 855 public final boolean focusAllowedFor() { 856 if (isNativelyNonFocusableWindow()) { 857 return false; 858 } 859 /* 860 Window target = (Window)this.target; 861 if (!target.isVisible() || 862 !target.isEnabled() || 863 !target.isFocusable()) 864 { 865 return false; 866 } 867 */ 868 if (isModalBlocked()) { 869 return false; 870 } 871 return true; 872 } 873 874 public void handleFocusEvent(XEvent xev) { 875 XFocusChangeEvent xfe = xev.get_xfocus(); 876 FocusEvent fe; 877 if (focusLog.isLoggable(PlatformLogger.Level.FINE)) { 878 focusLog.fine("{0}", xfe); 879 } 880 if (isEventDisabled(xev)) { 881 return; 882 } 883 if (xev.get_type() == XConstants.FocusIn) 884 { 885 // If this window is non-focusable don't post any java focus event 886 if (focusAllowedFor()) { 887 if (xfe.get_mode() == XConstants.NotifyNormal // Normal notify 888 || xfe.get_mode() == XConstants.NotifyWhileGrabbed) // Alt-Tab notify 889 { 890 handleWindowFocusIn(xfe.get_serial()); 891 } 892 } 893 } 894 else 895 { 896 if (xfe.get_mode() == XConstants.NotifyNormal // Normal notify 897 || xfe.get_mode() == XConstants.NotifyWhileGrabbed) // Alt-Tab notify 898 { 899 // If this window is non-focusable don't post any java focus event 900 if (!isNativelyNonFocusableWindow()) { 901 XWindowPeer oppositeXWindow = getNativeFocusedWindowPeer(); 902 Object oppositeTarget = (oppositeXWindow!=null)? oppositeXWindow.getTarget() : null; 903 Window oppositeWindow = null; 904 if (oppositeTarget instanceof Window) { 905 oppositeWindow = (Window) oppositeTarget; 906 } 907 // Check if opposite window is non-focusable. In that case we don't want to 908 // post any event. 909 if (oppositeXWindow != null && oppositeXWindow.isNativelyNonFocusableWindow()) { 910 return; 911 } 912 if (this == oppositeXWindow) { 913 oppositeWindow = null; 914 } else if (oppositeXWindow instanceof XDecoratedPeer) { 915 if (((XDecoratedPeer) oppositeXWindow).actualFocusedWindow != null) { 916 oppositeXWindow = ((XDecoratedPeer) oppositeXWindow).actualFocusedWindow; 917 oppositeTarget = oppositeXWindow.getTarget(); 918 if (oppositeTarget instanceof Window 919 && oppositeXWindow.isVisible() 920 && oppositeXWindow.isNativelyNonFocusableWindow()) 921 { 922 oppositeWindow = ((Window) oppositeTarget); 923 } 924 } 925 } 926 handleWindowFocusOut(oppositeWindow, xfe.get_serial()); 927 } 928 } 929 } 930 } 931 932 void setSaveUnder(boolean state) {} 933 934 public void toFront() { 935 if (isOverrideRedirect() && mustControlStackPosition) { 936 mustControlStackPosition = false; 937 removeRootPropertyEventDispatcher(); 938 } 939 if (isVisible()) { 940 super.toFront(); 941 if (isFocusableWindow() && isAutoRequestFocus() && 942 !isModalBlocked() && !isWithdrawn()) 943 { 944 requestInitialFocus(); 945 } 946 } else { 947 setVisible(true); 948 } 949 } 950 951 public void toBack() { 952 XToolkit.awtLock(); 953 try { 954 if(!isOverrideRedirect()) { 955 XlibWrapper.XLowerWindow(XToolkit.getDisplay(), getWindow()); 956 }else{ 957 lowerOverrideRedirect(); 958 } 959 } 960 finally { 961 XToolkit.awtUnlock(); 962 } 963 } 964 private void lowerOverrideRedirect() { 965 // 966 // make new hash of toplevels of all windows from 'windows' hash. 967 // FIXME: do not call them "toplevel" as it is misleading. 968 // 969 HashSet<Long> toplevels = new HashSet<>(); 970 long topl = 0, mytopl = 0; 971 972 for (XWindowPeer xp : windows) { 973 topl = getToplevelWindow( xp.getWindow() ); 974 if( xp.equals( this ) ) { 975 mytopl = topl; 976 } 977 if( topl > 0 ) 978 toplevels.add( Long.valueOf( topl ) ); 979 } 980 981 // 982 // find in the root's tree: 983 // (1) my toplevel, (2) lowest java toplevel, (3) desktop 984 // We must enforce (3), (1), (2) order, upward; 985 // note that nautilus on the next restacking will do (1),(3),(2). 986 // 987 long laux, wDesktop = -1, wBottom = -1; 988 int iMy = -1, iDesktop = -1, iBottom = -1; 989 int i = 0; 990 XQueryTree xqt = new XQueryTree(XToolkit.getDefaultRootWindow()); 991 try { 992 if( xqt.execute() > 0 ) { 993 int nchildren = xqt.get_nchildren(); 994 long children = xqt.get_children(); 995 for(i = 0; i < nchildren; i++) { 996 laux = Native.getWindow(children, i); 997 if( laux == mytopl ) { 998 iMy = i; 999 }else if( isDesktopWindow( laux ) ) { 1000 // we need topmost desktop of them all. 1001 iDesktop = i; 1002 wDesktop = laux; 1003 }else if(iBottom < 0 && 1004 toplevels.contains( Long.valueOf(laux) ) && 1005 laux != mytopl) { 1006 iBottom = i; 1007 wBottom = laux; 1008 } 1009 } 1010 } 1011 1012 if( (iMy < iBottom || iBottom < 0 )&& iDesktop < iMy) 1013 return; // no action necessary 1014 1015 long to_restack = Native.allocateLongArray(2); 1016 Native.putLong(to_restack, 0, wBottom); 1017 Native.putLong(to_restack, 1, mytopl); 1018 XlibWrapper.XRestackWindows(XToolkit.getDisplay(), to_restack, 2); 1019 XlibWrapper.unsafe.freeMemory(to_restack); 1020 1021 1022 if( !mustControlStackPosition ) { 1023 mustControlStackPosition = true; 1024 // add root window property listener: 1025 // somebody (eg nautilus desktop) may obscure us 1026 addRootPropertyEventDispatcher(); 1027 } 1028 } finally { 1029 xqt.dispose(); 1030 } 1031 } 1032 /** 1033 Get XID of closest to root window in a given window hierarchy. 1034 FIXME: do not call it "toplevel" as it is misleading. 1035 On error return 0. 1036 */ 1037 private long getToplevelWindow( long w ) { 1038 long wi = w, ret, root; 1039 do { 1040 ret = wi; 1041 XQueryTree qt = new XQueryTree(wi); 1042 try { 1043 if (qt.execute() == 0) { 1044 return 0; 1045 } 1046 root = qt.get_root(); 1047 wi = qt.get_parent(); 1048 } finally { 1049 qt.dispose(); 1050 } 1051 1052 } while (wi != root); 1053 1054 return ret; 1055 } 1056 1057 private static boolean isDesktopWindow( long wi ) { 1058 return XWM.getWM().isDesktopWindow( wi ); 1059 } 1060 1061 private void updateAlwaysOnTop() { 1062 if (log.isLoggable(PlatformLogger.Level.FINE)) { 1063 log.fine("Promoting always-on-top state {0}", Boolean.valueOf(alwaysOnTop)); 1064 } 1065 XWM.getWM().setLayer(this, 1066 alwaysOnTop ? 1067 XLayerProtocol.LAYER_ALWAYS_ON_TOP : 1068 XLayerProtocol.LAYER_NORMAL); 1069 } 1070 1071 public void updateAlwaysOnTopState() { 1072 this.alwaysOnTop = ((Window) this.target).isAlwaysOnTop(); 1073 if (ownerPeer != null) { 1074 XToolkit.awtLock(); 1075 try { 1076 restoreTransientFor(this); 1077 applyWindowType(); 1078 } 1079 finally { 1080 XToolkit.awtUnlock(); 1081 } 1082 } 1083 updateAlwaysOnTop(); 1084 } 1085 1086 boolean isLocationByPlatform() { 1087 return locationByPlatform; 1088 } 1089 1090 private void promoteDefaultPosition() { 1091 this.locationByPlatform = ((Window)target).isLocationByPlatform(); 1092 if (locationByPlatform) { 1093 XToolkit.awtLock(); 1094 try { 1095 Rectangle bounds = getBounds(); 1096 XSizeHints hints = getHints(); 1097 setSizeHints(hints.get_flags() & ~(XUtilConstants.USPosition | XUtilConstants.PPosition), 1098 bounds.x, bounds.y, bounds.width, bounds.height); 1099 } finally { 1100 XToolkit.awtUnlock(); 1101 } 1102 } 1103 } 1104 1105 public void setVisible(boolean vis) { 1106 if (!isVisible() && vis) { 1107 isBeforeFirstMapNotify = true; 1108 winAttr.initialFocus = isAutoRequestFocus(); 1109 if (!winAttr.initialFocus) { 1110 /* 1111 * It's easier and safer to temporary suppress WM_TAKE_FOCUS 1112 * protocol itself than to ignore WM_TAKE_FOCUS client message. 1113 * Because we will have to make the difference between 1114 * the message come after showing and the message come after 1115 * activation. Also, on Metacity, for some reason, we have _two_ 1116 * WM_TAKE_FOCUS client messages when showing a frame/dialog. 1117 */ 1118 suppressWmTakeFocus(true); 1119 } 1120 } 1121 updateFocusability(); 1122 promoteDefaultPosition(); 1123 if (!vis && warningWindow != null) { 1124 warningWindow.setSecurityWarningVisible(false, false); 1125 } 1126 boolean refreshChildsTransientFor = isVisible() != vis; 1127 super.setVisible(vis); 1128 if (refreshChildsTransientFor) { 1129 for (Window child : ((Window) target).getOwnedWindows()) { 1130 XToolkit.awtLock(); 1131 try { 1132 if(!child.isLightweight() && child.isVisible()) { 1133 ComponentPeer childPeer = AWTAccessor. 1134 getComponentAccessor().getPeer(child); 1135 if(childPeer instanceof XWindowPeer) { 1136 XWindowPeer windowPeer = (XWindowPeer) childPeer; 1137 restoreTransientFor(windowPeer); 1138 windowPeer.applyWindowType(); 1139 } 1140 } 1141 } 1142 finally { 1143 XToolkit.awtUnlock(); 1144 } 1145 } 1146 } 1147 if (!vis && !isWithdrawn()) { 1148 // ICCCM, 4.1.4. Changing Window State: 1149 // "Iconic -> Withdrawn - The client should unmap the window and follow it 1150 // with a synthetic UnmapNotify event as described later in this section." 1151 // The same is true for Normal -> Withdrawn 1152 XToolkit.awtLock(); 1153 try { 1154 XUnmapEvent unmap = new XUnmapEvent(); 1155 unmap.set_window(window); 1156 unmap.set_event(XToolkit.getDefaultRootWindow()); 1157 unmap.set_type(XConstants.UnmapNotify); 1158 unmap.set_from_configure(false); 1159 XlibWrapper.XSendEvent(XToolkit.getDisplay(), XToolkit.getDefaultRootWindow(), 1160 false, XConstants.SubstructureNotifyMask | XConstants.SubstructureRedirectMask, 1161 unmap.pData); 1162 unmap.dispose(); 1163 } 1164 finally { 1165 XToolkit.awtUnlock(); 1166 } 1167 } 1168 // method called somewhere in parent does not generate configure-notify 1169 // event for override-redirect. 1170 // Ergo, no reshape and bugs like 5085647 in case setBounds was 1171 // called before setVisible. 1172 if (isOverrideRedirect() && vis) { 1173 updateChildrenSizes(); 1174 } 1175 repositionSecurityWarning(); 1176 } 1177 1178 protected void suppressWmTakeFocus(boolean doSuppress) { 1179 } 1180 1181 final boolean isSimpleWindow() { 1182 return !(target instanceof Frame || target instanceof Dialog); 1183 } 1184 boolean hasWarningWindow() { 1185 return ((Window)target).getWarningString() != null; 1186 } 1187 1188 // The height of menu bar window 1189 int getMenuBarHeight() { 1190 return 0; 1191 } 1192 1193 // Called when shell changes its size and requires children windows 1194 // to update their sizes appropriately 1195 void updateChildrenSizes() { 1196 } 1197 1198 public void repositionSecurityWarning() { 1199 // NOTE: On KWin if the window/border snapping option is enabled, 1200 // the Java window may be swinging while it's being moved. 1201 // This doesn't make the application unusable though looks quite ugly. 1202 // Probobly we need to find some hint to assign to our Security 1203 // Warning window in order to exclude it from the snapping option. 1204 // We are not currently aware of existance of such a property. 1205 if (warningWindow != null) { 1206 // We can't use the coordinates stored in the XBaseWindow since 1207 // they are zeros for decorated frames. 1208 ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 1209 int x = compAccessor.getX(target); 1210 int y = compAccessor.getY(target); 1211 int width = compAccessor.getWidth(target); 1212 int height = compAccessor.getHeight(target); 1213 warningWindow.reposition(x, y, width, height); 1214 } 1215 } 1216 1217 @Override 1218 protected void setMouseAbove(boolean above) { 1219 super.setMouseAbove(above); 1220 updateSecurityWarningVisibility(); 1221 } 1222 1223 @Override 1224 public void setFullScreenExclusiveModeState(boolean state) { 1225 super.setFullScreenExclusiveModeState(state); 1226 updateSecurityWarningVisibility(); 1227 } 1228 1229 public void updateSecurityWarningVisibility() { 1230 if (warningWindow == null) { 1231 return; 1232 } 1233 1234 if (!isVisible()) { 1235 return; // The warning window should already be hidden. 1236 } 1237 1238 boolean show = false; 1239 1240 if (!isFullScreenExclusiveMode()) { 1241 int state = getWMState(); 1242 1243 // getWMState() always returns 0 (Withdrawn) for simple windows. Hence 1244 // we ignore the state for such windows. 1245 if (isVisible() && (state == XUtilConstants.NormalState || isSimpleWindow())) { 1246 if (XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow() == 1247 getTarget()) 1248 { 1249 show = true; 1250 } 1251 1252 if (isMouseAbove() || warningWindow.isMouseAbove()) 1253 { 1254 show = true; 1255 } 1256 } 1257 } 1258 1259 warningWindow.setSecurityWarningVisible(show, true); 1260 } 1261 1262 boolean isOverrideRedirect() { 1263 return XWM.getWMID() == XWM.OPENLOOK_WM || 1264 Window.Type.POPUP.equals(getWindowType()); 1265 } 1266 1267 final boolean isOLWMDecorBug() { 1268 return XWM.getWMID() == XWM.OPENLOOK_WM && 1269 winAttr.nativeDecor == false; 1270 } 1271 1272 public void dispose() { 1273 if (isGrabbed()) { 1274 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 1275 grabLog.fine("Generating UngrabEvent on {0} because of the window disposal", this); 1276 } 1277 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 1278 } 1279 1280 SunToolkit.awtLock(); 1281 1282 try { 1283 windows.remove(this); 1284 } finally { 1285 SunToolkit.awtUnlock(); 1286 } 1287 1288 if (warningWindow != null) { 1289 warningWindow.destroy(); 1290 } 1291 1292 removeRootPropertyEventDispatcher(); 1293 mustControlStackPosition = false; 1294 super.dispose(); 1295 1296 /* 1297 * Fix for 6457980. 1298 * When disposing an owned Window we should implicitly 1299 * return focus to its decorated owner because it won't 1300 * receive WM_TAKE_FOCUS. 1301 */ 1302 if (isSimpleWindow()) { 1303 if (target == XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow()) { 1304 Window owner = getDecoratedOwner((Window)target); 1305 ((XWindowPeer)AWTAccessor.getComponentAccessor().getPeer(owner)).requestWindowFocus(); 1306 } 1307 } 1308 } 1309 1310 boolean isResizable() { 1311 return winAttr.isResizable; 1312 } 1313 1314 public void handleVisibilityEvent(XEvent xev) { 1315 super.handleVisibilityEvent(xev); 1316 XVisibilityEvent ve = xev.get_xvisibility(); 1317 winAttr.visibilityState = ve.get_state(); 1318 // if (ve.get_state() == XlibWrapper.VisibilityUnobscured) { 1319 // // raiseInputMethodWindow 1320 // } 1321 repositionSecurityWarning(); 1322 } 1323 1324 void handleRootPropertyNotify(XEvent xev) { 1325 XPropertyEvent ev = xev.get_xproperty(); 1326 if( mustControlStackPosition && 1327 ev.get_atom() == XAtom.get("_NET_CLIENT_LIST_STACKING").getAtom()){ 1328 // Restore stack order unhadled/spoiled by WM or some app (nautilus). 1329 // As of now, don't use any generic machinery: just 1330 // do toBack() again. 1331 if(isOverrideRedirect()) { 1332 toBack(); 1333 } 1334 } 1335 } 1336 1337 private void removeStartupNotification() { 1338 if (isStartupNotificationRemoved.getAndSet(true)) { 1339 return; 1340 } 1341 1342 final String desktopStartupId = AccessController.doPrivileged(new PrivilegedAction<String>() { 1343 public String run() { 1344 return XToolkit.getEnv("DESKTOP_STARTUP_ID"); 1345 } 1346 }); 1347 if (desktopStartupId == null) { 1348 return; 1349 } 1350 1351 final StringBuilder messageBuilder = new StringBuilder("remove: ID="); 1352 messageBuilder.append('"'); 1353 for (int i = 0; i < desktopStartupId.length(); i++) { 1354 if (desktopStartupId.charAt(i) == '"' || desktopStartupId.charAt(i) == '\\') { 1355 messageBuilder.append('\\'); 1356 } 1357 messageBuilder.append(desktopStartupId.charAt(i)); 1358 } 1359 messageBuilder.append('"'); 1360 messageBuilder.append('\0'); 1361 final byte[] message; 1362 try { 1363 message = messageBuilder.toString().getBytes("UTF-8"); 1364 } catch (UnsupportedEncodingException cannotHappen) { 1365 return; 1366 } 1367 1368 XClientMessageEvent req = null; 1369 1370 XToolkit.awtLock(); 1371 try { 1372 final XAtom netStartupInfoBeginAtom = XAtom.get("_NET_STARTUP_INFO_BEGIN"); 1373 final XAtom netStartupInfoAtom = XAtom.get("_NET_STARTUP_INFO"); 1374 1375 req = new XClientMessageEvent(); 1376 req.set_type(XConstants.ClientMessage); 1377 req.set_window(getWindow()); 1378 req.set_message_type(netStartupInfoBeginAtom.getAtom()); 1379 req.set_format(8); 1380 1381 for (int pos = 0; pos < message.length; pos += 20) { 1382 final int msglen = Math.min(message.length - pos, 20); 1383 int i = 0; 1384 for (; i < msglen; i++) { 1385 XlibWrapper.unsafe.putByte(req.get_data() + i, message[pos + i]); 1386 } 1387 for (; i < 20; i++) { 1388 XlibWrapper.unsafe.putByte(req.get_data() + i, (byte)0); 1389 } 1390 XlibWrapper.XSendEvent(XToolkit.getDisplay(), 1391 XlibWrapper.RootWindow(XToolkit.getDisplay(), getScreenNumber()), 1392 false, 1393 XConstants.PropertyChangeMask, 1394 req.pData); 1395 req.set_message_type(netStartupInfoAtom.getAtom()); 1396 } 1397 } finally { 1398 XToolkit.awtUnlock(); 1399 if (req != null) { 1400 req.dispose(); 1401 } 1402 } 1403 } 1404 1405 public void handleMapNotifyEvent(XEvent xev) { 1406 removeStartupNotification(); 1407 1408 // See 6480534. 1409 isUnhiding |= isWMStateNetHidden(); 1410 1411 super.handleMapNotifyEvent(xev); 1412 if (!winAttr.initialFocus) { 1413 suppressWmTakeFocus(false); // restore the protocol. 1414 /* 1415 * For some reason, on Metacity, a frame/dialog being shown 1416 * without WM_TAKE_FOCUS protocol doesn't get moved to the front. 1417 * So, we do it evidently. 1418 */ 1419 XToolkit.awtLock(); 1420 try { 1421 XlibWrapper.XRaiseWindow(XToolkit.getDisplay(), getWindow()); 1422 } finally { 1423 XToolkit.awtUnlock(); 1424 } 1425 } 1426 if (shouldFocusOnMapNotify()) { 1427 focusLog.fine("Automatically request focus on window"); 1428 requestInitialFocus(); 1429 } 1430 isUnhiding = false; 1431 isBeforeFirstMapNotify = false; 1432 updateAlwaysOnTop(); 1433 1434 synchronized (getStateLock()) { 1435 if (!isMapped) { 1436 isMapped = true; 1437 } 1438 } 1439 } 1440 1441 public void handleUnmapNotifyEvent(XEvent xev) { 1442 super.handleUnmapNotifyEvent(xev); 1443 1444 // On Metacity UnmapNotify comes before PropertyNotify (for _NET_WM_STATE_HIDDEN). 1445 // So we also check for the property later in MapNotify. See 6480534. 1446 isUnhiding |= isWMStateNetHidden(); 1447 1448 synchronized (getStateLock()) { 1449 if (isMapped) { 1450 isMapped = false; 1451 } 1452 } 1453 } 1454 1455 private boolean shouldFocusOnMapNotify() { 1456 boolean res = false; 1457 1458 if (isBeforeFirstMapNotify) { 1459 res = (winAttr.initialFocus || // Window.autoRequestFocus 1460 isFocusedWindowModalBlocker()); 1461 } else { 1462 res = isUnhiding; // Unhiding 1463 } 1464 res = res && 1465 isFocusableWindow() && // General focusability 1466 !isModalBlocked(); // Modality 1467 1468 return res; 1469 } 1470 1471 protected boolean isWMStateNetHidden() { 1472 XNETProtocol protocol = XWM.getWM().getNETProtocol(); 1473 return (protocol != null && protocol.isWMStateNetHidden(this)); 1474 } 1475 1476 protected void requestInitialFocus() { 1477 requestXFocus(); 1478 } 1479 1480 public void addToplevelStateListener(ToplevelStateListener l){ 1481 toplevelStateListeners.add(l); 1482 } 1483 1484 public void removeToplevelStateListener(ToplevelStateListener l){ 1485 toplevelStateListeners.remove(l); 1486 } 1487 1488 /** 1489 * Override this methods to get notifications when top-level window state changes. The state is 1490 * meant in terms of ICCCM: WithdrawnState, IconicState, NormalState 1491 */ 1492 @Override 1493 protected void stateChanged(long time, int oldState, int newState) { 1494 // Fix for 6401700, 6412803 1495 // If this window is modal blocked, it is put into the transient_for 1496 // chain using prevTransientFor and nextTransientFor hints. However, 1497 // the real WM_TRANSIENT_FOR hint shouldn't be set for windows in 1498 // different WM states (except for owner-window relationship), so 1499 // if the window changes its state, its real WM_TRANSIENT_FOR hint 1500 // should be updated accordingly. 1501 updateTransientFor(); 1502 1503 for (ToplevelStateListener topLevelListenerTmp : toplevelStateListeners) { 1504 topLevelListenerTmp.stateChangedICCCM(oldState, newState); 1505 } 1506 1507 updateSecurityWarningVisibility(); 1508 } 1509 1510 boolean isWithdrawn() { 1511 return getWMState() == XUtilConstants.WithdrawnState; 1512 } 1513 1514 boolean hasDecorations(int decor) { 1515 if (!winAttr.nativeDecor) { 1516 return false; 1517 } 1518 else { 1519 int myDecor = winAttr.decorations; 1520 boolean hasBits = ((myDecor & decor) == decor); 1521 if ((myDecor & XWindowAttributesData.AWT_DECOR_ALL) != 0) 1522 return !hasBits; 1523 else 1524 return hasBits; 1525 } 1526 } 1527 1528 void setReparented(boolean newValue) { 1529 super.setReparented(newValue); 1530 XToolkit.awtLock(); 1531 try { 1532 if (isReparented() && delayedModalBlocking) { 1533 addToTransientFors(AWTAccessor.getComponentAccessor().getPeer(modalBlocker)); 1534 delayedModalBlocking = false; 1535 } 1536 } finally { 1537 XToolkit.awtUnlock(); 1538 } 1539 } 1540 1541 /* 1542 * Returns a Vector of all Java top-level windows, 1543 * sorted by their current Z-order 1544 */ 1545 static Vector<XWindowPeer> collectJavaToplevels() { 1546 Vector<XWindowPeer> javaToplevels = new Vector<XWindowPeer>(); 1547 Vector<Long> v = new Vector<Long>(); 1548 X11GraphicsEnvironment ge = 1549 (X11GraphicsEnvironment)GraphicsEnvironment.getLocalGraphicsEnvironment(); 1550 GraphicsDevice[] gds = ge.getScreenDevices(); 1551 if (!ge.runningXinerama() && (gds.length > 1)) { 1552 for (GraphicsDevice gd : gds) { 1553 int screen = ((X11GraphicsDevice)gd).getScreen(); 1554 long rootWindow = XlibWrapper.RootWindow(XToolkit.getDisplay(), screen); 1555 v.add(rootWindow); 1556 } 1557 } else { 1558 v.add(XToolkit.getDefaultRootWindow()); 1559 } 1560 final int windowsCount = windows.size(); 1561 while ((v.size() > 0) && (javaToplevels.size() < windowsCount)) { 1562 long win = v.remove(0); 1563 XQueryTree qt = new XQueryTree(win); 1564 try { 1565 if (qt.execute() != 0) { 1566 int nchildren = qt.get_nchildren(); 1567 long children = qt.get_children(); 1568 // XQueryTree returns window children ordered by z-order 1569 for (int i = 0; i < nchildren; i++) { 1570 long child = Native.getWindow(children, i); 1571 XBaseWindow childWindow = XToolkit.windowToXWindow(child); 1572 // filter out Java non-toplevels 1573 if ((childWindow != null) && !(childWindow instanceof XWindowPeer)) { 1574 continue; 1575 } else { 1576 v.add(child); 1577 } 1578 if (childWindow instanceof XWindowPeer) { 1579 XWindowPeer np = (XWindowPeer)childWindow; 1580 javaToplevels.add(np); 1581 // XQueryTree returns windows sorted by their z-order. However, 1582 // if WM has not handled transient for hint for a child window, 1583 // it may appear in javaToplevels before its owner. Move such 1584 // children after their owners. 1585 int k = 0; 1586 XWindowPeer toCheck = javaToplevels.get(k); 1587 while (toCheck != np) { 1588 XWindowPeer toCheckOwnerPeer = toCheck.getOwnerPeer(); 1589 if (toCheckOwnerPeer == np) { 1590 javaToplevels.remove(k); 1591 javaToplevels.add(toCheck); 1592 } else { 1593 k++; 1594 } 1595 toCheck = javaToplevels.get(k); 1596 } 1597 } 1598 } 1599 } 1600 } finally { 1601 qt.dispose(); 1602 } 1603 } 1604 return javaToplevels; 1605 } 1606 1607 public void setModalBlocked(Dialog d, boolean blocked) { 1608 setModalBlocked(d, blocked, null); 1609 } 1610 public void setModalBlocked(Dialog d, boolean blocked, 1611 Vector<XWindowPeer> javaToplevels) 1612 { 1613 XToolkit.awtLock(); 1614 try { 1615 // State lock should always be after awtLock 1616 synchronized(getStateLock()) { 1617 XDialogPeer blockerPeer = AWTAccessor.getComponentAccessor().getPeer(d); 1618 if (blocked) { 1619 if (log.isLoggable(PlatformLogger.Level.FINE)) { 1620 log.fine("{0} is blocked by {1}", this, blockerPeer); 1621 } 1622 modalBlocker = d; 1623 1624 if (isReparented() || XWM.isNonReparentingWM()) { 1625 addToTransientFors(blockerPeer, javaToplevels); 1626 } else { 1627 delayedModalBlocking = true; 1628 } 1629 } else { 1630 if (d != modalBlocker) { 1631 throw new IllegalStateException("Trying to unblock window blocked by another dialog"); 1632 } 1633 modalBlocker = null; 1634 1635 if (isReparented() || XWM.isNonReparentingWM()) { 1636 removeFromTransientFors(); 1637 } else { 1638 delayedModalBlocking = false; 1639 } 1640 } 1641 1642 updateTransientFor(); 1643 } 1644 } finally { 1645 XToolkit.awtUnlock(); 1646 } 1647 } 1648 1649 /* 1650 * Sets the TRANSIENT_FOR hint to the given top-level window. This 1651 * method is used when a window is modal blocked/unblocked or 1652 * changed its state from/to NormalState to/from other states. 1653 * If window or transientForWindow are embedded frames, the containing 1654 * top-level windows are used. 1655 * 1656 * @param window specifies the top-level window that the hint 1657 * is to be set to 1658 * @param transientForWindow the top-level window 1659 * @param updateChain specifies if next/prevTransientFor fields are 1660 * to be updated 1661 * @param allStates if set to {@code true} then TRANSIENT_FOR hint 1662 * is set regardless of the state of window and transientForWindow, 1663 * otherwise it is set only if both are in the same state 1664 */ 1665 static void setToplevelTransientFor(XWindowPeer window, XWindowPeer transientForWindow, 1666 boolean updateChain, boolean allStates) 1667 { 1668 if ((window == null) || (transientForWindow == null)) { 1669 return; 1670 } 1671 if (updateChain) { 1672 window.prevTransientFor = transientForWindow; 1673 transientForWindow.nextTransientFor = window; 1674 } 1675 if (!allStates && (window.getWMState() != transientForWindow.getWMState())) { 1676 return; 1677 } 1678 if (window.getScreenNumber() != transientForWindow.getScreenNumber()) { 1679 return; 1680 } 1681 long bpw = window.getWindow(); 1682 while (!XlibUtil.isToplevelWindow(bpw) && !XlibUtil.isXAWTToplevelWindow(bpw)) { 1683 bpw = XlibUtil.getParentWindow(bpw); 1684 } 1685 long tpw = transientForWindow.getWindow(); 1686 XBaseWindow parent = transientForWindow; 1687 while (tpw != 0 && ((!XlibUtil.isToplevelWindow(tpw) && 1688 !XlibUtil.isXAWTToplevelWindow(tpw)) || !parent.isVisible())) { 1689 tpw = XlibUtil.getParentWindow(tpw); 1690 parent = XToolkit.windowToXWindow(tpw); 1691 } 1692 1693 if (parent instanceof XLightweightFramePeer) { 1694 XLightweightFramePeer peer = (XLightweightFramePeer) parent; 1695 long ownerWindowPtr = peer.getOverridenWindowHandle(); 1696 if (ownerWindowPtr != 0) { 1697 tpw = ownerWindowPtr; 1698 } 1699 } 1700 XlibWrapper.XSetTransientFor(XToolkit.getDisplay(), bpw, tpw); 1701 window.curRealTransientFor = parent; 1702 } 1703 1704 /* 1705 * This method does nothing if this window is not blocked by any modal dialog. 1706 * For modal blocked windows this method looks up for the nearest 1707 * prevTransiendFor window that is in the same state (Normal/Iconified/Withdrawn) 1708 * as this one and makes this window transient for it. The same operation is 1709 * performed for nextTransientFor window. 1710 * Values of prevTransientFor and nextTransientFor fields are not changed. 1711 */ 1712 void updateTransientFor() { 1713 int state = getWMState(); 1714 XWindowPeer p = prevTransientFor; 1715 while ((p != null) && ((p.getWMState() != state) || (p.getScreenNumber() != getScreenNumber()))) { 1716 p = p.prevTransientFor; 1717 } 1718 if (p != null) { 1719 setToplevelTransientFor(this, p, false, false); 1720 } else { 1721 restoreTransientFor(this); 1722 } 1723 XWindowPeer n = nextTransientFor; 1724 while ((n != null) && ((n.getWMState() != state) || (n.getScreenNumber() != getScreenNumber()))) { 1725 n = n.nextTransientFor; 1726 } 1727 if (n != null) { 1728 setToplevelTransientFor(n, this, false, false); 1729 } 1730 } 1731 1732 /* 1733 * Removes the TRANSIENT_FOR hint from the given top-level window. 1734 * If window or transientForWindow are embedded frames, the containing 1735 * top-level windows are used. 1736 * 1737 * @param window specifies the top-level window that the hint 1738 * is to be removed from 1739 */ 1740 private static void removeTransientForHint(XWindowPeer window) { 1741 XAtom XA_WM_TRANSIENT_FOR = XAtom.get(XAtom.XA_WM_TRANSIENT_FOR); 1742 long bpw = window.getWindow(); 1743 while (!XlibUtil.isToplevelWindow(bpw) && !XlibUtil.isXAWTToplevelWindow(bpw)) { 1744 bpw = XlibUtil.getParentWindow(bpw); 1745 } 1746 XlibWrapper.XDeleteProperty(XToolkit.getDisplay(), bpw, XA_WM_TRANSIENT_FOR.getAtom()); 1747 window.curRealTransientFor = null; 1748 } 1749 1750 /* 1751 * When a modal dialog is shown, all its blocked windows are lined up into 1752 * a chain in such a way that each window is a transient_for window for 1753 * the next one. That allows us to keep the modal dialog above all its 1754 * blocked windows (even if there are some another modal dialogs between 1755 * them). 1756 * This method adds this top-level window to the chain of the given modal 1757 * dialog. To keep the current relative z-order, we should use the 1758 * XQueryTree to find the place to insert this window to. As each window 1759 * can be blocked by only one modal dialog (such checks are performed in 1760 * shared code), both this and blockerPeer are on the top of their chains 1761 * (chains may be empty). 1762 * If this window is a modal dialog and has its own chain, these chains are 1763 * merged according to the current z-order (XQueryTree is used again). 1764 * Below are some simple examples (z-order is from left to right, -- is 1765 * modal blocking). 1766 * 1767 * Example 0: 1768 * T (current chain of this, no windows are blocked by this) 1769 * W1---B (current chain of blockerPeer, W2 is blocked by blockerPeer) 1770 * Result is: 1771 * W1-T-B (merged chain, all the windows are blocked by blockerPeer) 1772 * 1773 * Example 1: 1774 * W1-T (current chain of this, W1 is blocked by this) 1775 * W2-B (current chain of blockerPeer, W2 is blocked by blockerPeer) 1776 * Result is: 1777 * W1-T-W2-B (merged chain, all the windows are blocked by blockerPeer) 1778 * 1779 * Example 2: 1780 * W1----T (current chain of this, W1 is blocked by this) 1781 * W2---B (current chain of blockerPeer, W2 is blocked by blockerPeer) 1782 * Result is: 1783 * W1-W2-T-B (merged chain, all the windows are blocked by blockerPeer) 1784 * 1785 * This method should be called under the AWT lock. 1786 * 1787 * @see #removeFromTransientFors 1788 * @see #setModalBlocked 1789 */ 1790 private void addToTransientFors(XDialogPeer blockerPeer) { 1791 addToTransientFors(blockerPeer, null); 1792 } 1793 1794 private void addToTransientFors(XDialogPeer blockerPeer, Vector<XWindowPeer> javaToplevels) 1795 { 1796 // blockerPeer chain iterator 1797 XWindowPeer blockerChain = blockerPeer; 1798 while (blockerChain.prevTransientFor != null) { 1799 blockerChain = blockerChain.prevTransientFor; 1800 } 1801 // this window chain iterator 1802 // each window can be blocked no more than once, so this window 1803 // is on top of its chain 1804 XWindowPeer thisChain = this; 1805 while (thisChain.prevTransientFor != null) { 1806 thisChain = thisChain.prevTransientFor; 1807 } 1808 // if there are no windows blocked by modalBlocker, simply add this window 1809 // and its chain to blocker's chain 1810 if (blockerChain == blockerPeer) { 1811 setToplevelTransientFor(blockerPeer, this, true, false); 1812 } else { 1813 // Collect all the Java top-levels, if required 1814 if (javaToplevels == null) { 1815 javaToplevels = collectJavaToplevels(); 1816 } 1817 // merged chain tail 1818 XWindowPeer mergedChain = null; 1819 for (XWindowPeer w : javaToplevels) { 1820 XWindowPeer prevMergedChain = mergedChain; 1821 if (w == thisChain) { 1822 if (thisChain == this) { 1823 if (prevMergedChain != null) { 1824 setToplevelTransientFor(this, prevMergedChain, true, false); 1825 } 1826 setToplevelTransientFor(blockerChain, this, true, false); 1827 break; 1828 } else { 1829 mergedChain = thisChain; 1830 thisChain = thisChain.nextTransientFor; 1831 } 1832 } else if (w == blockerChain) { 1833 mergedChain = blockerChain; 1834 blockerChain = blockerChain.nextTransientFor; 1835 } else { 1836 continue; 1837 } 1838 if (prevMergedChain == null) { 1839 mergedChain.prevTransientFor = null; 1840 } else { 1841 setToplevelTransientFor(mergedChain, prevMergedChain, true, false); 1842 mergedChain.updateTransientFor(); 1843 } 1844 if (blockerChain == blockerPeer) { 1845 setToplevelTransientFor(thisChain, mergedChain, true, false); 1846 setToplevelTransientFor(blockerChain, this, true, false); 1847 break; 1848 } 1849 } 1850 } 1851 1852 XToolkit.XSync(); 1853 } 1854 1855 static void restoreTransientFor(XWindowPeer window) { 1856 XWindowPeer ownerPeer = window.getOwnerPeer(); 1857 if (ownerPeer != null) { 1858 setToplevelTransientFor(window, ownerPeer, false, true); 1859 } else { 1860 removeTransientForHint(window); 1861 } 1862 } 1863 1864 /* 1865 * When a window is modally unblocked, it should be removed from its blocker 1866 * chain, see {@link #addToTransientFor addToTransientFors} method for the 1867 * chain definition. 1868 * The problem is that we cannot simply restore window's original 1869 * TRANSIENT_FOR hint (if any) and link prevTransientFor and 1870 * nextTransientFor together as the whole chain could be created as a merge 1871 * of two other chains in addToTransientFors. In that case, if this window is 1872 * a modal dialog, it would lost all its own chain, if we simply exclude it 1873 * from the chain. 1874 * The correct behaviour of this method should be to split the chain, this 1875 * window is currently in, into two chains. First chain is this window own 1876 * chain (i. e. all the windows blocked by this one, directly or indirectly), 1877 * if any, and the rest windows from the current chain. 1878 * 1879 * Example: 1880 * Original state: 1881 * W1-B1 (window W1 is blocked by B1) 1882 * W2-B2 (window W2 is blocked by B2) 1883 * B3 is shown and blocks B1 and B2: 1884 * W1-W2-B1-B2-B3 (a single chain after B1.addToTransientFors() and B2.addToTransientFors()) 1885 * If we then unblock B1, the state should be: 1886 * W1-B1 (window W1 is blocked by B1) 1887 * W2-B2-B3 (window W2 is blocked by B2 and B2 is blocked by B3) 1888 * 1889 * This method should be called under the AWT lock. 1890 * 1891 * @see #addToTransientFors 1892 * @see #setModalBlocked 1893 */ 1894 private void removeFromTransientFors() { 1895 // the head of the chain of this window 1896 XWindowPeer thisChain = this; 1897 // the head of the current chain 1898 // nextTransientFor is always not null as this window is in the chain 1899 XWindowPeer otherChain = nextTransientFor; 1900 // the set of blockers in this chain: if this dialog blocks some other 1901 // modal dialogs, their blocked windows should stay in this dialog's chain 1902 Set<XWindowPeer> thisChainBlockers = new HashSet<XWindowPeer>(); 1903 thisChainBlockers.add(this); 1904 // current chain iterator in the order from next to prev 1905 XWindowPeer chainToSplit = prevTransientFor; 1906 while (chainToSplit != null) { 1907 XWindowPeer blocker = AWTAccessor.getComponentAccessor().getPeer(chainToSplit.modalBlocker); 1908 if (thisChainBlockers.contains(blocker)) { 1909 // add to this dialog's chain 1910 setToplevelTransientFor(thisChain, chainToSplit, true, false); 1911 thisChain = chainToSplit; 1912 thisChainBlockers.add(chainToSplit); 1913 } else { 1914 // leave in the current chain 1915 setToplevelTransientFor(otherChain, chainToSplit, true, false); 1916 otherChain = chainToSplit; 1917 } 1918 chainToSplit = chainToSplit.prevTransientFor; 1919 } 1920 restoreTransientFor(thisChain); 1921 thisChain.prevTransientFor = null; 1922 restoreTransientFor(otherChain); 1923 otherChain.prevTransientFor = null; 1924 nextTransientFor = null; 1925 1926 XToolkit.XSync(); 1927 } 1928 1929 boolean isModalBlocked() { 1930 return modalBlocker != null; 1931 } 1932 1933 static Window getDecoratedOwner(Window window) { 1934 while ((null != window) && !(window instanceof Frame || window instanceof Dialog)) { 1935 window = (Window) AWTAccessor.getComponentAccessor().getParent(window); 1936 } 1937 return window; 1938 } 1939 1940 public boolean requestWindowFocus(XWindowPeer actualFocusedWindow) { 1941 setActualFocusedWindow(actualFocusedWindow); 1942 return requestWindowFocus(); 1943 } 1944 1945 public boolean requestWindowFocus() { 1946 return requestWindowFocus(0, false); 1947 } 1948 1949 public boolean requestWindowFocus(long time, boolean timeProvided) { 1950 focusLog.fine("Request for window focus"); 1951 // If this is Frame or Dialog we can't assure focus request success - but we still can try 1952 // If this is Window and its owner Frame is active we can be sure request succedded. 1953 Window ownerWindow = XWindowPeer.getDecoratedOwner((Window)target); 1954 Window focusedWindow = XKeyboardFocusManagerPeer.getInstance().getCurrentFocusedWindow(); 1955 Window activeWindow = XWindowPeer.getDecoratedOwner(focusedWindow); 1956 1957 if (isWMStateNetHidden()) { 1958 focusLog.fine("The window is unmapped, so rejecting the request"); 1959 return false; 1960 } 1961 if (activeWindow == ownerWindow) { 1962 focusLog.fine("Parent window is active - generating focus for this window"); 1963 handleWindowFocusInSync(-1); 1964 return true; 1965 } 1966 focusLog.fine("Parent window is not active"); 1967 1968 XDecoratedPeer wpeer = AWTAccessor.getComponentAccessor().getPeer(ownerWindow); 1969 if (wpeer != null && wpeer.requestWindowFocus(this, time, timeProvided)) { 1970 focusLog.fine("Parent window accepted focus request - generating focus for this window"); 1971 return true; 1972 } 1973 focusLog.fine("Denied - parent window is not active and didn't accept focus request"); 1974 return false; 1975 } 1976 1977 // This method is to be overriden in XDecoratedPeer. 1978 void setActualFocusedWindow(XWindowPeer actualFocusedWindow) { 1979 } 1980 1981 /** 1982 * Applies the current window type. 1983 */ 1984 private void applyWindowType() { 1985 XNETProtocol protocol = XWM.getWM().getNETProtocol(); 1986 if (protocol == null) { 1987 return; 1988 } 1989 1990 XAtom typeAtom = null; 1991 1992 switch (getWindowType()) 1993 { 1994 case NORMAL: 1995 typeAtom = curRealTransientFor == null ? 1996 protocol.XA_NET_WM_WINDOW_TYPE_NORMAL : 1997 protocol.XA_NET_WM_WINDOW_TYPE_DIALOG; 1998 break; 1999 case UTILITY: 2000 typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_UTILITY; 2001 break; 2002 case POPUP: 2003 typeAtom = protocol.XA_NET_WM_WINDOW_TYPE_POPUP_MENU; 2004 break; 2005 } 2006 2007 if (typeAtom != null) { 2008 XAtomList wtype = new XAtomList(); 2009 wtype.add(typeAtom); 2010 protocol.XA_NET_WM_WINDOW_TYPE. 2011 setAtomListProperty(getWindow(), wtype); 2012 } else { 2013 protocol.XA_NET_WM_WINDOW_TYPE. 2014 DeleteProperty(getWindow()); 2015 } 2016 } 2017 2018 @Override 2019 public void xSetVisible(boolean visible) { 2020 if (log.isLoggable(PlatformLogger.Level.FINE)) { 2021 log.fine("Setting visible on " + this + " to " + visible); 2022 } 2023 XToolkit.awtLock(); 2024 try { 2025 this.visible = visible; 2026 if (visible) { 2027 applyWindowType(); 2028 XlibWrapper.XMapRaised(XToolkit.getDisplay(), getWindow()); 2029 } else { 2030 XlibWrapper.XUnmapWindow(XToolkit.getDisplay(), getWindow()); 2031 } 2032 XlibWrapper.XFlush(XToolkit.getDisplay()); 2033 } 2034 finally { 2035 XToolkit.awtUnlock(); 2036 } 2037 } 2038 2039 // should be synchronized on awtLock 2040 private int dropTargetCount = 0; 2041 2042 public void addDropTarget() { 2043 XToolkit.awtLock(); 2044 try { 2045 if (dropTargetCount == 0) { 2046 long window = getWindow(); 2047 if (window != 0) { 2048 XDropTargetRegistry.getRegistry().registerDropSite(window); 2049 } 2050 } 2051 dropTargetCount++; 2052 } finally { 2053 XToolkit.awtUnlock(); 2054 } 2055 } 2056 2057 public void removeDropTarget() { 2058 XToolkit.awtLock(); 2059 try { 2060 dropTargetCount--; 2061 if (dropTargetCount == 0) { 2062 long window = getWindow(); 2063 if (window != 0) { 2064 XDropTargetRegistry.getRegistry().unregisterDropSite(window); 2065 } 2066 } 2067 } finally { 2068 XToolkit.awtUnlock(); 2069 } 2070 } 2071 void addRootPropertyEventDispatcher() { 2072 if( rootPropertyEventDispatcher == null ) { 2073 rootPropertyEventDispatcher = new XEventDispatcher() { 2074 public void dispatchEvent(XEvent ev) { 2075 if( ev.get_type() == XConstants.PropertyNotify ) { 2076 handleRootPropertyNotify( ev ); 2077 } 2078 } 2079 }; 2080 XlibWrapper.XSelectInput( XToolkit.getDisplay(), 2081 XToolkit.getDefaultRootWindow(), 2082 XConstants.PropertyChangeMask); 2083 XToolkit.addEventDispatcher(XToolkit.getDefaultRootWindow(), 2084 rootPropertyEventDispatcher); 2085 } 2086 } 2087 void removeRootPropertyEventDispatcher() { 2088 if( rootPropertyEventDispatcher != null ) { 2089 XToolkit.removeEventDispatcher(XToolkit.getDefaultRootWindow(), 2090 rootPropertyEventDispatcher); 2091 rootPropertyEventDispatcher = null; 2092 } 2093 } 2094 public void updateFocusableWindowState() { 2095 cachedFocusableWindow = isFocusableWindow(); 2096 } 2097 2098 XAtom XA_NET_WM_STATE; 2099 XAtomList net_wm_state; 2100 public XAtomList getNETWMState() { 2101 if (net_wm_state == null) { 2102 net_wm_state = XA_NET_WM_STATE.getAtomListPropertyList(this); 2103 } 2104 return net_wm_state; 2105 } 2106 2107 public void setNETWMState(XAtomList state) { 2108 net_wm_state = state; 2109 if (state != null) { 2110 XA_NET_WM_STATE.setAtomListProperty(this, state); 2111 } 2112 } 2113 2114 public PropMwmHints getMWMHints() { 2115 if (mwm_hints == null) { 2116 mwm_hints = new PropMwmHints(); 2117 if (!XWM.XA_MWM_HINTS.getAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS)) { 2118 mwm_hints.zero(); 2119 } 2120 } 2121 return mwm_hints; 2122 } 2123 2124 public void setMWMHints(PropMwmHints hints) { 2125 mwm_hints = hints; 2126 if (hints != null) { 2127 XWM.XA_MWM_HINTS.setAtomData(getWindow(), mwm_hints.pData, MWMConstants.PROP_MWM_HINTS_ELEMENTS); 2128 } 2129 } 2130 2131 protected void updateDropTarget() { 2132 XToolkit.awtLock(); 2133 try { 2134 if (dropTargetCount > 0) { 2135 long window = getWindow(); 2136 if (window != 0) { 2137 XDropTargetRegistry.getRegistry().unregisterDropSite(window); 2138 XDropTargetRegistry.getRegistry().registerDropSite(window); 2139 } 2140 } 2141 } finally { 2142 XToolkit.awtUnlock(); 2143 } 2144 } 2145 2146 public void setGrab(boolean grab) { 2147 this.grab = grab; 2148 if (grab) { 2149 pressTarget = this; 2150 grabInput(); 2151 } else { 2152 ungrabInput(); 2153 } 2154 } 2155 2156 public boolean isGrabbed() { 2157 return grab && XAwtState.getGrabWindow() == this; 2158 } 2159 2160 public void handleXCrossingEvent(XEvent xev) { 2161 XCrossingEvent xce = xev.get_xcrossing(); 2162 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2163 grabLog.fine("{0}, when grabbed {1}, contains {2}", 2164 xce, isGrabbed(), 2165 containsGlobal(scaleDown(xce.get_x_root()), 2166 scaleDown(xce.get_y_root()))); 2167 } 2168 if (isGrabbed()) { 2169 // When window is grabbed, all events are dispatched to 2170 // it. Retarget them to the corresponding windows (notice 2171 // that XBaseWindow.dispatchEvent does the opposite 2172 // translation) 2173 // Note that we need to retarget XCrossingEvents to content window 2174 // since it generates MOUSE_ENTERED/MOUSE_EXITED for frame and dialog. 2175 // (fix for 6390326) 2176 XBaseWindow target = XToolkit.windowToXWindow(xce.get_window()); 2177 if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { 2178 grabLog.finer(" - Grab event target {0}", target); 2179 } 2180 if (target != null && target != this) { 2181 target.dispatchEvent(xev); 2182 return; 2183 } 2184 } 2185 super.handleXCrossingEvent(xev); 2186 } 2187 2188 public void handleMotionNotify(XEvent xev) { 2189 XMotionEvent xme = xev.get_xmotion(); 2190 if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { 2191 grabLog.finer("{0}, when grabbed {1}, contains {2}", 2192 xme, isGrabbed(), 2193 containsGlobal(scaleDown(xme.get_x_root()), 2194 scaleDown(xme.get_y_root()))); 2195 } 2196 if (isGrabbed()) { 2197 boolean dragging = false; 2198 final int buttonsNumber = XToolkit.getNumberOfButtonsForMask(); 2199 2200 for (int i = 0; i < buttonsNumber; i++){ 2201 // here is the bug in WM: extra buttons doesn't have state!=0 as they should. 2202 if ((i != 4) && (i != 5)){ 2203 dragging = dragging || ((xme.get_state() & XlibUtil.getButtonMask(i + 1)) != 0); 2204 } 2205 } 2206 // When window is grabbed, all events are dispatched to 2207 // it. Retarget them to the corresponding windows (notice 2208 // that XBaseWindow.dispatchEvent does the opposite 2209 // translation) 2210 XBaseWindow target = XToolkit.windowToXWindow(xme.get_window()); 2211 if (dragging && pressTarget != target) { 2212 // for some reasons if we grab input MotionNotify for drag is reported with target 2213 // to underlying window, not to window on which we have initiated drag 2214 // so we need to retarget them. Here I use simplified logic which retarget all 2215 // such events to source of mouse press (or the grabber). It helps with fix for 6390326. 2216 // So, I do not want to implement complicated logic for better retargeting. 2217 target = pressTarget.isVisible() ? pressTarget : this; 2218 xme.set_window(target.getWindow()); 2219 Point localCoord = target.toLocal(scaleDown(xme.get_x_root()), 2220 scaleDown(xme.get_y_root())); 2221 xme.set_x(scaleUp(localCoord.x)); 2222 xme.set_y(scaleUp(localCoord.y)); 2223 } 2224 if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { 2225 grabLog.finer(" - Grab event target {0}", target); 2226 } 2227 if (target != null) { 2228 if (target != getContentXWindow() && target != this) { 2229 target.dispatchEvent(xev); 2230 return; 2231 } 2232 } 2233 2234 // note that we need to pass dragging events to the grabber (6390326) 2235 // see comment above for more inforamtion. 2236 if (!containsGlobal(scaleDown(xme.get_x_root()), 2237 scaleDown(xme.get_y_root())) 2238 && !dragging) { 2239 // Outside of Java 2240 return; 2241 } 2242 } 2243 super.handleMotionNotify(xev); 2244 } 2245 2246 // we use it to retarget mouse drag and mouse release during grab. 2247 private XBaseWindow pressTarget = this; 2248 2249 public void handleButtonPressRelease(XEvent xev) { 2250 XButtonEvent xbe = xev.get_xbutton(); 2251 /* 2252 * Ignore the buttons above 20 due to the bit limit for 2253 * InputEvent.BUTTON_DOWN_MASK. 2254 * One more bit is reserved for FIRST_HIGH_BIT. 2255 */ 2256 if (xbe.get_button() > SunToolkit.MAX_BUTTONS_SUPPORTED) { 2257 return; 2258 } 2259 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2260 grabLog.fine("{0}, when grabbed {1}, contains {2} ({3}, {4}, {5}x{6})", 2261 xbe, isGrabbed(), 2262 containsGlobal(scaleDown(xbe.get_x_root()), 2263 scaleDown(xbe.get_y_root())), 2264 getAbsoluteX(), getAbsoluteY(), 2265 getWidth(), getHeight()); 2266 } 2267 if (isGrabbed()) { 2268 // When window is grabbed, all events are dispatched to 2269 // it. Retarget them to the corresponding windows (notice 2270 // that XBaseWindow.dispatchEvent does the opposite 2271 // translation) 2272 XBaseWindow target = XToolkit.windowToXWindow(xbe.get_window()); 2273 try { 2274 if (grabLog.isLoggable(PlatformLogger.Level.FINER)) { 2275 grabLog.finer(" - Grab event target {0} (press target {1})", target, pressTarget); 2276 } 2277 if (xbe.get_type() == XConstants.ButtonPress 2278 && xbe.get_button() == XConstants.buttons[0]) 2279 { 2280 // need to keep it to retarget mouse release 2281 pressTarget = target; 2282 } else if (xbe.get_type() == XConstants.ButtonRelease 2283 && xbe.get_button() == XConstants.buttons[0] 2284 && pressTarget != target) 2285 { 2286 // during grab we do receive mouse release on different component (not on the source 2287 // of mouse press). So we need to retarget it. 2288 // see 6390326 for more information. 2289 target = pressTarget.isVisible() ? pressTarget : this; 2290 xbe.set_window(target.getWindow()); 2291 Point localCoord = target.toLocal(scaleDown(xbe.get_x_root()), 2292 scaleDown(xbe.get_y_root())); 2293 xbe.set_x(scaleUp(localCoord.x)); 2294 xbe.set_y(scaleUp(localCoord.y)); 2295 pressTarget = this; 2296 } 2297 if (target != null && target != getContentXWindow() && target != this) { 2298 target.dispatchEvent(xev); 2299 return; 2300 } 2301 } finally { 2302 if (target != null) { 2303 // Target is either us or our content window - 2304 // check that event is inside. 'Us' in case of 2305 // shell will mean that this will also filter out press on title 2306 if ((target == this || target == getContentXWindow()) 2307 && !containsGlobal(scaleDown(xbe.get_x_root()), 2308 scaleDown(xbe.get_y_root()))) 2309 { 2310 // Outside this toplevel hierarchy 2311 // According to the specification of UngrabEvent, post it 2312 // when press occurs outside of the window and not on its owned windows 2313 if (xbe.get_type() == XConstants.ButtonPress) { 2314 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2315 grabLog.fine("Generating UngrabEvent on {0} because not inside of shell", this); 2316 } 2317 // Do not post Ungrab Event for mouse scroll 2318 if ((xbe.get_button() != XConstants.buttons[3]) 2319 && (xbe.get_button() != XConstants.buttons[4])) { 2320 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2321 } 2322 return; 2323 } 2324 } 2325 // First, get the toplevel 2326 XWindowPeer toplevel = target.getToplevelXWindow(); 2327 if (toplevel != null) { 2328 Window w = (Window)toplevel.target; 2329 while (w != null && toplevel != this && !(toplevel instanceof XDialogPeer)) { 2330 w = (Window) AWTAccessor.getComponentAccessor().getParent(w); 2331 if (w != null) { 2332 toplevel = AWTAccessor.getComponentAccessor().getPeer(w); 2333 } 2334 } 2335 if (w == null || (w != this.target && w instanceof Dialog)) { 2336 // toplevel == null - outside of 2337 // hierarchy, toplevel is Dialog - should 2338 // send ungrab (but shouldn't for Window) 2339 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2340 grabLog.fine("Generating UngrabEvent on {0} because hierarchy ended", this); 2341 } 2342 // For mouse wheel event, do not send UngrabEvent 2343 if (xbe.get_type() != XConstants.ButtonPress) { 2344 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2345 } else if ((xbe.get_button() != XConstants.buttons[3]) 2346 && (xbe.get_button() != XConstants.buttons[4])) { 2347 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2348 } 2349 } 2350 } else { 2351 // toplevel is null - outside of hierarchy 2352 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2353 grabLog.fine("Generating UngrabEvent on {0} because toplevel is null", this); 2354 } 2355 // For mouse wheel event, do not send UngrabEvent 2356 if (xbe.get_type() != XConstants.ButtonPress) { 2357 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2358 } else if ((xbe.get_button() != XConstants.buttons[3]) 2359 && (xbe.get_button() != XConstants.buttons[4])) { 2360 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2361 } 2362 return; 2363 } 2364 } else { 2365 // target doesn't map to XAWT window - outside of hierarchy 2366 if (grabLog.isLoggable(PlatformLogger.Level.FINE)) { 2367 grabLog.fine("Generating UngrabEvent on because target is null {0}", this); 2368 } 2369 // For mouse wheel event, do not send UngrabEvent 2370 if (xbe.get_type() != XConstants.ButtonPress) { 2371 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2372 } else if ((xbe.get_button() != XConstants.buttons[3]) 2373 && (xbe.get_button() != XConstants.buttons[4])) { 2374 postEventToEventQueue(new sun.awt.UngrabEvent(getEventSource())); 2375 } 2376 return; 2377 } 2378 } 2379 } 2380 super.handleButtonPressRelease(xev); 2381 } 2382 2383 public void print(Graphics g) { 2384 // We assume we print the whole frame, 2385 // so we expect no clip was set previously 2386 Shape shape = AWTAccessor.getWindowAccessor().getShape((Window)target); 2387 if (shape != null) { 2388 g.setClip(shape); 2389 } 2390 super.print(g); 2391 } 2392 2393 @Override 2394 public void setOpacity(float opacity) { 2395 final long maxOpacity = 0xffffffffl; 2396 long iOpacity = (long)(opacity * maxOpacity); 2397 if (iOpacity < 0) { 2398 iOpacity = 0; 2399 } 2400 if (iOpacity > maxOpacity) { 2401 iOpacity = maxOpacity; 2402 } 2403 2404 XAtom netWmWindowOpacityAtom = XAtom.get("_NET_WM_WINDOW_OPACITY"); 2405 2406 if (iOpacity == maxOpacity) { 2407 netWmWindowOpacityAtom.DeleteProperty(getWindow()); 2408 } else { 2409 netWmWindowOpacityAtom.setCard32Property(getWindow(), iOpacity); 2410 } 2411 } 2412 2413 @Override 2414 public void setOpaque(boolean isOpaque) { 2415 // no-op 2416 } 2417 2418 @Override 2419 public void updateWindow() { 2420 // no-op 2421 } 2422 }