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