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