|
1 /* |
|
2 * Copyright 2006 Sun Microsystems, Inc. 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. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 |
|
27 1. Useful API: |
|
28 |
|
29 XWindowPeer.isModalBlocked() |
|
30 Checks if this window is blocked by any modal dialog |
|
31 For common component peers use getToplevelXWindow().isModalBlocked() |
|
32 |
|
33 XWindowPeer.setModalBlocked(Dialog blocker, boolean blocked) |
|
34 Implementation of WindoePeer.setModalBlocked() method |
|
35 Marks this window blocked/unblocked and adds/removes it |
|
36 from transient_for chain (see below) |
|
37 Don't call this method directly, it should be used from shared |
|
38 code only |
|
39 |
|
40 XWindowPeer.addToTransientFors() |
|
41 XWindowPeer.removeFromTransientFors() |
|
42 See below |
|
43 |
|
44 2. Filtering mouse events |
|
45 |
|
46 Mouse events are filtered in the shared code. See |
|
47 java.awt.ModalFilter class for details |
|
48 |
|
49 3. Filtering key events |
|
50 |
|
51 Key events are filtering by preventing the blocked windows |
|
52 to get native focus. All the AWT windows use global active focus |
|
53 input model (see ICCCM for details) and listens to WM_TAKE_FOCUS |
|
54 protocol. If the window manager asks AWT to set focus on the |
|
55 blocked window, in XDecoratedPeer.handleWmTakeFocus() method we |
|
56 set the focus to the window's blocker. |
|
57 |
|
58 4. Z-order |
|
59 |
|
60 According to the Modality spec any modal dialog should be always on |
|
61 top of its blocked windows. It is implemented with using |
|
62 WM_TRANSIENT_FOR hint. |
|
63 |
|
64 WM_TRANSIENT_FOR is used to mark one window to be a child of another |
|
65 one, in particular for any kind of dialogs. When a modal dialog |
|
66 is shown it temporary becomes a child of all its blocked windows |
|
67 and thus remains on top of them. |
|
68 |
|
69 WM_TRANSIENT_FOR value is a single window, so we can't directly make |
|
70 a dialog be a child of several other windows. It is implemented |
|
71 as a "transient_for chain": all the blocked windows are arranged |
|
72 into a chain, each next window is transient for the prev. |
|
73 |
|
74 The chain is stored in XWindowPeer's fields 'prevTransientFor' and |
|
75 'nextTransientFor'. If window is not blocked both of these fields |
|
76 are set to null. |
|
77 |
|
78 However, the value of WM_TRANSIENT_FOR hint and prevTransientFor |
|
79 may differ sometimes. This happens when two windows are in |
|
80 different window states, usually NormalState and IconifiedState. |
|
81 Some window managers don't allow a dialog to be visible is its |
|
82 parent window is iconified. The situation is even worse: we |
|
83 don't receive any notifications when the dialog is iconified |
|
84 together with its parent frame. |
|
85 |
|
86 Thus we need to track all the window's state changes. Also, for |
|
87 any window state (NormalState, IconifiedState, WithdrawnState) |
|
88 a distinct chain is tracked. Below is a brief example. |
|
89 |
|
90 Let's consider two frames F1 and F2 and two modeless dialogs D1 |
|
91 (with F1 as a parent) and D2 (F2). Their Z-order is: |
|
92 F1 - D1 - F2 - D2 (D1 is above F1, F2 is above D1, etc). Then |
|
93 a modal dialog D3 is shown and all these four windows become |
|
94 blocked by it. Transient_for chain is constructed in the |
|
95 following way: F1 - D2 - F2 - D2 - D3. Respectively, F2 |
|
96 temporarily becomes a child of D1 (WM_TRANSIENT_FOR hint is |
|
97 set to F2 with a value of D1), etc. |
|
98 |
|
99 Then F1 is iconified (some window managers allow this action). |
|
100 F1.nextTransientFor and D1.prevTransientFor aren't changed, |
|
101 however the values of WM_TRANSIENT_FOR hint for them are |
|
102 changed: hint value for F1 is set to None, and hint value for |
|
103 D1 is set to None. |
|
104 |
|
105 Let's iconify another window, F2. prev/nextTransientFor field |
|
106 values aren't changed again, but WM_TRANSIENT_FOR hint is: |
|
107 the value for D2 is D1, the value for F2 is F1 (both are |
|
108 iconified). |
|
109 |
|
110 When either F1 or F2 is restored, the value for its hint is |
|
111 restored according to the value stored in prevTransientFor |
|
112 and nextTransientFor fields. |
|
113 |
|
114 Note that some window managers don't allow iconifying for |
|
115 those windows that are children of some other toplevel. That |
|
116 is any dialog can't be iconified and any blocked window |
|
117 that is not the first in the transient_for chain too. |
|
118 |
|
119 All the updates of the hint's value is performed in the |
|
120 XWindowPeer.setToplevelTransientFor() method. |
|
121 |
|
122 5. Multiscreen |
|
123 |
|
124 All the problems with WM_TRANSIENT_FOR hint and different |
|
125 window states can be applied to different X screens (if |
|
126 Xinerama is off). For example, some window managers ignore |
|
127 the hint if window and transient_for window are on different |
|
128 screens. |
|
129 |
|
130 That leads to us to track a separate transient_for chain for |
|
131 every screen in the system, as well as for every window |
|
132 state. See XWindowPeer.updateTransientFor() for details. |
|
133 |
|
134 6. See also |
|
135 |
|
136 Some examples how transient_for chain is constructed and |
|
137 destructed can be found in JavaDoc comments for the |
|
138 following methods: XWindowPeer.addToTransientFors(), |
|
139 XWindowPeer.removeFromTransientFors(), |
|
140 XWindowPeer.setToplevelTransientFor(), |
|
141 XWindowPeer.stateChanged(). |
|
142 |