widget/gtkxtbin/gtk2xtbin.c

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

mercurial