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