michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: set expandtab shiftwidth=2 tabstop=2: */ michael@0: michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * The GtkXtBin widget allows for Xt toolkit code to be used michael@0: * inside a GTK application. michael@0: */ michael@0: michael@0: #include "xembed.h" michael@0: #include "gtk2xtbin.h" michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: /* Xlib/Xt stuff */ michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: /* uncomment this if you want debugging information about widget michael@0: creation and destruction */ michael@0: #undef DEBUG_XTBIN michael@0: michael@0: #define XTBIN_MAX_EVENTS 30 michael@0: michael@0: static void gtk_xtbin_class_init (GtkXtBinClass *klass); michael@0: static void gtk_xtbin_init (GtkXtBin *xtbin); michael@0: static void gtk_xtbin_realize (GtkWidget *widget); michael@0: static void gtk_xtbin_unrealize (GtkWidget *widget); michael@0: static void gtk_xtbin_destroy (GtkObject *object); michael@0: static void gtk_xtbin_shutdown (GtkObject *object); michael@0: michael@0: /* Xt aware XEmbed */ michael@0: static void xt_client_handle_xembed_message (Widget w, michael@0: XtPointer client_data, michael@0: XEvent *event); michael@0: static void xt_add_focus_listener( Widget w, XtPointer user_data ); michael@0: static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data); michael@0: static void xt_remove_focus_listener(Widget w, XtPointer user_data); michael@0: static void xt_client_event_handler (Widget w, XtPointer client_data, XEvent *event); michael@0: static void xt_client_focus_listener (Widget w, XtPointer user_data, XEvent *event); michael@0: static void xt_client_set_info (Widget xtplug, unsigned long flags); michael@0: static void send_xembed_message (XtClient *xtclient, michael@0: long message, michael@0: long detail, michael@0: long data1, michael@0: long data2, michael@0: long time); michael@0: static int error_handler (Display *display, michael@0: XErrorEvent *error); michael@0: /* For error trap of XEmbed */ michael@0: static void trap_errors(void); michael@0: static int untrap_error(void); michael@0: static int (*old_error_handler) (Display *, XErrorEvent *); michael@0: static int trapped_error_code = 0; michael@0: michael@0: static GtkWidgetClass *parent_class = NULL; michael@0: michael@0: static Display *xtdisplay = NULL; michael@0: static String *fallback = NULL; michael@0: static gboolean xt_is_initialized = FALSE; michael@0: static gint num_widgets = 0; michael@0: michael@0: static GPollFD xt_event_poll_fd; michael@0: static gint xt_polling_timer_id = 0; michael@0: static guint tag = 0; michael@0: michael@0: static gboolean michael@0: xt_event_prepare (GSource* source_data, michael@0: gint *timeout) michael@0: { michael@0: int mask; michael@0: michael@0: GDK_THREADS_ENTER(); michael@0: mask = XPending(xtdisplay); michael@0: GDK_THREADS_LEAVE(); michael@0: michael@0: return (gboolean)mask; michael@0: } michael@0: michael@0: static gboolean michael@0: xt_event_check (GSource* source_data) michael@0: { michael@0: GDK_THREADS_ENTER (); michael@0: michael@0: if (xt_event_poll_fd.revents & G_IO_IN) { michael@0: int mask; michael@0: mask = XPending(xtdisplay); michael@0: GDK_THREADS_LEAVE (); michael@0: return (gboolean)mask; michael@0: } michael@0: michael@0: GDK_THREADS_LEAVE (); michael@0: return FALSE; michael@0: } michael@0: michael@0: static gboolean michael@0: xt_event_dispatch (GSource* source_data, michael@0: GSourceFunc call_back, michael@0: gpointer user_data) michael@0: { michael@0: XEvent event; michael@0: XtAppContext ac; michael@0: int i = 0; michael@0: michael@0: ac = XtDisplayToApplicationContext(xtdisplay); michael@0: michael@0: GDK_THREADS_ENTER (); michael@0: michael@0: /* Process only real X traffic here. We only look for data on the michael@0: * pipe, limit it to XTBIN_MAX_EVENTS and only call michael@0: * XtAppProcessEvent so that it will look for X events. There's no michael@0: * timer processing here since we already have a timer callback that michael@0: * does it. */ michael@0: for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) { michael@0: XtAppProcessEvent(ac, XtIMXEvent); michael@0: } michael@0: michael@0: GDK_THREADS_LEAVE (); michael@0: michael@0: return TRUE; michael@0: } michael@0: michael@0: static GSourceFuncs xt_event_funcs = { michael@0: xt_event_prepare, michael@0: xt_event_check, michael@0: xt_event_dispatch, michael@0: NULL, michael@0: (GSourceFunc)NULL, michael@0: (GSourceDummyMarshal)NULL michael@0: }; michael@0: michael@0: static gboolean michael@0: xt_event_polling_timer_callback(gpointer user_data) michael@0: { michael@0: Display * display; michael@0: XtAppContext ac; michael@0: int eventsToProcess = 20; michael@0: michael@0: display = (Display *)user_data; michael@0: ac = XtDisplayToApplicationContext(display); michael@0: michael@0: /* We need to process many Xt events here. If we just process michael@0: one event we might starve one or more Xt consumers. On the other hand michael@0: this could hang the whole app if Xt events come pouring in. So process michael@0: up to 20 Xt events right now and save the rest for later. This is a hack, michael@0: but it oughta work. We *really* should have out of process plugins. michael@0: */ michael@0: while (eventsToProcess-- && XtAppPending(ac)) michael@0: XtAppProcessEvent(ac, XtIMAll); michael@0: return TRUE; michael@0: } michael@0: michael@0: GType michael@0: gtk_xtbin_get_type (void) michael@0: { michael@0: static GType xtbin_type = 0; michael@0: michael@0: if (!xtbin_type) { michael@0: static const GTypeInfo xtbin_info = michael@0: { michael@0: sizeof (GtkXtBinClass), /* class_size */ michael@0: NULL, /* base_init */ michael@0: NULL, /* base_finalize */ michael@0: (GClassInitFunc) gtk_xtbin_class_init, /* class_init */ michael@0: NULL, /* class_finalize */ michael@0: NULL, /* class_data */ michael@0: sizeof (GtkXtBin), /* instance_size */ michael@0: 0, /* n_preallocs */ michael@0: (GInstanceInitFunc) gtk_xtbin_init, /* instance_init */ michael@0: NULL /* value_table */ michael@0: }; michael@0: xtbin_type = g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin", michael@0: &xtbin_info, 0); michael@0: } michael@0: return xtbin_type; michael@0: } michael@0: michael@0: static void michael@0: gtk_xtbin_class_init (GtkXtBinClass *klass) michael@0: { michael@0: GtkWidgetClass *widget_class; michael@0: GtkObjectClass *object_class; michael@0: michael@0: parent_class = g_type_class_peek_parent(klass); michael@0: michael@0: widget_class = GTK_WIDGET_CLASS (klass); michael@0: widget_class->realize = gtk_xtbin_realize; michael@0: widget_class->unrealize = gtk_xtbin_unrealize; michael@0: michael@0: object_class = GTK_OBJECT_CLASS (klass); michael@0: object_class->destroy = gtk_xtbin_destroy; michael@0: } michael@0: michael@0: static void michael@0: gtk_xtbin_init (GtkXtBin *xtbin) michael@0: { michael@0: xtbin->xtdisplay = NULL; michael@0: xtbin->parent_window = NULL; michael@0: xtbin->xtwindow = 0; michael@0: } michael@0: michael@0: static void michael@0: gtk_xtbin_realize (GtkWidget *widget) michael@0: { michael@0: GtkXtBin *xtbin; michael@0: GtkAllocation allocation = { 0, 0, 200, 200 }; michael@0: gint x, y, w, h, d; /* geometry of window */ michael@0: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("gtk_xtbin_realize()\n"); michael@0: #endif michael@0: michael@0: g_return_if_fail (GTK_IS_XTBIN (widget)); michael@0: michael@0: xtbin = GTK_XTBIN (widget); michael@0: michael@0: /* caculate the allocation before realize */ michael@0: gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d); michael@0: allocation.width = w; michael@0: allocation.height = h; michael@0: gtk_widget_size_allocate (widget, &allocation); michael@0: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("initial allocation %d %d %d %d\n", x, y, w, h); michael@0: #endif michael@0: michael@0: /* use GtkSocket's realize */ michael@0: (*GTK_WIDGET_CLASS(parent_class)->realize)(widget); michael@0: michael@0: /* create the Xt client widget */ michael@0: xt_client_create(&(xtbin->xtclient), michael@0: gtk_socket_get_id(GTK_SOCKET(xtbin)), michael@0: h, w); michael@0: xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget); michael@0: michael@0: gdk_flush(); michael@0: michael@0: /* now that we have created the xt client, add it to the socket. */ michael@0: gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow); michael@0: } michael@0: michael@0: michael@0: michael@0: GtkWidget* michael@0: gtk_xtbin_new (GdkWindow *parent_window, String * f) michael@0: { michael@0: GtkXtBin *xtbin; michael@0: gpointer user_data; michael@0: michael@0: assert(parent_window != NULL); michael@0: xtbin = g_object_new (GTK_TYPE_XTBIN, NULL); michael@0: michael@0: if (!xtbin) michael@0: return (GtkWidget*)NULL; michael@0: michael@0: if (f) michael@0: fallback = f; michael@0: michael@0: /* Initialize the Xt toolkit */ michael@0: xtbin->parent_window = parent_window; michael@0: michael@0: xt_client_init(&(xtbin->xtclient), michael@0: GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()), michael@0: GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()), michael@0: gdk_rgb_get_visual()->depth); michael@0: michael@0: if (!xtbin->xtclient.xtdisplay) { michael@0: /* If XtOpenDisplay failed, we can't go any further. michael@0: * Bail out. michael@0: */ michael@0: #ifdef DEBUG_XTBIN michael@0: printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n"); michael@0: #endif michael@0: g_free (xtbin); michael@0: return (GtkWidget *)NULL; michael@0: } michael@0: michael@0: /* Launch X event loop */ michael@0: xt_client_xloop_create(); michael@0: michael@0: /* Build the hierachy */ michael@0: xtbin->xtdisplay = xtbin->xtclient.xtdisplay; michael@0: gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window); michael@0: gdk_window_get_user_data(xtbin->parent_window, &user_data); michael@0: if (user_data) michael@0: gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin)); michael@0: michael@0: /* This GtkSocket has a visible window, but the Xt plug will cover this michael@0: * window. Normally GtkSockets let the X server paint their background and michael@0: * this would happen immediately (before the plug is mapped). Setting the michael@0: * background to None prevents the server from painting this window, michael@0: * avoiding flicker. michael@0: */ michael@0: gtk_widget_realize(GTK_WIDGET(xtbin)); michael@0: gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE); michael@0: michael@0: return GTK_WIDGET (xtbin); michael@0: } michael@0: michael@0: static void michael@0: gtk_xtbin_unrealize (GtkWidget *object) michael@0: { michael@0: GtkXtBin *xtbin; michael@0: GtkWidget *widget; michael@0: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("gtk_xtbin_unrealize()\n"); michael@0: #endif michael@0: michael@0: /* gtk_object_destroy() will already hold a refcount on object michael@0: */ michael@0: xtbin = GTK_XTBIN(object); michael@0: widget = GTK_WIDGET(object); michael@0: michael@0: GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE); michael@0: if (GTK_WIDGET_REALIZED (widget)) { michael@0: xt_client_unrealize(&(xtbin->xtclient)); michael@0: } michael@0: michael@0: (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); michael@0: } michael@0: michael@0: static void michael@0: gtk_xtbin_destroy (GtkObject *object) michael@0: { michael@0: GtkXtBin *xtbin; michael@0: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("gtk_xtbin_destroy()\n"); michael@0: #endif michael@0: michael@0: g_return_if_fail (object != NULL); michael@0: g_return_if_fail (GTK_IS_XTBIN (object)); michael@0: michael@0: xtbin = GTK_XTBIN (object); michael@0: michael@0: if(xtbin->xtwindow) { michael@0: /* remove the event handler */ michael@0: xt_client_destroy(&(xtbin->xtclient)); michael@0: xtbin->xtwindow = 0; michael@0: michael@0: /* stop X event loop */ michael@0: xt_client_xloop_destroy(); michael@0: } michael@0: michael@0: GTK_OBJECT_CLASS(parent_class)->destroy(object); michael@0: } michael@0: michael@0: /* michael@0: * Following is the implementation of Xt XEmbedded for client side michael@0: */ michael@0: michael@0: /* Initial Xt plugin */ michael@0: void michael@0: xt_client_init( XtClient * xtclient, michael@0: Visual *xtvisual, michael@0: Colormap xtcolormap, michael@0: int xtdepth) michael@0: { michael@0: XtAppContext app_context; michael@0: char *mArgv[1]; michael@0: int mArgc = 0; michael@0: michael@0: /* michael@0: * Initialize Xt stuff michael@0: */ michael@0: xtclient->top_widget = NULL; michael@0: xtclient->child_widget = NULL; michael@0: xtclient->xtdisplay = NULL; michael@0: xtclient->xtvisual = NULL; michael@0: xtclient->xtcolormap = 0; michael@0: xtclient->xtdepth = 0; michael@0: michael@0: if (!xt_is_initialized) { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("starting up Xt stuff\n"); michael@0: #endif michael@0: XtToolkitInitialize(); michael@0: app_context = XtCreateApplicationContext(); michael@0: if (fallback) michael@0: XtAppSetFallbackResources(app_context, fallback); michael@0: michael@0: xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL, michael@0: "Wrapper", NULL, 0, &mArgc, mArgv); michael@0: if (xtdisplay) michael@0: xt_is_initialized = TRUE; michael@0: } michael@0: xtclient->xtdisplay = xtdisplay; michael@0: xtclient->xtvisual = xtvisual; michael@0: xtclient->xtcolormap = xtcolormap; michael@0: xtclient->xtdepth = xtdepth; michael@0: } michael@0: michael@0: void michael@0: xt_client_xloop_create(void) michael@0: { michael@0: /* If this is the first running widget, hook this display into the michael@0: mainloop */ michael@0: if (0 == num_widgets) { michael@0: int cnumber; michael@0: GSource* gs; michael@0: michael@0: /* Set up xtdisplay in case we're missing one */ michael@0: if (!xtdisplay) { michael@0: (void)xt_client_get_display(); michael@0: } michael@0: michael@0: /* michael@0: * hook Xt event loop into the glib event loop. michael@0: */ michael@0: /* the assumption is that gtk_init has already been called */ michael@0: gs = g_source_new(&xt_event_funcs, sizeof(GSource)); michael@0: if (!gs) { michael@0: return; michael@0: } michael@0: michael@0: g_source_set_priority(gs, GDK_PRIORITY_EVENTS); michael@0: g_source_set_can_recurse(gs, TRUE); michael@0: tag = g_source_attach(gs, (GMainContext*)NULL); michael@0: g_source_unref(gs); michael@0: #ifdef VMS michael@0: cnumber = XConnectionNumber(xtdisplay); michael@0: #else michael@0: cnumber = ConnectionNumber(xtdisplay); michael@0: #endif michael@0: xt_event_poll_fd.fd = cnumber; michael@0: xt_event_poll_fd.events = G_IO_IN; michael@0: xt_event_poll_fd.revents = 0; /* hmm... is this correct? */ michael@0: michael@0: g_main_context_add_poll ((GMainContext*)NULL, michael@0: &xt_event_poll_fd, michael@0: G_PRIORITY_LOW); michael@0: /* add a timer so that we can poll and process Xt timers */ michael@0: xt_polling_timer_id = michael@0: g_timeout_add(25, michael@0: (GtkFunction)xt_event_polling_timer_callback, michael@0: xtdisplay); michael@0: } michael@0: michael@0: /* Bump up our usage count */ michael@0: num_widgets++; michael@0: } michael@0: michael@0: void michael@0: xt_client_xloop_destroy(void) michael@0: { michael@0: num_widgets--; /* reduce our usage count */ michael@0: michael@0: /* If this is the last running widget, remove the Xt display michael@0: connection from the mainloop */ michael@0: if (0 == num_widgets) { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("removing the Xt connection from the main loop\n"); michael@0: #endif michael@0: g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd); michael@0: g_source_remove(tag); michael@0: michael@0: g_source_remove(xt_polling_timer_id); michael@0: xt_polling_timer_id = 0; michael@0: } michael@0: } michael@0: michael@0: /* Get Xt Client display */ michael@0: Display * michael@0: xt_client_get_display(void) michael@0: { michael@0: if (!xtdisplay) { michael@0: XtClient tmp; michael@0: xt_client_init(&tmp,NULL,0,0); michael@0: } michael@0: return xtdisplay; michael@0: } michael@0: michael@0: /* Create the Xt client widgets michael@0: * */ michael@0: void michael@0: xt_client_create ( XtClient* xtclient , michael@0: Window embedderid, michael@0: int height, michael@0: int width ) michael@0: { michael@0: int n; michael@0: Arg args[6]; michael@0: Widget child_widget; michael@0: Widget top_widget; michael@0: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("xt_client_create() \n"); michael@0: #endif michael@0: top_widget = XtAppCreateShell("drawingArea", "Wrapper", michael@0: applicationShellWidgetClass, michael@0: xtclient->xtdisplay, michael@0: NULL, 0); michael@0: xtclient->top_widget = top_widget; michael@0: michael@0: /* set size of Xt window */ michael@0: n = 0; michael@0: XtSetArg(args[n], XtNheight, height);n++; michael@0: XtSetArg(args[n], XtNwidth, width);n++; michael@0: XtSetValues(top_widget, args, n); michael@0: michael@0: child_widget = XtVaCreateWidget("form", michael@0: compositeWidgetClass, michael@0: top_widget, NULL); michael@0: michael@0: n = 0; michael@0: XtSetArg(args[n], XtNheight, height);n++; michael@0: XtSetArg(args[n], XtNwidth, width);n++; michael@0: XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++; michael@0: XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++; michael@0: XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++; michael@0: XtSetArg(args[n], XtNborderWidth, 0); n++; michael@0: XtSetValues(child_widget, args, n); michael@0: michael@0: XSync(xtclient->xtdisplay, FALSE); michael@0: xtclient->oldwindow = top_widget->core.window; michael@0: top_widget->core.window = embedderid; michael@0: michael@0: /* this little trick seems to finish initializing the widget */ michael@0: #if XlibSpecificationRelease >= 6 michael@0: XtRegisterDrawable(xtclient->xtdisplay, michael@0: embedderid, michael@0: top_widget); michael@0: #else michael@0: _XtRegisterWindow( embedderid, michael@0: top_widget); michael@0: #endif michael@0: XtRealizeWidget(child_widget); michael@0: michael@0: /* listen to all Xt events */ michael@0: XSelectInput(xtclient->xtdisplay, michael@0: embedderid, michael@0: XtBuildEventMask(top_widget)); michael@0: xt_client_set_info (child_widget, 0); michael@0: michael@0: XtManageChild(child_widget); michael@0: xtclient->child_widget = child_widget; michael@0: michael@0: /* set the event handler */ michael@0: XtAddEventHandler(child_widget, michael@0: StructureNotifyMask | KeyPressMask, michael@0: TRUE, michael@0: (XtEventHandler)xt_client_event_handler, xtclient); michael@0: XtAddEventHandler(child_widget, michael@0: SubstructureNotifyMask | ButtonReleaseMask, michael@0: FALSE, michael@0: (XtEventHandler)xt_client_focus_listener, michael@0: xtclient); michael@0: XSync(xtclient->xtdisplay, FALSE); michael@0: } michael@0: michael@0: void michael@0: xt_client_unrealize ( XtClient* xtclient ) michael@0: { michael@0: /* Explicitly destroy the child_widget window because this is actually a michael@0: child of the socket window. It is not a child of top_widget's window michael@0: when that is destroyed. */ michael@0: XtUnrealizeWidget(xtclient->child_widget); michael@0: michael@0: #if XlibSpecificationRelease >= 6 michael@0: XtUnregisterDrawable(xtclient->xtdisplay, michael@0: xtclient->top_widget->core.window); michael@0: #else michael@0: _XtUnregisterWindow(xtclient->top_widget->core.window, michael@0: xtclient->top_widget); michael@0: #endif michael@0: michael@0: /* flush the queue before we returning origin top_widget->core.window michael@0: or we can get X error since the window is gone */ michael@0: XSync(xtclient->xtdisplay, False); michael@0: michael@0: xtclient->top_widget->core.window = xtclient->oldwindow; michael@0: XtUnrealizeWidget(xtclient->top_widget); michael@0: } michael@0: michael@0: void michael@0: xt_client_destroy (XtClient* xtclient) michael@0: { michael@0: if(xtclient->top_widget) { michael@0: XtRemoveEventHandler(xtclient->child_widget, michael@0: StructureNotifyMask | KeyPressMask, michael@0: TRUE, michael@0: (XtEventHandler)xt_client_event_handler, xtclient); michael@0: XtDestroyWidget(xtclient->top_widget); michael@0: xtclient->top_widget = NULL; michael@0: } michael@0: } michael@0: michael@0: void michael@0: xt_client_set_info (Widget xtplug, unsigned long flags) michael@0: { michael@0: unsigned long buffer[2]; michael@0: michael@0: Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False); michael@0: michael@0: buffer[1] = 0; /* Protocol version */ michael@0: buffer[1] = flags; michael@0: michael@0: XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug), michael@0: infoAtom, infoAtom, 32, michael@0: PropModeReplace, michael@0: (unsigned char *)buffer, 2); michael@0: } michael@0: michael@0: static void michael@0: xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event) michael@0: { michael@0: XtClient *xtplug = (XtClient*)client_data; michael@0: switch (event->xclient.data.l[1]) michael@0: { michael@0: case XEMBED_EMBEDDED_NOTIFY: michael@0: break; michael@0: case XEMBED_WINDOW_ACTIVATE: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Xt client get XEMBED_WINDOW_ACTIVATE\n"); michael@0: #endif michael@0: break; michael@0: case XEMBED_WINDOW_DEACTIVATE: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n"); michael@0: #endif michael@0: break; michael@0: case XEMBED_MODALITY_ON: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Xt client get XEMBED_MODALITY_ON\n"); michael@0: #endif michael@0: break; michael@0: case XEMBED_MODALITY_OFF: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Xt client get XEMBED_MODALITY_OFF\n"); michael@0: #endif michael@0: break; michael@0: case XEMBED_FOCUS_IN: michael@0: case XEMBED_FOCUS_OUT: michael@0: { michael@0: XEvent xevent; michael@0: memset(&xevent, 0, sizeof(xevent)); michael@0: michael@0: if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("XTEMBED got focus in\n"); michael@0: #endif michael@0: xevent.xfocus.type = FocusIn; michael@0: } michael@0: else { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("XTEMBED got focus out\n"); michael@0: #endif michael@0: xevent.xfocus.type = FocusOut; michael@0: } michael@0: michael@0: xevent.xfocus.window = XtWindow(xtplug->child_widget); michael@0: xevent.xfocus.display = XtDisplay(xtplug->child_widget); michael@0: XSendEvent(XtDisplay(xtplug->child_widget), michael@0: xevent.xfocus.window, michael@0: False, NoEventMask, michael@0: &xevent ); michael@0: XSync( XtDisplay(xtplug->child_widget), False); michael@0: } michael@0: break; michael@0: default: michael@0: break; michael@0: } /* End of XEmbed Message */ michael@0: } michael@0: michael@0: void michael@0: xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event) michael@0: { michael@0: XtClient *xtplug = (XtClient*)client_data; michael@0: michael@0: switch(event->type) michael@0: { michael@0: case ClientMessage: michael@0: /* Handle xembed message */ michael@0: if (event->xclient.message_type== michael@0: XInternAtom (XtDisplay(xtplug->child_widget), michael@0: "_XEMBED", False)) { michael@0: xt_client_handle_xembed_message(w, client_data, event); michael@0: } michael@0: break; michael@0: case ReparentNotify: michael@0: break; michael@0: case MappingNotify: michael@0: xt_client_set_info (w, XEMBED_MAPPED); michael@0: break; michael@0: case UnmapNotify: michael@0: xt_client_set_info (w, 0); michael@0: break; michael@0: case KeyPress: michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Key Press Got!\n"); michael@0: #endif michael@0: break; michael@0: default: michael@0: break; michael@0: } /* End of switch(event->type) */ michael@0: } michael@0: michael@0: static void michael@0: send_xembed_message (XtClient *xtclient, michael@0: long message, michael@0: long detail, michael@0: long data1, michael@0: long data2, michael@0: long time) michael@0: { michael@0: XEvent xevent; michael@0: Window w=XtWindow(xtclient->top_widget); michael@0: Display* dpy=xtclient->xtdisplay; michael@0: int errorcode; michael@0: michael@0: memset(&xevent,0,sizeof(xevent)); michael@0: xevent.xclient.window = w; michael@0: xevent.xclient.type = ClientMessage; michael@0: xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False); michael@0: xevent.xclient.format = 32; michael@0: xevent.xclient.data.l[0] = time; michael@0: xevent.xclient.data.l[1] = message; michael@0: xevent.xclient.data.l[2] = detail; michael@0: xevent.xclient.data.l[3] = data1; michael@0: xevent.xclient.data.l[4] = data2; michael@0: michael@0: trap_errors (); michael@0: XSendEvent (dpy, w, False, NoEventMask, &xevent); michael@0: XSync (dpy,False); michael@0: michael@0: if((errorcode = untrap_error())) { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("send_xembed_message error(%d)!!!\n",errorcode); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: static int michael@0: error_handler(Display *display, XErrorEvent *error) michael@0: { michael@0: trapped_error_code = error->error_code; michael@0: return 0; michael@0: } michael@0: michael@0: static void michael@0: trap_errors(void) michael@0: { michael@0: trapped_error_code =0; michael@0: old_error_handler = XSetErrorHandler(error_handler); michael@0: } michael@0: michael@0: static int michael@0: untrap_error(void) michael@0: { michael@0: XSetErrorHandler(old_error_handler); michael@0: if(trapped_error_code) { michael@0: #ifdef DEBUG_XTBIN michael@0: printf("Get X Window Error = %d\n", trapped_error_code); michael@0: #endif michael@0: } michael@0: return trapped_error_code; michael@0: } michael@0: michael@0: void michael@0: xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event) michael@0: { michael@0: Display *dpy = XtDisplay(w); michael@0: XtClient *xtclient = user_data; michael@0: Window win = XtWindow(w); michael@0: michael@0: switch(event->type) michael@0: { michael@0: case CreateNotify: michael@0: if(event->xcreatewindow.parent == win) { michael@0: Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window); michael@0: if (child) michael@0: xt_add_focus_listener_tree(child, user_data); michael@0: } michael@0: break; michael@0: case DestroyNotify: michael@0: xt_remove_focus_listener( w, user_data); michael@0: break; michael@0: case ReparentNotify: michael@0: if(event->xreparent.parent == win) { michael@0: /* I am the new parent */ michael@0: Widget child=XtWindowToWidget(dpy, event->xreparent.window); michael@0: if (child) michael@0: xt_add_focus_listener_tree( child, user_data); michael@0: } michael@0: else if(event->xreparent.window == win) { michael@0: /* I am the new child */ michael@0: } michael@0: else { michael@0: /* I am the old parent */ michael@0: } michael@0: break; michael@0: case ButtonRelease: michael@0: #if 0 michael@0: XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time); michael@0: #endif michael@0: send_xembed_message ( xtclient, michael@0: XEMBED_REQUEST_FOCUS, 0, 0, 0, 0); michael@0: break; michael@0: default: michael@0: break; michael@0: } /* End of switch(event->type) */ michael@0: } michael@0: michael@0: static void michael@0: xt_add_focus_listener( Widget w, XtPointer user_data) michael@0: { michael@0: XtClient *xtclient = user_data; michael@0: michael@0: trap_errors (); michael@0: XtAddEventHandler(w, michael@0: SubstructureNotifyMask | ButtonReleaseMask, michael@0: FALSE, michael@0: (XtEventHandler)xt_client_focus_listener, michael@0: xtclient); michael@0: untrap_error(); michael@0: } michael@0: michael@0: static void michael@0: xt_remove_focus_listener(Widget w, XtPointer user_data) michael@0: { michael@0: trap_errors (); michael@0: XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, FALSE, michael@0: (XtEventHandler)xt_client_focus_listener, user_data); michael@0: michael@0: untrap_error(); michael@0: } michael@0: michael@0: static void michael@0: xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data) michael@0: { michael@0: Window win = XtWindow(treeroot); michael@0: Window *children; michael@0: Window root, parent; michael@0: Display *dpy = XtDisplay(treeroot); michael@0: unsigned int i, nchildren; michael@0: michael@0: /* ensure we don't add more than once */ michael@0: xt_remove_focus_listener( treeroot, user_data); michael@0: xt_add_focus_listener( treeroot, user_data); michael@0: trap_errors(); michael@0: if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) { michael@0: untrap_error(); michael@0: return; michael@0: } michael@0: michael@0: if(untrap_error()) michael@0: return; michael@0: michael@0: for(i=0; i