blob: 86bfae68f661e6d31584bccb05ce292bedf72951 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 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#ifdef HEADLESS
27 #error This file should not be included in headless library
28#endif
29
30#include "awt_p.h"
31
32#include <X11/Xproto.h>
33#include <X11/Xlib.h>
34#include <X11/Xatom.h>
35#include <Xm/MwmUtil.h>
36
37/* JNI headers */
38#include "java_awt_Frame.h" /* for frame state constants */
39
40#include "awt_wm.h"
41#include "awt_util.h" /* for X11 error handling macros */
42#include "awt_xembed.h"
43#include "awt_MToolkit.h"
44#include "awt_DataTransferer.h" /* for DECLARE_XXX macros */
45
46#ifdef DOTRACE
47#define MTRACE(param) fprintf(myerr, param)
48#define MTRACEP1(format, p1) fprintf(myerr, format, p1)
49#define MTRACEP2(format, p1, p2) fprintf(myerr, format, p1, p2)
50#define MTRACEP3(format, p1, p2, p3) fprintf(myerr, format, p1, p2, p3)
51#define MTRACEP4(format, p1, p2, p3, p4) fprintf(myerr, format, p1, p2, p3, p4)
52#define MTRACEP5(format, p1, p2, p3, p4, p5) fprintf(myerr, format, p1, p2, p3, p4, p5)
53#define MTRACEP6(format, p1, p2, p3, p4, p5, p6) fprintf(myerr, format, p1, p2, p3, p4, p5, p6)
54#define MTRACEP7(format, p1, p2, p3, p4, p5, p6, p7) fprintf(myerr, format, p1, p2, p3, p4, p5, p6, p7)
55#else
56#define MTRACE(param)
57#define MTRACEP1(format, p1)
58#define MTRACEP2(format, p1, p2)
59#define MTRACEP3(format, p1, p2, p3)
60#define MTRACEP4(format, p1, p2, p3, p4)
61#define MTRACEP5(format, p1, p2, p3, p4, p5)
62#define MTRACEP6(format, p1, p2, p3, p4, p5, p6)
63#define MTRACEP7(format, p1, p2, p3, p4, p5, p6, p7)
64#endif
65
66#ifdef DOTRACE
67static FILE* myerr;
68#endif
69
70static Window getParent(Window window);
71static Window getEmbedder(Window client);
72static jmethodID handleFocusInMID;
73
74const char * error_msg = "UNKNOWN XEMBED MESSAGE";
75
76const char * xembed_strs[] = {
77 "EMBEDDED_NOTIFY",
78 "WINDOW_ACTIVATE",
79 "WINDOW_DEACTIVATE",
80 "REQUEST_FOCUS",
81 "FOCUS_IN",
82 "FOCUS_OUT",
83 "FOCUS_NEXT",
84 "FOCUS_PREV" ,
85 "GRAB_KEY",
86 "UNGRAB_KEY",
87 "MODALITY_ON" ,
88 "MODALITY_OFF",
89 "REGISTER_ACCELERATOR",
90 "UNREGISTER_ACCELERATOR",
91 "ACTIVATE_ACCELERATOR"
92};
93
94const char *
95msg_to_str(int msg) {
96 if (msg >= 0 && msg <= XEMBED_LAST_MSG) {
97 return xembed_strs[msg];
98 } else {
99 return error_msg;
100 }
101}
102
103DECLARE_JAVA_CLASS(MEmbeddedFramePeerClass, "sun/awt/motif/MEmbeddedFramePeer");
104
105typedef struct _xembed_info {
106 CARD32 version;
107 CARD32 flags;
108} xembed_info;
109
110typedef struct _xembed_data {
111 struct FrameData * wdata; // pointer to EmbeddedFrame wdata
112 Window client; // pointer to plugin intermediate widget, XEmbed client
113 Boolean active; // whether xembed is active for this client
114 Boolean applicationActive; // whether the embedding application is active
115 Window embedder; // Window ID of the embedder
116 struct _xembed_data * next;
117} xembed_data, * pxembed_data;
118
119static pxembed_data xembed_list = NULL;
120
121static pxembed_data
122getData(Window client) {
123 pxembed_data temp = xembed_list;
124 while (temp != NULL) {
125 if (temp->client == client) {
126 return temp;
127 }
128 temp = temp->next;
129 }
130 return NULL;
131}
132
133static pxembed_data
134getDataByFrame(struct FrameData* wdata) {
135 pxembed_data temp = xembed_list;
136 while (temp != NULL) {
137 if (temp->wdata == wdata) {
138 return temp;
139 }
140 temp = temp->next;
141 }
142 return NULL;
143}
144
145static pxembed_data
146addData(Window client) {
147 xembed_data * data = malloc(sizeof(xembed_data));
148 memset(data, 0, sizeof(xembed_data));
149 data->client = client;
150 data->next = xembed_list;
151 xembed_list = data;
152 return data;
153}
154
155static void
156removeData(Window client) {
157 pxembed_data * temp = &xembed_list;
158 while (*temp != NULL) {
159 if ((*temp)->client == client) {
160 xembed_data * data = *temp;
161 *temp = (*temp)->next;
162 free(data);
163 return;
164 }
165 temp = &(*temp)->next;
166 }
167}
168
169static Atom XA_XEmbedInfo;
170static Atom XA_XEmbed;
171
172void
173init_xembed() {
174 XA_XEmbedInfo = XInternAtom(awt_display, "_XEMBED_INFO", False);
175 XA_XEmbed = XInternAtom(awt_display, "_XEMBED", False);
176#ifdef DOTRACE
177 myerr = fopen("xembedclient.log","w");
178#endif
179}
180
181static Time
182getCurrentServerTime() {
183 return awt_util_getCurrentServerTime();
184}
185
186
187void
188sendMessageHelper(Window window, int message, long detail,
189 long data1, long data2)
190{
191 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
192 XEvent ev;
193 XClientMessageEvent * req = (XClientMessageEvent*)&ev;
194 memset(&ev, 0, sizeof(ev));
195
196 req->type = ClientMessage;
197 req->window = window;
198 req->message_type = XA_XEmbed;
199 req->format = 32;
200 req->data.l[0] = getCurrentServerTime();
201 req->data.l[1] = message;
202 req->data.l[2] = detail;
203 req->data.l[3] = data1;
204 req->data.l[4] = data2;
205 AWT_LOCK();
206 XSendEvent(awt_display, window, False, NoEventMask, &ev);
207 AWT_UNLOCK();
208}
209
210void
211sendMessage(Window window, int message) {
212 sendMessageHelper(window, message, 0, 0, 0);
213}
214
215
216static Window
217getParent(Window window) {
218 Window root, parent = None, *children = NULL;
219 unsigned int count;
220 XQueryTree(awt_display, window, &root, &parent, &children, &count);
221 if (children != NULL) {
222 XFree(children);
223 }
224 return parent;
225}
226
227static Window
228getEmbedder(Window client) {
229 return getParent(client);
230}
231
232
233static void
234handleFocusIn(struct FrameData* wdata, int detail) {
235 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
236 struct WidgetInfo* winfo;
237 MTRACE("HandleFocusIn\n");
238 winfo = findWidgetInfo(wdata->winData.comp.widget);
239 if (winfo != NULL) {
240 jobject peer = winfo->peer;
241 if (handleFocusInMID == NULL) {
242 jclass clazz = (*env)->FindClass(env, "sun/awt/motif/MEmbeddedFramePeer");
243 DASSERT(clazz != NULL);
244 handleFocusInMID = (*env)->GetMethodID(env, clazz, "handleFocusIn", "(I)V");
245 DASSERT(handleFocusInMID != NULL);
246 if (clazz != NULL) {
247 (*env)->DeleteLocalRef(env, clazz);
248 }
249 }
250 if (handleFocusInMID != NULL) {
251 (*env)->CallVoidMethod(env, peer, handleFocusInMID, (jint)detail);
252 }
253 }
254}
255
256static void
257genWindowFocus(struct FrameData *wdata, Boolean gain) {
258 XEvent ev;
259 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
260 memset(&ev, 0, sizeof(ev));
261
262 ev.type = (gain?FocusIn:FocusOut);
263 ev.xany.send_event = True;
264 ev.xany.display = awt_display;
265 ev.xfocus.mode = NotifyNormal;
266 ev.xfocus.detail = NotifyNonlinear;
267 ev.xfocus.window = XtWindow(wdata->winData.shell);
268 awt_put_back_event(env, &ev);
269}
270
271extern Boolean skipNextFocusIn;
272
273static void
274callNotifyStarted(JNIEnv* env, jobject peer) {
275 DECLARE_VOID_JAVA_METHOD(notifyStartedMID, MEmbeddedFramePeerClass,
276 "notifyStarted", "()V");
277
278 (*env)->CallVoidMethod(env, peer, notifyStartedMID);
279}
280
281void
282xembed_eventHandler(XEvent *event)
283{
284 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
285 struct FrameData *wdata;
286 xembed_data * data;
287
288 data = getData(event->xany.window);
289 if (data == NULL) {
290 MTRACEP1("No XEMBED client registered for this window %x\n", event->xany.window);
291 if (event->xany.type == ClientMessage) {
292 MTRACEP7("Unprocessed handleClientMessage: type=%d 0=%ld 1=%ld(%s) 2=%ld 3=%ld 4=%ld\n",
293 event->xclient.message_type, event->xclient.data.l[0],
294 event->xclient.data.l[1], msg_to_str(event->xclient.data.l[1]),
295 event->xclient.data.l[2],
296 event->xclient.data.l[3], event->xclient.data.l[4]);
297 }
298 return;
299 }
300
301 wdata = data->wdata;
302
303 if (event->xany.type == ClientMessage) {
304 MTRACEP6("handleClientMessage: type=%d 0=%ld 1=%ld 2=%ld 3=%ld 4=%ld\n",
305 event->xclient.message_type, event->xclient.data.l[0],
306 event->xclient.data.l[1], event->xclient.data.l[2],
307 event->xclient.data.l[3], event->xclient.data.l[4]);
308 // Probably a message from embedder
309 if (event->xclient.message_type == XA_XEmbed) {
310 // XEmbed message, data[1] contains message
311 switch ((int)event->xclient.data.l[1]) {
312 case XEMBED_EMBEDDED_NOTIFY:
313 MTRACE("EMBEDDED_NOTIFY\n");
314 data->active = True;
315 data->embedder = getEmbedder(data->client);
316 // If Frame has not been reparented already we should "reparent"
317 // it manually
318 if (!(wdata->reparented)) {
319 wdata->reparented = True;
320 // in XAWT we also update WM_NORMAL_HINTS here.
321 }
322 {
323 struct WidgetInfo* winfo =
324 findWidgetInfo(wdata->winData.comp.widget);
325 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_4);
326 if (winfo != NULL) {
327 callNotifyStarted(env, winfo->peer);
328 }
329 }
330 MTRACE("Embedded notify in client\n");
331 break;
332 case XEMBED_WINDOW_DEACTIVATE:
333 MTRACE("DEACTIVATE\n");
334 data->applicationActive = False;
335 break;
336 case XEMBED_WINDOW_ACTIVATE:
337 MTRACE("ACTIVATE\n");
338 data->applicationActive = True;
339 break;
340 case XEMBED_FOCUS_IN:
341 MTRACE("FOCUS IN\n");
342 skipNextFocusIn = False;
343 handleFocusIn(wdata, (int)(event->xclient.data.l[2]));
344 genWindowFocus(wdata, True);
345 break;
346 case XEMBED_FOCUS_OUT:
347 MTRACE("FOCUS OUT\n");
348 genWindowFocus(wdata, False);
349 break;
350 }
351 }
352 } else if (event->xany.type == ReparentNotify) {
353 data->embedder = event->xreparent.parent;
354 }
355}
356
357void
358notify_ready(Window client) {
359 sendMessage(getEmbedder(client), _SUN_XEMBED_START);
360}
361
362void
363install_xembed(Widget client_widget, struct FrameData* wdata) {
364 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
365 xembed_info info = {XEMBED_VERSION, XEMBED_MAPPED};
366 Window client = XtWindow(client_widget);
367 xembed_data * data;
368
369 AWT_LOCK();
370 data = addData(client);
371 data->wdata = wdata;
372
373 // Install event handler for messages from embedder
374 XSelectInput(awt_display, client, StructureNotifyMask);
375
376 // Install XEMBED_INFO information
377 XChangeProperty(awt_display, client, XA_XEmbedInfo,
378 XA_XEmbedInfo, 32, PropModeReplace,
379 (unsigned char*)&info, 2);
380 MTRACE("Installing xembed\n");
381
382 notify_ready(client);
383
384 AWT_UNLOCK();
385}
386
387void
388deinstall_xembed(struct FrameData* wdata) {
389 xembed_data * data = getDataByFrame(wdata);
390
391 if (data != NULL) {
392 removeData(data->client);
393 }
394}
395
396void
397requestXEmbedFocus(struct FrameData * wdata) {
398 xembed_data * data = getDataByFrame(wdata);
399
400 if (data != NULL) {
401 if (data->active && data->applicationActive) {
402 sendMessage(data->embedder, XEMBED_REQUEST_FOCUS);
403 }
404 }
405}
406
407Boolean
408isXEmbedActive(struct FrameData * wdata) {
409 xembed_data * data = getDataByFrame(wdata);
410 return (data != NULL && data->active);
411}
412
413Boolean
414isXEmbedActiveByWindow(Window client) {
415 xembed_data * data = getData(client);
416 return (data != NULL && data->active);
417}
418
419
420Boolean
421isXEmbedApplicationActive(struct FrameData * wdata) {
422 xembed_data * data = getDataByFrame(wdata);
423 return (data != NULL && data->applicationActive);
424}
425
426void
427xembed_traverse_out(struct FrameData * wdata, jboolean direction) {
428 xembed_data * data = getDataByFrame(wdata);
429 sendMessage(data->embedder, (direction == JNI_TRUE)?XEMBED_FOCUS_NEXT:XEMBED_FOCUS_PREV);
430}