Coverage Report

Created: 2018-09-25 14:53

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