| /* | |
| * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| 1. Useful API: | |
| XWindowPeer.isModalBlocked() | |
| Checks if this window is blocked by any modal dialog | |
| For common component peers use getToplevelXWindow().isModalBlocked() | |
| XWindowPeer.setModalBlocked(Dialog blocker, boolean blocked) | |
| Implementation of WindoePeer.setModalBlocked() method | |
| Marks this window blocked/unblocked and adds/removes it | |
| from transient_for chain (see below) | |
| Don't call this method directly, it should be used from shared | |
| code only | |
| XWindowPeer.addToTransientFors() | |
| XWindowPeer.removeFromTransientFors() | |
| See below | |
| 2. Filtering mouse events | |
| Mouse events are filtered in the shared code. See | |
| java.awt.ModalFilter class for details | |
| 3. Filtering key events | |
| Key events are filtering by preventing the blocked windows | |
| to get native focus. All the AWT windows use global active focus | |
| input model (see ICCCM for details) and listens to WM_TAKE_FOCUS | |
| protocol. If the window manager asks AWT to set focus on the | |
| blocked window, in XDecoratedPeer.handleWmTakeFocus() method we | |
| set the focus to the window's blocker. | |
| 4. Z-order | |
| According to the Modality spec any modal dialog should be always on | |
| top of its blocked windows. It is implemented with using | |
| WM_TRANSIENT_FOR hint. | |
| WM_TRANSIENT_FOR is used to mark one window to be a child of another | |
| one, in particular for any kind of dialogs. When a modal dialog | |
| is shown it temporary becomes a child of all its blocked windows | |
| and thus remains on top of them. | |
| WM_TRANSIENT_FOR value is a single window, so we can't directly make | |
| a dialog be a child of several other windows. It is implemented | |
| as a "transient_for chain": all the blocked windows are arranged | |
| into a chain, each next window is transient for the prev. | |
| The chain is stored in XWindowPeer's fields 'prevTransientFor' and | |
| 'nextTransientFor'. If window is not blocked both of these fields | |
| are set to null. | |
| However, the value of WM_TRANSIENT_FOR hint and prevTransientFor | |
| may differ sometimes. This happens when two windows are in | |
| different window states, usually NormalState and IconifiedState. | |
| Some window managers don't allow a dialog to be visible is its | |
| parent window is iconified. The situation is even worse: we | |
| don't receive any notifications when the dialog is iconified | |
| together with its parent frame. | |
| Thus we need to track all the window's state changes. Also, for | |
| any window state (NormalState, IconifiedState, WithdrawnState) | |
| a distinct chain is tracked. Below is a brief example. | |
| Let's consider two frames F1 and F2 and two modeless dialogs D1 | |
| (with F1 as a parent) and D2 (F2). Their Z-order is: | |
| F1 - D1 - F2 - D2 (D1 is above F1, F2 is above D1, etc). Then | |
| a modal dialog D3 is shown and all these four windows become | |
| blocked by it. Transient_for chain is constructed in the | |
| following way: F1 - D2 - F2 - D2 - D3. Respectively, F2 | |
| temporarily becomes a child of D1 (WM_TRANSIENT_FOR hint is | |
| set to F2 with a value of D1), etc. | |
| Then F1 is iconified (some window managers allow this action). | |
| F1.nextTransientFor and D1.prevTransientFor aren't changed, | |
| however the values of WM_TRANSIENT_FOR hint for them are | |
| changed: hint value for F1 is set to None, and hint value for | |
| D1 is set to None. | |
| Let's iconify another window, F2. prev/nextTransientFor field | |
| values aren't changed again, but WM_TRANSIENT_FOR hint is: | |
| the value for D2 is D1, the value for F2 is F1 (both are | |
| iconified). | |
| When either F1 or F2 is restored, the value for its hint is | |
| restored according to the value stored in prevTransientFor | |
| and nextTransientFor fields. | |
| Note that some window managers don't allow iconifying for | |
| those windows that are children of some other toplevel. That | |
| is any dialog can't be iconified and any blocked window | |
| that is not the first in the transient_for chain too. | |
| All the updates of the hint's value is performed in the | |
| XWindowPeer.setToplevelTransientFor() method. | |
| 5. Multiscreen | |
| All the problems with WM_TRANSIENT_FOR hint and different | |
| window states can be applied to different X screens (if | |
| Xinerama is off). For example, some window managers ignore | |
| the hint if window and transient_for window are on different | |
| screens. | |
| That leads to us to track a separate transient_for chain for | |
| every screen in the system, as well as for every window | |
| state. See XWindowPeer.updateTransientFor() for details. | |
| 6. See also | |
| Some examples how transient_for chain is constructed and | |
| destructed can be found in JavaDoc comments for the | |
| following methods: XWindowPeer.addToTransientFors(), | |
| XWindowPeer.removeFromTransientFors(), | |
| XWindowPeer.setToplevelTransientFor(), | |
| XWindowPeer.stateChanged(). | |