Back to index

lightning-sunbird  0.9+nobinonly
gtk2xtbin.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  * vim:expandtab:shiftwidth=2:tabstop=2: */
00003  
00004 /* ***** BEGIN LICENSE BLOCK *****
00005  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00006  *
00007  * The contents of this file are subject to the Mozilla Public License Version
00008  * 1.1 (the "License"); you may not use this file except in compliance with
00009  * the License. You may obtain a copy of the License at
00010  * http://www.mozilla.org/MPL/
00011  *
00012  * Software distributed under the License is distributed on an "AS IS" basis,
00013  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00014  * for the specific language governing rights and limitations under the
00015  * License.
00016  *
00017  * The Original Code is the Gtk2XtBin Widget Implementation.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Sun Microsystems, Inc.
00021  * Portions created by the Initial Developer are Copyright (C) 2002
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039  
00040 /*
00041  * The GtkXtBin widget allows for Xt toolkit code to be used
00042  * inside a GTK application.  
00043  */
00044 
00045 #include "xembed.h"
00046 #include "gtk2xtbin.h"
00047 #include <gtk/gtkmain.h>
00048 #include <gtk/gtkprivate.h>
00049 #include <gdk/gdkx.h>
00050 #include <glib.h>
00051 #include <assert.h>
00052 #include <sys/time.h>
00053 #include <sys/types.h>
00054 #include <stdio.h>
00055 #include <stdlib.h>
00056 #include <unistd.h>
00057 
00058 /* Xlib/Xt stuff */
00059 #include <X11/Xlib.h>
00060 #include <X11/Xutil.h>
00061 #include <X11/Shell.h>
00062 #include <X11/Intrinsic.h>
00063 #include <X11/StringDefs.h>
00064 
00065 /* uncomment this if you want debugging information about widget
00066    creation and destruction */
00067 #undef DEBUG_XTBIN
00068 
00069 #define XTBIN_MAX_EVENTS 30
00070 
00071 static void            gtk_xtbin_class_init (GtkXtBinClass *klass);
00072 static void            gtk_xtbin_init       (GtkXtBin      *xtbin);
00073 static void            gtk_xtbin_realize    (GtkWidget      *widget);
00074 static void            gtk_xtbin_unrealize    (GtkWidget      *widget);
00075 static void            gtk_xtbin_destroy    (GtkObject      *object);
00076 static void            gtk_xtbin_shutdown   (GtkObject      *object);
00077 
00078 /* Xt aware XEmbed */
00079 static void       xt_client_init      (XtClient * xtclient, 
00080                                        Visual *xtvisual, 
00081                                        Colormap xtcolormap, 
00082                                        int xtdepth);
00083 static void       xt_client_create    (XtClient * xtclient, 
00084                                        Window embeder, 
00085                                        int height, 
00086                                        int width );
00087 static void       xt_client_unrealize (XtClient* xtclient);
00088 static void       xt_client_destroy   (XtClient* xtclient);
00089 static void       xt_client_set_info  (Widget xtplug, 
00090                                        unsigned long flags);
00091 static void       xt_client_event_handler (Widget w, 
00092                                            XtPointer client_data, 
00093                                            XEvent *event);
00094 static void       xt_client_handle_xembed_message (Widget w, 
00095                                                    XtPointer client_data, 
00096                                                    XEvent *event);
00097 static void       xt_client_focus_listener       (Widget w, 
00098                                                    XtPointer user_data, 
00099                                                    XEvent *event);
00100 static void       xt_add_focus_listener( Widget w, XtPointer user_data );
00101 static void       xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data); 
00102 static void       xt_remove_focus_listener(Widget w, XtPointer user_data);
00103 static void       send_xembed_message (XtClient *xtclient,
00104                                        long message, 
00105                                        long detail, 
00106                                        long data1, 
00107                                        long data2,
00108                                        long time);  
00109 static int        error_handler       (Display *display, 
00110                                        XErrorEvent *error);
00111 /* For error trap of XEmbed */
00112 static void       trap_errors(void);
00113 static int        untrap_error(void);
00114 static int        (*old_error_handler) (Display *, XErrorEvent *);
00115 static int        trapped_error_code = 0;
00116 
00117 static GtkWidgetClass *parent_class = NULL;
00118 
00119 static Display         *xtdisplay = NULL;
00120 static String          *fallback = NULL;
00121 static gboolean         xt_is_initialized = FALSE;
00122 static gint             num_widgets = 0;
00123 
00124 static GPollFD          xt_event_poll_fd;
00125 static gint             xt_polling_timer_id = 0;
00126 static guint            tag = 0;
00127 
00128 static gboolean
00129 xt_event_prepare (GSource*  source_data,
00130                    gint     *timeout)
00131 {   
00132   int mask;
00133 
00134   GDK_THREADS_ENTER();
00135   mask = XPending(xtdisplay);
00136   GDK_THREADS_LEAVE();
00137 
00138   return (gboolean)mask;
00139 }
00140 
00141 static gboolean
00142 xt_event_check (GSource*  source_data)
00143 {
00144   GDK_THREADS_ENTER ();
00145 
00146   if (xt_event_poll_fd.revents & G_IO_IN) {
00147     int mask;
00148     mask = XPending(xtdisplay);
00149     GDK_THREADS_LEAVE ();
00150     return (gboolean)mask;
00151   }
00152 
00153   GDK_THREADS_LEAVE ();
00154   return FALSE;
00155 }   
00156 
00157 static gboolean
00158 xt_event_dispatch (GSource*  source_data,
00159                     GSourceFunc call_back,
00160                     gpointer  user_data)
00161 {
00162   XEvent event;
00163   XtAppContext ac;
00164   int i = 0;
00165 
00166   ac = XtDisplayToApplicationContext(xtdisplay);
00167 
00168   GDK_THREADS_ENTER ();
00169 
00170   /* Process only real X traffic here.  We only look for data on the
00171    * pipe, limit it to XTBIN_MAX_EVENTS and only call
00172    * XtAppProcessEvent so that it will look for X events.  There's no
00173    * timer processing here since we already have a timer callback that
00174    * does it.  */
00175   for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
00176     XtAppProcessEvent(ac, XtIMXEvent);
00177   }
00178 
00179   GDK_THREADS_LEAVE ();
00180 
00181   return TRUE;  
00182 }
00183 
00184 static GSourceFuncs xt_event_funcs = {
00185   xt_event_prepare,
00186   xt_event_check,
00187   xt_event_dispatch,
00188   g_free,
00189   (GSourceFunc)NULL,
00190   (GSourceDummyMarshal)NULL
00191 };
00192 
00193 static gboolean
00194 xt_event_polling_timer_callback(gpointer user_data)
00195 {
00196   Display * display;
00197   XtAppContext ac;
00198   int eventsToProcess = 20;
00199 
00200   display = (Display *)user_data;
00201   ac = XtDisplayToApplicationContext(display);
00202 
00203   /* We need to process many Xt events here. If we just process
00204      one event we might starve one or more Xt consumers. On the other hand
00205      this could hang the whole app if Xt events come pouring in. So process
00206      up to 20 Xt events right now and save the rest for later. This is a hack,
00207      but it oughta work. We *really* should have out of process plugins.
00208   */
00209   while (eventsToProcess-- && XtAppPending(ac))
00210     XtAppProcessEvent(ac, XtIMAll);
00211   return TRUE;
00212 }
00213 
00214 GtkType
00215 gtk_xtbin_get_type (void)
00216 {
00217   static GtkType xtbin_type = 0;
00218 
00219   if (!xtbin_type) {
00220       static const GtkTypeInfo xtbin_info =
00221       {
00222         "GtkXtBin",
00223         sizeof (GtkXtBin),
00224         sizeof (GtkXtBinClass),
00225         (GtkClassInitFunc) gtk_xtbin_class_init,
00226         (GtkObjectInitFunc) gtk_xtbin_init,
00227         /* reserved_1 */ NULL,
00228         /* reserved_2 */ NULL,
00229         (GtkClassInitFunc) NULL
00230       };
00231       xtbin_type = gtk_type_unique (GTK_TYPE_SOCKET, &xtbin_info);
00232     }
00233   return xtbin_type;
00234 }
00235 
00236 static void
00237 gtk_xtbin_class_init (GtkXtBinClass *klass)
00238 {
00239   GtkWidgetClass *widget_class;
00240   GtkObjectClass *object_class;
00241 
00242   parent_class = gtk_type_class (GTK_TYPE_SOCKET);
00243 
00244   widget_class = GTK_WIDGET_CLASS (klass);
00245   widget_class->realize = gtk_xtbin_realize;
00246   widget_class->unrealize = gtk_xtbin_unrealize;
00247 
00248   object_class = GTK_OBJECT_CLASS (klass);
00249   object_class->destroy = gtk_xtbin_destroy;
00250 }
00251 
00252 static void
00253 gtk_xtbin_init (GtkXtBin *xtbin)
00254 {
00255   xtbin->xtdisplay = NULL;
00256   xtbin->parent_window = NULL;
00257   xtbin->xtwindow = 0;
00258   xtbin->x = 0;
00259   xtbin->y = 0;
00260 }
00261 
00262 static void
00263 gtk_xtbin_realize (GtkWidget *widget)
00264 {
00265   GtkXtBin     *xtbin;
00266   GtkAllocation allocation = { 0, 0, 200, 200 };
00267   gint  x, y, w, h, d; /* geometry of window */
00268 
00269 #ifdef DEBUG_XTBIN
00270   printf("gtk_xtbin_realize()\n");
00271 #endif
00272 
00273   g_return_if_fail (GTK_IS_XTBIN (widget));
00274 
00275   xtbin = GTK_XTBIN (widget);
00276 
00277   /* caculate the allocation before realize */
00278   gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
00279   allocation.width = w;
00280   allocation.height = h;
00281   gtk_widget_size_allocate (widget, &allocation);
00282 
00283 #ifdef DEBUG_XTBIN
00284   printf("initial allocation %d %d %d %d\n", x, y, w, h);
00285 #endif
00286 
00287   xtbin->width = widget->allocation.width;
00288   xtbin->height = widget->allocation.height;
00289 
00290   /* use GtkSocket's realize */
00291   (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
00292 
00293   /* create the Xt client widget */
00294   xt_client_create(&(xtbin->xtclient), 
00295        gtk_socket_get_id(GTK_SOCKET(xtbin)), 
00296        xtbin->height, 
00297        xtbin->width);
00298   xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
00299 
00300   gdk_flush();
00301 
00302   /* now that we have created the xt client, add it to the socket. */
00303   gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
00304 }
00305 
00306 
00307 
00308 GtkWidget*
00309 gtk_xtbin_new (GdkWindow *parent_window, String * f)
00310 {
00311   GtkXtBin *xtbin;
00312   gpointer user_data;
00313 
00314   assert(parent_window != NULL);
00315   xtbin = gtk_type_new (GTK_TYPE_XTBIN);
00316 
00317   if (!xtbin)
00318     return (GtkWidget*)NULL;
00319 
00320   if (f)
00321     fallback = f;
00322 
00323   /* Initialize the Xt toolkit */
00324   xtbin->parent_window = parent_window;
00325 
00326   xt_client_init(&(xtbin->xtclient), 
00327       GDK_VISUAL_XVISUAL(gdk_window_get_visual(parent_window )),
00328       GDK_COLORMAP_XCOLORMAP(gdk_window_get_colormap(parent_window)),
00329       gdk_window_get_visual(parent_window )->depth);
00330 
00331   if (!xtbin->xtclient.xtdisplay) {
00332     /* If XtOpenDisplay failed, we can't go any further.
00333      *  Bail out.
00334      */
00335 #ifdef DEBUG_XTBIN
00336     printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
00337 #endif
00338     g_free (xtbin);
00339     return (GtkWidget *)NULL;
00340   }
00341 
00342   /* If this is the first running widget, hook this display into the
00343      mainloop */
00344   if (0 == num_widgets) {
00345     int           cnumber;
00346     /*
00347      * hook Xt event loop into the glib event loop.
00348      */
00349 
00350     /* the assumption is that gtk_init has already been called */
00351     GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
00352       if (!gs) {
00353        return NULL;
00354       }
00355     
00356     g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
00357     g_source_set_can_recurse(gs, TRUE);
00358     tag = g_source_attach(gs, (GMainContext*)NULL);
00359 #ifdef VMS
00360     cnumber = XConnectionNumber(xtdisplay);
00361 #else
00362     cnumber = ConnectionNumber(xtdisplay);
00363 #endif
00364     xt_event_poll_fd.fd = cnumber;
00365     xt_event_poll_fd.events = G_IO_IN; 
00366     xt_event_poll_fd.revents = 0;    /* hmm... is this correct? */
00367 
00368     g_main_context_add_poll ((GMainContext*)NULL, 
00369                              &xt_event_poll_fd, 
00370                              G_PRIORITY_LOW);
00371     /* add a timer so that we can poll and process Xt timers */
00372     xt_polling_timer_id =
00373       gtk_timeout_add(25,
00374                       (GtkFunction)xt_event_polling_timer_callback,
00375                       xtdisplay);
00376   }
00377 
00378   /* Bump up our usage count */
00379   num_widgets++;
00380 
00381   /* Build the hierachy */
00382   xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
00383   gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
00384   gdk_window_get_user_data(xtbin->parent_window, &user_data);
00385   if (user_data)
00386     gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
00387 
00388   return GTK_WIDGET (xtbin);
00389 }
00390 
00391 void
00392 gtk_xtbin_set_position (GtkXtBin *xtbin,
00393                         gint       x,
00394                         gint       y)
00395 {
00396   xtbin->x = x;
00397   xtbin->y = y;
00398 
00399   if (GTK_WIDGET_REALIZED (xtbin))
00400     gdk_window_move (GTK_WIDGET (xtbin)->window, x, y);
00401 }
00402 
00403 void
00404 gtk_xtbin_resize (GtkWidget *widget,
00405                   gint       width,
00406                   gint       height)
00407 {
00408   Arg args[2];
00409   GtkXtBin *xtbin = GTK_XTBIN (widget);
00410   GtkAllocation allocation;
00411 
00412 #ifdef DEBUG_XTBIN
00413   printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height);
00414 #endif
00415 
00416   XtSetArg(args[0], XtNheight, height);
00417   XtSetArg(args[1], XtNwidth,  width);
00418   XtSetValues(xtbin->xtclient.top_widget, args, 2);
00419   xtbin->height = height;
00420   xtbin->width  = width;
00421 
00422   /* we need to send a size allocate so the socket knows about the
00423      size changes */
00424   allocation.x = xtbin->x;
00425   allocation.y = xtbin->y;
00426   allocation.width = xtbin->width;
00427   allocation.height = xtbin->height;
00428 
00429   gtk_widget_size_allocate(widget, &allocation);
00430 }
00431 
00432 static void
00433 gtk_xtbin_unrealize (GtkWidget *object)
00434 {
00435   GtkXtBin *xtbin;
00436   GtkWidget *widget;
00437 
00438 #ifdef DEBUG_XTBIN
00439   printf("gtk_xtbin_unrealize()\n");
00440 #endif
00441 
00442   /* gtk_object_destroy() will already hold a refcount on object
00443    */
00444   xtbin = GTK_XTBIN(object);
00445   widget = GTK_WIDGET(object);
00446 
00447   GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
00448   if (GTK_WIDGET_REALIZED (widget)) {
00449     xt_client_unrealize(&(xtbin->xtclient));
00450   }
00451 
00452   (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
00453 }
00454 
00455 static void
00456 gtk_xtbin_destroy (GtkObject *object)
00457 {
00458   GtkXtBin *xtbin;
00459 
00460 #ifdef DEBUG_XTBIN
00461   printf("gtk_xtbin_destroy()\n");
00462 #endif
00463 
00464   g_return_if_fail (object != NULL);
00465   g_return_if_fail (GTK_IS_XTBIN (object));
00466 
00467   xtbin = GTK_XTBIN (object);
00468 
00469   if(xtbin->xtwindow) {
00470     /* remove the event handler */
00471     xt_client_destroy(&(xtbin->xtclient));
00472     xtbin->xtwindow = 0;
00473 
00474     num_widgets--; /* reduce our usage count */
00475 
00476     /* If this is the last running widget, remove the Xt display
00477        connection from the mainloop */
00478     if (0 == num_widgets) {
00479 #ifdef DEBUG_XTBIN
00480       printf("removing the Xt connection from the main loop\n");
00481 #endif
00482       g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
00483       g_source_remove(tag);
00484 
00485       gtk_timeout_remove(xt_polling_timer_id);
00486       xt_polling_timer_id = 0;
00487     }
00488   }
00489 
00490   GTK_OBJECT_CLASS(parent_class)->destroy(object);
00491 }
00492 
00493 /*
00494 * Following is the implementation of Xt XEmbedded for client side
00495 */
00496 
00497 /* Initial Xt plugin */
00498 static void
00499 xt_client_init( XtClient * xtclient, 
00500                 Visual *xtvisual, 
00501                 Colormap xtcolormap,
00502                 int xtdepth)
00503 {
00504   XtAppContext  app_context;
00505   char         *mArgv[1];
00506   int           mArgc = 0;
00507 
00508   /*
00509    * Initialize Xt stuff
00510    */
00511   xtclient->top_widget = NULL;
00512   xtclient->child_widget = NULL;
00513   xtclient->xtdisplay  = NULL;
00514   xtclient->xtvisual   = NULL;
00515   xtclient->xtcolormap = 0;
00516   xtclient->xtdepth = 0;
00517 
00518   if (!xt_is_initialized) {
00519 #ifdef DEBUG_XTBIN
00520     printf("starting up Xt stuff\n");
00521 #endif
00522     XtToolkitInitialize();
00523     app_context = XtCreateApplicationContext();
00524     if (fallback)
00525       XtAppSetFallbackResources(app_context, fallback);
00526 
00527     xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL, 
00528                             "Wrapper", NULL, 0, &mArgc, mArgv);
00529     if (xtdisplay)
00530       xt_is_initialized = TRUE;
00531   }
00532   xtclient->xtdisplay  = xtdisplay;
00533   xtclient->xtvisual   = xtvisual;
00534   xtclient->xtcolormap = xtcolormap;
00535   xtclient->xtdepth    = xtdepth;
00536 }
00537 
00538 /* Create the Xt client widgets
00539 *  */
00540 static void
00541 xt_client_create ( XtClient* xtclient , 
00542                    Window embedderid, 
00543                    int height, 
00544                    int width ) 
00545 {
00546   int           n;
00547   Arg           args[6];
00548   Widget        child_widget;
00549   Widget        top_widget;
00550 
00551 #ifdef DEBUG_XTBIN
00552   printf("xt_client_create() \n");
00553 #endif
00554   top_widget = XtAppCreateShell("drawingArea", "Wrapper", 
00555                                 applicationShellWidgetClass, 
00556                                 xtclient->xtdisplay, 
00557                                 NULL, 0);
00558   xtclient->top_widget = top_widget;
00559 
00560   /* set size of Xt window */
00561   n = 0;
00562   XtSetArg(args[n], XtNheight,   height);n++;
00563   XtSetArg(args[n], XtNwidth,    width);n++;
00564   XtSetValues(top_widget, args, n);
00565 
00566   child_widget = XtVaCreateWidget("form", 
00567                                   compositeWidgetClass, 
00568                                   top_widget, NULL);
00569 
00570   n = 0;
00571   XtSetArg(args[n], XtNheight,   height);n++;
00572   XtSetArg(args[n], XtNwidth,    width);n++;
00573   XtSetArg(args[n], XtNvisual,   xtclient->xtvisual ); n++;
00574   XtSetArg(args[n], XtNdepth,    xtclient->xtdepth ); n++;
00575   XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
00576   XtSetArg(args[n], XtNborderWidth, 0); n++;
00577   XtSetValues(child_widget, args, n);
00578 
00579   XSync(xtclient->xtdisplay, FALSE);
00580   xtclient->oldwindow = top_widget->core.window;
00581   top_widget->core.window = embedderid;
00582 
00583   /* this little trick seems to finish initializing the widget */
00584 #if XlibSpecificationRelease >= 6
00585   XtRegisterDrawable(xtclient->xtdisplay, 
00586                      embedderid,
00587                      top_widget);
00588 #else
00589   _XtRegisterWindow( embedderid,
00590                      top_widget);
00591 #endif
00592   XtRealizeWidget(child_widget);
00593 
00594   /* listen to all Xt events */
00595   XSelectInput(xtclient->xtdisplay, 
00596                XtWindow(top_widget), 
00597                0x0FFFFF);
00598   xt_client_set_info (child_widget, 0);
00599 
00600   XtManageChild(child_widget);
00601   xtclient->child_widget = child_widget;
00602 
00603   /* set the event handler */
00604   XtAddEventHandler(child_widget,
00605                     0x0FFFFF & ~ResizeRedirectMask,
00606                     TRUE, 
00607                     (XtEventHandler)xt_client_event_handler, xtclient);
00608   XtAddEventHandler(child_widget, 
00609                     SubstructureNotifyMask | ButtonReleaseMask, 
00610                     TRUE, 
00611                     (XtEventHandler)xt_client_focus_listener, 
00612                     xtclient);
00613   XSync(xtclient->xtdisplay, FALSE);
00614 }
00615 
00616 static void
00617 xt_client_unrealize ( XtClient* xtclient )
00618 {
00619 #if XlibSpecificationRelease >= 6
00620   XtUnregisterDrawable(xtclient->xtdisplay,
00621                        xtclient->top_widget->core.window);
00622 #else
00623   _XtUnregisterWindow(xtclient->top_widget->core.window,
00624                       xtclient->top_widget);
00625 #endif
00626 
00627   /* flush the queue before we returning origin top_widget->core.window
00628      or we can get X error since the window is gone */
00629   XSync(xtclient->xtdisplay, False);
00630 
00631   xtclient->top_widget->core.window = xtclient->oldwindow;
00632   XtUnrealizeWidget(xtclient->top_widget);
00633 }
00634 
00635 static void            
00636 xt_client_destroy   (XtClient* xtclient)
00637 {
00638   if(xtclient->top_widget) {
00639     XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE, 
00640                          (XtEventHandler)xt_client_event_handler, xtclient);
00641     XtDestroyWidget(xtclient->top_widget);
00642     xtclient->top_widget = NULL;
00643   }
00644 }
00645 
00646 static void         
00647 xt_client_set_info (Widget xtplug, unsigned long flags)
00648 {
00649   unsigned long buffer[2];
00650 
00651   Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False); 
00652 
00653   buffer[1] = 0;                /* Protocol version */
00654   buffer[1] = flags;
00655 
00656   XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
00657                    infoAtom, infoAtom, 32,
00658                    PropModeReplace,
00659                    (unsigned char *)buffer, 2);
00660 }
00661 
00662 static void
00663 xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
00664 {
00665   XtClient *xtplug = (XtClient*)client_data;
00666   switch (event->xclient.data.l[1])
00667   {
00668   case XEMBED_EMBEDDED_NOTIFY:
00669     break;
00670   case XEMBED_WINDOW_ACTIVATE:
00671 #ifdef DEBUG_XTBIN
00672     printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
00673 #endif
00674     break;
00675   case XEMBED_WINDOW_DEACTIVATE:
00676 #ifdef DEBUG_XTBIN
00677     printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
00678 #endif
00679     break;
00680   case XEMBED_MODALITY_ON:
00681 #ifdef DEBUG_XTBIN
00682     printf("Xt client get XEMBED_MODALITY_ON\n");
00683 #endif
00684     break;
00685   case XEMBED_MODALITY_OFF:
00686 #ifdef DEBUG_XTBIN
00687     printf("Xt client get XEMBED_MODALITY_OFF\n");
00688 #endif
00689     break;
00690   case XEMBED_FOCUS_IN:
00691   case XEMBED_FOCUS_OUT:
00692     {
00693       XEvent xevent;
00694       memset(&xevent, 0, sizeof(xevent));
00695 
00696       if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
00697 #ifdef DEBUG_XTBIN
00698         printf("XTEMBED got focus in\n");
00699 #endif
00700         xevent.xfocus.type = FocusIn;
00701       }
00702       else {
00703 #ifdef DEBUG_XTBIN
00704         printf("XTEMBED got focus out\n");
00705 #endif
00706         xevent.xfocus.type = FocusOut;
00707       }
00708 
00709       xevent.xfocus.window = XtWindow(xtplug->child_widget);
00710       xevent.xfocus.display = XtDisplay(xtplug->child_widget);
00711       XSendEvent(XtDisplay(xtplug->child_widget), 
00712                  xevent.xfocus.window,
00713                  False, NoEventMask,
00714                  &xevent );
00715       XSync( XtDisplay(xtplug->child_widget), False);
00716     }
00717     break;
00718   default:
00719     break;
00720   } /* End of XEmbed Message */
00721 }
00722 
00723 static void         
00724 xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
00725 {
00726   XtClient *xtplug = (XtClient*)client_data;
00727   
00728   switch(event->type)
00729     {
00730     case ClientMessage:
00731       /* Handle xembed message */
00732       if (event->xclient.message_type==
00733                  XInternAtom (XtDisplay(xtplug->child_widget),
00734                               "_XEMBED", False)) {
00735         xt_client_handle_xembed_message(w, client_data, event);
00736       }
00737       break;
00738     case ReparentNotify:
00739       break;
00740     case MappingNotify:
00741       xt_client_set_info (w, XEMBED_MAPPED);
00742       break;
00743     case UnmapNotify:
00744       xt_client_set_info (w, 0);
00745       break;
00746     case FocusIn:
00747       send_xembed_message ( xtplug,
00748                             XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
00749       break;
00750     case FocusOut:
00751       break;
00752     case KeyPress:
00753 #ifdef DEBUG_XTBIN
00754       printf("Key Press Got!\n");
00755 #endif
00756       break;
00757     default:
00758       break;
00759     } /* End of switch(event->type) */
00760 }
00761 
00762 static void
00763 send_xembed_message (XtClient  *xtclient,
00764                      long      message,
00765                      long      detail, 
00766                      long      data1,  
00767                      long      data2,  
00768                      long      time)   
00769 {
00770   XEvent xevent; 
00771   Window w=XtWindow(xtclient->top_widget);
00772   Display* dpy=xtclient->xtdisplay;
00773   int errorcode;
00774 
00775   memset(&xevent,0,sizeof(xevent));
00776   xevent.xclient.window = w;
00777   xevent.xclient.type = ClientMessage;
00778   xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
00779   xevent.xclient.format = 32;
00780   xevent.xclient.data.l[0] = time; 
00781   xevent.xclient.data.l[1] = message;
00782   xevent.xclient.data.l[2] = detail; 
00783   xevent.xclient.data.l[3] = data1;
00784   xevent.xclient.data.l[4] = data2;
00785 
00786   trap_errors ();
00787   XSendEvent (dpy, w, False, NoEventMask, &xevent);
00788   XSync (dpy,False);
00789 
00790   if((errorcode = untrap_error())) {
00791 #ifdef DEBUG_XTBIN
00792     printf("send_xembed_message error(%d)!!!\n",errorcode);
00793 #endif
00794   }
00795 }
00796 
00797 static int             
00798 error_handler(Display *display, XErrorEvent *error)
00799 {
00800   trapped_error_code = error->error_code;
00801   return 0;
00802 }
00803 
00804 static void          
00805 trap_errors(void)
00806 {
00807   trapped_error_code =0;
00808   old_error_handler = XSetErrorHandler(error_handler);
00809 }
00810 
00811 static int         
00812 untrap_error(void)
00813 {
00814   XSetErrorHandler(old_error_handler);
00815   if(trapped_error_code) {
00816 #ifdef DEBUG_XTBIN
00817     printf("Get X Window Error = %d\n", trapped_error_code);
00818 #endif
00819   }
00820   return trapped_error_code;
00821 }
00822 
00823 static void         
00824 xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
00825 {
00826   Display *dpy = XtDisplay(w);
00827   XtClient *xtclient = user_data;
00828   Window win = XtWindow(w);
00829 
00830   switch(event->type)
00831     {
00832     case CreateNotify:
00833       if(event->xcreatewindow.parent == win) {
00834         Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
00835         if (child)
00836           xt_add_focus_listener_tree(child, user_data);
00837       }
00838       break;
00839     case DestroyNotify:
00840       xt_remove_focus_listener( w, user_data);
00841       break;
00842     case ReparentNotify:
00843       if(event->xreparent.parent == win) {
00844         /* I am the new parent */
00845         Widget child=XtWindowToWidget(dpy, event->xreparent.window);
00846         if (child)
00847           xt_add_focus_listener_tree( child, user_data);
00848       }
00849       else if(event->xreparent.window == win) {
00850         /* I am the new child */
00851       }
00852       else {
00853         /* I am the old parent */
00854       }
00855       break;
00856     case ButtonRelease:
00857 #if 0
00858       XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
00859 #endif
00860       send_xembed_message ( xtclient,
00861                             XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
00862       break;
00863     default:
00864       break;
00865     } /* End of switch(event->type) */
00866 }
00867 
00868 static void
00869 xt_add_focus_listener( Widget w, XtPointer user_data)
00870 {
00871   XWindowAttributes attr;
00872   long eventmask;
00873   XtClient *xtclient = user_data;
00874   int errorcode;
00875 
00876   trap_errors ();
00877   XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr);
00878   eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask;
00879   XSelectInput(XtDisplay(w),
00880                XtWindow(w), 
00881                eventmask);
00882 
00883   XtAddEventHandler(w, 
00884                     SubstructureNotifyMask | ButtonReleaseMask, 
00885                     TRUE, 
00886                     (XtEventHandler)xt_client_focus_listener, 
00887                     xtclient);
00888   untrap_error();
00889 }
00890 
00891 static void
00892 xt_remove_focus_listener(Widget w, XtPointer user_data)
00893 {
00894   int errorcode;
00895 
00896   trap_errors ();
00897   XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE, 
00898                       (XtEventHandler)xt_client_focus_listener, user_data);
00899 
00900   untrap_error();
00901 }
00902 
00903 static void
00904 xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data) 
00905 {
00906   Window win = XtWindow(treeroot);
00907   Window *children;
00908   Window root, parent;
00909   Display *dpy = XtDisplay(treeroot);
00910   unsigned int i, nchildren;
00911 
00912   /* ensure we don't add more than once */
00913   xt_remove_focus_listener( treeroot, user_data);
00914   xt_add_focus_listener( treeroot, user_data);
00915   trap_errors();
00916   if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
00917     untrap_error();
00918     return;
00919   }
00920 
00921   if(untrap_error()) 
00922     return;
00923 
00924   for(i=0; i<nchildren; ++i) {
00925     Widget child = XtWindowToWidget(dpy, children[i]);
00926     if (child) 
00927       xt_add_focus_listener_tree( child, user_data);
00928   }
00929   XFree((void*)children);
00930 
00931   return;
00932 }
00933