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