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 "GtkVersioning.h" 46 #include "xembed.h" 47 #include "gtk2xtbin.h" 48 #include <gtk/gtk.h> 49 #ifdef GTK_API_VERSION_2 50 #include <gdk/gdkx.h> 51 #endif 52 #include <glib.h> 53 #include <assert.h> 54 #include <sys/time.h> 55 #include <sys/types.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <unistd.h> 59 60 /* Xlib/Xt stuff */ 61 #include <X11/Xlib.h> 62 #include <X11/Xutil.h> 63 #include <X11/Shell.h> 64 #include <X11/Intrinsic.h> 65 #include <X11/StringDefs.h> 66 67 /* uncomment this if you want debugging information about widget 68 creation and destruction */ 69 #undef DEBUG_XTBIN 70 71 #define XTBIN_MAX_EVENTS 30 72 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); 78 79 /* Xt aware XEmbed */ 80 static void xt_client_init (XtClient * xtclient, 81 Visual *xtvisual, 82 Colormap xtcolormap, 83 int xtdepth); 84 static void xt_client_create (XtClient * xtclient, 85 Window embeder, 86 int height, 87 int width ); 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, 91 unsigned long flags); 92 static void xt_client_event_handler (Widget w, 93 XtPointer client_data, 94 XEvent *event); 95 static void xt_client_handle_xembed_message (Widget w, 96 XtPointer client_data, 97 XEvent *event); 98 static void xt_client_focus_listener (Widget w, 99 XtPointer user_data, 100 XEvent *event); 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, 105 long message, 106 long detail, 107 long data1, 108 long data2, 109 long time); 110 static int error_handler (Display *display, 111 XErrorEvent *error); 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; 117 118 static GtkWidgetClass *parent_class = NULL; 119 120 static Display *xtdisplay = NULL; 121 static String *fallback = NULL; 122 static gboolean xt_is_initialized = FALSE; 123 static gint num_widgets = 0; 124 125 static GPollFD xt_event_poll_fd; 126 static gint xt_polling_timer_id = 0; 127 static guint tag = 0; 128 129 static gboolean 130 xt_event_prepare (GSource* source_data, 131 gint *timeout) 132 { 133 int mask; 134 135 GDK_THREADS_ENTER(); 136 mask = XPending(xtdisplay); 137 GDK_THREADS_LEAVE(); 138 139 return (gboolean)mask; 140 } 141 142 static gboolean 143 xt_event_check (GSource* source_data) 144 { 145 GDK_THREADS_ENTER (); 146 147 if (xt_event_poll_fd.revents & G_IO_IN) { 148 int mask; 149 mask = XPending(xtdisplay); 150 GDK_THREADS_LEAVE (); 151 return (gboolean)mask; 152 } 153 154 GDK_THREADS_LEAVE (); 155 return FALSE; 156 } 157 158 static gboolean 159 xt_event_dispatch (GSource* source_data, 160 GSourceFunc call_back, 161 gpointer user_data) 162 { 163 XtAppContext ac; 164 int i = 0; 165 166 ac = XtDisplayToApplicationContext(xtdisplay); 167 168 GDK_THREADS_ENTER (); 169 170 /* Process only real X traffic here. We only look for data on the 171 * pipe, limit it to XTBIN_MAX_EVENTS and only call 172 * XtAppProcessEvent so that it will look for X events. There's no 173 * timer processing here since we already have a timer callback that 174 * does it. */ 175 for (i=0; i < XTBIN_MAX_EVENTS && XPending(xtdisplay); i++) { 176 XtAppProcessEvent(ac, XtIMXEvent); 177 } 178 179 GDK_THREADS_LEAVE (); 180 181 return TRUE; 182 } 183 184 typedef void (*GSourceFuncsFinalize) (GSource* source); 185 186 static GSourceFuncs xt_event_funcs = { 187 xt_event_prepare, 188 xt_event_check, 189 xt_event_dispatch, 190 (GSourceFuncsFinalize)g_free, 191 (GSourceFunc)NULL, 192 (GSourceDummyMarshal)NULL 193 }; 194 195 static gboolean 196 xt_event_polling_timer_callback(gpointer user_data) 197 { 198 Display * display; 199 XtAppContext ac; 200 int eventsToProcess = 20; 201 202 display = (Display *)user_data; 203 ac = XtDisplayToApplicationContext(display); 204 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. 210 */ 211 while (eventsToProcess-- && XtAppPending(ac)) 212 XtAppProcessEvent(ac, XtIMAll); 213 return TRUE; 214 } 215 216 GType 217 gtk_xtbin_get_type (void) 218 { 219 static GType xtbin_type = 0; 220 221 if (!xtbin_type) { 222 static const GTypeInfo xtbin_info = 223 { 224 sizeof (GtkXtBinClass), 225 NULL, 226 NULL, 227 228 (GClassInitFunc)gtk_xtbin_class_init, 229 NULL, 230 NULL, 231 232 sizeof (GtkXtBin), 233 0, 234 (GInstanceInitFunc)gtk_xtbin_init, 235 NULL 236 }; 237 xtbin_type = g_type_register_static (GTK_TYPE_SOCKET, 238 "GtkXtBin", 239 &xtbin_info, 240 0); 241 } 242 return xtbin_type; 243 } 244 245 static void 246 gtk_xtbin_class_init (GtkXtBinClass *klass) 247 { 248 GtkWidgetClass *widget_class; 249 GObjectClass *object_class; 250 251 parent_class = g_type_class_peek_parent (klass); 252 253 widget_class = GTK_WIDGET_CLASS (klass); 254 widget_class->realize = gtk_xtbin_realize; 255 widget_class->unrealize = gtk_xtbin_unrealize; 256 257 object_class = G_OBJECT_CLASS (klass); 258 object_class->dispose = gtk_xtbin_dispose; 259 } 260 261 static void 262 gtk_xtbin_init (GtkXtBin *xtbin) 263 { 264 xtbin->xtdisplay = NULL; 265 xtbin->parent_window = NULL; 266 xtbin->xtwindow = 0; 267 xtbin->x = 0; 268 xtbin->y = 0; 269 } 270 271 static void 272 gtk_xtbin_realize (GtkWidget *widget) 273 { 274 GtkXtBin *xtbin; 275 GtkAllocation allocation = { 0, 0, 200, 200 }; 276 #if GTK_CHECK_VERSION(2, 18, 0) 277 GtkAllocation widget_allocation; 278 #endif 279 280 #ifdef DEBUG_XTBIN 281 printf("gtk_xtbin_realize()\n"); 282 #endif 283 284 g_return_if_fail (GTK_IS_XTBIN (widget)); 285 286 xtbin = GTK_XTBIN (widget); 287 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); 292 #else 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; 297 #endif 298 gtk_widget_size_allocate (widget, &allocation); 299 300 #ifdef DEBUG_XTBIN 301 printf("initial allocation %d %d %d %d\n", x, y, w, h); 302 #endif 303 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; 308 #else 309 xtbin->width = widget->allocation.width; 310 xtbin->height = widget->allocation.height; 311 #endif 312 313 /* use GtkSocket's realize */ 314 (*GTK_WIDGET_CLASS(parent_class)->realize)(widget); 315 316 /* create the Xt client widget */ 317 xt_client_create(&(xtbin->xtclient), 318 gtk_socket_get_id(GTK_SOCKET(xtbin)), 319 xtbin->height, 320 xtbin->width); 321 xtbin->xtwindow = XtWindow(xtbin->xtclient.child_widget); 322 323 gdk_flush(); 324 325 /* now that we have created the xt client, add it to the socket. */ 326 gtk_socket_add_id(GTK_SOCKET(widget), xtbin->xtwindow); 327 } 328 329 330 331 GtkWidget* 332 gtk_xtbin_new (GtkWidget *parent_widget, String *f) 333 { 334 GtkXtBin *xtbin; 335 gpointer user_data; 336 GdkScreen *screen; 337 GdkVisual* visual; 338 Colormap colormap; 339 GdkWindow* parent_window = gtk_widget_get_window(parent_widget); 340 341 assert(parent_window != NULL); 342 xtbin = g_object_new (GTK_TYPE_XTBIN, NULL); 343 344 if (!xtbin) 345 return (GtkWidget*)NULL; 346 347 if (f) 348 fallback = f; 349 350 /* Initialize the Xt toolkit */ 351 xtbin->parent_window = parent_window; 352 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); 358 359 xt_client_init(&(xtbin->xtclient), 360 GDK_VISUAL_XVISUAL(visual), 361 colormap, 362 gdk_visual_get_depth(visual)); 363 364 if (!xtbin->xtclient.xtdisplay) { 365 /* If XtOpenDisplay failed, we can't go any further. 366 * Bail out. 367 */ 368 #ifdef DEBUG_XTBIN 369 printf("gtk_xtbin_init: XtOpenDisplay() returned NULL.\n"); 370 #endif 371 g_free (xtbin); 372 return (GtkWidget *)NULL; 373 } 374 375 /* If this is the first running widget, hook this display into the 376 mainloop */ 377 if (0 == num_widgets) { 378 int cnumber; 379 /* 380 * hook Xt event loop into the glib event loop. 381 */ 382 383 /* the assumption is that gtk_init has already been called */ 384 GSource* gs = g_source_new(&xt_event_funcs, sizeof(GSource)); 385 if (!gs) { 386 return NULL; 387 } 388 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); 392 #ifdef VMS 393 cnumber = XConnectionNumber(xtdisplay); 394 #else 395 cnumber = ConnectionNumber(xtdisplay); 396 #endif 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? */ 400 401 g_main_context_add_poll ((GMainContext*)NULL, 402 &xt_event_poll_fd, 403 G_PRIORITY_LOW); 404 /* add a timer so that we can poll and process Xt timers */ 405 xt_polling_timer_id = 406 g_timeout_add(25, 407 (GSourceFunc)xt_event_polling_timer_callback, 408 xtdisplay); 409 } 410 411 /* Bump up our usage count */ 412 num_widgets++; 413 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); 418 if (user_data) 419 gtk_container_add(GTK_CONTAINER(user_data), GTK_WIDGET(xtbin)); 420 421 return GTK_WIDGET (xtbin); 422 } 423 424 void 425 gtk_xtbin_set_position (GtkXtBin *xtbin, 426 gint x, 427 gint y) 428 { 429 xtbin->x = x; 430 xtbin->y = y; 431 432 if (gtk_widget_get_realized (GTK_WIDGET(xtbin))) 433 gdk_window_move (gtk_widget_get_window(GTK_WIDGET (xtbin)), x, y); 434 } 435 436 void 437 gtk_xtbin_resize (GtkWidget *widget, 438 gint width, 439 gint height) 440 { 441 Arg args[2]; 442 GtkXtBin *xtbin = GTK_XTBIN (widget); 443 GtkAllocation allocation; 444 445 #ifdef DEBUG_XTBIN 446 printf("gtk_xtbin_resize %p %d %d\n", (void *)widget, width, height); 447 #endif 448 449 xtbin->height = height; 450 xtbin->width = width; 451 452 // Avoid BadValue errors in XtSetValues 453 if (height <= 0 || width <=0) { 454 height = 1; 455 width = 1; 456 } 457 XtSetArg(args[0], XtNheight, height); 458 XtSetArg(args[1], XtNwidth, width); 459 XtSetValues(xtbin->xtclient.top_widget, args, 2); 460 461 /* we need to send a size allocate so the socket knows about the 462 size changes */ 463 allocation.x = xtbin->x; 464 allocation.y = xtbin->y; 465 allocation.width = xtbin->width; 466 allocation.height = xtbin->height; 467 468 gtk_widget_size_allocate(widget, &allocation); 469 } 470 471 static void 472 gtk_xtbin_unrealize (GtkWidget *object) 473 { 474 GtkXtBin *xtbin; 475 GtkWidget *widget; 476 477 #ifdef DEBUG_XTBIN 478 printf("gtk_xtbin_unrealize()\n"); 479 #endif 480 481 /* gtk_object_destroy() will already hold a refcount on object 482 */ 483 xtbin = GTK_XTBIN(object); 484 widget = GTK_WIDGET(object); 485 486 gtk_widget_set_visible(widget, FALSE); 487 if (gtk_widget_get_realized (widget)) { 488 xt_client_unrealize(&(xtbin->xtclient)); 489 } 490 491 (*GTK_WIDGET_CLASS (parent_class)->unrealize)(widget); 492 } 493 494 static void 495 gtk_xtbin_dispose (GObject *object) 496 { 497 GtkXtBin *xtbin; 498 499 #ifdef DEBUG_XTBIN 500 printf("gtk_xtbin_destroy()\n"); 501 #endif 502 503 g_return_if_fail (object != NULL); 504 g_return_if_fail (GTK_IS_XTBIN (object)); 505 506 xtbin = GTK_XTBIN (object); 507 508 if(xtbin->xtwindow) { 509 /* remove the event handler */ 510 xt_client_destroy(&(xtbin->xtclient)); 511 xtbin->xtwindow = 0; 512 513 num_widgets--; /* reduce our usage count */ 514 515 /* If this is the last running widget, remove the Xt display 516 connection from the mainloop */ 517 if (0 == num_widgets) { 518 #ifdef DEBUG_XTBIN 519 printf("removing the Xt connection from the main loop\n"); 520 #endif 521 g_main_context_remove_poll((GMainContext*)NULL, &xt_event_poll_fd); 522 g_source_remove(tag); 523 524 g_source_remove(xt_polling_timer_id); 525 xt_polling_timer_id = 0; 526 } 527 } 528 529 G_OBJECT_CLASS(parent_class)->dispose(object); 530 } 531 532 /* 533 * Following is the implementation of Xt XEmbedded for client side 534 */ 535 536 /* Initial Xt plugin */ 537 static void 538 xt_client_init( XtClient * xtclient, 539 Visual *xtvisual, 540 Colormap xtcolormap, 541 int xtdepth) 542 { 543 XtAppContext app_context; 544 char *mArgv[1]; 545 int mArgc = 0; 546 547 /* 548 * Initialize Xt stuff 549 */ 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; 556 557 if (!xt_is_initialized) { 558 #ifdef DEBUG_XTBIN 559 printf("starting up Xt stuff\n"); 560 #endif 561 XtToolkitInitialize(); 562 app_context = XtCreateApplicationContext(); 563 if (fallback) 564 XtAppSetFallbackResources(app_context, fallback); 565 566 xtdisplay = XtOpenDisplay(app_context, gdk_get_display(), NULL, 567 "Wrapper", NULL, 0, &mArgc, mArgv); 568 if (xtdisplay) 569 xt_is_initialized = TRUE; 570 } 571 xtclient->xtdisplay = xtdisplay; 572 xtclient->xtvisual = xtvisual; 573 xtclient->xtcolormap = xtcolormap; 574 xtclient->xtdepth = xtdepth; 575 } 576 577 /* Create the Xt client widgets 578 * */ 579 static void 580 xt_client_create ( XtClient* xtclient , 581 Window embedderid, 582 int height, 583 int width ) 584 { 585 int n; 586 Arg args[6]; 587 Widget child_widget; 588 Widget top_widget; 589 590 #ifdef DEBUG_XTBIN 591 printf("xt_client_create() \n"); 592 #endif 593 top_widget = XtAppCreateShell("drawingArea", "Wrapper", 594 applicationShellWidgetClass, 595 xtclient->xtdisplay, 596 NULL, 0); 597 xtclient->top_widget = top_widget; 598 599 /* set size of Xt window */ 600 n = 0; 601 XtSetArg(args[n], XtNheight, height);n++; 602 XtSetArg(args[n], XtNwidth, width);n++; 603 XtSetValues(top_widget, args, n); 604 605 child_widget = XtVaCreateWidget("form", 606 compositeWidgetClass, 607 top_widget, NULL); 608 609 n = 0; 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); 617 618 XSync(xtclient->xtdisplay, FALSE); 619 xtclient->oldwindow = top_widget->core.window; 620 top_widget->core.window = embedderid; 621 622 /* this little trick seems to finish initializing the widget */ 623 #if XlibSpecificationRelease >= 6 624 XtRegisterDrawable(xtclient->xtdisplay, 625 embedderid, 626 top_widget); 627 #else 628 _XtRegisterWindow( embedderid, 629 top_widget); 630 #endif 631 XtRealizeWidget(child_widget); 632 633 /* listen to all Xt events */ 634 XSelectInput(xtclient->xtdisplay, 635 XtWindow(top_widget), 636 0x0FFFFF); 637 xt_client_set_info (child_widget, 0); 638 639 XtManageChild(child_widget); 640 xtclient->child_widget = child_widget; 641 642 /* set the event handler */ 643 XtAddEventHandler(child_widget, 644 0x0FFFFF & ~ResizeRedirectMask, 645 TRUE, 646 (XtEventHandler)xt_client_event_handler, xtclient); 647 XtAddEventHandler(child_widget, 648 SubstructureNotifyMask | ButtonReleaseMask, 649 TRUE, 650 (XtEventHandler)xt_client_focus_listener, 651 xtclient); 652 XSync(xtclient->xtdisplay, FALSE); 653 } 654 655 static void 656 xt_client_unrealize ( XtClient* xtclient ) 657 { 658 #if XlibSpecificationRelease >= 6 659 XtUnregisterDrawable(xtclient->xtdisplay, 660 xtclient->top_widget->core.window); 661 #else 662 _XtUnregisterWindow(xtclient->top_widget->core.window, 663 xtclient->top_widget); 664 #endif 665 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); 669 670 xtclient->top_widget->core.window = xtclient->oldwindow; 671 XtUnrealizeWidget(xtclient->top_widget); 672 } 673 674 static void 675 xt_client_destroy (XtClient* xtclient) 676 { 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; 682 } 683 } 684 685 static void 686 xt_client_set_info (Widget xtplug, unsigned long flags) 687 { 688 unsigned long buffer[2]; 689 690 Atom infoAtom = XInternAtom(XtDisplay(xtplug), "_XEMBED_INFO", False); 691 692 buffer[1] = 0; /* Protocol version */ 693 buffer[1] = flags; 694 695 XChangeProperty (XtDisplay(xtplug), XtWindow(xtplug), 696 infoAtom, infoAtom, 32, 697 PropModeReplace, 698 (unsigned char *)buffer, 2); 699 } 700 701 static void 702 xt_client_handle_xembed_message(Widget w, XtPointer client_data, XEvent *event) 703 { 704 XtClient *xtplug = (XtClient*)client_data; 705 switch (event->xclient.data.l[1]) 706 { 707 case XEMBED_EMBEDDED_NOTIFY: 708 break; 709 case XEMBED_WINDOW_ACTIVATE: 710 #ifdef DEBUG_XTBIN 711 printf("Xt client get XEMBED_WINDOW_ACTIVATE\n"); 712 #endif 713 break; 714 case XEMBED_WINDOW_DEACTIVATE: 715 #ifdef DEBUG_XTBIN 716 printf("Xt client get XEMBED_WINDOW_DEACTIVATE\n"); 717 #endif 718 break; 719 case XEMBED_MODALITY_ON: 720 #ifdef DEBUG_XTBIN 721 printf("Xt client get XEMBED_MODALITY_ON\n"); 722 #endif 723 break; 724 case XEMBED_MODALITY_OFF: 725 #ifdef DEBUG_XTBIN 726 printf("Xt client get XEMBED_MODALITY_OFF\n"); 727 #endif 728 break; 729 case XEMBED_FOCUS_IN: 730 case XEMBED_FOCUS_OUT: 731 { 732 XEvent xevent; 733 memset(&xevent, 0, sizeof(xevent)); 734 735 if(event->xclient.data.l[1] == XEMBED_FOCUS_IN) { 736 #ifdef DEBUG_XTBIN 737 printf("XTEMBED got focus in\n"); 738 #endif 739 xevent.xfocus.type = FocusIn; 740 } 741 else { 742 #ifdef DEBUG_XTBIN 743 printf("XTEMBED got focus out\n"); 744 #endif 745 xevent.xfocus.type = FocusOut; 746 } 747 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, 752 False, NoEventMask, 753 &xevent ); 754 XSync( XtDisplay(xtplug->child_widget), False); 755 } 756 break; 757 default: 758 break; 759 } /* End of XEmbed Message */ 760 } 761 762 static void 763 xt_client_event_handler( Widget w, XtPointer client_data, XEvent *event) 764 { 765 XtClient *xtplug = (XtClient*)client_data; 766 767 switch(event->type) 768 { 769 case ClientMessage: 770 /* Handle xembed message */ 771 if (event->xclient.message_type== 772 XInternAtom (XtDisplay(xtplug->child_widget), 773 "_XEMBED", False)) { 774 xt_client_handle_xembed_message(w, client_data, event); 775 } 776 break; 777 case ReparentNotify: 778 break; 779 case MappingNotify: 780 xt_client_set_info (w, XEMBED_MAPPED); 781 break; 782 case UnmapNotify: 783 xt_client_set_info (w, 0); 784 break; 785 case FocusIn: 786 send_xembed_message ( xtplug, 787 XEMBED_REQUEST_FOCUS, 0, 0, 0, 0); 788 break; 789 case FocusOut: 790 break; 791 case KeyPress: 792 #ifdef DEBUG_XTBIN 793 printf("Key Press Got!\n"); 794 #endif 795 break; 796 default: 797 break; 798 } /* End of switch(event->type) */ 799 } 800 801 static void 802 send_xembed_message (XtClient *xtclient, 803 long message, 804 long detail, 805 long data1, 806 long data2, 807 long time) 808 { 809 XEvent xevent; 810 Window w=XtWindow(xtclient->top_widget); 811 Display* dpy=xtclient->xtdisplay; 812 int errorcode; 813 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; 824 825 trap_errors (); 826 XSendEvent (dpy, w, False, NoEventMask, &xevent); 827 XSync (dpy,False); 828 829 if((errorcode = untrap_error())) { 830 #ifdef DEBUG_XTBIN 831 printf("send_xembed_message error(%d)!!!\n",errorcode); 832 #endif 833 } 834 } 835 836 static int 837 error_handler(Display *display, XErrorEvent *error) 838 { 839 trapped_error_code = error->error_code; 840 return 0; 841 } 842 843 static void 844 trap_errors(void) 845 { 846 trapped_error_code =0; 847 old_error_handler = XSetErrorHandler(error_handler); 848 } 849 850 static int 851 untrap_error(void) 852 { 853 XSetErrorHandler(old_error_handler); 854 if(trapped_error_code) { 855 #ifdef DEBUG_XTBIN 856 printf("Get X Window Error = %d\n", trapped_error_code); 857 #endif 858 } 859 return trapped_error_code; 860 } 861 862 static void 863 xt_client_focus_listener( Widget w, XtPointer user_data, XEvent *event) 864 { 865 Display *dpy = XtDisplay(w); 866 XtClient *xtclient = user_data; 867 Window win = XtWindow(w); 868 869 switch(event->type) 870 { 871 case CreateNotify: 872 if(event->xcreatewindow.parent == win) { 873 Widget child=XtWindowToWidget( dpy, event->xcreatewindow.window); 874 if (child) 875 xt_add_focus_listener_tree(child, user_data); 876 } 877 break; 878 case DestroyNotify: 879 xt_remove_focus_listener( w, user_data); 880 break; 881 case ReparentNotify: 882 if(event->xreparent.parent == win) { 883 /* I am the new parent */ 884 Widget child=XtWindowToWidget(dpy, event->xreparent.window); 885 if (child) 886 xt_add_focus_listener_tree( child, user_data); 887 } 888 else if(event->xreparent.window == win) { 889 /* I am the new child */ 890 } 891 else { 892 /* I am the old parent */ 893 } 894 break; 895 case ButtonRelease: 896 #if 0 897 XSetInputFocus(dpy, XtWindow(xtclient->child_widget), RevertToParent, event->xbutton.time); 898 #endif 899 send_xembed_message ( xtclient, 900 XEMBED_REQUEST_FOCUS, 0, 0, 0, 0); 901 break; 902 default: 903 break; 904 } /* End of switch(event->type) */ 905 } 906 907 static void 908 xt_add_focus_listener( Widget w, XtPointer user_data) 909 { 910 XWindowAttributes attr; 911 long eventmask; 912 XtClient *xtclient = user_data; 913 914 trap_errors (); 915 XGetWindowAttributes(XtDisplay(w), XtWindow(w), &attr); 916 eventmask = attr.your_event_mask | SubstructureNotifyMask | ButtonReleaseMask; 917 XSelectInput(XtDisplay(w), 918 XtWindow(w), 919 eventmask); 920 921 XtAddEventHandler(w, 922 SubstructureNotifyMask | ButtonReleaseMask, 923 TRUE, 924 (XtEventHandler)xt_client_focus_listener, 925 xtclient); 926 untrap_error(); 927 } 928 929 static void 930 xt_remove_focus_listener(Widget w, XtPointer user_data) 931 { 932 trap_errors (); 933 XtRemoveEventHandler(w, SubstructureNotifyMask | ButtonReleaseMask, TRUE, 934 (XtEventHandler)xt_client_focus_listener, user_data); 935 936 untrap_error(); 937 } 938 939 static void 940 xt_add_focus_listener_tree ( Widget treeroot, XtPointer user_data) 941 { 942 Window win = XtWindow(treeroot); 943 Window *children; 944 Window root, parent; 945 Display *dpy = XtDisplay(treeroot); 946 unsigned int i, nchildren; 947 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); 951 trap_errors(); 952 if(!XQueryTree(dpy, win, &root, &parent, &children, &nchildren)) { 953 untrap_error(); 954 return; 955 } 956 957 if(untrap_error()) 958 return; 959 960 for(i=0; i<nchildren; ++i) { 961 Widget child = XtWindowToWidget(dpy, children[i]); 962 if (child) 963 xt_add_focus_listener_tree( child, user_data); 964 } 965 XFree((void*)children); 966 967 return; 968 } 969