Bug 1624907 - Split tree.css into shadow and non-shadow stylesheets. r=dao
[gecko.git] / widget / gtkxtbin / gtk2xtbin.c
blobf4ef9755f7c425892754d715a3ab3718c927158d
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);
44 /* Xt aware XEmbed */
45 static void xt_client_handle_xembed_message(Widget w, XtPointer client_data,
46 XEvent* event);
47 static void xt_add_focus_listener(Widget w, XtPointer user_data);
48 static void xt_add_focus_listener_tree(Widget treeroot, XtPointer user_data);
49 static void xt_remove_focus_listener(Widget w, XtPointer user_data);
50 static void xt_client_event_handler(Widget w, XtPointer client_data,
51 XEvent* event);
52 static void xt_client_focus_listener(Widget w, XtPointer user_data,
53 XEvent* event);
54 static void xt_client_set_info(Widget xtplug, unsigned long flags);
55 static void send_xembed_message(XtClient* xtclient, long message, long detail,
56 long data1, long data2, long time);
57 static int error_handler(Display* display, XErrorEvent* error);
58 /* For error trap of XEmbed */
59 static void trap_errors(void);
60 static int untrap_error(void);
61 static int (*old_error_handler)(Display*, XErrorEvent*);
62 static int trapped_error_code = 0;
64 static GtkWidgetClass* parent_class = NULL;
66 static Display* xtdisplay = NULL;
67 static String* fallback = NULL;
68 static gboolean xt_is_initialized = FALSE;
69 static gint num_widgets = 0;
71 static GPollFD xt_event_poll_fd;
72 static gint xt_polling_timer_id = 0;
73 static guint tag = 0;
75 static gboolean xt_event_prepare(GSource* source_data, gint* timeout) {
76 int mask;
78 mask = XPending(xtdisplay);
80 return (gboolean)mask;
83 static gboolean xt_event_check(GSource* source_data) {
84 if (xt_event_poll_fd.revents & G_IO_IN) {
85 int mask;
86 mask = XPending(xtdisplay);
87 return (gboolean)mask;
90 return FALSE;
93 static gboolean xt_event_dispatch(GSource* source_data, GSourceFunc call_back,
94 gpointer user_data) {
95 XtAppContext ac;
96 int i = 0;
98 ac = XtDisplayToApplicationContext(xtdisplay);
100 /* Process only real X traffic here. We only look for data on the
101 * pipe, limit it to XTBIN_MAX_EVENTS and only call
102 * XtAppProcessEvent so that it will look for X events. There's no
103 * timer processing here since we already have a timer callback that
104 * does it. */
105 for (i = 0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
106 XtAppProcessEvent(ac, XtIMXEvent);
109 return TRUE;
112 static GSourceFuncs xt_event_funcs = {
113 xt_event_prepare, xt_event_check, xt_event_dispatch, NULL,
114 (GSourceFunc)NULL, (GSourceDummyMarshal)NULL};
116 static gboolean xt_event_polling_timer_callback(gpointer user_data) {
117 Display* display;
118 XtAppContext ac;
119 int eventsToProcess = 20;
121 display = (Display*)user_data;
122 ac = XtDisplayToApplicationContext(display);
124 /* We need to process many Xt events here. If we just process
125 one event we might starve one or more Xt consumers. On the other hand
126 this could hang the whole app if Xt events come pouring in. So process
127 up to 20 Xt events right now and save the rest for later. This is a hack,
128 but it oughta work. We *really* should have out of process plugins.
130 while (eventsToProcess-- && XtAppPending(ac)) XtAppProcessEvent(ac, XtIMAll);
131 return TRUE;
134 GType gtk_xtbin_get_type(void) {
135 static GType xtbin_type = 0;
137 if (!xtbin_type) {
138 static const GTypeInfo xtbin_info = {
139 sizeof(GtkXtBinClass), /* class_size */
140 NULL, /* base_init */
141 NULL, /* base_finalize */
142 (GClassInitFunc)gtk_xtbin_class_init, /* class_init */
143 NULL, /* class_finalize */
144 NULL, /* class_data */
145 sizeof(GtkXtBin), /* instance_size */
146 0, /* n_preallocs */
147 (GInstanceInitFunc)gtk_xtbin_init, /* instance_init */
148 NULL /* value_table */
150 xtbin_type =
151 g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin", &xtbin_info, 0);
153 return xtbin_type;
156 static void gtk_xtbin_class_init(GtkXtBinClass* klass) {
157 GtkWidgetClass* widget_class;
158 GtkObjectClass* object_class;
160 parent_class = g_type_class_peek_parent(klass);
162 widget_class = GTK_WIDGET_CLASS(klass);
163 widget_class->realize = gtk_xtbin_realize;
164 widget_class->unrealize = gtk_xtbin_unrealize;
166 object_class = GTK_OBJECT_CLASS(klass);
167 object_class->destroy = gtk_xtbin_destroy;
170 static void gtk_xtbin_init(GtkXtBin* xtbin) {
171 xtbin->xtdisplay = NULL;
172 xtbin->parent_window = NULL;
173 xtbin->xtwindow = 0;
176 static void gtk_xtbin_realize(GtkWidget* widget) {
177 GtkXtBin* xtbin;
178 GtkAllocation allocation = {0, 0, 200, 200};
179 gint x, y, w, h, d; /* geometry of window */
181 #ifdef DEBUG_XTBIN
182 printf("gtk_xtbin_realize()\n");
183 #endif
185 g_return_if_fail(GTK_IS_XTBIN(widget));
187 xtbin = GTK_XTBIN(widget);
189 /* caculate the allocation before realize */
190 gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
191 allocation.width = w;
192 allocation.height = h;
193 gtk_widget_size_allocate(widget, &allocation);
195 #ifdef DEBUG_XTBIN
196 printf("initial allocation %d %d %d %d\n", x, y, w, h);
197 #endif
199 /* use GtkSocket's realize */
200 (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
202 /* create the Xt client widget */
203 xt_client_create(&(xtbin->xtclient), gtk_socket_get_id(GTK_SOCKET(xtbin)), h,
205 xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
207 gdk_flush();
209 /* now that we have created the xt client, add it to the socket. */
210 gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
213 GtkWidget* gtk_xtbin_new(GdkWindow* parent_window, String* f) {
214 GtkXtBin* xtbin;
215 gpointer user_data;
217 assert(parent_window != NULL);
218 xtbin = g_object_new(GTK_TYPE_XTBIN, NULL);
220 if (!xtbin) return (GtkWidget*)NULL;
222 if (f) fallback = f;
224 /* Initialize the Xt toolkit */
225 xtbin->parent_window = parent_window;
227 xt_client_init(&(xtbin->xtclient), GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()),
228 GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()),
229 gdk_rgb_get_visual()->depth);
231 if (!xtbin->xtclient.xtdisplay) {
232 /* If XtOpenDisplay failed, we can't go any further.
233 * Bail out.
235 #ifdef DEBUG_XTBIN
236 printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
237 #endif
238 g_free(xtbin);
239 return (GtkWidget*)NULL;
242 /* Launch X event loop */
243 xt_client_xloop_create();
245 /* Build the hierachy */
246 xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
247 gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
248 gdk_window_get_user_data(xtbin->parent_window, &user_data);
249 if (user_data) gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
251 /* This GtkSocket has a visible window, but the Xt plug will cover this
252 * window. Normally GtkSockets let the X server paint their background and
253 * this would happen immediately (before the plug is mapped). Setting the
254 * background to None prevents the server from painting this window,
255 * avoiding flicker.
257 gtk_widget_realize(GTK_WIDGET(xtbin));
258 gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE);
260 return GTK_WIDGET(xtbin);
263 static void gtk_xtbin_unrealize(GtkWidget* object) {
264 GtkXtBin* xtbin;
265 GtkWidget* widget;
267 #ifdef DEBUG_XTBIN
268 printf("gtk_xtbin_unrealize()\n");
269 #endif
271 /* gtk_object_destroy() will already hold a refcount on object
273 xtbin = GTK_XTBIN(object);
274 widget = GTK_WIDGET(object);
276 GTK_WIDGET_UNSET_FLAGS(widget, GTK_VISIBLE);
277 if (GTK_WIDGET_REALIZED(widget)) {
278 xt_client_unrealize(&(xtbin->xtclient));
281 (*GTK_WIDGET_CLASS(parent_class)->unrealize)(widget);
284 static void gtk_xtbin_destroy(GtkObject* object) {
285 GtkXtBin* xtbin;
287 #ifdef DEBUG_XTBIN
288 printf("gtk_xtbin_destroy()\n");
289 #endif
291 g_return_if_fail(object != NULL);
292 g_return_if_fail(GTK_IS_XTBIN(object));
294 xtbin = GTK_XTBIN(object);
296 if (xtbin->xtwindow) {
297 /* remove the event handler */
298 xt_client_destroy(&(xtbin->xtclient));
299 xtbin->xtwindow = 0;
301 /* stop X event loop */
302 xt_client_xloop_destroy();
305 GTK_OBJECT_CLASS(parent_class)->destroy(object);
309 * Following is the implementation of Xt XEmbedded for client side
312 /* Initial Xt plugin */
313 void xt_client_init(XtClient* xtclient, Visual* xtvisual, Colormap xtcolormap,
314 int xtdepth) {
315 XtAppContext app_context;
316 char* mArgv[1];
317 int mArgc = 0;
320 * Initialize Xt stuff
322 xtclient->top_widget = NULL;
323 xtclient->child_widget = NULL;
324 xtclient->xtdisplay = NULL;
325 xtclient->xtvisual = NULL;
326 xtclient->xtcolormap = 0;
327 xtclient->xtdepth = 0;
329 if (!xt_is_initialized) {
330 #ifdef DEBUG_XTBIN
331 printf("starting up Xt stuff\n");
332 #endif
333 XtToolkitInitialize();
334 app_context = XtCreateApplicationContext();
335 if (fallback) XtAppSetFallbackResources(app_context, fallback);
337 xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL, "Wrapper",
338 NULL, 0, &mArgc, mArgv);
339 if (xtdisplay) xt_is_initialized = TRUE;
341 xtclient->xtdisplay = xtdisplay;
342 xtclient->xtvisual = xtvisual;
343 xtclient->xtcolormap = xtcolormap;
344 xtclient->xtdepth = xtdepth;
347 void xt_client_xloop_create(void) {
348 /* If this is the first running widget, hook this display into the
349 mainloop */
350 if (0 == num_widgets) {
351 int cnumber;
352 GSource* gs;
354 /* Set up xtdisplay in case we're missing one */
355 if (!xtdisplay) {
356 (void)xt_client_get_display();
360 * hook Xt event loop into the glib event loop.
362 /* the assumption is that gtk_init has already been called */
363 gs = g_source_new(&xt_event_funcs, sizeof(GSource));
364 if (!gs) {
365 return;
368 g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
369 g_source_set_can_recurse(gs, TRUE);
370 tag = g_source_attach(gs, (GMainContext*)NULL);
371 g_source_unref(gs);
372 #ifdef VMS
373 cnumber = XConnectionNumber(xtdisplay);
374 #else
375 cnumber = ConnectionNumber(xtdisplay);
376 #endif
377 xt_event_poll_fd.fd = cnumber;
378 xt_event_poll_fd.events = G_IO_IN;
379 xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
381 g_main_context_add_poll((GMainContext*)NULL, &xt_event_poll_fd,
382 G_PRIORITY_LOW);
383 /* add a timer so that we can poll and process Xt timers */
384 xt_polling_timer_id = g_timeout_add(
385 25, (GtkFunction)xt_event_polling_timer_callback, xtdisplay);
388 /* Bump up our usage count */
389 num_widgets++;
392 void xt_client_xloop_destroy(void) {
393 num_widgets--; /* reduce our usage count */
395 /* If this is the last running widget, remove the Xt display
396 connection from the mainloop */
397 if (0 == num_widgets) {
398 #ifdef DEBUG_XTBIN
399 printf("removing the Xt connection from the main loop\n");
400 #endif
401 g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
402 g_source_remove(tag);
404 g_source_remove(xt_polling_timer_id);
405 xt_polling_timer_id = 0;
409 /* Get Xt Client display */
410 Display* xt_client_get_display(void) {
411 if (!xtdisplay) {
412 XtClient tmp;
413 xt_client_init(&tmp, NULL, 0, 0);
415 return xtdisplay;
418 /* Create the Xt client widgets
419 * */
420 void xt_client_create(XtClient* xtclient, Window embedderid, int height,
421 int width) {
422 int n;
423 Arg args[6];
424 Widget child_widget;
425 Widget top_widget;
427 #ifdef DEBUG_XTBIN
428 printf("xt_client_create() \n");
429 #endif
430 top_widget =
431 XtAppCreateShell("drawingArea", "Wrapper", applicationShellWidgetClass,
432 xtclient->xtdisplay, NULL, 0);
433 xtclient->top_widget = top_widget;
435 /* set size of Xt window */
436 n = 0;
437 XtSetArg(args[n], XtNheight, height);
438 n++;
439 XtSetArg(args[n], XtNwidth, width);
440 n++;
441 XtSetValues(top_widget, args, n);
443 child_widget =
444 XtVaCreateWidget("form", compositeWidgetClass, top_widget, NULL);
446 n = 0;
447 XtSetArg(args[n], XtNheight, height);
448 n++;
449 XtSetArg(args[n], XtNwidth, width);
450 n++;
451 XtSetArg(args[n], XtNvisual, xtclient->xtvisual);
452 n++;
453 XtSetArg(args[n], XtNdepth, xtclient->xtdepth);
454 n++;
455 XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap);
456 n++;
457 XtSetArg(args[n], XtNborderWidth, 0);
458 n++;
459 XtSetValues(child_widget, args, n);
461 XSync(xtclient->xtdisplay, FALSE);
462 xtclient->oldwindow = top_widget->core.window;
463 top_widget->core.window = embedderid;
465 /* this little trick seems to finish initializing the widget */
466 #if XlibSpecificationRelease >= 6
467 XtRegisterDrawable(xtclient->xtdisplay, embedderid, top_widget);
468 #else
469 _XtRegisterWindow(embedderid, top_widget);
470 #endif
471 XtRealizeWidget(child_widget);
473 /* listen to all Xt events */
474 XSelectInput(xtclient->xtdisplay, embedderid, XtBuildEventMask(top_widget));
475 xt_client_set_info(child_widget, 0);
477 XtManageChild(child_widget);
478 xtclient->child_widget = child_widget;
480 /* set the event handler */
481 XtAddEventHandler(child_widget, StructureNotifyMask | KeyPressMask, TRUE,
482 (XtEventHandler)xt_client_event_handler, xtclient);
483 XtAddEventHandler(child_widget, SubstructureNotifyMask | ButtonReleaseMask,
484 FALSE, (XtEventHandler)xt_client_focus_listener, xtclient);
485 XSync(xtclient->xtdisplay, FALSE);
488 void xt_client_unrealize(XtClient* xtclient) {
489 /* Explicitly destroy the child_widget window because this is actually a
490 child of the socket window. It is not a child of top_widget's window
491 when that is destroyed. */
492 XtUnrealizeWidget(xtclient->child_widget);
494 #if XlibSpecificationRelease >= 6
495 XtUnregisterDrawable(xtclient->xtdisplay, xtclient->top_widget->core.window);
496 #else
497 _XtUnregisterWindow(xtclient->top_widget->core.window, xtclient->top_widget);
498 #endif
500 /* flush the queue before we returning origin top_widget->core.window
501 or we can get X error since the window is gone */
502 XSync(xtclient->xtdisplay, False);
504 xtclient->top_widget->core.window = xtclient->oldwindow;
505 XtUnrealizeWidget(xtclient->top_widget);
508 void xt_client_destroy(XtClient* xtclient) {
509 if (xtclient->top_widget) {
510 XtRemoveEventHandler(xtclient->child_widget,
511 StructureNotifyMask | KeyPressMask, TRUE,
512 (XtEventHandler)xt_client_event_handler, xtclient);
513 XtDestroyWidget(xtclient->top_widget);
514 xtclient->top_widget = NULL;
518 void xt_client_set_info(Widget xtplug, unsigned long flags) {
519 unsigned long buffer[2];
521 Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
523 buffer[1] = 0; /* Protocol version */
524 buffer[1] = flags;
526 XChangeProperty(XtDisplay(xtplug), XtWindow(xtplug), infoAtom, infoAtom, 32,
527 PropModeReplace, (unsigned char*)buffer, 2);
530 static void xt_client_handle_xembed_message(Widget w, XtPointer client_data,
531 XEvent* event) {
532 XtClient* xtplug = (XtClient*)client_data;
533 switch (event->xclient.data.l[1]) {
534 case XEMBED_EMBEDDED_NOTIFY:
535 break;
536 case XEMBED_WINDOW_ACTIVATE:
537 #ifdef DEBUG_XTBIN
538 printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
539 #endif
540 break;
541 case XEMBED_WINDOW_DEACTIVATE:
542 #ifdef DEBUG_XTBIN
543 printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
544 #endif
545 break;
546 case XEMBED_MODALITY_ON:
547 #ifdef DEBUG_XTBIN
548 printf("Xt client get XEMBED_MODALITY_ON\n");
549 #endif
550 break;
551 case XEMBED_MODALITY_OFF:
552 #ifdef DEBUG_XTBIN
553 printf("Xt client get XEMBED_MODALITY_OFF\n");
554 #endif
555 break;
556 case XEMBED_FOCUS_IN:
557 case XEMBED_FOCUS_OUT: {
558 XEvent xevent;
559 memset(&xevent, 0, sizeof(xevent));
561 if (event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
562 #ifdef DEBUG_XTBIN
563 printf("XTEMBED got focus in\n");
564 #endif
565 xevent.xfocus.type = FocusIn;
566 } else {
567 #ifdef DEBUG_XTBIN
568 printf("XTEMBED got focus out\n");
569 #endif
570 xevent.xfocus.type = FocusOut;
573 xevent.xfocus.window = XtWindow(xtplug->child_widget);
574 xevent.xfocus.display = XtDisplay(xtplug->child_widget);
575 XSendEvent(XtDisplay(xtplug->child_widget), xevent.xfocus.window, False,
576 NoEventMask, &xevent);
577 XSync(XtDisplay(xtplug->child_widget), False);
578 } break;
579 default:
580 break;
581 } /* End of XEmbed Message */
584 void xt_client_event_handler(Widget w, XtPointer client_data, XEvent* event) {
585 XtClient* xtplug = (XtClient*)client_data;
587 switch (event->type) {
588 case ClientMessage:
589 /* Handle xembed message */
590 if (event->xclient.message_type ==
591 XInternAtom(XtDisplay(xtplug->child_widget), "_XEMBED", False)) {
592 xt_client_handle_xembed_message(w, client_data, event);
594 break;
595 case ReparentNotify:
596 break;
597 case MappingNotify:
598 xt_client_set_info(w, XEMBED_MAPPED);
599 break;
600 case UnmapNotify:
601 xt_client_set_info(w, 0);
602 break;
603 case KeyPress:
604 #ifdef DEBUG_XTBIN
605 printf("Key Press Got!\n");
606 #endif
607 break;
608 default:
609 break;
610 } /* End of switch(event->type) */
613 static void send_xembed_message(XtClient* xtclient, long message, long detail,
614 long data1, long data2, long time) {
615 XEvent xevent;
616 Window w = XtWindow(xtclient->top_widget);
617 Display* dpy = xtclient->xtdisplay;
618 int errorcode;
620 memset(&xevent, 0, sizeof(xevent));
621 xevent.xclient.window = w;
622 xevent.xclient.type = ClientMessage;
623 xevent.xclient.message_type = XInternAtom(dpy, "_XEMBED", False);
624 xevent.xclient.format = 32;
625 xevent.xclient.data.l[0] = time;
626 xevent.xclient.data.l[1] = message;
627 xevent.xclient.data.l[2] = detail;
628 xevent.xclient.data.l[3] = data1;
629 xevent.xclient.data.l[4] = data2;
631 trap_errors();
632 XSendEvent(dpy, w, False, NoEventMask, &xevent);
633 XSync(dpy, False);
635 if ((errorcode = untrap_error())) {
636 #ifdef DEBUG_XTBIN
637 printf("send_xembed_message error(%d)!!!\n", errorcode);
638 #endif
642 static int error_handler(Display* display, XErrorEvent* error) {
643 trapped_error_code = error->error_code;
644 return 0;
647 static void trap_errors(void) {
648 trapped_error_code = 0;
649 old_error_handler = XSetErrorHandler(error_handler);
652 static int untrap_error(void) {
653 XSetErrorHandler(old_error_handler);
654 if (trapped_error_code) {
655 #ifdef DEBUG_XTBIN
656 printf("Get X Window Error = %d\n", trapped_error_code);
657 #endif
659 return trapped_error_code;
662 void xt_client_focus_listener(Widget w, XtPointer user_data, XEvent* event) {
663 Display* dpy = XtDisplay(w);
664 XtClient* xtclient = user_data;
665 Window win = XtWindow(w);
667 switch (event->type) {
668 case CreateNotify:
669 if (event->xcreatewindow.parent == win) {
670 Widget child = XtWindowToWidget(dpy, event->xcreatewindow.window);
671 if (child) xt_add_focus_listener_tree(child, user_data);
673 break;
674 case DestroyNotify:
675 xt_remove_focus_listener(w, user_data);
676 break;
677 case ReparentNotify:
678 if (event->xreparent.parent == win) {
679 /* I am the new parent */
680 Widget child = XtWindowToWidget(dpy, event->xreparent.window);
681 if (child) xt_add_focus_listener_tree(child, user_data);
682 } else if (event->xreparent.window == win) {
683 /* I am the new child */
684 } else {
685 /* I am the old parent */
687 break;
688 case ButtonRelease:
689 #if 0
690 XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
691 #endif
692 send_xembed_message(xtclient, XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
693 break;
694 default:
695 break;
696 } /* End of switch(event->type) */
699 static void xt_add_focus_listener(Widget w, XtPointer user_data) {
700 XtClient* xtclient = user_data;
702 trap_errors();
703 XtAddEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE,
704 (XtEventHandler)xt_client_focus_listener, xtclient);
705 untrap_error();
708 static void xt_remove_focus_listener(Widget w, XtPointer user_data) {
709 trap_errors();
710 XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE,
711 (XtEventHandler)xt_client_focus_listener, user_data);
713 untrap_error();
716 static void xt_add_focus_listener_tree(Widget treeroot, XtPointer user_data) {
717 Window win = XtWindow(treeroot);
718 Window* children;
719 Window root, parent;
720 Display* dpy = XtDisplay(treeroot);
721 unsigned int i, nchildren;
723 /* ensure we don't add more than once */
724 xt_remove_focus_listener(treeroot, user_data);
725 xt_add_focus_listener(treeroot, user_data);
726 trap_errors();
727 if (!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
728 untrap_error();
729 return;
732 if (untrap_error()) return;
734 for (i = 0; i < nchildren; ++i) {
735 Widget child = XtWindowToWidget(dpy, children[i]);
736 if (child) xt_add_focus_listener_tree(child, user_data);
738 XFree((void*)children);