widget/gtkxtbin/gtk2xtbin.c

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

     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.  
    11  */
    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)
    83 {   
    84   int mask;
    86   GDK_THREADS_ENTER();
    87   mask = XPending(xtdisplay);
    88   GDK_THREADS_LEAVE();
    90   return (gboolean)mask;
    91 }
    93 static gboolean
    94 xt_event_check (GSource*  source_data)
    95 {
    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;
   103   }
   105   GDK_THREADS_LEAVE ();
   106   return FALSE;
   107 }   
   109 static gboolean
   110 xt_event_dispatch (GSource*  source_data,
   111                     GSourceFunc call_back,
   112                     gpointer  user_data)
   113 {
   114   XEvent event;
   115   XtAppContext ac;
   116   int i = 0;
   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);
   129   }
   131   GDK_THREADS_LEAVE ();
   133   return TRUE;  
   134 }
   136 static GSourceFuncs xt_event_funcs = {
   137   xt_event_prepare,
   138   xt_event_check,
   139   xt_event_dispatch,
   140   NULL,
   141   (GSourceFunc)NULL,
   142   (GSourceDummyMarshal)NULL
   143 };
   145 static gboolean
   146 xt_event_polling_timer_callback(gpointer user_data)
   147 {
   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.
   160   */
   161   while (eventsToProcess-- && XtAppPending(ac))
   162     XtAppProcessEvent(ac, XtIMAll);
   163   return TRUE;
   164 }
   166 GType
   167 gtk_xtbin_get_type (void)
   168 {
   169   static GType xtbin_type = 0;
   171   if (!xtbin_type) {
   172       static const GTypeInfo xtbin_info =
   173       {
   174         sizeof (GtkXtBinClass), /* class_size */
   175         NULL, /* base_init */
   176         NULL, /* base_finalize */
   177         (GClassInitFunc) gtk_xtbin_class_init, /* class_init */
   178         NULL, /* class_finalize */
   179         NULL, /* class_data */
   180         sizeof (GtkXtBin), /* instance_size */
   181         0, /* n_preallocs */
   182         (GInstanceInitFunc) gtk_xtbin_init, /* instance_init */
   183         NULL /* value_table */
   184       };
   185       xtbin_type = g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin",
   186         &xtbin_info, 0);
   187     }
   188   return xtbin_type;
   189 }
   191 static void
   192 gtk_xtbin_class_init (GtkXtBinClass *klass)
   193 {
   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;
   205 }
   207 static void
   208 gtk_xtbin_init (GtkXtBin *xtbin)
   209 {
   210   xtbin->xtdisplay = NULL;
   211   xtbin->parent_window = NULL;
   212   xtbin->xtwindow = 0;
   213 }
   215 static void
   216 gtk_xtbin_realize (GtkWidget *widget)
   217 {
   218   GtkXtBin     *xtbin;
   219   GtkAllocation allocation = { 0, 0, 200, 200 };
   220   gint  x, y, w, h, d; /* geometry of window */
   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);
   253 }
   257 GtkWidget*
   258 gtk_xtbin_new (GdkWindow *parent_window, String * f)
   259 {
   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.
   283      */
   284 #ifdef DEBUG_XTBIN
   285     printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
   286 #endif
   287     g_free (xtbin);
   288     return (GtkWidget *)NULL;
   289   }
   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.
   306    */
   307   gtk_widget_realize(GTK_WIDGET(xtbin));
   308   gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE);
   310   return GTK_WIDGET (xtbin);
   311 }
   313 static void
   314 gtk_xtbin_unrealize (GtkWidget *object)
   315 {
   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
   324    */
   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));
   331   }
   333   (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
   334 }
   336 static void
   337 gtk_xtbin_destroy (GtkObject *object)
   338 {
   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();
   357   }
   359   GTK_OBJECT_CLASS(parent_class)->destroy(object);
   360 }
   362 /*
   363 * Following is the implementation of Xt XEmbedded for client side
   364 */
   366 /* Initial Xt plugin */
   367 void
   368 xt_client_init( XtClient * xtclient, 
   369                 Visual *xtvisual, 
   370                 Colormap xtcolormap,
   371                 int xtdepth)
   372 {
   373   XtAppContext  app_context;
   374   char         *mArgv[1];
   375   int           mArgc = 0;
   377   /*
   378    * Initialize Xt stuff
   379    */
   380   xtclient->top_widget = NULL;
   381   xtclient->child_widget = NULL;
   382   xtclient->xtdisplay  = NULL;
   383   xtclient->xtvisual   = NULL;
   384   xtclient->xtcolormap = 0;
   385   xtclient->xtdepth = 0;
   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;
   400   }
   401   xtclient->xtdisplay  = xtdisplay;
   402   xtclient->xtvisual   = xtvisual;
   403   xtclient->xtcolormap = xtcolormap;
   404   xtclient->xtdepth    = xtdepth;
   405 }
   407 void
   408 xt_client_xloop_create(void)
   409 {
   410   /* If this is the first running widget, hook this display into the
   411      mainloop */
   412   if (0 == num_widgets) {
   413     int cnumber;
   414     GSource* gs;
   416     /* Set up xtdisplay in case we're missing one */
   417     if (!xtdisplay) {
   418       (void)xt_client_get_display();
   419     }
   421     /*
   422      * hook Xt event loop into the glib event loop.
   423      */
   424     /* the assumption is that gtk_init has already been called */
   425     gs = g_source_new(&xt_event_funcs, sizeof(GSource));
   426     if (!gs) {
   427       return;
   428     }
   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);
   451   }
   453   /* Bump up our usage count */
   454   num_widgets++;
   455 }
   457 void
   458 xt_client_xloop_destroy(void)
   459 {
   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;
   473   }
   474 }
   476 /* Get Xt Client display */
   477 Display	*
   478 xt_client_get_display(void)
   479 {
   480   if (!xtdisplay) {
   481     XtClient tmp;
   482     xt_client_init(&tmp,NULL,0,0);
   483   }
   484   return xtdisplay;
   485 }
   487 /* Create the Xt client widgets
   488 *  */
   489 void
   490 xt_client_create ( XtClient* xtclient , 
   491                    Window embedderid, 
   492                    int height, 
   493                    int width ) 
   494 {
   495   int           n;
   496   Arg           args[6];
   497   Widget        child_widget;
   498   Widget        top_widget;
   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);
   563 }
   565 void
   566 xt_client_unrealize ( XtClient* xtclient )
   567 {
   568   /* Explicitly destroy the child_widget window because this is actually a
   569      child of the socket window.  It is not a child of top_widget's window
   570      when that is destroyed. */
   571   XtUnrealizeWidget(xtclient->child_widget);
   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);
   587 }
   589 void            
   590 xt_client_destroy   (XtClient* xtclient)
   591 {
   592   if(xtclient->top_widget) {
   593     XtRemoveEventHandler(xtclient->child_widget,
   594                          StructureNotifyMask | KeyPressMask,
   595                          TRUE, 
   596                          (XtEventHandler)xt_client_event_handler, xtclient);
   597     XtDestroyWidget(xtclient->top_widget);
   598     xtclient->top_widget = NULL;
   599   }
   600 }
   602 void         
   603 xt_client_set_info (Widget xtplug, unsigned long flags)
   604 {
   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);
   616 }
   618 static void
   619 xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
   620 {
   621   XtClient *xtplug = (XtClient*)client_data;
   622   switch (event->xclient.data.l[1])
   623   {
   624   case XEMBED_EMBEDDED_NOTIFY:
   625     break;
   626   case XEMBED_WINDOW_ACTIVATE:
   627 #ifdef DEBUG_XTBIN
   628     printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
   629 #endif
   630     break;
   631   case XEMBED_WINDOW_DEACTIVATE:
   632 #ifdef DEBUG_XTBIN
   633     printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
   634 #endif
   635     break;
   636   case XEMBED_MODALITY_ON:
   637 #ifdef DEBUG_XTBIN
   638     printf("Xt client get XEMBED_MODALITY_ON\n");
   639 #endif
   640     break;
   641   case XEMBED_MODALITY_OFF:
   642 #ifdef DEBUG_XTBIN
   643     printf("Xt client get XEMBED_MODALITY_OFF\n");
   644 #endif
   645     break;
   646   case XEMBED_FOCUS_IN:
   647   case XEMBED_FOCUS_OUT:
   648     {
   649       XEvent xevent;
   650       memset(&xevent, 0, sizeof(xevent));
   652       if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
   653 #ifdef DEBUG_XTBIN
   654         printf("XTEMBED got focus in\n");
   655 #endif
   656         xevent.xfocus.type = FocusIn;
   657       }
   658       else {
   659 #ifdef DEBUG_XTBIN
   660         printf("XTEMBED got focus out\n");
   661 #endif
   662         xevent.xfocus.type = FocusOut;
   663       }
   665       xevent.xfocus.window = XtWindow(xtplug->child_widget);
   666       xevent.xfocus.display = XtDisplay(xtplug->child_widget);
   667       XSendEvent(XtDisplay(xtplug->child_widget), 
   668                  xevent.xfocus.window,
   669                  False, NoEventMask,
   670                  &xevent );
   671       XSync( XtDisplay(xtplug->child_widget), False);
   672     }
   673     break;
   674   default:
   675     break;
   676   } /* End of XEmbed Message */
   677 }
   679 void         
   680 xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
   681 {
   682   XtClient *xtplug = (XtClient*)client_data;
   684   switch(event->type)
   685     {
   686     case ClientMessage:
   687       /* Handle xembed message */
   688       if (event->xclient.message_type==
   689                  XInternAtom (XtDisplay(xtplug->child_widget),
   690                               "_XEMBED", False)) {
   691         xt_client_handle_xembed_message(w, client_data, event);
   692       }
   693       break;
   694     case ReparentNotify:
   695       break;
   696     case MappingNotify:
   697       xt_client_set_info (w, XEMBED_MAPPED);
   698       break;
   699     case UnmapNotify:
   700       xt_client_set_info (w, 0);
   701       break;
   702     case KeyPress:
   703 #ifdef DEBUG_XTBIN
   704       printf("Key Press Got!\n");
   705 #endif
   706       break;
   707     default:
   708       break;
   709     } /* End of switch(event->type) */
   710 }
   712 static void
   713 send_xembed_message (XtClient  *xtclient,
   714                      long      message,
   715                      long      detail, 
   716                      long      data1,  
   717                      long      data2,  
   718                      long      time)   
   719 {
   720   XEvent xevent; 
   721   Window w=XtWindow(xtclient->top_widget);
   722   Display* dpy=xtclient->xtdisplay;
   723   int errorcode;
   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
   744   }
   745 }
   747 static int             
   748 error_handler(Display *display, XErrorEvent *error)
   749 {
   750   trapped_error_code = error->error_code;
   751   return 0;
   752 }
   754 static void          
   755 trap_errors(void)
   756 {
   757   trapped_error_code =0;
   758   old_error_handler = XSetErrorHandler(error_handler);
   759 }
   761 static int         
   762 untrap_error(void)
   763 {
   764   XSetErrorHandler(old_error_handler);
   765   if(trapped_error_code) {
   766 #ifdef DEBUG_XTBIN
   767     printf("Get X Window Error = %d\n", trapped_error_code);
   768 #endif
   769   }
   770   return trapped_error_code;
   771 }
   773 void         
   774 xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
   775 {
   776   Display *dpy = XtDisplay(w);
   777   XtClient *xtclient = user_data;
   778   Window win = XtWindow(w);
   780   switch(event->type)
   781     {
   782     case CreateNotify:
   783       if(event->xcreatewindow.parent == win) {
   784         Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
   785         if (child)
   786           xt_add_focus_listener_tree(child, user_data);
   787       }
   788       break;
   789     case DestroyNotify:
   790       xt_remove_focus_listener( w, user_data);
   791       break;
   792     case ReparentNotify:
   793       if(event->xreparent.parent == win) {
   794         /* I am the new parent */
   795         Widget child=XtWindowToWidget(dpy, event->xreparent.window);
   796         if (child)
   797           xt_add_focus_listener_tree( child, user_data);
   798       }
   799       else if(event->xreparent.window == win) {
   800         /* I am the new child */
   801       }
   802       else {
   803         /* I am the old parent */
   804       }
   805       break;
   806     case ButtonRelease:
   807 #if 0
   808       XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
   809 #endif
   810       send_xembed_message ( xtclient,
   811                             XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
   812       break;
   813     default:
   814       break;
   815     } /* End of switch(event->type) */
   816 }
   818 static void
   819 xt_add_focus_listener( Widget w, XtPointer user_data)
   820 {
   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();
   830 }
   832 static void
   833 xt_remove_focus_listener(Widget w, XtPointer user_data)
   834 {
   835   trap_errors ();
   836   XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE, 
   837                       (XtEventHandler)xt_client_focus_listener, user_data);
   839   untrap_error();
   840 }
   842 static void
   843 xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data) 
   844 {
   845   Window win = XtWindow(treeroot);
   846   Window *children;
   847   Window root, parent;
   848   Display *dpy = XtDisplay(treeroot);
   849   unsigned int i, nchildren;
   851   /* ensure we don't add more than once */
   852   xt_remove_focus_listener( treeroot, user_data);
   853   xt_add_focus_listener( treeroot, user_data);
   854   trap_errors();
   855   if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
   856     untrap_error();
   857     return;
   858   }
   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);
   867   }
   868   XFree((void*)children);
   870   return;
   871 }

mercurial