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