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