Backed out changeset 838f865fa1c7 (bug 933231) for bustage on some platforms.
[gecko.git] / widget / gtkxtbin / gtk2xtbin.c
blob61244dd2706de0038c8adfb51cbf9e0e81ea5c50
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set expandtab shiftwidth=2 tabstop=2: */
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/. */
8 /*
9 * The GtkXtBin widget allows for Xt toolkit code to be used
10 * inside a GTK application.
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>
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>
32 /* uncomment this if you want debugging information about widget
33 creation and destruction */
34 #undef DEBUG_XTBIN
36 #define XTBIN_MAX_EVENTS 30
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);
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;
69 static GtkWidgetClass *parent_class = NULL;
71 static Display *xtdisplay = NULL;
72 static String *fallback = NULL;
73 static gboolean xt_is_initialized = FALSE;
74 static gint num_widgets = 0;
76 static GPollFD xt_event_poll_fd;
77 static gint xt_polling_timer_id = 0;
78 static guint tag = 0;
80 static gboolean
81 xt_event_prepare (GSource* source_data,
82 gint *timeout)
84 int mask;
86 GDK_THREADS_ENTER();
87 mask = XPending(xtdisplay);
88 GDK_THREADS_LEAVE();
90 return (gboolean)mask;
93 static gboolean
94 xt_event_check (GSource* source_data)
96 GDK_THREADS_ENTER ();
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;
105 GDK_THREADS_LEAVE ();
106 return FALSE;
109 static gboolean
110 xt_event_dispatch (GSource* source_data,
111 GSourceFunc call_back,
112 gpointer user_data)
114 XEvent event;
115 XtAppContext ac;
116 int i = 0;
118 ac = XtDisplayToApplicationContext(xtdisplay);
120 GDK_THREADS_ENTER ();
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);
131 GDK_THREADS_LEAVE ();
133 return TRUE;
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
145 static gboolean
146 xt_event_polling_timer_callback(gpointer user_data)
148 Display * display;
149 XtAppContext ac;
150 int eventsToProcess = 20;
152 display = (Display *)user_data;
153 ac = XtDisplayToApplicationContext(display);
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.
161 while (eventsToProcess-- && XtAppPending(ac))
162 XtAppProcessEvent(ac, XtIMAll);
163 return TRUE;
166 GType
167 gtk_xtbin_get_type (void)
169 static GType xtbin_type = 0;
171 if (!xtbin_type) {
172 static const GTypeInfo xtbin_info =
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 */
185 xtbin_type = g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin",
186 &xtbin_info, 0);
188 return xtbin_type;
191 static void
192 gtk_xtbin_class_init (GtkXtBinClass *klass)
194 GtkWidgetClass *widget_class;
195 GtkObjectClass *object_class;
197 parent_class = g_type_class_peek_parent(klass);
199 widget_class = GTK_WIDGET_CLASS (klass);
200 widget_class->realize = gtk_xtbin_realize;
201 widget_class->unrealize = gtk_xtbin_unrealize;
203 object_class = GTK_OBJECT_CLASS (klass);
204 object_class->destroy = gtk_xtbin_destroy;
207 static void
208 gtk_xtbin_init (GtkXtBin *xtbin)
210 xtbin->xtdisplay = NULL;
211 xtbin->parent_window = NULL;
212 xtbin->xtwindow = 0;
215 static void
216 gtk_xtbin_realize (GtkWidget *widget)
218 GtkXtBin *xtbin;
219 GtkAllocation allocation = { 0, 0, 200, 200 };
220 gint x, y, w, h, d; /* geometry of window */
222 #ifdef DEBUG_XTBIN
223 printf("gtk_xtbin_realize()\n");
224 #endif
226 g_return_if_fail (GTK_IS_XTBIN (widget));
228 xtbin = GTK_XTBIN (widget);
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);
236 #ifdef DEBUG_XTBIN
237 printf("initial allocation %d %d %d %d\n", x, y, w, h);
238 #endif
240 /* use GtkSocket's realize */
241 (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
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);
249 gdk_flush();
251 /* now that we have created the xt client, add it to the socket. */
252 gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
257 GtkWidget*
258 gtk_xtbin_new (GdkWindow *parent_window, String * f)
260 GtkXtBin *xtbin;
261 gpointer user_data;
263 assert(parent_window != NULL);
264 xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
266 if (!xtbin)
267 return (GtkWidget*)NULL;
269 if (f)
270 fallback = f;
272 /* Initialize the Xt toolkit */
273 xtbin->parent_window = parent_window;
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);
280 if (!xtbin->xtclient.xtdisplay) {
281 /* If XtOpenDisplay failed, we can't go any further.
282 * Bail out.
284 #ifdef DEBUG_XTBIN
285 printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
286 #endif
287 g_free (xtbin);
288 return (GtkWidget *)NULL;
291 /* Launch X event loop */
292 xt_client_xloop_create();
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));
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.
307 gtk_widget_realize(GTK_WIDGET(xtbin));
308 gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE);
310 return GTK_WIDGET (xtbin);
313 static void
314 gtk_xtbin_unrealize (GtkWidget *object)
316 GtkXtBin *xtbin;
317 GtkWidget *widget;
319 #ifdef DEBUG_XTBIN
320 printf("gtk_xtbin_unrealize()\n");
321 #endif
323 /* gtk_object_destroy() will already hold a refcount on object
325 xtbin = GTK_XTBIN(object);
326 widget = GTK_WIDGET(object);
328 GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
329 if (GTK_WIDGET_REALIZED (widget)) {
330 xt_client_unrealize(&(xtbin->xtclient));
333 (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
336 static void
337 gtk_xtbin_destroy (GtkObject *object)
339 GtkXtBin *xtbin;
341 #ifdef DEBUG_XTBIN
342 printf("gtk_xtbin_destroy()\n");
343 #endif
345 g_return_if_fail (object != NULL);
346 g_return_if_fail (GTK_IS_XTBIN (object));
348 xtbin = GTK_XTBIN (object);
350 if(xtbin->xtwindow) {
351 /* remove the event handler */
352 xt_client_destroy(&(xtbin->xtclient));
353 xtbin->xtwindow = 0;
355 /* stop X event loop */
356 xt_client_xloop_destroy();
359 GTK_OBJECT_CLASS(parent_class)->destroy(object);
363 * Following is the implementation of Xt XEmbedded for client side
366 /* Initial Xt plugin */
367 void
368 xt_client_init( XtClient * xtclient,
369 Visual *xtvisual,
370 Colormap xtcolormap,
371 int xtdepth)
373 XtAppContext app_context;
374 char *mArgv[1];
375 int mArgc = 0;
378 * Initialize Xt stuff
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;
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);
396 xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
397 "Wrapper", NULL, 0, &mArgc, mArgv);
398 if (xtdisplay)
399 xt_is_initialized = TRUE;
401 xtclient->xtdisplay = xtdisplay;
402 xtclient->xtvisual = xtvisual;
403 xtclient->xtcolormap = xtcolormap;
404 xtclient->xtdepth = xtdepth;
407 void
408 xt_client_xloop_create(void)
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;
416 /* Set up xtdisplay in case we're missing one */
417 if (!xtdisplay) {
418 (void)xt_client_get_display();
422 * hook Xt event loop into the glib event loop.
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;
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? */
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);
453 /* Bump up our usage count */
454 num_widgets++;
457 void
458 xt_client_xloop_destroy(void)
460 num_widgets--; /* reduce our usage count */
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);
471 g_source_remove(xt_polling_timer_id);
472 xt_polling_timer_id = 0;
476 /* Get Xt Client display */
477 Display *
478 xt_client_get_display(void)
480 if (!xtdisplay) {
481 XtClient tmp;
482 xt_client_init(&tmp,NULL,0,0);
484 return xtdisplay;
487 /* Create the Xt client widgets
488 * */
489 void
490 xt_client_create ( XtClient* xtclient ,
491 Window embedderid,
492 int height,
493 int width )
495 int n;
496 Arg args[6];
497 Widget child_widget;
498 Widget top_widget;
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;
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);
515 child_widget = XtVaCreateWidget("form",
516 compositeWidgetClass,
517 top_widget, NULL);
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);
528 XSync(xtclient->xtdisplay, FALSE);
529 xtclient->oldwindow = top_widget->core.window;
530 top_widget->core.window = embedderid;
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);
543 /* listen to all Xt events */
544 XSelectInput(xtclient->xtdisplay,
545 embedderid,
546 XtBuildEventMask(top_widget));
547 xt_client_set_info (child_widget, 0);
549 XtManageChild(child_widget);
550 xtclient->child_widget = child_widget;
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);
565 void
566 xt_client_unrealize ( XtClient* xtclient )
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);
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
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);
585 xtclient->top_widget->core.window = xtclient->oldwindow;
586 XtUnrealizeWidget(xtclient->top_widget);
589 void
590 xt_client_destroy (XtClient* xtclient)
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;
602 void
603 xt_client_set_info (Widget xtplug, unsigned long flags)
605 unsigned long buffer[2];
607 Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
609 buffer[1] = 0; /* Protocol version */
610 buffer[1] = flags;
612 XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
613 infoAtom, infoAtom, 32,
614 PropModeReplace,
615 (unsigned char *)buffer, 2);
618 static void
619 xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
621 XtClient *xtplug = (XtClient*)client_data;
622 switch (event->xclient.data.l[1])
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:
649 XEvent xevent;
650 memset(&xevent, 0, sizeof(xevent));
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;
658 else {
659 #ifdef DEBUG_XTBIN
660 printf("XTEMBED got focus out\n");
661 #endif
662 xevent.xfocus.type = FocusOut;
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);
673 break;
674 default:
675 break;
676 } /* End of XEmbed Message */
679 void
680 xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
682 XtClient *xtplug = (XtClient*)client_data;
684 switch(event->type)
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);
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) */
712 static void
713 send_xembed_message (XtClient *xtclient,
714 long message,
715 long detail,
716 long data1,
717 long data2,
718 long time)
720 XEvent xevent;
721 Window w=XtWindow(xtclient->top_widget);
722 Display* dpy=xtclient->xtdisplay;
723 int errorcode;
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;
736 trap_errors ();
737 XSendEvent (dpy, w, False, NoEventMask, &xevent);
738 XSync (dpy,False);
740 if((errorcode = untrap_error())) {
741 #ifdef DEBUG_XTBIN
742 printf("send_xembed_message error(%d)!!!\n",errorcode);
743 #endif
747 static int
748 error_handler(Display *display, XErrorEvent *error)
750 trapped_error_code = error->error_code;
751 return 0;
754 static void
755 trap_errors(void)
757 trapped_error_code =0;
758 old_error_handler = XSetErrorHandler(error_handler);
761 static int
762 untrap_error(void)
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
770 return trapped_error_code;
773 void
774 xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
776 Display *dpy = XtDisplay(w);
777 XtClient *xtclient = user_data;
778 Window win = XtWindow(w);
780 switch(event->type)
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);
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);
799 else if(event->xreparent.window == win) {
800 /* I am the new child */
802 else {
803 /* I am the old parent */
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) */
818 static void
819 xt_add_focus_listener( Widget w, XtPointer user_data)
821 XtClient *xtclient = user_data;
823 trap_errors ();
824 XtAddEventHandler(w,
825 SubstructureNotifyMask | ButtonReleaseMask,
826 FALSE,
827 (XtEventHandler)xt_client_focus_listener,
828 xtclient);
829 untrap_error();
832 static void
833 xt_remove_focus_listener(Widget w, XtPointer user_data)
835 trap_errors ();
836 XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE,
837 (XtEventHandler)xt_client_focus_listener, user_data);
839 untrap_error();
842 static void
843 xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
845 Window win = XtWindow(treeroot);
846 Window *children;
847 Window root, parent;
848 Display *dpy = XtDisplay(treeroot);
849 unsigned int i, nchildren;
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;
860 if(untrap_error())
861 return;
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);
868 XFree((void*)children);
870 return;