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