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