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