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