Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: set expandtab shiftwidth=2 tabstop=2: */
3 :
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : /*
9 : * The GtkXtBin widget allows for Xt toolkit code to be used
10 : * inside a GTK application.
11 : */
12 :
13 : #include "xembed.h"
14 : #include "gtk2xtbin.h"
15 : #include <gtk/gtk.h>
16 : #include <gdk/gdkx.h>
17 : #include <glib.h>
18 : #include <assert.h>
19 : #include <sys/time.h>
20 : #include <sys/types.h>
21 : #include <stdio.h>
22 : #include <stdlib.h>
23 : #include <unistd.h>
24 :
25 : /* Xlib/Xt stuff */
26 : #include <X11/Xlib.h>
27 : #include <X11/Xutil.h>
28 : #include <X11/Shell.h>
29 : #include <X11/Intrinsic.h>
30 : #include <X11/StringDefs.h>
31 :
32 : /* uncomment this if you want debugging information about widget
33 : creation and destruction */
34 : #undef DEBUG_XTBIN
35 :
36 : #define XTBIN_MAX_EVENTS 30
37 :
38 : static void gtk_xtbin_class_init (GtkXtBinClass *klass);
39 : static void gtk_xtbin_init (GtkXtBin *xtbin);
40 : static void gtk_xtbin_realize (GtkWidget *widget);
41 : static void gtk_xtbin_unrealize (GtkWidget *widget);
42 : static void gtk_xtbin_destroy (GtkObject *object);
43 :
44 : /* Xt aware XEmbed */
45 : static void xt_client_handle_xembed_message (Widget w,
46 : XtPointer client_data,
47 : XEvent *event);
48 : static void xt_add_focus_listener( Widget w, XtPointer user_data );
49 : static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data);
50 : static void xt_remove_focus_listener(Widget w, XtPointer user_data);
51 : static void xt_client_event_handler (Widget w, XtPointer client_data, XEvent *event);
52 : static void xt_client_focus_listener (Widget w, XtPointer user_data, XEvent *event);
53 : static void xt_client_set_info (Widget xtplug, unsigned long flags);
54 : static void send_xembed_message (XtClient *xtclient,
55 : long message,
56 : long detail,
57 : long data1,
58 : long data2,
59 : long time);
60 : static int error_handler (Display *display,
61 : XErrorEvent *error);
62 : /* For error trap of XEmbed */
63 : static void trap_errors(void);
64 : static int untrap_error(void);
65 : static int (*old_error_handler) (Display *, XErrorEvent *);
66 : static int trapped_error_code = 0;
67 :
68 : static GtkWidgetClass *parent_class = NULL;
69 :
70 : static Display *xtdisplay = NULL;
71 : static String *fallback = NULL;
72 : static gboolean xt_is_initialized = FALSE;
73 : static gint num_widgets = 0;
74 :
75 : static GPollFD xt_event_poll_fd;
76 : static gint xt_polling_timer_id = 0;
77 : static guint tag = 0;
78 :
79 : static gboolean
80 0 : xt_event_prepare (GSource* source_data,
81 : gint *timeout)
82 : {
83 : int mask;
84 :
85 0 : mask = XPending(xtdisplay);
86 :
87 0 : return (gboolean)mask;
88 : }
89 :
90 : static gboolean
91 0 : xt_event_check (GSource* source_data)
92 : {
93 0 : if (xt_event_poll_fd.revents & G_IO_IN) {
94 : int mask;
95 0 : mask = XPending(xtdisplay);
96 0 : return (gboolean)mask;
97 : }
98 :
99 0 : return FALSE;
100 : }
101 :
102 : static gboolean
103 0 : xt_event_dispatch (GSource* source_data,
104 : GSourceFunc call_back,
105 : gpointer user_data)
106 : {
107 : XtAppContext ac;
108 0 : int i = 0;
109 :
110 0 : ac = XtDisplayToApplicationContext(xtdisplay);
111 :
112 : /* Process only real X traffic here. We only look for data on the
113 : * pipe, limit it to XTBIN_MAX_EVENTS and only call
114 : * XtAppProcessEvent so that it will look for X events. There's no
115 : * timer processing here since we already have a timer callback that
116 : * does it. */
117 0 : for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
118 0 : XtAppProcessEvent(ac, XtIMXEvent);
119 : }
120 :
121 0 : return TRUE;
122 : }
123 :
124 : static GSourceFuncs xt_event_funcs = {
125 : xt_event_prepare,
126 : xt_event_check,
127 : xt_event_dispatch,
128 : NULL,
129 : (GSourceFunc)NULL,
130 : (GSourceDummyMarshal)NULL
131 : };
132 :
133 : static gboolean
134 0 : xt_event_polling_timer_callback(gpointer user_data)
135 : {
136 : Display * display;
137 : XtAppContext ac;
138 0 : int eventsToProcess = 20;
139 :
140 0 : display = (Display *)user_data;
141 0 : ac = XtDisplayToApplicationContext(display);
142 :
143 : /* We need to process many Xt events here. If we just process
144 : one event we might starve one or more Xt consumers. On the other hand
145 : this could hang the whole app if Xt events come pouring in. So process
146 : up to 20 Xt events right now and save the rest for later. This is a hack,
147 : but it oughta work. We *really* should have out of process plugins.
148 : */
149 0 : while (eventsToProcess-- && XtAppPending(ac))
150 0 : XtAppProcessEvent(ac, XtIMAll);
151 0 : return TRUE;
152 : }
153 :
154 : GType
155 0 : gtk_xtbin_get_type (void)
156 : {
157 : static GType xtbin_type = 0;
158 :
159 0 : if (!xtbin_type) {
160 : static const GTypeInfo xtbin_info =
161 : {
162 : sizeof (GtkXtBinClass), /* class_size */
163 : NULL, /* base_init */
164 : NULL, /* base_finalize */
165 : (GClassInitFunc) gtk_xtbin_class_init, /* class_init */
166 : NULL, /* class_finalize */
167 : NULL, /* class_data */
168 : sizeof (GtkXtBin), /* instance_size */
169 : 0, /* n_preallocs */
170 : (GInstanceInitFunc) gtk_xtbin_init, /* instance_init */
171 : NULL /* value_table */
172 : };
173 0 : xtbin_type = g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin",
174 : &xtbin_info, 0);
175 : }
176 0 : return xtbin_type;
177 : }
178 :
179 : static void
180 0 : gtk_xtbin_class_init (GtkXtBinClass *klass)
181 : {
182 : GtkWidgetClass *widget_class;
183 : GtkObjectClass *object_class;
184 :
185 0 : parent_class = g_type_class_peek_parent(klass);
186 :
187 0 : widget_class = GTK_WIDGET_CLASS (klass);
188 0 : widget_class->realize = gtk_xtbin_realize;
189 0 : widget_class->unrealize = gtk_xtbin_unrealize;
190 :
191 0 : object_class = GTK_OBJECT_CLASS (klass);
192 0 : object_class->destroy = gtk_xtbin_destroy;
193 0 : }
194 :
195 : static void
196 0 : gtk_xtbin_init (GtkXtBin *xtbin)
197 : {
198 0 : xtbin->xtdisplay = NULL;
199 0 : xtbin->parent_window = NULL;
200 0 : xtbin->xtwindow = 0;
201 0 : }
202 :
203 : static void
204 0 : gtk_xtbin_realize (GtkWidget *widget)
205 : {
206 : GtkXtBin *xtbin;
207 0 : GtkAllocation allocation = { 0, 0, 200, 200 };
208 : gint x, y, w, h, d; /* geometry of window */
209 :
210 : #ifdef DEBUG_XTBIN
211 : printf("gtk_xtbin_realize()\n");
212 : #endif
213 :
214 0 : g_return_if_fail (GTK_IS_XTBIN (widget));
215 :
216 0 : xtbin = GTK_XTBIN (widget);
217 :
218 : /* caculate the allocation before realize */
219 0 : gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
220 0 : allocation.width = w;
221 0 : allocation.height = h;
222 0 : gtk_widget_size_allocate (widget, &allocation);
223 :
224 : #ifdef DEBUG_XTBIN
225 : printf("initial allocation %d %d %d %d\n", x, y, w, h);
226 : #endif
227 :
228 : /* use GtkSocket's realize */
229 0 : (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
230 :
231 : /* create the Xt client widget */
232 0 : xt_client_create(&(xtbin->xtclient),
233 0 : gtk_socket_get_id(GTK_SOCKET(xtbin)),
234 : h, w);
235 0 : xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
236 :
237 0 : gdk_flush();
238 :
239 : /* now that we have created the xt client, add it to the socket. */
240 0 : gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
241 : }
242 :
243 :
244 :
245 : GtkWidget*
246 0 : gtk_xtbin_new (GdkWindow *parent_window, String * f)
247 : {
248 : GtkXtBin *xtbin;
249 : gpointer user_data;
250 :
251 0 : assert(parent_window != NULL);
252 0 : xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
253 :
254 0 : if (!xtbin)
255 0 : return (GtkWidget*)NULL;
256 :
257 0 : if (f)
258 0 : fallback = f;
259 :
260 : /* Initialize the Xt toolkit */
261 0 : xtbin->parent_window = parent_window;
262 :
263 0 : xt_client_init(&(xtbin->xtclient),
264 : GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()),
265 : GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()),
266 0 : gdk_rgb_get_visual()->depth);
267 :
268 0 : if (!xtbin->xtclient.xtdisplay) {
269 : /* If XtOpenDisplay failed, we can't go any further.
270 : * Bail out.
271 : */
272 : #ifdef DEBUG_XTBIN
273 : printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
274 : #endif
275 0 : g_free (xtbin);
276 0 : return (GtkWidget *)NULL;
277 : }
278 :
279 : /* Launch X event loop */
280 0 : xt_client_xloop_create();
281 :
282 : /* Build the hierachy */
283 0 : xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
284 0 : gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
285 0 : gdk_window_get_user_data(xtbin->parent_window, &user_data);
286 0 : if (user_data)
287 0 : gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
288 :
289 : /* This GtkSocket has a visible window, but the Xt plug will cover this
290 : * window. Normally GtkSockets let the X server paint their background and
291 : * this would happen immediately (before the plug is mapped). Setting the
292 : * background to None prevents the server from painting this window,
293 : * avoiding flicker.
294 : */
295 0 : gtk_widget_realize(GTK_WIDGET(xtbin));
296 0 : gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE);
297 :
298 0 : return GTK_WIDGET (xtbin);
299 : }
300 :
301 : static void
302 0 : gtk_xtbin_unrealize (GtkWidget *object)
303 : {
304 : GtkXtBin *xtbin;
305 : GtkWidget *widget;
306 :
307 : #ifdef DEBUG_XTBIN
308 : printf("gtk_xtbin_unrealize()\n");
309 : #endif
310 :
311 : /* gtk_object_destroy() will already hold a refcount on object
312 : */
313 0 : xtbin = GTK_XTBIN(object);
314 0 : widget = GTK_WIDGET(object);
315 :
316 0 : GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
317 0 : if (GTK_WIDGET_REALIZED (widget)) {
318 0 : xt_client_unrealize(&(xtbin->xtclient));
319 : }
320 :
321 0 : (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
322 0 : }
323 :
324 : static void
325 0 : gtk_xtbin_destroy (GtkObject *object)
326 : {
327 : GtkXtBin *xtbin;
328 :
329 : #ifdef DEBUG_XTBIN
330 : printf("gtk_xtbin_destroy()\n");
331 : #endif
332 :
333 0 : g_return_if_fail (object != NULL);
334 0 : g_return_if_fail (GTK_IS_XTBIN (object));
335 :
336 0 : xtbin = GTK_XTBIN (object);
337 :
338 0 : if(xtbin->xtwindow) {
339 : /* remove the event handler */
340 0 : xt_client_destroy(&(xtbin->xtclient));
341 0 : xtbin->xtwindow = 0;
342 :
343 : /* stop X event loop */
344 0 : xt_client_xloop_destroy();
345 : }
346 :
347 0 : GTK_OBJECT_CLASS(parent_class)->destroy(object);
348 : }
349 :
350 : /*
351 : * Following is the implementation of Xt XEmbedded for client side
352 : */
353 :
354 : /* Initial Xt plugin */
355 : void
356 0 : xt_client_init( XtClient * xtclient,
357 : Visual *xtvisual,
358 : Colormap xtcolormap,
359 : int xtdepth)
360 : {
361 : XtAppContext app_context;
362 : char *mArgv[1];
363 0 : int mArgc = 0;
364 :
365 : /*
366 : * Initialize Xt stuff
367 : */
368 0 : xtclient->top_widget = NULL;
369 0 : xtclient->child_widget = NULL;
370 0 : xtclient->xtdisplay = NULL;
371 0 : xtclient->xtvisual = NULL;
372 0 : xtclient->xtcolormap = 0;
373 0 : xtclient->xtdepth = 0;
374 :
375 0 : if (!xt_is_initialized) {
376 : #ifdef DEBUG_XTBIN
377 : printf("starting up Xt stuff\n");
378 : #endif
379 0 : XtToolkitInitialize();
380 0 : app_context = XtCreateApplicationContext();
381 0 : if (fallback)
382 0 : XtAppSetFallbackResources(app_context, fallback);
383 :
384 0 : xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
385 : "Wrapper", NULL, 0, &mArgc, mArgv);
386 0 : if (xtdisplay)
387 0 : xt_is_initialized = TRUE;
388 : }
389 0 : xtclient->xtdisplay = xtdisplay;
390 0 : xtclient->xtvisual = xtvisual;
391 0 : xtclient->xtcolormap = xtcolormap;
392 0 : xtclient->xtdepth = xtdepth;
393 0 : }
394 :
395 : void
396 0 : xt_client_xloop_create(void)
397 : {
398 : /* If this is the first running widget, hook this display into the
399 : mainloop */
400 0 : if (0 == num_widgets) {
401 : int cnumber;
402 : GSource* gs;
403 :
404 : /* Set up xtdisplay in case we're missing one */
405 0 : if (!xtdisplay) {
406 0 : (void)xt_client_get_display();
407 : }
408 :
409 : /*
410 : * hook Xt event loop into the glib event loop.
411 : */
412 : /* the assumption is that gtk_init has already been called */
413 0 : gs = g_source_new(&xt_event_funcs, sizeof(GSource));
414 0 : if (!gs) {
415 0 : return;
416 : }
417 :
418 0 : g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
419 0 : g_source_set_can_recurse(gs, TRUE);
420 0 : tag = g_source_attach(gs, (GMainContext*)NULL);
421 0 : g_source_unref(gs);
422 : #ifdef VMS
423 : cnumber = XConnectionNumber(xtdisplay);
424 : #else
425 0 : cnumber = ConnectionNumber(xtdisplay);
426 : #endif
427 0 : xt_event_poll_fd.fd = cnumber;
428 0 : xt_event_poll_fd.events = G_IO_IN;
429 0 : xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
430 :
431 0 : g_main_context_add_poll ((GMainContext*)NULL,
432 : &xt_event_poll_fd,
433 : G_PRIORITY_LOW);
434 : /* add a timer so that we can poll and process Xt timers */
435 0 : xt_polling_timer_id =
436 0 : g_timeout_add(25,
437 : (GtkFunction)xt_event_polling_timer_callback,
438 : xtdisplay);
439 : }
440 :
441 : /* Bump up our usage count */
442 0 : num_widgets++;
443 : }
444 :
445 : void
446 0 : xt_client_xloop_destroy(void)
447 : {
448 0 : num_widgets--; /* reduce our usage count */
449 :
450 : /* If this is the last running widget, remove the Xt display
451 : connection from the mainloop */
452 0 : if (0 == num_widgets) {
453 : #ifdef DEBUG_XTBIN
454 : printf("removing the Xt connection from the main loop\n");
455 : #endif
456 0 : g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
457 0 : g_source_remove(tag);
458 :
459 0 : g_source_remove(xt_polling_timer_id);
460 0 : xt_polling_timer_id = 0;
461 : }
462 0 : }
463 :
464 : /* Get Xt Client display */
465 : Display *
466 0 : xt_client_get_display(void)
467 : {
468 0 : if (!xtdisplay) {
469 : XtClient tmp;
470 0 : xt_client_init(&tmp,NULL,0,0);
471 : }
472 0 : return xtdisplay;
473 : }
474 :
475 : /* Create the Xt client widgets
476 : * */
477 : void
478 0 : xt_client_create ( XtClient* xtclient ,
479 : Window embedderid,
480 : int height,
481 : int width )
482 : {
483 : int n;
484 : Arg args[6];
485 : Widget child_widget;
486 : Widget top_widget;
487 :
488 : #ifdef DEBUG_XTBIN
489 : printf("xt_client_create() \n");
490 : #endif
491 0 : top_widget = XtAppCreateShell("drawingArea", "Wrapper",
492 : applicationShellWidgetClass,
493 : xtclient->xtdisplay,
494 : NULL, 0);
495 0 : xtclient->top_widget = top_widget;
496 :
497 : /* set size of Xt window */
498 0 : n = 0;
499 0 : XtSetArg(args[n], XtNheight, height);n++;
500 0 : XtSetArg(args[n], XtNwidth, width);n++;
501 0 : XtSetValues(top_widget, args, n);
502 :
503 0 : child_widget = XtVaCreateWidget("form",
504 : compositeWidgetClass,
505 : top_widget, NULL);
506 :
507 0 : n = 0;
508 0 : XtSetArg(args[n], XtNheight, height);n++;
509 0 : XtSetArg(args[n], XtNwidth, width);n++;
510 0 : XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++;
511 0 : XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++;
512 0 : XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
513 0 : XtSetArg(args[n], XtNborderWidth, 0); n++;
514 0 : XtSetValues(child_widget, args, n);
515 :
516 0 : XSync(xtclient->xtdisplay, FALSE);
517 0 : xtclient->oldwindow = top_widget->core.window;
518 0 : top_widget->core.window = embedderid;
519 :
520 : /* this little trick seems to finish initializing the widget */
521 : #if XlibSpecificationRelease >= 6
522 0 : XtRegisterDrawable(xtclient->xtdisplay,
523 : embedderid,
524 : top_widget);
525 : #else
526 : _XtRegisterWindow( embedderid,
527 : top_widget);
528 : #endif
529 0 : XtRealizeWidget(child_widget);
530 :
531 : /* listen to all Xt events */
532 0 : XSelectInput(xtclient->xtdisplay,
533 : embedderid,
534 0 : XtBuildEventMask(top_widget));
535 0 : xt_client_set_info (child_widget, 0);
536 :
537 0 : XtManageChild(child_widget);
538 0 : xtclient->child_widget = child_widget;
539 :
540 : /* set the event handler */
541 0 : XtAddEventHandler(child_widget,
542 : StructureNotifyMask | KeyPressMask,
543 : TRUE,
544 : (XtEventHandler)xt_client_event_handler, xtclient);
545 0 : XtAddEventHandler(child_widget,
546 : SubstructureNotifyMask | ButtonReleaseMask,
547 : FALSE,
548 : (XtEventHandler)xt_client_focus_listener,
549 : xtclient);
550 0 : XSync(xtclient->xtdisplay, FALSE);
551 0 : }
552 :
553 : void
554 0 : xt_client_unrealize ( XtClient* xtclient )
555 : {
556 : /* Explicitly destroy the child_widget window because this is actually a
557 : child of the socket window. It is not a child of top_widget's window
558 : when that is destroyed. */
559 0 : XtUnrealizeWidget(xtclient->child_widget);
560 :
561 : #if XlibSpecificationRelease >= 6
562 0 : XtUnregisterDrawable(xtclient->xtdisplay,
563 0 : xtclient->top_widget->core.window);
564 : #else
565 : _XtUnregisterWindow(xtclient->top_widget->core.window,
566 : xtclient->top_widget);
567 : #endif
568 :
569 : /* flush the queue before we returning origin top_widget->core.window
570 : or we can get X error since the window is gone */
571 0 : XSync(xtclient->xtdisplay, False);
572 :
573 0 : xtclient->top_widget->core.window = xtclient->oldwindow;
574 0 : XtUnrealizeWidget(xtclient->top_widget);
575 0 : }
576 :
577 : void
578 0 : xt_client_destroy (XtClient* xtclient)
579 : {
580 0 : if(xtclient->top_widget) {
581 0 : XtRemoveEventHandler(xtclient->child_widget,
582 : StructureNotifyMask | KeyPressMask,
583 : TRUE,
584 : (XtEventHandler)xt_client_event_handler, xtclient);
585 0 : XtDestroyWidget(xtclient->top_widget);
586 0 : xtclient->top_widget = NULL;
587 : }
588 0 : }
589 :
590 : void
591 0 : xt_client_set_info (Widget xtplug, unsigned long flags)
592 : {
593 : unsigned long buffer[2];
594 :
595 0 : Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
596 :
597 0 : buffer[1] = 0; /* Protocol version */
598 0 : buffer[1] = flags;
599 :
600 0 : XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
601 : infoAtom, infoAtom, 32,
602 : PropModeReplace,
603 : (unsigned char *)buffer, 2);
604 0 : }
605 :
606 : static void
607 0 : xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
608 : {
609 0 : XtClient *xtplug = (XtClient*)client_data;
610 0 : switch (event->xclient.data.l[1])
611 : {
612 : case XEMBED_EMBEDDED_NOTIFY:
613 0 : break;
614 : case XEMBED_WINDOW_ACTIVATE:
615 : #ifdef DEBUG_XTBIN
616 : printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
617 : #endif
618 0 : break;
619 : case XEMBED_WINDOW_DEACTIVATE:
620 : #ifdef DEBUG_XTBIN
621 : printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
622 : #endif
623 0 : break;
624 : case XEMBED_MODALITY_ON:
625 : #ifdef DEBUG_XTBIN
626 : printf("Xt client get XEMBED_MODALITY_ON\n");
627 : #endif
628 0 : break;
629 : case XEMBED_MODALITY_OFF:
630 : #ifdef DEBUG_XTBIN
631 : printf("Xt client get XEMBED_MODALITY_OFF\n");
632 : #endif
633 0 : break;
634 : case XEMBED_FOCUS_IN:
635 : case XEMBED_FOCUS_OUT:
636 : {
637 : XEvent xevent;
638 0 : memset(&xevent, 0, sizeof(xevent));
639 :
640 0 : if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
641 : #ifdef DEBUG_XTBIN
642 : printf("XTEMBED got focus in\n");
643 : #endif
644 0 : xevent.xfocus.type = FocusIn;
645 : }
646 : else {
647 : #ifdef DEBUG_XTBIN
648 : printf("XTEMBED got focus out\n");
649 : #endif
650 0 : xevent.xfocus.type = FocusOut;
651 : }
652 :
653 0 : xevent.xfocus.window = XtWindow(xtplug->child_widget);
654 0 : xevent.xfocus.display = XtDisplay(xtplug->child_widget);
655 0 : XSendEvent(XtDisplay(xtplug->child_widget),
656 : xevent.xfocus.window,
657 : False, NoEventMask,
658 : &xevent );
659 0 : XSync( XtDisplay(xtplug->child_widget), False);
660 : }
661 0 : break;
662 : default:
663 0 : break;
664 : } /* End of XEmbed Message */
665 0 : }
666 :
667 : void
668 0 : xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
669 : {
670 0 : XtClient *xtplug = (XtClient*)client_data;
671 :
672 0 : switch(event->type)
673 : {
674 : case ClientMessage:
675 : /* Handle xembed message */
676 0 : if (event->xclient.message_type==
677 0 : XInternAtom (XtDisplay(xtplug->child_widget),
678 : "_XEMBED", False)) {
679 0 : xt_client_handle_xembed_message(w, client_data, event);
680 : }
681 0 : break;
682 : case ReparentNotify:
683 0 : break;
684 : case MappingNotify:
685 0 : xt_client_set_info (w, XEMBED_MAPPED);
686 0 : break;
687 : case UnmapNotify:
688 0 : xt_client_set_info (w, 0);
689 0 : break;
690 : case KeyPress:
691 : #ifdef DEBUG_XTBIN
692 : printf("Key Press Got!\n");
693 : #endif
694 0 : break;
695 : default:
696 0 : break;
697 : } /* End of switch(event->type) */
698 0 : }
699 :
700 : static void
701 0 : send_xembed_message (XtClient *xtclient,
702 : long message,
703 : long detail,
704 : long data1,
705 : long data2,
706 : long time)
707 : {
708 : XEvent xevent;
709 0 : Window w=XtWindow(xtclient->top_widget);
710 0 : Display* dpy=xtclient->xtdisplay;
711 : int errorcode;
712 :
713 0 : memset(&xevent,0,sizeof(xevent));
714 0 : xevent.xclient.window = w;
715 0 : xevent.xclient.type = ClientMessage;
716 0 : xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
717 0 : xevent.xclient.format = 32;
718 0 : xevent.xclient.data.l[0] = time;
719 0 : xevent.xclient.data.l[1] = message;
720 0 : xevent.xclient.data.l[2] = detail;
721 0 : xevent.xclient.data.l[3] = data1;
722 0 : xevent.xclient.data.l[4] = data2;
723 :
724 0 : trap_errors ();
725 0 : XSendEvent (dpy, w, False, NoEventMask, &xevent);
726 0 : XSync (dpy,False);
727 :
728 0 : if((errorcode = untrap_error())) {
729 : #ifdef DEBUG_XTBIN
730 : printf("send_xembed_message error(%d)!!!\n",errorcode);
731 : #endif
732 : }
733 0 : }
734 :
735 : static int
736 0 : error_handler(Display *display, XErrorEvent *error)
737 : {
738 0 : trapped_error_code = error->error_code;
739 0 : return 0;
740 : }
741 :
742 : static void
743 0 : trap_errors(void)
744 : {
745 0 : trapped_error_code =0;
746 0 : old_error_handler = XSetErrorHandler(error_handler);
747 0 : }
748 :
749 : static int
750 0 : untrap_error(void)
751 : {
752 0 : XSetErrorHandler(old_error_handler);
753 0 : if(trapped_error_code) {
754 : #ifdef DEBUG_XTBIN
755 : printf("Get X Window Error = %d\n", trapped_error_code);
756 : #endif
757 : }
758 0 : return trapped_error_code;
759 : }
760 :
761 : void
762 0 : xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
763 : {
764 0 : Display *dpy = XtDisplay(w);
765 0 : XtClient *xtclient = user_data;
766 0 : Window win = XtWindow(w);
767 :
768 0 : switch(event->type)
769 : {
770 : case CreateNotify:
771 0 : if(event->xcreatewindow.parent == win) {
772 0 : Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
773 0 : if (child)
774 0 : xt_add_focus_listener_tree(child, user_data);
775 : }
776 0 : break;
777 : case DestroyNotify:
778 0 : xt_remove_focus_listener( w, user_data);
779 0 : break;
780 : case ReparentNotify:
781 0 : if(event->xreparent.parent == win) {
782 : /* I am the new parent */
783 0 : Widget child=XtWindowToWidget(dpy, event->xreparent.window);
784 0 : if (child)
785 0 : xt_add_focus_listener_tree( child, user_data);
786 : }
787 0 : else if(event->xreparent.window == win) {
788 : /* I am the new child */
789 : }
790 : else {
791 : /* I am the old parent */
792 : }
793 0 : break;
794 : case ButtonRelease:
795 : #if 0
796 : XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
797 : #endif
798 0 : send_xembed_message ( xtclient,
799 : XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
800 0 : break;
801 : default:
802 0 : break;
803 : } /* End of switch(event->type) */
804 0 : }
805 :
806 : static void
807 0 : xt_add_focus_listener( Widget w, XtPointer user_data)
808 : {
809 0 : XtClient *xtclient = user_data;
810 :
811 0 : trap_errors ();
812 0 : XtAddEventHandler(w,
813 : SubstructureNotifyMask | ButtonReleaseMask,
814 : FALSE,
815 : (XtEventHandler)xt_client_focus_listener,
816 : xtclient);
817 0 : untrap_error();
818 0 : }
819 :
820 : static void
821 0 : xt_remove_focus_listener(Widget w, XtPointer user_data)
822 : {
823 0 : trap_errors ();
824 0 : XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE,
825 : (XtEventHandler)xt_client_focus_listener, user_data);
826 :
827 0 : untrap_error();
828 0 : }
829 :
830 : static void
831 0 : xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
832 : {
833 0 : Window win = XtWindow(treeroot);
834 : Window *children;
835 : Window root, parent;
836 0 : Display *dpy = XtDisplay(treeroot);
837 : unsigned int i, nchildren;
838 :
839 : /* ensure we don't add more than once */
840 0 : xt_remove_focus_listener( treeroot, user_data);
841 0 : xt_add_focus_listener( treeroot, user_data);
842 0 : trap_errors();
843 0 : if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
844 0 : untrap_error();
845 0 : return;
846 : }
847 :
848 0 : if(untrap_error())
849 0 : return;
850 :
851 0 : for(i=0; i<nchildren; ++i) {
852 0 : Widget child = XtWindowToWidget(dpy, children[i]);
853 0 : if (child)
854 0 : xt_add_focus_listener_tree( child, user_data);
855 : }
856 0 : XFree((void*)children);
857 :
858 0 : return;
859 : }
860 :
|