blob: 582c2f05578fd9e4a4e87be1e0e8050e17182600 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 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
26package sun.awt.X11;
27
28import java.awt.AWTKeyStroke;
29import java.util.logging.*;
30import sun.awt.SunToolkit;
31import java.awt.Component;
32import java.awt.Container;
33
34/**
35 * Helper class implementing XEmbed protocol handling routines(client side)
36 * Window which wants to participate in a protocol should create an instance,
37 * call install and forward all XClientMessageEvents to it.
38 */
39public class XEmbedClientHelper extends XEmbedHelper implements XEventDispatcher {
40 private static final Logger xembedLog = Logger.getLogger("sun.awt.X11.xembed.XEmbedClientHelper");
41
42 private XEmbeddedFramePeer embedded;
43 private boolean active;
44 private long server;
45 private boolean applicationActive;
46
47 XEmbedClientHelper() {
48 super();
49 }
50
51 void install(XEmbeddedFramePeer embedded) {
52 this.embedded = embedded;
53
54 if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Installing xembedder on " + embedded);
55 XToolkit.addEventDispatcher(embedded.getWindow(), this);
56 long[] info = new long[] { XEMBED_VERSION, XEMBED_MAPPED };
57 long data = Native.card32ToData(info);
58 try {
59 XEmbedInfo.setAtomData(embedded.getWindow(), data, 2);
60 } finally {
61 unsafe.freeMemory(data);
62 }
63 // XEmbeddedFrame is initially created with a null parent..
64 // Here it is reparented to the proper parent window.
65 long parentWindow = embedded.getParentWindowHandle();
66 if (parentWindow != 0) {
67 XToolkit.awtLock();
68 try {
69 XlibWrapper.XReparentWindow(XToolkit.getDisplay(),
70 embedded.getWindow(),
71 parentWindow,
72 0, 0);
73 } finally {
74 XToolkit.awtUnlock();
75 }
76 }
77 notifyReady();
78 }
79
80 void handleClientMessage(XEvent xev) {
81 XClientMessageEvent msg = xev.get_xclient();
82 if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine(msg.toString());
83 if (msg.get_message_type() == XEmbed.getAtom()) {
84 if (xembedLog.isLoggable(Level.FINE)) xembedLog.fine("Embedded message: " + msgidToString((int)msg.get_data(1)));
85 switch ((int)msg.get_data(1)) {
86 case XEMBED_EMBEDDED_NOTIFY: // Notification about embedding protocol start
87 // NOTE: May be called two times because we send _SUN_XEMBED_START
88 active = true;
89 server = getEmbedder(embedded, msg);
90 // Check if window is reparented. If not - it was created with
91 // parent and so we should update it here.
92 if (!embedded.isReparented()) {
93 embedded.setReparented(true);
94 embedded.updateSizeHints();
95 }
96 embedded.notifyStarted();
97 break;
98 case XEMBED_WINDOW_ACTIVATE:
99 applicationActive = true;
100 break;
101 case XEMBED_WINDOW_DEACTIVATE:
102 if (applicationActive) {
103 applicationActive = false;
104 handleWindowFocusOut();
105 }
106 break;
107 case XEMBED_FOCUS_IN: // We got focus!
108 // Check for direction
109 handleFocusIn((int)msg.get_data(2));
110 break;
111 case XEMBED_FOCUS_OUT:
112 if (applicationActive) {
113 handleWindowFocusOut();
114 }
115 break;
116 }
117 }
118 }
119 void handleFocusIn(int detail) {
120 if (embedded.focusAllowedFor()) {
121 embedded.handleWindowFocusInSync(0);
122 }
123 switch(detail) {
124 case XEMBED_FOCUS_CURRENT:
125 // Do nothing - just restore to the current value
126 break;
127 case XEMBED_FOCUS_FIRST:
128 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() {
129 public void run() {
130 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getFirstComponent((Container)embedded.target);
131 if (comp != null) {
132 comp.requestFocusInWindow();
133 }
134 }});
135 break;
136 case XEMBED_FOCUS_LAST:
137 SunToolkit.executeOnEventHandlerThread(embedded.target, new Runnable() {
138 public void run() {
139 Component comp = ((Container)embedded.target).getFocusTraversalPolicy().getLastComponent((Container)embedded.target);
140 if (comp != null) {
141 comp.requestFocusInWindow();
142 }
143 }});
144 break;
145 }
146 }
147
148 public void dispatchEvent(XEvent xev) {
149 switch(xev.get_type()) {
150 case XlibWrapper.ClientMessage:
151 handleClientMessage(xev);
152 break;
153 case XlibWrapper.ReparentNotify:
154 handleReparentNotify(xev);
155 break;
156 }
157 }
158 public void handleReparentNotify(XEvent xev) {
159 XReparentEvent re = xev.get_xreparent();
160 server = re.get_parent();
161 }
162 boolean requestFocus() {
163 if (active && embedded.focusAllowedFor()) {
164 sendMessage(server, XEMBED_REQUEST_FOCUS);
165 return true;
166 }
167 return false;
168 }
169 void handleWindowFocusOut() {
170 // fix for 6269309: it is possible that we call this method twice
171 // (for example, when receiving XEMBED_WINDOW_DEACTIVATE and then
172 // XEMBED_FOCUS_OUT client messages), so we first need to check if
173 // embedded is an active window before sending WINDOW_LOST_FOCUS
174 // to shared code
175 if (XKeyboardFocusManagerPeer.getCurrentNativeFocusedWindow() == embedded.target) {
176 embedded.handleWindowFocusOutSync(null, 0);
177 }
178 }
179
180 long getEmbedder(XWindowPeer embedded, XClientMessageEvent info) {
181 // Embedder is the parent of embedded.
182 return XlibUtil.getParentWindow(embedded.getWindow());
183 }
184
185 boolean isApplicationActive() {
186 return applicationActive;
187 }
188
189 boolean isActive() {
190 return active;
191 }
192
193 void traverseOutForward() {
194 if (active) {
195 sendMessage(server, XEMBED_FOCUS_NEXT);
196 }
197 }
198
199 void traverseOutBackward() {
200 if (active) {
201 sendMessage(server, XEMBED_FOCUS_PREV);
202 }
203 }
204
205 void registerAccelerator(AWTKeyStroke stroke, int id) {
206 long sym = getX11KeySym(stroke);
207 long mods = getX11Mods(stroke);
208 sendMessage(server, XEMBED_REGISTER_ACCELERATOR, id, sym, mods);
209 }
210 void unregisterAccelerator(int id) {
211 sendMessage(server, XEMBED_UNREGISTER_ACCELERATOR, id, 0, 0);
212 }
213
214 long getX11KeySym(AWTKeyStroke stroke) {
215 XToolkit.awtLock();
216 try {
217 return XWindow.getKeySymForAWTKeyCode(stroke.getKeyCode());
218 } finally {
219 XToolkit.awtUnlock();
220 }
221 }
222
223 long getX11Mods(AWTKeyStroke stroke) {
224 return XWindow.getXModifiers(stroke);
225 }
226
227 void notifyReady() {
228 long wnd = server;
229 if (wnd == 0) {
230 // Server is still 0, get the parent
231 wnd = embedded.getParentWindowHandle();
232 }
233 sendMessage(wnd, _SUN_XEMBED_START);
234 }
235}