J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 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 | |