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
128 0 : xt_event_prepare (GSource* source_data,
129 : gint *timeout)
130 : {
131 : int mask;
132 :
133 0 : GDK_THREADS_ENTER();
134 0 : mask = XPending(xtdisplay);
135 0 : GDK_THREADS_LEAVE();
136 :
137 0 : return (gboolean)mask;
138 : }
139 :
140 : static gboolean
141 0 : xt_event_check (GSource* source_data)
142 : {
143 0 : GDK_THREADS_ENTER ();
144 :
145 0 : if (xt_event_poll_fd.revents & G_IO_IN) {
146 : int mask;
147 0 : mask = XPending(xtdisplay);
148 0 : GDK_THREADS_LEAVE ();
149 0 : return (gboolean)mask;
150 : }
151 :
152 0 : GDK_THREADS_LEAVE ();
153 0 : return FALSE;
154 : }
155 :
156 : static gboolean
157 0 : xt_event_dispatch (GSource* source_data,
158 : GSourceFunc call_back,
159 : gpointer user_data)
160 : {
161 : XEvent event;
162 : XtAppContext ac;
163 0 : int i = 0;
164 :
165 0 : ac = XtDisplayToApplicationContext(xtdisplay);
166 :
167 0 : 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 0 : for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
175 0 : XtAppProcessEvent(ac, XtIMXEvent);
176 : }
177 :
178 0 : GDK_THREADS_LEAVE ();
179 :
180 0 : 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
193 0 : xt_event_polling_timer_callback(gpointer user_data)
194 : {
195 : Display * display;
196 : XtAppContext ac;
197 0 : int eventsToProcess = 20;
198 :
199 0 : display = (Display *)user_data;
200 0 : 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 0 : while (eventsToProcess-- && XtAppPending(ac))
209 0 : XtAppProcessEvent(ac, XtIMAll);
210 0 : return TRUE;
211 : }
212 :
213 : GType
214 0 : gtk_xtbin_get_type (void)
215 : {
216 : static GType xtbin_type = 0;
217 :
218 0 : if (!xtbin_type) {
219 : static const GTypeInfo xtbin_info =
220 : {
221 : sizeof (GtkXtBinClass), /* class_size */
222 : NULL, /* base_init */
223 : NULL, /* base_finalize */
224 : (GClassInitFunc) gtk_xtbin_class_init, /* class_init */
225 : NULL, /* class_finalize */
226 : NULL, /* class_data */
227 : sizeof (GtkXtBin), /* instance_size */
228 : 0, /* n_preallocs */
229 : (GInstanceInitFunc) gtk_xtbin_init, /* instance_init */
230 : NULL /* value_table */
231 : };
232 0 : xtbin_type = g_type_register_static(GTK_TYPE_SOCKET, "GtkXtBin",
233 : &xtbin_info, 0);
234 : }
235 0 : return xtbin_type;
236 : }
237 :
238 : static void
239 0 : gtk_xtbin_class_init (GtkXtBinClass *klass)
240 : {
241 : GtkWidgetClass *widget_class;
242 : GtkObjectClass *object_class;
243 :
244 0 : parent_class = g_type_class_peek_parent(klass);
245 :
246 0 : widget_class = GTK_WIDGET_CLASS (klass);
247 0 : widget_class->realize = gtk_xtbin_realize;
248 0 : widget_class->unrealize = gtk_xtbin_unrealize;
249 :
250 0 : object_class = GTK_OBJECT_CLASS (klass);
251 0 : object_class->destroy = gtk_xtbin_destroy;
252 0 : }
253 :
254 : static void
255 0 : gtk_xtbin_init (GtkXtBin *xtbin)
256 : {
257 0 : xtbin->xtdisplay = NULL;
258 0 : xtbin->parent_window = NULL;
259 0 : xtbin->xtwindow = 0;
260 0 : xtbin->x = 0;
261 0 : xtbin->y = 0;
262 0 : }
263 :
264 : static void
265 0 : gtk_xtbin_realize (GtkWidget *widget)
266 : {
267 : GtkXtBin *xtbin;
268 0 : GtkAllocation allocation = { 0, 0, 200, 200 };
269 : gint x, y, w, h, d; /* geometry of window */
270 :
271 : #ifdef DEBUG_XTBIN
272 : printf("gtk_xtbin_realize()\n");
273 : #endif
274 :
275 0 : g_return_if_fail (GTK_IS_XTBIN (widget));
276 :
277 0 : xtbin = GTK_XTBIN (widget);
278 :
279 : /* caculate the allocation before realize */
280 0 : gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
281 0 : allocation.width = w;
282 0 : allocation.height = h;
283 0 : gtk_widget_size_allocate (widget, &allocation);
284 :
285 : #ifdef DEBUG_XTBIN
286 : printf("initial allocation %d %d %d %d\n", x, y, w, h);
287 : #endif
288 :
289 0 : xtbin->width = widget->allocation.width;
290 0 : xtbin->height = widget->allocation.height;
291 :
292 : /* use GtkSocket's realize */
293 0 : (*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
294 :
295 : /* create the Xt client widget */
296 0 : xt_client_create(&(xtbin->xtclient),
297 0 : gtk_socket_get_id(GTK_SOCKET(xtbin)),
298 : xtbin->height,
299 : xtbin->width);
300 0 : xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
301 :
302 0 : gdk_flush();
303 :
304 : /* now that we have created the xt client, add it to the socket. */
305 0 : gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
306 : }
307 :
308 :
309 :
310 : GtkWidget*
311 0 : gtk_xtbin_new (GdkWindow *parent_window, String * f)
312 : {
313 : GtkXtBin *xtbin;
314 : gpointer user_data;
315 :
316 0 : assert(parent_window != NULL);
317 0 : xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
318 :
319 0 : if (!xtbin)
320 0 : return (GtkWidget*)NULL;
321 :
322 0 : if (f)
323 0 : fallback = f;
324 :
325 : /* Initialize the Xt toolkit */
326 0 : xtbin->parent_window = parent_window;
327 :
328 0 : xt_client_init(&(xtbin->xtclient),
329 : GDK_VISUAL_XVISUAL(gdk_rgb_get_visual()),
330 : GDK_COLORMAP_XCOLORMAP(gdk_rgb_get_colormap()),
331 0 : gdk_rgb_get_visual()->depth);
332 :
333 0 : if (!xtbin->xtclient.xtdisplay) {
334 : /* If XtOpenDisplay failed, we can't go any further.
335 : * Bail out.
336 : */
337 : #ifdef DEBUG_XTBIN
338 : printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
339 : #endif
340 0 : g_free (xtbin);
341 0 : return (GtkWidget *)NULL;
342 : }
343 :
344 : /* If this is the first running widget, hook this display into the
345 : mainloop */
346 0 : if (0 == num_widgets) {
347 : int cnumber;
348 : /*
349 : * hook Xt event loop into the glib event loop.
350 : */
351 :
352 : /* the assumption is that gtk_init has already been called */
353 0 : GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
354 0 : if (!gs) {
355 0 : return NULL;
356 : }
357 :
358 0 : g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
359 0 : g_source_set_can_recurse(gs, TRUE);
360 0 : tag = g_source_attach(gs, (GMainContext*)NULL);
361 : #ifdef VMS
362 : cnumber = XConnectionNumber(xtdisplay);
363 : #else
364 0 : cnumber = ConnectionNumber(xtdisplay);
365 : #endif
366 0 : xt_event_poll_fd.fd = cnumber;
367 0 : xt_event_poll_fd.events = G_IO_IN;
368 0 : xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
369 :
370 0 : g_main_context_add_poll ((GMainContext*)NULL,
371 : &xt_event_poll_fd,
372 : G_PRIORITY_LOW);
373 : /* add a timer so that we can poll and process Xt timers */
374 0 : xt_polling_timer_id =
375 0 : g_timeout_add(25,
376 : (GtkFunction)xt_event_polling_timer_callback,
377 : xtdisplay);
378 : }
379 :
380 : /* Bump up our usage count */
381 0 : num_widgets++;
382 :
383 : /* Build the hierachy */
384 0 : xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
385 0 : gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
386 0 : gdk_window_get_user_data(xtbin->parent_window, &user_data);
387 0 : if (user_data)
388 0 : gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
389 :
390 : /* This GtkSocket has a visible window, but the Xt plug will cover this
391 : * window. Normally GtkSockets let the X server paint their background and
392 : * this would happen immediately (before the plug is mapped). Setting the
393 : * background to None prevents the server from painting this window,
394 : * avoiding flicker.
395 : */
396 0 : gtk_widget_realize(GTK_WIDGET(xtbin));
397 0 : gdk_window_set_back_pixmap(GTK_WIDGET(xtbin)->window, NULL, FALSE);
398 :
399 0 : return GTK_WIDGET (xtbin);
400 : }
401 :
402 : void
403 0 : gtk_xtbin_set_position (GtkXtBin *xtbin,
404 : gint x,
405 : gint y)
406 : {
407 0 : xtbin->x = x;
408 0 : xtbin->y = y;
409 :
410 0 : if (GTK_WIDGET_REALIZED (xtbin))
411 0 : gdk_window_move (GTK_WIDGET (xtbin)->window, x, y);
412 0 : }
413 :
414 : void
415 0 : gtk_xtbin_resize (GtkWidget *widget,
416 : gint width,
417 : gint height)
418 : {
419 : Arg args[2];
420 0 : GtkXtBin *xtbin = GTK_XTBIN (widget);
421 : GtkAllocation allocation;
422 :
423 : #ifdef DEBUG_XTBIN
424 : printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height);
425 : #endif
426 :
427 0 : xtbin->height = height;
428 0 : xtbin->width = width;
429 :
430 : /* Avoid BadValue errors in XtSetValues */
431 0 : if (height <= 0 || width <=0) {
432 0 : height = 1;
433 0 : width = 1;
434 : }
435 0 : XtSetArg(args[0], XtNheight, height);
436 0 : XtSetArg(args[1], XtNwidth, width);
437 0 : if (xtbin->xtclient.top_widget)
438 0 : XtSetValues(xtbin->xtclient.top_widget, args, 2);
439 :
440 : /* we need to send a size allocate so the socket knows about the
441 : size changes */
442 0 : allocation.x = xtbin->x;
443 0 : allocation.y = xtbin->y;
444 0 : allocation.width = xtbin->width;
445 0 : allocation.height = xtbin->height;
446 :
447 0 : gtk_widget_size_allocate(widget, &allocation);
448 0 : }
449 :
450 : static void
451 0 : gtk_xtbin_unrealize (GtkWidget *object)
452 : {
453 : GtkXtBin *xtbin;
454 : GtkWidget *widget;
455 :
456 : #ifdef DEBUG_XTBIN
457 : printf("gtk_xtbin_unrealize()\n");
458 : #endif
459 :
460 : /* gtk_object_destroy() will already hold a refcount on object
461 : */
462 0 : xtbin = GTK_XTBIN(object);
463 0 : widget = GTK_WIDGET(object);
464 :
465 0 : GTK_WIDGET_UNSET_FLAGS (widget, GTK_VISIBLE);
466 0 : if (GTK_WIDGET_REALIZED (widget)) {
467 0 : xt_client_unrealize(&(xtbin->xtclient));
468 : }
469 :
470 0 : (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
471 0 : }
472 :
473 : static void
474 0 : gtk_xtbin_destroy (GtkObject *object)
475 : {
476 : GtkXtBin *xtbin;
477 :
478 : #ifdef DEBUG_XTBIN
479 : printf("gtk_xtbin_destroy()\n");
480 : #endif
481 :
482 0 : g_return_if_fail (object != NULL);
483 0 : g_return_if_fail (GTK_IS_XTBIN (object));
484 :
485 0 : xtbin = GTK_XTBIN (object);
486 :
487 0 : if(xtbin->xtwindow) {
488 : /* remove the event handler */
489 0 : xt_client_destroy(&(xtbin->xtclient));
490 0 : xtbin->xtwindow = 0;
491 :
492 0 : num_widgets--; /* reduce our usage count */
493 :
494 : /* If this is the last running widget, remove the Xt display
495 : connection from the mainloop */
496 0 : if (0 == num_widgets) {
497 : #ifdef DEBUG_XTBIN
498 : printf("removing the Xt connection from the main loop\n");
499 : #endif
500 0 : g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
501 0 : g_source_remove(tag);
502 :
503 0 : g_source_remove(xt_polling_timer_id);
504 0 : xt_polling_timer_id = 0;
505 : }
506 : }
507 :
508 0 : GTK_OBJECT_CLASS(parent_class)->destroy(object);
509 : }
510 :
511 : /*
512 : * Following is the implementation of Xt XEmbedded for client side
513 : */
514 :
515 : /* Initial Xt plugin */
516 : static void
517 0 : xt_client_init( XtClient * xtclient,
518 : Visual *xtvisual,
519 : Colormap xtcolormap,
520 : int xtdepth)
521 : {
522 : XtAppContext app_context;
523 : char *mArgv[1];
524 0 : int mArgc = 0;
525 :
526 : /*
527 : * Initialize Xt stuff
528 : */
529 0 : xtclient->top_widget = NULL;
530 0 : xtclient->child_widget = NULL;
531 0 : xtclient->xtdisplay = NULL;
532 0 : xtclient->xtvisual = NULL;
533 0 : xtclient->xtcolormap = 0;
534 0 : xtclient->xtdepth = 0;
535 :
536 0 : if (!xt_is_initialized) {
537 : #ifdef DEBUG_XTBIN
538 : printf("starting up Xt stuff\n");
539 : #endif
540 0 : XtToolkitInitialize();
541 0 : app_context = XtCreateApplicationContext();
542 0 : if (fallback)
543 0 : XtAppSetFallbackResources(app_context, fallback);
544 :
545 0 : xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
546 : "Wrapper", NULL, 0, &mArgc, mArgv);
547 0 : if (xtdisplay)
548 0 : xt_is_initialized = TRUE;
549 : }
550 0 : xtclient->xtdisplay = xtdisplay;
551 0 : xtclient->xtvisual = xtvisual;
552 0 : xtclient->xtcolormap = xtcolormap;
553 0 : xtclient->xtdepth = xtdepth;
554 0 : }
555 :
556 : /* Create the Xt client widgets
557 : * */
558 : static void
559 0 : xt_client_create ( XtClient* xtclient ,
560 : Window embedderid,
561 : int height,
562 : int width )
563 : {
564 : int n;
565 : Arg args[6];
566 : Widget child_widget;
567 : Widget top_widget;
568 :
569 : #ifdef DEBUG_XTBIN
570 : printf("xt_client_create() \n");
571 : #endif
572 0 : top_widget = XtAppCreateShell("drawingArea", "Wrapper",
573 : applicationShellWidgetClass,
574 : xtclient->xtdisplay,
575 : NULL, 0);
576 0 : xtclient->top_widget = top_widget;
577 :
578 : /* set size of Xt window */
579 0 : n = 0;
580 0 : XtSetArg(args[n], XtNheight, height);n++;
581 0 : XtSetArg(args[n], XtNwidth, width);n++;
582 0 : XtSetValues(top_widget, args, n);
583 :
584 0 : child_widget = XtVaCreateWidget("form",
585 : compositeWidgetClass,
586 : top_widget, NULL);
587 :
588 0 : n = 0;
589 0 : XtSetArg(args[n], XtNheight, height);n++;
590 0 : XtSetArg(args[n], XtNwidth, width);n++;
591 0 : XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++;
592 0 : XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++;
593 0 : XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
594 0 : XtSetArg(args[n], XtNborderWidth, 0); n++;
595 0 : XtSetValues(child_widget, args, n);
596 :
597 0 : XSync(xtclient->xtdisplay, FALSE);
598 0 : xtclient->oldwindow = top_widget->core.window;
599 0 : top_widget->core.window = embedderid;
600 :
601 : /* this little trick seems to finish initializing the widget */
602 : #if XlibSpecificationRelease >= 6
603 0 : XtRegisterDrawable(xtclient->xtdisplay,
604 : embedderid,
605 : top_widget);
606 : #else
607 : _XtRegisterWindow( embedderid,
608 : top_widget);
609 : #endif
610 0 : XtRealizeWidget(child_widget);
611 :
612 : /* listen to all Xt events */
613 0 : XSelectInput(xtclient->xtdisplay,
614 : XtWindow(top_widget),
615 : 0x0FFFFF);
616 0 : xt_client_set_info (child_widget, 0);
617 :
618 0 : XtManageChild(child_widget);
619 0 : xtclient->child_widget = child_widget;
620 :
621 : /* set the event handler */
622 0 : XtAddEventHandler(child_widget,
623 : 0x0FFFFF & ~ResizeRedirectMask,
624 : TRUE,
625 : (XtEventHandler)xt_client_event_handler, xtclient);
626 0 : XtAddEventHandler(child_widget,
627 : SubstructureNotifyMask | ButtonReleaseMask,
628 : TRUE,
629 : (XtEventHandler)xt_client_focus_listener,
630 : xtclient);
631 0 : XSync(xtclient->xtdisplay, FALSE);
632 0 : }
633 :
634 : static void
635 0 : xt_client_unrealize ( XtClient* xtclient )
636 : {
637 : #if XlibSpecificationRelease >= 6
638 0 : XtUnregisterDrawable(xtclient->xtdisplay,
639 0 : xtclient->top_widget->core.window);
640 : #else
641 : _XtUnregisterWindow(xtclient->top_widget->core.window,
642 : xtclient->top_widget);
643 : #endif
644 :
645 : /* flush the queue before we returning origin top_widget->core.window
646 : or we can get X error since the window is gone */
647 0 : XSync(xtclient->xtdisplay, False);
648 :
649 0 : xtclient->top_widget->core.window = xtclient->oldwindow;
650 0 : XtUnrealizeWidget(xtclient->top_widget);
651 0 : }
652 :
653 : static void
654 0 : xt_client_destroy (XtClient* xtclient)
655 : {
656 0 : if(xtclient->top_widget) {
657 0 : XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE,
658 : (XtEventHandler)xt_client_event_handler, xtclient);
659 0 : XtDestroyWidget(xtclient->top_widget);
660 0 : xtclient->top_widget = NULL;
661 : }
662 0 : }
663 :
664 : static void
665 0 : xt_client_set_info (Widget xtplug, unsigned long flags)
666 : {
667 : unsigned long buffer[2];
668 :
669 0 : Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
670 :
671 0 : buffer[1] = 0; /* Protocol version */
672 0 : buffer[1] = flags;
673 :
674 0 : XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
675 : infoAtom, infoAtom, 32,
676 : PropModeReplace,
677 : (unsigned char *)buffer, 2);
678 0 : }
679 :
680 : static void
681 0 : xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
682 : {
683 0 : XtClient *xtplug = (XtClient*)client_data;
684 0 : switch (event->xclient.data.l[1])
685 : {
686 : case XEMBED_EMBEDDED_NOTIFY:
687 0 : break;
688 : case XEMBED_WINDOW_ACTIVATE:
689 : #ifdef DEBUG_XTBIN
690 : printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
691 : #endif
692 0 : break;
693 : case XEMBED_WINDOW_DEACTIVATE:
694 : #ifdef DEBUG_XTBIN
695 : printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
696 : #endif
697 0 : break;
698 : case XEMBED_MODALITY_ON:
699 : #ifdef DEBUG_XTBIN
700 : printf("Xt client get XEMBED_MODALITY_ON\n");
701 : #endif
702 0 : break;
703 : case XEMBED_MODALITY_OFF:
704 : #ifdef DEBUG_XTBIN
705 : printf("Xt client get XEMBED_MODALITY_OFF\n");
706 : #endif
707 0 : break;
708 : case XEMBED_FOCUS_IN:
709 : case XEMBED_FOCUS_OUT:
710 : {
711 : XEvent xevent;
712 0 : memset(&xevent, 0, sizeof(xevent));
713 :
714 0 : if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
715 : #ifdef DEBUG_XTBIN
716 : printf("XTEMBED got focus in\n");
717 : #endif
718 0 : xevent.xfocus.type = FocusIn;
719 : }
720 : else {
721 : #ifdef DEBUG_XTBIN
722 : printf("XTEMBED got focus out\n");
723 : #endif
724 0 : xevent.xfocus.type = FocusOut;
725 : }
726 :
727 0 : xevent.xfocus.window = XtWindow(xtplug->child_widget);
728 0 : xevent.xfocus.display = XtDisplay(xtplug->child_widget);
729 0 : XSendEvent(XtDisplay(xtplug->child_widget),
730 : xevent.xfocus.window,
731 : False, NoEventMask,
732 : &xevent );
733 0 : XSync( XtDisplay(xtplug->child_widget), False);
734 : }
735 0 : break;
736 : default:
737 0 : break;
738 : } /* End of XEmbed Message */
739 0 : }
740 :
741 : static void
742 0 : xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
743 : {
744 0 : XtClient *xtplug = (XtClient*)client_data;
745 :
746 0 : switch(event->type)
747 : {
748 : case ClientMessage:
749 : /* Handle xembed message */
750 0 : if (event->xclient.message_type==
751 0 : XInternAtom (XtDisplay(xtplug->child_widget),
752 : "_XEMBED", False)) {
753 0 : xt_client_handle_xembed_message(w, client_data, event);
754 : }
755 0 : break;
756 : case ReparentNotify:
757 0 : break;
758 : case MappingNotify:
759 0 : xt_client_set_info (w, XEMBED_MAPPED);
760 0 : break;
761 : case UnmapNotify:
762 0 : xt_client_set_info (w, 0);
763 0 : break;
764 : case FocusIn:
765 0 : send_xembed_message ( xtplug,
766 : XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
767 0 : break;
768 : case FocusOut:
769 0 : break;
770 : case KeyPress:
771 : #ifdef DEBUG_XTBIN
772 : printf("Key Press Got!\n");
773 : #endif
774 0 : break;
775 : default:
776 0 : break;
777 : } /* End of switch(event->type) */
778 0 : }
779 :
780 : static void
781 0 : send_xembed_message (XtClient *xtclient,
782 : long message,
783 : long detail,
784 : long data1,
785 : long data2,
786 : long time)
787 : {
788 : XEvent xevent;
789 0 : Window w=XtWindow(xtclient->top_widget);
790 0 : Display* dpy=xtclient->xtdisplay;
791 : int errorcode;
792 :
793 0 : memset(&xevent,0,sizeof(xevent));
794 0 : xevent.xclient.window = w;
795 0 : xevent.xclient.type = ClientMessage;
796 0 : xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
797 0 : xevent.xclient.format = 32;
798 0 : xevent.xclient.data.l[0] = time;
799 0 : xevent.xclient.data.l[1] = message;
800 0 : xevent.xclient.data.l[2] = detail;
801 0 : xevent.xclient.data.l[3] = data1;
802 0 : xevent.xclient.data.l[4] = data2;
803 :
804 0 : trap_errors ();
805 0 : XSendEvent (dpy, w, False, NoEventMask, &xevent);
806 0 : XSync (dpy,False);
807 :
808 0 : if((errorcode = untrap_error())) {
809 : #ifdef DEBUG_XTBIN
810 : printf("send_xembed_message error(%d)!!!\n",errorcode);
811 : #endif
812 : }
813 0 : }
814 :
815 : static int
816 0 : error_handler(Display *display, XErrorEvent *error)
817 : {
818 0 : trapped_error_code = error->error_code;
819 0 : return 0;
820 : }
821 :
822 : static void
823 0 : trap_errors(void)
824 : {
825 0 : trapped_error_code =0;
826 0 : old_error_handler = XSetErrorHandler(error_handler);
827 0 : }
828 :
829 : static int
830 0 : untrap_error(void)
831 : {
832 0 : XSetErrorHandler(old_error_handler);
833 0 : if(trapped_error_code) {
834 : #ifdef DEBUG_XTBIN
835 : printf("Get X Window Error = %d\n", trapped_error_code);
836 : #endif
837 : }
838 0 : return trapped_error_code;
839 : }
840 :
841 : static void
842 0 : xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
843 : {
844 0 : Display *dpy = XtDisplay(w);
845 0 : XtClient *xtclient = user_data;
846 0 : Window win = XtWindow(w);
847 :
848 0 : switch(event->type)
849 : {
850 : case CreateNotify:
851 0 : if(event->xcreatewindow.parent == win) {
852 0 : Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
853 0 : if (child)
854 0 : xt_add_focus_listener_tree(child, user_data);
855 : }
856 0 : break;
857 : case DestroyNotify:
858 0 : xt_remove_focus_listener( w, user_data);
859 0 : break;
860 : case ReparentNotify:
861 0 : if(event->xreparent.parent == win) {
862 : /* I am the new parent */
863 0 : Widget child=XtWindowToWidget(dpy, event->xreparent.window);
864 0 : if (child)
865 0 : xt_add_focus_listener_tree( child, user_data);
866 : }
867 0 : else if(event->xreparent.window == win) {
868 : /* I am the new child */
869 : }
870 : else {
871 : /* I am the old parent */
872 : }
873 0 : break;
874 : case ButtonRelease:
875 : #if 0
876 : XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
877 : #endif
878 0 : send_xembed_message ( xtclient,
879 : XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
880 0 : break;
881 : default:
882 0 : break;
883 : } /* End of switch(event->type) */
884 0 : }
885 :
886 : static void
887 0 : xt_add_focus_listener( Widget w, XtPointer user_data)
888 : {
889 : XWindowAttributes attr;
890 : long eventmask;
891 0 : XtClient *xtclient = user_data;
892 : int errorcode;
893 :
894 0 : trap_errors ();
895 0 : XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr);
896 0 : eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask;
897 0 : XSelectInput(XtDisplay(w),
898 : XtWindow(w),
899 : eventmask);
900 :
901 0 : XtAddEventHandler(w,
902 : SubstructureNotifyMask | ButtonReleaseMask,
903 : TRUE,
904 : (XtEventHandler)xt_client_focus_listener,
905 : xtclient);
906 0 : untrap_error();
907 0 : }
908 :
909 : static void
910 0 : xt_remove_focus_listener(Widget w, XtPointer user_data)
911 : {
912 : int errorcode;
913 :
914 0 : trap_errors ();
915 0 : XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE,
916 : (XtEventHandler)xt_client_focus_listener, user_data);
917 :
918 0 : untrap_error();
919 0 : }
920 :
921 : static void
922 0 : xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
923 : {
924 0 : Window win = XtWindow(treeroot);
925 : Window *children;
926 : Window root, parent;
927 0 : Display *dpy = XtDisplay(treeroot);
928 : unsigned int i, nchildren;
929 :
930 : /* ensure we don't add more than once */
931 0 : xt_remove_focus_listener( treeroot, user_data);
932 0 : xt_add_focus_listener( treeroot, user_data);
933 0 : trap_errors();
934 0 : if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
935 0 : untrap_error();
936 0 : return;
937 : }
938 :
939 0 : if(untrap_error())
940 0 : return;
941 :
942 0 : for(i=0; i<nchildren; ++i) {
943 0 : Widget child = XtWindowToWidget(dpy, children[i]);
944 0 : if (child)
945 0 : xt_add_focus_listener_tree( child, user_data);
946 : }
947 0 : XFree((void*)children);
948 :
949 0 : return;
950 : }
951 :
|