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