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