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
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.
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 "GtkVersioning.h"
47
#include "gtk2xtbin.h"
49
#ifdef GTK_API_VERSION_2
55
#include <sys/types.h>
62
#include <X11/Xutil.h>
63
#include <X11/Shell.h>
64
#include <X11/Intrinsic.h>
65
#include <X11/StringDefs.h>
67
/* uncomment this if you want debugging information about widget
68
creation and destruction */
71
#define XTBIN_MAX_EVENTS 30
73
static void gtk_xtbin_class_init (GtkXtBinClass *klass);
74
static void gtk_xtbin_init (GtkXtBin *xtbin);
75
static void gtk_xtbin_realize (GtkWidget *widget);
76
static void gtk_xtbin_unrealize (GtkWidget *widget);
77
static void gtk_xtbin_dispose (GObject *object);
80
static void xt_client_init (XtClient * xtclient,
84
static void xt_client_create (XtClient * xtclient,
88
static void xt_client_unrealize (XtClient* xtclient);
89
static void xt_client_destroy (XtClient* xtclient);
90
static void xt_client_set_info (Widget xtplug,
92
static void xt_client_event_handler (Widget w,
93
XtPointer client_data,
95
static void xt_client_handle_xembed_message (Widget w,
96
XtPointer client_data,
98
static void xt_client_focus_listener (Widget w,
101
static void xt_add_focus_listener( Widget w, XtPointer user_data );
102
static void xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data);
103
static void xt_remove_focus_listener(Widget w, XtPointer user_data);
104
static void send_xembed_message (XtClient *xtclient,
110
static int error_handler (Display *display,
112
/* For error trap of XEmbed */
113
static void trap_errors(void);
114
static int untrap_error(void);
115
static int (*old_error_handler) (Display *, XErrorEvent *);
116
static int trapped_error_code = 0;
118
static GtkWidgetClass *parent_class = NULL;
120
static Display *xtdisplay = NULL;
121
static String *fallback = NULL;
122
static gboolean xt_is_initialized = FALSE;
123
static gint num_widgets = 0;
125
static GPollFD xt_event_poll_fd;
126
static gint xt_polling_timer_id = 0;
127
static guint tag = 0;
130
xt_event_prepare (GSource* source_data,
136
mask = XPending(xtdisplay);
139
return (gboolean)mask;
143
xt_event_check (GSource* source_data)
147
if (xt_event_poll_fd.revents & G_IO_IN) {
149
mask = XPending(xtdisplay);
151
return (gboolean)mask;
159
xt_event_dispatch (GSource* source_data,
160
GSourceFunc call_back,
166
ac = XtDisplayToApplicationContext(xtdisplay);
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
175
for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) {
176
XtAppProcessEvent(ac, XtIMXEvent);
184
typedef void (*GSourceFuncsFinalize) (GSource* source);
186
static GSourceFuncs xt_event_funcs = {
190
(GSourceFuncsFinalize)g_free,
192
(GSourceDummyMarshal)NULL
196
xt_event_polling_timer_callback(gpointer user_data)
200
int eventsToProcess = 20;
202
display = (Display *)user_data;
203
ac = XtDisplayToApplicationContext(display);
205
/* We need to process many Xt events here. If we just process
206
one event we might starve one or more Xt consumers. On the other hand
207
this could hang the whole app if Xt events come pouring in. So process
208
up to 20 Xt events right now and save the rest for later. This is a hack,
209
but it oughta work. We *really* should have out of process plugins.
211
while (eventsToProcess-- && XtAppPending(ac))
212
XtAppProcessEvent(ac, XtIMAll);
217
gtk_xtbin_get_type (void)
219
static GType xtbin_type = 0;
222
static const GTypeInfo xtbin_info =
224
sizeof (GtkXtBinClass),
228
(GClassInitFunc)gtk_xtbin_class_init,
234
(GInstanceInitFunc)gtk_xtbin_init,
237
xtbin_type = g_type_register_static (GTK_TYPE_SOCKET,
246
gtk_xtbin_class_init (GtkXtBinClass *klass)
248
GtkWidgetClass *widget_class;
249
GObjectClass *object_class;
251
parent_class = g_type_class_peek_parent (klass);
253
widget_class = GTK_WIDGET_CLASS (klass);
254
widget_class->realize = gtk_xtbin_realize;
255
widget_class->unrealize = gtk_xtbin_unrealize;
257
object_class = G_OBJECT_CLASS (klass);
258
object_class->dispose = gtk_xtbin_dispose;
262
gtk_xtbin_init (GtkXtBin *xtbin)
264
xtbin->xtdisplay = NULL;
265
xtbin->parent_window = NULL;
272
gtk_xtbin_realize (GtkWidget *widget)
275
GtkAllocation allocation = { 0, 0, 200, 200 };
276
#if GTK_CHECK_VERSION(2, 18, 0)
277
GtkAllocation widget_allocation;
281
printf("gtk_xtbin_realize()\n");
284
g_return_if_fail (GTK_IS_XTBIN (widget));
286
xtbin = GTK_XTBIN (widget);
288
/* caculate the allocation before realize */
289
#if GTK_CHECK_VERSION(2, 24, 0)
290
allocation.width = gdk_window_get_width(xtbin->parent_window);
291
allocation.height = gdk_window_get_height(xtbin->parent_window);
293
gint x, y, w, h, d; /* geometry of window */
294
gdk_window_get_geometry(xtbin->parent_window, &x, &y, &w, &h, &d);
295
allocation.width = w;
296
allocation.height = h;
298
gtk_widget_size_allocate (widget, &allocation);
301
printf("initial allocation %d %d %d %d\n", x, y, w, h);
304
#if GTK_CHECK_VERSION(2, 18, 0)
305
gtk_widget_get_allocation(widget, &widget_allocation);
306
xtbin->width = widget_allocation.width;
307
xtbin->height = widget_allocation.height;
309
xtbin->width = widget->allocation.width;
310
xtbin->height = widget->allocation.height;
313
/* use GtkSocket's realize */
314
(*GTK_WIDGET_CLASS(parent_class)->realize)(widget);
316
/* create the Xt client widget */
317
xt_client_create(&(xtbin->xtclient),
318
gtk_socket_get_id(GTK_SOCKET(xtbin)),
321
xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget);
325
/* now that we have created the xt client, add it to the socket. */
326
gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow);
332
gtk_xtbin_new (GtkWidget *parent_widget, String *f)
339
GdkWindow* parent_window = gtk_widget_get_window(parent_widget);
341
assert(parent_window != NULL);
342
xtbin = g_object_new (GTK_TYPE_XTBIN, NULL);
345
return (GtkWidget*)NULL;
350
/* Initialize the Xt toolkit */
351
xtbin->parent_window = parent_window;
353
screen = gtk_widget_get_screen(parent_widget);
354
visual = gdk_screen_get_system_visual(screen);
355
colormap = XCreateColormap(GDK_DISPLAY_XDISPLAY(gdk_screen_get_display(screen)),
356
GDK_WINDOW_XWINDOW(gdk_screen_get_root_window(screen)),
357
GDK_VISUAL_XVISUAL(visual), AllocNone);
359
xt_client_init(&(xtbin->xtclient),
360
GDK_VISUAL_XVISUAL(visual),
362
gdk_visual_get_depth(visual));
364
if (!xtbin->xtclient.xtdisplay) {
365
/* If XtOpenDisplay failed, we can't go any further.
369
printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n");
372
return (GtkWidget *)NULL;
375
/* If this is the first running widget, hook this display into the
377
if (0 == num_widgets) {
380
* hook Xt event loop into the glib event loop.
383
/* the assumption is that gtk_init has already been called */
384
GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource));
389
g_source_set_priority(gs, GDK_PRIORITY_EVENTS);
390
g_source_set_can_recurse(gs, TRUE);
391
tag = g_source_attach(gs, (GMainContext*)NULL);
393
cnumber = XConnectionNumber(xtdisplay);
395
cnumber = ConnectionNumber(xtdisplay);
397
xt_event_poll_fd.fd = cnumber;
398
xt_event_poll_fd.events = G_IO_IN;
399
xt_event_poll_fd.revents = 0; /* hmm... is this correct? */
401
g_main_context_add_poll ((GMainContext*)NULL,
404
/* add a timer so that we can poll and process Xt timers */
405
xt_polling_timer_id =
407
(GSourceFunc)xt_event_polling_timer_callback,
411
/* Bump up our usage count */
414
/* Build the hierachy */
415
xtbin->xtdisplay = xtbin->xtclient.xtdisplay;
416
gtk_widget_set_parent_window(GTK_WIDGET(xtbin), parent_window);
417
gdk_window_get_user_data(xtbin->parent_window, &user_data);
419
gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin));
421
return GTK_WIDGET (xtbin);
425
gtk_xtbin_set_position (GtkXtBin *xtbin,
432
if (gtk_widget_get_realized (GTK_WIDGET(xtbin)))
433
gdk_window_move (gtk_widget_get_window(GTK_WIDGET (xtbin)), x, y);
437
gtk_xtbin_resize (GtkWidget *widget,
442
GtkXtBin *xtbin = GTK_XTBIN (widget);
443
GtkAllocation allocation;
446
printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height);
449
xtbin->height = height;
450
xtbin->width = width;
452
// Avoid BadValue errors in XtSetValues
453
if (height <= 0 || width <=0) {
457
XtSetArg(args[0], XtNheight, height);
458
XtSetArg(args[1], XtNwidth, width);
459
XtSetValues(xtbin->xtclient.top_widget, args, 2);
461
/* we need to send a size allocate so the socket knows about the
463
allocation.x = xtbin->x;
464
allocation.y = xtbin->y;
465
allocation.width = xtbin->width;
466
allocation.height = xtbin->height;
468
gtk_widget_size_allocate(widget, &allocation);
472
gtk_xtbin_unrealize (GtkWidget *object)
478
printf("gtk_xtbin_unrealize()\n");
481
/* gtk_object_destroy() will already hold a refcount on object
483
xtbin = GTK_XTBIN(object);
484
widget = GTK_WIDGET(object);
486
gtk_widget_set_visible(widget, FALSE);
487
if (gtk_widget_get_realized (widget)) {
488
xt_client_unrealize(&(xtbin->xtclient));
491
(*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget);
495
gtk_xtbin_dispose (GObject *object)
500
printf("gtk_xtbin_destroy()\n");
503
g_return_if_fail (object != NULL);
504
g_return_if_fail (GTK_IS_XTBIN (object));
506
xtbin = GTK_XTBIN (object);
508
if(xtbin->xtwindow) {
509
/* remove the event handler */
510
xt_client_destroy(&(xtbin->xtclient));
513
num_widgets--; /* reduce our usage count */
515
/* If this is the last running widget, remove the Xt display
516
connection from the mainloop */
517
if (0 == num_widgets) {
519
printf("removing the Xt connection from the main loop\n");
521
g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd);
522
g_source_remove(tag);
524
g_source_remove(xt_polling_timer_id);
525
xt_polling_timer_id = 0;
529
G_OBJECT_CLASS(parent_class)->dispose(object);
533
* Following is the implementation of Xt XEmbedded for client side
536
/* Initial Xt plugin */
538
xt_client_init( XtClient * xtclient,
543
XtAppContext app_context;
548
* Initialize Xt stuff
550
xtclient->top_widget = NULL;
551
xtclient->child_widget = NULL;
552
xtclient->xtdisplay = NULL;
553
xtclient->xtvisual = NULL;
554
xtclient->xtcolormap = 0;
555
xtclient->xtdepth = 0;
557
if (!xt_is_initialized) {
559
printf("starting up Xt stuff\n");
561
XtToolkitInitialize();
562
app_context = XtCreateApplicationContext();
564
XtAppSetFallbackResources(app_context, fallback);
566
xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL,
567
"Wrapper", NULL, 0, &mArgc, mArgv);
569
xt_is_initialized = TRUE;
571
xtclient->xtdisplay = xtdisplay;
572
xtclient->xtvisual = xtvisual;
573
xtclient->xtcolormap = xtcolormap;
574
xtclient->xtdepth = xtdepth;
577
/* Create the Xt client widgets
580
xt_client_create ( XtClient* xtclient ,
591
printf("xt_client_create() \n");
593
top_widget = XtAppCreateShell("drawingArea", "Wrapper",
594
applicationShellWidgetClass,
597
xtclient->top_widget = top_widget;
599
/* set size of Xt window */
601
XtSetArg(args[n], XtNheight, height);n++;
602
XtSetArg(args[n], XtNwidth, width);n++;
603
XtSetValues(top_widget, args, n);
605
child_widget = XtVaCreateWidget("form",
606
compositeWidgetClass,
610
XtSetArg(args[n], XtNheight, height);n++;
611
XtSetArg(args[n], XtNwidth, width);n++;
612
XtSetArg(args[n], XtNvisual, xtclient->xtvisual ); n++;
613
XtSetArg(args[n], XtNdepth, xtclient->xtdepth ); n++;
614
XtSetArg(args[n], XtNcolormap, xtclient->xtcolormap ); n++;
615
XtSetArg(args[n], XtNborderWidth, 0); n++;
616
XtSetValues(child_widget, args, n);
618
XSync(xtclient->xtdisplay, FALSE);
619
xtclient->oldwindow = top_widget->core.window;
620
top_widget->core.window = embedderid;
622
/* this little trick seems to finish initializing the widget */
623
#if XlibSpecificationRelease >= 6
624
XtRegisterDrawable(xtclient->xtdisplay,
628
_XtRegisterWindow( embedderid,
631
XtRealizeWidget(child_widget);
633
/* listen to all Xt events */
634
XSelectInput(xtclient->xtdisplay,
635
XtWindow(top_widget),
637
xt_client_set_info (child_widget, 0);
639
XtManageChild(child_widget);
640
xtclient->child_widget = child_widget;
642
/* set the event handler */
643
XtAddEventHandler(child_widget,
644
0x0FFFFF & ~ResizeRedirectMask,
646
(XtEventHandler)xt_client_event_handler, xtclient);
647
XtAddEventHandler(child_widget,
648
SubstructureNotifyMask | ButtonReleaseMask,
650
(XtEventHandler)xt_client_focus_listener,
652
XSync(xtclient->xtdisplay, FALSE);
656
xt_client_unrealize ( XtClient* xtclient )
658
#if XlibSpecificationRelease >= 6
659
XtUnregisterDrawable(xtclient->xtdisplay,
660
xtclient->top_widget->core.window);
662
_XtUnregisterWindow(xtclient->top_widget->core.window,
663
xtclient->top_widget);
666
/* flush the queue before we returning origin top_widget->core.window
667
or we can get X error since the window is gone */
668
XSync(xtclient->xtdisplay, False);
670
xtclient->top_widget->core.window = xtclient->oldwindow;
671
XtUnrealizeWidget(xtclient->top_widget);
675
xt_client_destroy (XtClient* xtclient)
677
if(xtclient->top_widget) {
678
XtRemoveEventHandler(xtclient->child_widget, 0x0FFFFF, TRUE,
679
(XtEventHandler)xt_client_event_handler, xtclient);
680
XtDestroyWidget(xtclient->top_widget);
681
xtclient->top_widget = NULL;
686
xt_client_set_info (Widget xtplug, unsigned long flags)
688
unsigned long buffer[2];
690
Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False);
692
buffer[1] = 0; /* Protocol version */
695
XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug),
696
infoAtom, infoAtom, 32,
698
(unsigned char *)buffer, 2);
702
xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event)
704
XtClient *xtplug = (XtClient*)client_data;
705
switch (event->xclient.data.l[1])
707
case XEMBED_EMBEDDED_NOTIFY:
709
case XEMBED_WINDOW_ACTIVATE:
711
printf("Xt client get XEMBED_WINDOW_ACTIVATE\n");
714
case XEMBED_WINDOW_DEACTIVATE:
716
printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n");
719
case XEMBED_MODALITY_ON:
721
printf("Xt client get XEMBED_MODALITY_ON\n");
724
case XEMBED_MODALITY_OFF:
726
printf("Xt client get XEMBED_MODALITY_OFF\n");
729
case XEMBED_FOCUS_IN:
730
case XEMBED_FOCUS_OUT:
733
memset(&xevent, 0, sizeof(xevent));
735
if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) {
737
printf("XTEMBED got focus in\n");
739
xevent.xfocus.type = FocusIn;
743
printf("XTEMBED got focus out\n");
745
xevent.xfocus.type = FocusOut;
748
xevent.xfocus.window = XtWindow(xtplug->child_widget);
749
xevent.xfocus.display = XtDisplay(xtplug->child_widget);
750
XSendEvent(XtDisplay(xtplug->child_widget),
751
xevent.xfocus.window,
754
XSync( XtDisplay(xtplug->child_widget), False);
759
} /* End of XEmbed Message */
763
xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event)
765
XtClient *xtplug = (XtClient*)client_data;
770
/* Handle xembed message */
771
if (event->xclient.message_type==
772
XInternAtom (XtDisplay(xtplug->child_widget),
774
xt_client_handle_xembed_message(w, client_data, event);
780
xt_client_set_info (w, XEMBED_MAPPED);
783
xt_client_set_info (w, 0);
786
send_xembed_message ( xtplug,
787
XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
793
printf("Key Press Got!\n");
798
} /* End of switch(event->type) */
802
send_xembed_message (XtClient *xtclient,
810
Window w=XtWindow(xtclient->top_widget);
811
Display* dpy=xtclient->xtdisplay;
814
memset(&xevent,0,sizeof(xevent));
815
xevent.xclient.window = w;
816
xevent.xclient.type = ClientMessage;
817
xevent.xclient.message_type = XInternAtom(dpy,"_XEMBED",False);
818
xevent.xclient.format = 32;
819
xevent.xclient.data.l[0] = time;
820
xevent.xclient.data.l[1] = message;
821
xevent.xclient.data.l[2] = detail;
822
xevent.xclient.data.l[3] = data1;
823
xevent.xclient.data.l[4] = data2;
826
XSendEvent (dpy, w, False, NoEventMask, &xevent);
829
if((errorcode = untrap_error())) {
831
printf("send_xembed_message error(%d)!!!\n",errorcode);
837
error_handler(Display *display, XErrorEvent *error)
839
trapped_error_code = error->error_code;
846
trapped_error_code =0;
847
old_error_handler = XSetErrorHandler(error_handler);
853
XSetErrorHandler(old_error_handler);
854
if(trapped_error_code) {
856
printf("Get X Window Error = %d\n", trapped_error_code);
859
return trapped_error_code;
863
xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event)
865
Display *dpy = XtDisplay(w);
866
XtClient *xtclient = user_data;
867
Window win = XtWindow(w);
872
if(event->xcreatewindow.parent == win) {
873
Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window);
875
xt_add_focus_listener_tree(child, user_data);
879
xt_remove_focus_listener( w, user_data);
882
if(event->xreparent.parent == win) {
883
/* I am the new parent */
884
Widget child=XtWindowToWidget(dpy, event->xreparent.window);
886
xt_add_focus_listener_tree( child, user_data);
888
else if(event->xreparent.window == win) {
889
/* I am the new child */
892
/* I am the old parent */
897
XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time);
899
send_xembed_message ( xtclient,
900
XEMBED_REQUEST_FOCUS, 0, 0, 0, 0);
904
} /* End of switch(event->type) */
908
xt_add_focus_listener( Widget w, XtPointer user_data)
910
XWindowAttributes attr;
912
XtClient *xtclient = user_data;
915
XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr);
916
eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask;
917
XSelectInput(XtDisplay(w),
922
SubstructureNotifyMask | ButtonReleaseMask,
924
(XtEventHandler)xt_client_focus_listener,
930
xt_remove_focus_listener(Widget w, XtPointer user_data)
933
XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE,
934
(XtEventHandler)xt_client_focus_listener, user_data);
940
xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data)
942
Window win = XtWindow(treeroot);
945
Display *dpy = XtDisplay(treeroot);
946
unsigned int i, nchildren;
948
/* ensure we don't add more than once */
949
xt_remove_focus_listener( treeroot, user_data);
950
xt_add_focus_listener( treeroot, user_data);
952
if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) {
960
for(i=0; i<nchildren; ++i) {
961
Widget child = XtWindowToWidget(dpy, children[i]);
963
xt_add_focus_listener_tree( child, user_data);
965
XFree((void*)children);