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