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