widget/gtkxtbin/gtk2xtbin.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial