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