001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Dmitry A. Durnev
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.awt.event.FocusEvent;
023:
024: import org.apache.harmony.awt.wtk.NativeEvent;
025: import org.apache.harmony.awt.wtk.NativeWindow;
026:
027: /**
028: * "internal" focus manager
029: * Take decoded native focus events & generate
030: * WINDOW_GAINED_FOCUS, WINDOW_LOST_FOCUS if necessary.
031: * Move focus to focus Proxy to simulate "active" Frame/Dialog
032: * when a non-activateable Window gains focus.
033: * Interact with current KeyboardFocusManager: query focused, active
034: * window, and post all Focus(Window)Events to EventQueue
035: */
036:
037: class FocusDispatcher {
038: private Window nativeFocusedWindow;
039: private final Toolkit toolkit;
040:
041: FocusDispatcher(Toolkit toolkit) {
042: this .toolkit = toolkit;
043: }
044:
045: boolean dispatch(Component src, NativeEvent event) {
046: int id = event.getEventId();
047: long opositeId = event.getOtherWindowId();
048: long srcId = event.getWindowId();
049: boolean focusGained = (id == FocusEvent.FOCUS_GAINED);
050:
051: Window focusProxyOwner = null;
052: if (src == null) {
053: focusProxyOwner = getFocusProxyOwner(srcId);
054: if (focusProxyOwner == null) {
055: return false;
056: }
057: }
058: Component opposite = getComponentById(opositeId);
059: Window oppositeFocusProxyOwner = null;
060: if (opposite == null) {
061: oppositeFocusProxyOwner = getFocusProxyOwner(opositeId);
062: }
063:
064: dispatchFocusEvent(focusGained, src, opposite, focusProxyOwner,
065: oppositeFocusProxyOwner);
066: return false;
067: }
068:
069: private Window getFocusProxyOwner(long id) {
070: return toolkit.getFocusProxyOwnerById(id);
071: }
072:
073: private Component getComponentById(long srcId) {
074: return ((srcId != 0) ? toolkit.getComponentById(srcId) : null);
075: }
076:
077: boolean dispatchFocusEvent(boolean focusGained, Component comp,
078: Component oppositeComp, Window focusProxyOwner,
079: Window oppositeFocusProxyOwner) {
080:
081: Component other = oppositeComp;
082: Window wnd = getWindowAncestor(comp, focusProxyOwner);
083: Window oppositeWnd = getWindowAncestor(other,
084: oppositeFocusProxyOwner);
085: if (focusGained) {
086: nativeFocusedWindow = wnd;
087: } else if (wnd == nativeFocusedWindow) {
088: nativeFocusedWindow = null;
089: }
090:
091: boolean isFocusProxy = (focusProxyOwner != null);
092: boolean isOppositeFocusProxy = (oppositeFocusProxyOwner != null);
093:
094: if (discardFocusProxyEvent(focusGained, isFocusProxy,
095: isOppositeFocusProxy, wnd)) {
096: return true;
097: }
098:
099: // if a non-Frame/Dialog gains native focus, transfer focus
100: // to "focus proxy" in a nearest Frame/Dialog to make it look "active"
101: if (!DefaultKeyboardFocusManager.isActivateable(wnd)
102: && (wnd != oppositeWnd) && focusGained) {
103:
104: activateAncestor(wnd);
105: }
106:
107: return dispatchToKFM(focusGained, wnd, oppositeWnd,
108: isFocusProxy, isOppositeFocusProxy, other);
109: }
110:
111: private Window getWindowAncestor(Component comp, Window proxyOwner) {
112: if (comp != null) {
113: return comp.getWindowAncestor();
114: }
115: return proxyOwner;
116: }
117:
118: private boolean dispatchToKFM(boolean focusGained, Window wnd,
119: Window oppositeWnd, boolean isFocusProxy,
120: boolean isOppositeFocusProxy, Component other) {
121: KeyboardFocusManager kfm = KeyboardFocusManager
122: .getCurrentKeyboardFocusManager();
123: Component focusOwner = KeyboardFocusManager.actualFocusOwner;
124:
125: // change wnd/oppositeWnd to Java focused window
126: // if focusProxy is losing focus:
127:
128: Window focusedWindow = KeyboardFocusManager.actualFocusedWindow;
129:
130: if (!focusGained && isFocusProxy && (focusedWindow != null)) {
131: // discard event when focus proxy
132: // is losing focus to focused Window
133: if (oppositeWnd == focusedWindow) {
134: return true;
135: }
136: wnd = focusedWindow;
137: }
138:
139: if (focusGained && isOppositeFocusProxy) {
140: oppositeWnd = focusedWindow;
141: other = focusOwner;
142: }
143:
144: // if focus goes out of our app there's no requestFocus() call, so
145: // deliver native event to KFM:
146: if (!focusGained && (other == null)) {
147: kfm.setFocus(focusOwner, focusedWindow, false, other, true,
148: false);
149: }
150: if (focusGained && (wnd != oppositeWnd)) {
151: // set focus to the appropriate child component:
152: // contrary to focus spec KeyboardFocusManager doesn't
153: // have to do it
154: // [don't call behavior here to avoid endless loop]
155: kfm.requestFocusInWindow(wnd, false);
156: }
157: return true;
158: }
159:
160: /**
161: * Discard some focus events where focusProxy is source or opposite
162: * @param focusGained
163: * @param isFocusProxy
164: * @param isOppositeFocusProxy
165: * @param wnd
166: * @return true if event should be discarded
167: */
168: private boolean discardFocusProxyEvent(boolean focusGained,
169: boolean isFocusProxy, boolean isOppositeFocusProxy,
170: Window wnd) {
171: if (!focusGained && isOppositeFocusProxy) {
172: return true;
173: }
174: if (focusGained && isFocusProxy) {
175: return true;
176: }
177: return false;
178: }
179:
180: /**
181: * Try to activate nearest Dialog/Frame[if not already active]
182: * by setting native focus to focusProxy[dedicated child of Dialog/Frame]
183: */
184: private void activateAncestor(Window wnd) {
185:
186: Window decorWnd = wnd.getFrameDialogOwner();
187: if ((decorWnd != null) && (decorWnd != nativeFocusedWindow)) {
188: NativeWindow nativeWnd = decorWnd.getNativeWindow();
189: if (nativeWnd != null) {
190: NativeWindow focusProxyWnd = decorWnd.getFocusProxy();
191:
192: if ((focusProxyWnd != null)) {
193: focusProxyWnd.setFocus(true);
194: }
195: }
196: }
197: }
198:
199: }
|