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