Add copy of .ttf font with .eot extension for testing
[wine-gecko.git] / widget / src / gtkxtbin / gtk2xtbin.c
blob22301290548b465d27b4d6264441628a445146bc
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim:expandtab:shiftwidth=2:tabstop=2: */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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.
17 * The Original Code is the Gtk2XtBin Widget Implementation.
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.
24 * Contributor(s):
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.
38 * ***** END LICENSE BLOCK ***** */
41 * The GtkXtBin widget allows for Xt toolkit code to be used
42 * inside a GTK application.
45 #include "xembed.h"
46 #include "gtk2xtbin.h"
47 #include <gtk/gtkmain.h>
48 #include <gtk/gtkprivate.h>
49 #include <gdk/gdkx.h>
50 #include <glib.h>
51 #include <assert.h>
52 #include <sys/time.h>
53 #include <sys/types.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <unistd.h>
58 /* Xlib/Xt stuff */
59 #include <X11/Xlib.h>
60 #include <X11/Xutil.h>
61 #include <X11/Shell.h>
62 #include <X11/Intrinsic.h>
63 #include <X11/StringDefs.h>
65 /* uncomment this if you want debugging information about widget
66 creation and destruction */
67 #undef DEBUG_XTBIN
69 #define XTBIN_MAX_EVENTS 30
71 static void gtk_xtbin_class_init (GtkXtBinClass *klass);
72 static void gtk_xtbin_init (GtkXtBin *xtbin);
73 static void gtk_xtbin_realize (GtkWidget *widget);
74 static void gtk_xtbin_unrealize (GtkWidget *widget);
75 static void gtk_xtbin_destroy (GtkObject *object);
76 static void gtk_xtbin_shutdown (GtkObject *object);
78 /* Xt aware XEmbed */
79 static void xt_client_init (XtClient * xtclient,
80 Visual *xtvisual,
81 Colormap xtcolormap,
82 int xtdepth);
83 static void xt_client_create (XtClient * xtclient,
84 Window embeder,
85 int height,
86 int width );
87 static void xt_client_unrealize (XtClient* xtclient);
88 static void xt_client_destroy (XtClient* xtclient);
89 static void xt_client_set_info (Widget xtplug,
90 unsigned long flags);
91 static void xt_client_event_handler (Widget w,
92 XtPointer client_data,
93 XEvent *event);
94 static void xt_client_handle_xembed_message (Widget w,
95 XtPointer client_data,
96 XEvent *event);
97 static void xt_client_focus_listener (Widget w,
98 XtPointer user_data,
99 XEvent *event);
100 static void xt_add_focus_listener( Widget w, XtPointer user_data );
101 static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data);
102 static void xt_remove_focus_listener(Widget w, XtPointer user_data);
103 static void send_xembed_message (XtClient *xtclient,
104 long message,
105 long detail,
106 long data1,
107 long data2,
108 long time);
109 static int error_handler (Display *display,
110 XErrorEvent *error);
111 /* For error trap of XEmbed */
112 static void trap_errors(void);
113 static int untrap_error(void);
114 static int (*old_error_handler) (Display *, XErrorEvent *);
115 static int trapped_error_code = 0;
117 static GtkWidgetClass *parent_class = NULL;
119 static Display *xtdisplay = NULL;
120 static String *fallback = NULL;
121 static gboolean xt_is_initialized = FALSE;
122 static gint num_widgets = 0;
124 static GPollFD xt_event_poll_fd;
125 static gint xt_polling_timer_id = 0;
126 static guint tag = 0;
128 static gboolean
129 xt_event_prepare (GSource* source_data,
130 gint *timeout)
132 int mask;
134 GDK_THREADS_ENTER();
135 mask = XPending(xtdisplay);
136 GDK_THREADS_LEAVE();
138 return (gboolean)mask;
141 static gboolean
142 xt_event_check (GSource* source_data)
144 GDK_THREADS_ENTER ();
146 if (xt_event_poll_fd.revents & G_IO_IN) {
147 int mask;
148 mask = XPending(xtdisplay);
149 GDK_THREADS_LEAVE ();
150 return (gboolean)mask;
153 GDK_THREADS_LEAVE ();
154 return FALSE;
157 static gboolean
158 xt_event_dispatch (GSource* source_data,
159 GSourceFunc call_back,
160 gpointer user_data)
162 XEvent event;
163 XtAppContext ac;
164 int i = 0;
166 ac = XtDisplayToApplicationContext(xtdisplay);
168 GDK_THREADS_ENTER ();
170 /* Process only real X traffic here. We only look for data on the
171 * pipe, limit it to XTBIN_MAX_EVENTS and only call
172 * XtAppProcessEvent so that it will look for X events. There's no
173 * timer processing here since we already have a timer callback that
174 * does it. */
175 for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
176 XtAppProcessEvent(ac, XtIMXEvent);
179 GDK_THREADS_LEAVE ();
181 return TRUE;
184 static GSourceFuncs xt_event_funcs = {
185 xt_event_prepare,
186 xt_event_check,
187 xt_event_dispatch,
188 g_free,
189 (GSourceFunc)NULL,
190 (GSourceDummyMarshal)NULL
193 static gboolean
194 xt_event_polling_timer_callback(gpointer user_data)
196 Display * display;
197 XtAppContext ac;
198 int eventsToProcess = 20;
200 display = (Display *)user_data;
201 ac = XtDisplayToApplicationContext(display);
203 /* We need to process many Xt events here. If we just process
204 one event we might starve one or more Xt consumers. On the other hand
205 this could hang the whole app if Xt events come pouring in. So process
206 up to 20 Xt events right now and save the rest for later. This is a hack,
207 but it oughta work. We *really* should have out of process plugins.
209 while (eventsToProcess-- && XtAppPending(ac))
210 XtAppProcessEvent(ac, XtIMAll);
211 return TRUE;
214 GtkType
215 gtk_xtbin_get_type (void)
217 static GtkType xtbin_type = 0;
219 if (!xtbin_type) {
220 static const GtkTypeInfo xtbin_info =
222 "GtkXtBin",
223 sizeof (GtkXtBin),
224 sizeof (GtkXtBinClass),
225 (GtkClassInitFunc) gtk_xtbin_class_init,
226 (GtkObjectInitFunc) gtk_xtbin_init,
227 /* reserved_1 */ NULL,
228 /* reserved_2 */ NULL,
229 (GtkClassInitFunc) NULL
231 xtbin_type = gtk_type_unique (GTK_TYPE_SOCKET, &xtbin_info);
233 return xtbin_type;
236 static void
237 gtk_xtbin_class_init (GtkXtBinClass *klass)
239 GtkWidgetClass *widget_class;
240 GtkObjectClass *object_class;
242 parent_class = gtk_type_class (GTK_TYPE_SOCKET);
244 widget_class = GTK_WIDGET_CLASS (klass);
245 widget_class->realize = gtk_xtbin_realize;
246 widget_class->unrealize = gtk_xtbin_unrealize;
248 object_class = GTK_OBJECT_CLASS (klass);
249 object_class->destroy = gtk_xtbin_destroy;
252 static void
253 gtk_xtbin_init (GtkXtBin *xtbin)
255 xtbin->xtdisplay = NULL;
256 xtbin->parent_window = NULL;
257 xtbin->xtwindow = 0;
258 xtbin->x = 0;
259 xtbin->y = 0;
262 static void
263 gtk_xtbin_realize (GtkWidget *widget)
265 GtkXtBin *xtbin;
266 GtkAllocation allocation = { 0, 0, 200, 200 };
267 gint x, y, w, h, d; /* geometry of window */
269 #ifdef DEBUG_XTBIN
270 printf("gtk_xtbin_realize()\n");
271 #endif
273 g_return_if_fail (GTK_IS_XTBIN (widget));
275 xtbin = GTK_XTBIN (widget);
277 /* caculate the allocation before realize */
278 gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
279 allocation.width = w;
280 allocation.height = h;
281 gtk_widget_size_allocate (widget, &allocation);
283 #ifdef DEBUG_XTBIN
284 printf("initial allocation %d %d %d %d\n", x, y, w, h);
285 #endif
287 xtbin->width = widget->allocation.width;
288 xtbin->height = widget->allocation.height;
290 /* use GtkSocket's realize */
291 (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
293 /* create the Xt client widget */
294 xt_client_create(&(xtbin->xtclient),
295 gtk_socket_get_id(GTK_SOCKET(xtbin)),
296 xtbin->height,
297 xtbin->width);
298 xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
300 gdk_flush();
302 /* now that we have created the xt client, add it to the socket. */
303 gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
308 GtkWidget*
309 gtk_xtbin_new (GdkWindow *parent_window, String * f)
311 GtkXtBin *xtbin;
312 gpointer user_data;
314 assert(parent_window != NULL);
315 xtbin = gtk_type_new (GTK_TYPE_XTBIN);
317 if (!xtbin)
318 return (GtkWidget*)NULL;
320 if (f)
321 fallback = f;
323 /* Initialize the Xt toolkit */
324 xtbin->parent_window = parent_window;
326 xt_client_init(&(xtbin->xtclient),
327 GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()),
328 GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()),
329 gdk_rgb_get_visual()->depth);
331 if (!xtbin->xtclient.xtdisplay) {
332 /* If XtOpenDisplay failed, we can't go any further.
333 * Bail out.
335 #ifdef DEBUG_XTBIN
336 printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
337 #endif
338 g_free (xtbin);
339 return (GtkWidget *)NULL;
342 /* If this is the first running widget, hook this display into the
343 mainloop */
344 if (0 == num_widgets) {
345 int cnumber;
347 * hook Xt event loop into the glib event loop.
350 /* the assumption is that gtk_init has already been called */
351 GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
352 if (!gs) {
353 return NULL;
356 g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
357 g_source_set_can_recurse(gs, TRUE);
358 tag = g_source_attach(gs, (GMainContext*)NULL);
359 #ifdef VMS
360 cnumber = XConnectionNumber(xtdisplay);
361 #else
362 cnumber = ConnectionNumber(xtdisplay);
363 #endif
364 xt_event_poll_fd.fd = cnumber;
365 xt_event_poll_fd.events = G_IO_IN;
366 xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
368 g_main_context_add_poll ((GMainContext*)NULL,
369 &xt_event_poll_fd,
370 G_PRIORITY_LOW);
371 /* add a timer so that we can poll and process Xt timers */
372 xt_polling_timer_id =
373 gtk_timeout_add(25,
374 (GtkFunction)xt_event_polling_timer_callback,
375 xtdisplay);
378 /* Bump up our usage count */
379 num_widgets++;
381 /* Build the hierachy */
382 xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
383 gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
384 gdk_window_get_user_data(xtbin->parent_window, &user_data);
385 if (user_data)
386 gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
388 return GTK_WIDGET (xtbin);
391 void
392 gtk_xtbin_set_position (GtkXtBin *xtbin,
393 gint x,
394 gint y)
396 xtbin->x = x;
397 xtbin->y = y;
399 if (GTK_WIDGET_REALIZED (xtbin))
400 gdk_window_move (GTK_WIDGET (xtbin)->window, x, y);
403 void
404 gtk_xtbin_resize (GtkWidget *widget,
405 gint width,
406 gint height)
408 Arg args[2];
409 GtkXtBin *xtbin = GTK_XTBIN (widget);
410 GtkAllocation allocation;
412 #ifdef DEBUG_XTBIN
413 printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height);
414 #endif
416 xtbin->height = height;
417 xtbin->width = width;
419 // Avoid BadValue errors in XtSetValues
420 if (height <= 0 || width <=0) {
421 height = 1;
422 width = 1;
424 XtSetArg(args[0], XtNheight, height);
425 XtSetArg(args[1], XtNwidth, width);
426 XtSetValues(xtbin->xtclient.top_widget, args, 2);
428 /* we need to send a size allocate so the socket knows about the
429 size changes */
430 allocation.x = xtbin->x;
431 allocation.y = xtbin->y;
432 allocation.width = xtbin->width;
433 allocation.height = xtbin->height;
435 gtk_widget_size_allocate(widget, &allocation);
438 static void
439 gtk_xtbin_unrealize (GtkWidget *object)
441 GtkXtBin *xtbin;
442 GtkWidget *widget;
444 #ifdef DEBUG_XTBIN
445 printf("gtk_xtbin_unrealize()\n");
446 #endif
448 /* gtk_object_destroy() will already hold a refcount on object
450 xtbin = GTK_XTBIN(object);
451 widget = GTK_WIDGET(object);
453 GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
454 if (GTK_WIDGET_REALIZED (widget)) {
455 xt_client_unrealize(&(xtbin->xtclient));
458 (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
461 static void
462 gtk_xtbin_destroy (GtkObject *object)
464 GtkXtBin *xtbin;
466 #ifdef DEBUG_XTBIN
467 printf("gtk_xtbin_destroy()\n");
468 #endif
470 g_return_if_fail (object != NULL);
471 g_return_if_fail (GTK_IS_XTBIN (object));
473 xtbin = GTK_XTBIN (object);
475 if(xtbin->xtwindow) {
476 /* remove the event handler */
477 xt_client_destroy(&(xtbin->xtclient));
478 xtbin->xtwindow = 0;
480 num_widgets--; /* reduce our usage count */
482 /* If this is the last running widget, remove the Xt display
483 connection from the mainloop */
484 if (0 == num_widgets) {
485 #ifdef DEBUG_XTBIN
486 printf("removing the Xt connection from the main loop\n");
487 #endif
488 g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
489 g_source_remove(tag);
491 gtk_timeout_remove(xt_polling_timer_id);
492 xt_polling_timer_id = 0;
496 GTK_OBJECT_CLASS(parent_class)->destroy(object);
500 * Following is the implementation of Xt XEmbedded for client side
503 /* Initial Xt plugin */
504 static void
505 xt_client_init( XtClient * xtclient,
506 Visual *xtvisual,
507 Colormap xtcolormap,
508 int xtdepth)
510 XtAppContext app_context;
511 char *mArgv[1];
512 int mArgc = 0;
515 * Initialize Xt stuff
517 xtclient->top_widget = NULL;
518 xtclient->child_widget = NULL;
519 xtclient->xtdisplay = NULL;
520 xtclient->xtvisual = NULL;
521 xtclient->xtcolormap = 0;
522 xtclient->xtdepth = 0;
524 if (!xt_is_initialized) {
525 #ifdef DEBUG_XTBIN
526 printf("starting up Xt stuff\n");
527 #endif
528 XtToolkitInitialize();
529 app_context = XtCreateApplicationContext();
530 if (fallback)
531 XtAppSetFallbackResources(app_context, fallback);
533 xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
534 "Wrapper", NULL, 0, &mArgc, mArgv);
535 if (xtdisplay)
536 xt_is_initialized = TRUE;
538 xtclient->xtdisplay = xtdisplay;
539 xtclient->xtvisual = xtvisual;
540 xtclient->xtcolormap = xtcolormap;
541 xtclient->xtdepth = xtdepth;
544 /* Create the Xt client widgets
545 * */
546 static void
547 xt_client_create ( XtClient* xtclient ,
548 Window embedderid,
549 int height,
550 int width )
552 int n;
553 Arg args[6];
554 Widget child_widget;
555 Widget top_widget;
557 #ifdef DEBUG_XTBIN
558 printf("xt_client_create() \n");
559 #endif
560 top_widget = XtAppCreateShell("drawingArea", "Wrapper",
561 applicationShellWidgetClass,
562 xtclient->xtdisplay,
563 NULL, 0);
564 xtclient->top_widget = top_widget;
566 /* set size of Xt window */
567 n = 0;
568 XtSetArg(args[n], XtNheight, height);n++;
569 XtSetArg(args[n], XtNwidth, width);n++;
570 XtSetValues(top_widget, args, n);
572 child_widget = XtVaCreateWidget("form",
573 compositeWidgetClass,
574 top_widget, NULL);
576 n = 0;
577 XtSetArg(args[n], XtNheight, height);n++;
578 XtSetArg(args[n], XtNwidth, width);n++;
579 XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++;
580 XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++;
581 XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
582 XtSetArg(args[n], XtNborderWidth, 0); n++;
583 XtSetValues(child_widget, args, n);
585 XSync(xtclient->xtdisplay, FALSE);
586 xtclient->oldwindow = top_widget->core.window;
587 top_widget->core.window = embedderid;
589 /* this little trick seems to finish initializing the widget */
590 #if XlibSpecificationRelease >= 6
591 XtRegisterDrawable(xtclient->xtdisplay,
592 embedderid,
593 top_widget);
594 #else
595 _XtRegisterWindow( embedderid,
596 top_widget);
597 #endif
598 XtRealizeWidget(child_widget);
600 /* listen to all Xt events */
601 XSelectInput(xtclient->xtdisplay,
602 XtWindow(top_widget),
603 0x0FFFFF);
604 xt_client_set_info (child_widget, 0);
606 XtManageChild(child_widget);
607 xtclient->child_widget = child_widget;
609 /* set the event handler */
610 XtAddEventHandler(child_widget,
611 0x0FFFFF & ~ResizeRedirectMask,
612 TRUE,
613 (XtEventHandler)xt_client_event_handler, xtclient);
614 XtAddEventHandler(child_widget,
615 SubstructureNotifyMask | ButtonReleaseMask,
616 TRUE,
617 (XtEventHandler)xt_client_focus_listener,
618 xtclient);
619 XSync(xtclient->xtdisplay, FALSE);
622 static void
623 xt_client_unrealize ( XtClient* xtclient )
625 #if XlibSpecificationRelease >= 6
626 XtUnregisterDrawable(xtclient->xtdisplay,
627 xtclient->top_widget->core.window);
628 #else
629 _XtUnregisterWindow(xtclient->top_widget->core.window,
630 xtclient->top_widget);
631 #endif
633 /* flush the queue before we returning origin top_widget->core.window
634 or we can get X error since the window is gone */
635 XSync(xtclient->xtdisplay, False);
637 xtclient->top_widget->core.window = xtclient->oldwindow;
638 XtUnrealizeWidget(xtclient->top_widget);
641 static void
642 xt_client_destroy (XtClient* xtclient)
644 if(xtclient->top_widget) {
645 XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE,
646 (XtEventHandler)xt_client_event_handler, xtclient);
647 XtDestroyWidget(xtclient->top_widget);
648 xtclient->top_widget = NULL;
652 static void
653 xt_client_set_info (Widget xtplug, unsigned long flags)
655 unsigned long buffer[2];
657 Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
659 buffer[1] = 0; /* Protocol version */
660 buffer[1] = flags;
662 XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
663 infoAtom, infoAtom, 32,
664 PropModeReplace,
665 (unsigned char *)buffer, 2);
668 static void
669 xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
671 XtClient *xtplug = (XtClient*)client_data;
672 switch (event->xclient.data.l[1])
674 case XEMBED_EMBEDDED_NOTIFY:
675 break;
676 case XEMBED_WINDOW_ACTIVATE:
677 #ifdef DEBUG_XTBIN
678 printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
679 #endif
680 break;
681 case XEMBED_WINDOW_DEACTIVATE:
682 #ifdef DEBUG_XTBIN
683 printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
684 #endif
685 break;
686 case XEMBED_MODALITY_ON:
687 #ifdef DEBUG_XTBIN
688 printf("Xt client get XEMBED_MODALITY_ON\n");
689 #endif
690 break;
691 case XEMBED_MODALITY_OFF:
692 #ifdef DEBUG_XTBIN
693 printf("Xt client get XEMBED_MODALITY_OFF\n");
694 #endif
695 break;
696 case XEMBED_FOCUS_IN:
697 case XEMBED_FOCUS_OUT:
699 XEvent xevent;
700 memset(&xevent, 0, sizeof(xevent));
702 if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
703 #ifdef DEBUG_XTBIN
704 printf("XTEMBED got focus in\n");
705 #endif
706 xevent.xfocus.type = FocusIn;
708 else {
709 #ifdef DEBUG_XTBIN
710 printf("XTEMBED got focus out\n");
711 #endif
712 xevent.xfocus.type = FocusOut;
715 xevent.xfocus.window = XtWindow(xtplug->child_widget);
716 xevent.xfocus.display = XtDisplay(xtplug->child_widget);
717 XSendEvent(XtDisplay(xtplug->child_widget),
718 xevent.xfocus.window,
719 False, NoEventMask,
720 &xevent );
721 XSync( XtDisplay(xtplug->child_widget), False);
723 break;
724 default:
725 break;
726 } /* End of XEmbed Message */
729 static void
730 xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
732 XtClient *xtplug = (XtClient*)client_data;
734 switch(event->type)
736 case ClientMessage:
737 /* Handle xembed message */
738 if (event->xclient.message_type==
739 XInternAtom (XtDisplay(xtplug->child_widget),
740 "_XEMBED", False)) {
741 xt_client_handle_xembed_message(w, client_data, event);
743 break;
744 case ReparentNotify:
745 break;
746 case MappingNotify:
747 xt_client_set_info (w, XEMBED_MAPPED);
748 break;
749 case UnmapNotify:
750 xt_client_set_info (w, 0);
751 break;
752 case FocusIn:
753 send_xembed_message ( xtplug,
754 XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
755 break;
756 case FocusOut:
757 break;
758 case KeyPress:
759 #ifdef DEBUG_XTBIN
760 printf("Key Press Got!\n");
761 #endif
762 break;
763 default:
764 break;
765 } /* End of switch(event->type) */
768 static void
769 send_xembed_message (XtClient *xtclient,
770 long message,
771 long detail,
772 long data1,
773 long data2,
774 long time)
776 XEvent xevent;
777 Window w=XtWindow(xtclient->top_widget);
778 Display* dpy=xtclient->xtdisplay;
779 int errorcode;
781 memset(&xevent,0,sizeof(xevent));
782 xevent.xclient.window = w;
783 xevent.xclient.type = ClientMessage;
784 xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
785 xevent.xclient.format = 32;
786 xevent.xclient.data.l[0] = time;
787 xevent.xclient.data.l[1] = message;
788 xevent.xclient.data.l[2] = detail;
789 xevent.xclient.data.l[3] = data1;
790 xevent.xclient.data.l[4] = data2;
792 trap_errors ();
793 XSendEvent (dpy, w, False, NoEventMask, &xevent);
794 XSync (dpy,False);
796 if((errorcode = untrap_error())) {
797 #ifdef DEBUG_XTBIN
798 printf("send_xembed_message error(%d)!!!\n",errorcode);
799 #endif
803 static int
804 error_handler(Display *display, XErrorEvent *error)
806 trapped_error_code = error->error_code;
807 return 0;
810 static void
811 trap_errors(void)
813 trapped_error_code =0;
814 old_error_handler = XSetErrorHandler(error_handler);
817 static int
818 untrap_error(void)
820 XSetErrorHandler(old_error_handler);
821 if(trapped_error_code) {
822 #ifdef DEBUG_XTBIN
823 printf("Get X Window Error = %d\n", trapped_error_code);
824 #endif
826 return trapped_error_code;
829 static void
830 xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
832 Display *dpy = XtDisplay(w);
833 XtClient *xtclient = user_data;
834 Window win = XtWindow(w);
836 switch(event->type)
838 case CreateNotify:
839 if(event->xcreatewindow.parent == win) {
840 Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
841 if (child)
842 xt_add_focus_listener_tree(child, user_data);
844 break;
845 case DestroyNotify:
846 xt_remove_focus_listener( w, user_data);
847 break;
848 case ReparentNotify:
849 if(event->xreparent.parent == win) {
850 /* I am the new parent */
851 Widget child=XtWindowToWidget(dpy, event->xreparent.window);
852 if (child)
853 xt_add_focus_listener_tree( child, user_data);
855 else if(event->xreparent.window == win) {
856 /* I am the new child */
858 else {
859 /* I am the old parent */
861 break;
862 case ButtonRelease:
863 #if 0
864 XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
865 #endif
866 send_xembed_message ( xtclient,
867 XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
868 break;
869 default:
870 break;
871 } /* End of switch(event->type) */
874 static void
875 xt_add_focus_listener( Widget w, XtPointer user_data)
877 XWindowAttributes attr;
878 long eventmask;
879 XtClient *xtclient = user_data;
880 int errorcode;
882 trap_errors ();
883 XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr);
884 eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask;
885 XSelectInput(XtDisplay(w),
886 XtWindow(w),
887 eventmask);
889 XtAddEventHandler(w,
890 SubstructureNotifyMask | ButtonReleaseMask,
891 TRUE,
892 (XtEventHandler)xt_client_focus_listener,
893 xtclient);
894 untrap_error();
897 static void
898 xt_remove_focus_listener(Widget w, XtPointer user_data)
900 int errorcode;
902 trap_errors ();
903 XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE,
904 (XtEventHandler)xt_client_focus_listener, user_data);
906 untrap_error();
909 static void
910 xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
912 Window win = XtWindow(treeroot);
913 Window *children;
914 Window root, parent;
915 Display *dpy = XtDisplay(treeroot);
916 unsigned int i, nchildren;
918 /* ensure we don't add more than once */
919 xt_remove_focus_listener( treeroot, user_data);
920 xt_add_focus_listener( treeroot, user_data);
921 trap_errors();
922 if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
923 untrap_error();
924 return;
927 if(untrap_error())
928 return;
930 for(i=0; i<nchildren; ++i) {
931 Widget child = XtWindowToWidget(dpy, children[i]);
932 if (child)
933 xt_add_focus_listener_tree( child, user_data);
935 XFree((void*)children);
937 return;