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