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