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