001: /*
002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.X11;
027:
028: import java.awt.AWTKeyStroke;
029: import java.util.logging.*;
030: import sun.awt.SunToolkit;
031: import java.awt.Component;
032: import java.awt.Container;
033:
034: /**
035: * Helper class implementing XEmbed protocol handling routines(client side)
036: * Window which wants to participate in a protocol should create an instance,
037: * call install and forward all XClientMessageEvents to it.
038: */
039: public class XEmbedClientHelper extends XEmbedHelper implements
040: XEventDispatcher {
041: private static final Logger xembedLog = Logger
042: .getLogger("sun.awt.X11.xembed.XEmbedClientHelper");
043:
044: private XEmbeddedFramePeer embedded;
045: private boolean active;
046: private long server;
047: private boolean applicationActive;
048:
049: XEmbedClientHelper() {
050: super ();
051: }
052:
053: void install(XEmbeddedFramePeer embedded) {
054: this .embedded = embedded;
055:
056: if (xembedLog.isLoggable(Level.FINE))
057: xembedLog.fine("Installing xembedder on " + embedded);
058: XToolkit.addEventDispatcher(embedded.getWindow(), this );
059: long[] info = new long[] { XEMBED_VERSION, XEMBED_MAPPED };
060: long data = Native.card32ToData(info);
061: try {
062: XEmbedInfo.setAtomData(embedded.getWindow(), data, 2);
063: } finally {
064: unsafe.freeMemory(data);
065: }
066: // XEmbeddedFrame is initially created with a null parent..
067: // Here it is reparented to the proper parent window.
068: long parentWindow = embedded.getParentWindowHandle();
069: if (parentWindow != 0) {
070: XToolkit.awtLock();
071: try {
072: XlibWrapper.XReparentWindow(XToolkit.getDisplay(),
073: embedded.getWindow(), parentWindow, 0, 0);
074: } finally {
075: XToolkit.awtUnlock();
076: }
077: }
078: notifyReady();
079: }
080:
081: void handleClientMessage(XEvent xev) {
082: XClientMessageEvent msg = xev.get_xclient();
083: if (xembedLog.isLoggable(Level.FINE))
084: xembedLog.fine(msg.toString());
085: if (msg.get_message_type() == XEmbed.getAtom()) {
086: if (xembedLog.isLoggable(Level.FINE))
087: xembedLog.fine("Embedded message: "
088: + msgidToString((int) msg.get_data(1)));
089: switch ((int) msg.get_data(1)) {
090: case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start
091: // NOTE: May be called two times because we send _SUN_XEMBED_START
092: active = true;
093: server = getEmbedder(embedded, msg);
094: // Check if window is reparented. If not - it was created with
095: // parent and so we should update it here.
096: if (!embedded.isReparented()) {
097: embedded.setReparented(true);
098: embedded.updateSizeHints();
099: }
100: embedded.notifyStarted();
101: break;
102: case XEMBED_WINDOW_ACTIVATE:
103: applicationActive = true;
104: break;
105: case XEMBED_WINDOW_DEACTIVATE:
106: if (applicationActive) {
107: applicationActive = false;
108: handleWindowFocusOut();
109: }
110: break;
111: case XEMBED_FOCUS_IN: // We got focus!
112: // Check for direction
113: handleFocusIn((int) msg.get_data(2));
114: break;
115: case XEMBED_FOCUS_OUT:
116: if (applicationActive) {
117: handleWindowFocusOut();
118: }
119: break;
120: }
121: }
122: }
123:
124: void handleFocusIn(int detail) {
125: if (embedded.focusAllowedFor()) {
126: embedded.handleWindowFocusInSync(0);
127: }
128: switch (detail) {
129: case XEMBED_FOCUS_CURRENT:
130: // Do nothing - just restore to the current value
131: break;
132: case XEMBED_FOCUS_FIRST:
133: SunToolkit.executeOnEventHandlerThread(embedded.target,
134: new Runnable() {
135: public void run() {
136: Component comp = ((Container) embedded.target)
137: .getFocusTraversalPolicy()
138: .getFirstComponent(
139: (Container) embedded.target);
140: if (comp != null) {
141: comp.requestFocusInWindow();
142: }
143: }
144: });
145: break;
146: case XEMBED_FOCUS_LAST:
147: SunToolkit.executeOnEventHandlerThread(embedded.target,
148: new Runnable() {
149: public void run() {
150: Component comp = ((Container) embedded.target)
151: .getFocusTraversalPolicy()
152: .getLastComponent(
153: (Container) embedded.target);
154: if (comp != null) {
155: comp.requestFocusInWindow();
156: }
157: }
158: });
159: break;
160: }
161: }
162:
163: public void dispatchEvent(XEvent xev) {
164: switch (xev.get_type()) {
165: case XlibWrapper.ClientMessage:
166: handleClientMessage(xev);
167: break;
168: case XlibWrapper.ReparentNotify:
169: handleReparentNotify(xev);
170: break;
171: }
172: }
173:
174: public void handleReparentNotify(XEvent xev) {
175: XReparentEvent re = xev.get_xreparent();
176: server = re.get_parent();
177: }
178:
179: boolean requestFocus() {
180: if (active && embedded.focusAllowedFor()) {
181: sendMessage(server, XEMBED_REQUEST_FOCUS);
182: return true;
183: }
184: return false;
185: }
186:
187: void handleWindowFocusOut() {
188: // fix for 6269309: it is possible that we call this method twice
189: // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then
190: // XEMBED_FOCUS_OUT client messages), so we first need to check if
191: // embedded is an active window before sending WINDOW_LOST_FOCUS
192: // to shared code
193: if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == embedded.target) {
194: embedded.handleWindowFocusOutSync(null, 0);
195: }
196: }
197:
198: long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) {
199: // Embedder is the parent of embedded.
200: return XlibUtil.getParentWindow(embedded.getWindow());
201: }
202:
203: boolean isApplicationActive() {
204: return applicationActive;
205: }
206:
207: boolean isActive() {
208: return active;
209: }
210:
211: void traverseOutForward() {
212: if (active) {
213: sendMessage(server, XEMBED_FOCUS_NEXT);
214: }
215: }
216:
217: void traverseOutBackward() {
218: if (active) {
219: sendMessage(server, XEMBED_FOCUS_PREV);
220: }
221: }
222:
223: void registerAccelerator(AWTKeyStroke stroke, int id) {
224: long sym = getX11KeySym(stroke);
225: long mods = getX11Mods(stroke);
226: sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods);
227: }
228:
229: void unregisterAccelerator(int id) {
230: sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0);
231: }
232:
233: long getX11KeySym(AWTKeyStroke stroke) {
234: XToolkit.awtLock();
235: try {
236: return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode());
237: } finally {
238: XToolkit.awtUnlock();
239: }
240: }
241:
242: long getX11Mods(AWTKeyStroke stroke) {
243: return XWindow.getXModifiers(stroke);
244: }
245:
246: void notifyReady() {
247: long wnd = server;
248: if (wnd == 0) {
249: // Server is still 0, get the parent
250: wnd = embedded.getParentWindowHandle();
251: }
252: sendMessage(wnd, _SUN_XEMBED_START);
253: }
254: }
|