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