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