~ubuntu-branches/ubuntu/raring/qtwebkit-source/raring-proposed

« back to all changes in this revision

Viewing changes to Source/WebCore/plugins/gtk/gtk2xtbin.c

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-02-18 14:24:18 UTC
  • Revision ID: package-import@ubuntu.com-20130218142418-eon0jmjg3nj438uy
Tags: upstream-2.3
ImportĀ upstreamĀ versionĀ 2.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
}