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