1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library. If not, see <http://www.gnu.org/licenses/>.Free
16 */
17
18 /* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
19
20 /*
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
25 */
26
27 #include "config.h"
28
29 #include "gtksocketprivate.h"
30
31 #include <string.h>
32
33 #include "gtkmarshalers.h"
34 #include "gtksizerequest.h"
35 #include "gtkplug.h"
36 #include "gtkprivate.h"
37 #include "gtkrender.h"
38 #include "gtkdnd.h"
39 #include "gtkdragdest.h"
40 #include "gtkdebug.h"
41 #include "gtkintl.h"
42 #include "gtkmain.h"
43 #include "gtkwidgetprivate.h"
44
45 #include <gdk/gdkx.h>
46 #include <gdk/gdkprivate.h>
47
48 #ifdef HAVE_XFIXES
49 #include <X11/extensions/Xfixes.h>
50 #endif
51
52 #include "gtkxembed.h"
53
54 #include "a11y/gtksocketaccessible.h"
55
56
57 /**
58 * SECTION:gtksocket
59 * @Short_description: Container for widgets from other processes
60 * @Title: GtkSocket
61 * @include: gtk/gtkx.h
62 * @See_also: #GtkPlug, [XEmbed Protocol](http://www.freedesktop.org/Standards/xembed-spec)
63 *
64 * Together with #GtkPlug, #GtkSocket provides the ability to embed
65 * widgets from one process into another process in a fashion that
66 * is transparent to the user. One process creates a #GtkSocket widget
67 * and passes that widget’s window ID to the other process, which then
68 * creates a #GtkPlug with that window ID. Any widgets contained in the
69 * #GtkPlug then will appear inside the first application’s window.
70 *
71 * The socket’s window ID is obtained by using gtk_socket_get_id().
72 * Before using this function, the socket must have been realized,
73 * and for hence, have been added to its parent.
74 *
75 * ## Obtaining the window ID of a socket.
76 *
77 * |[<!-- language="C" -->
78 * GtkWidget *socket = gtk_socket_new ();
79 * gtk_widget_show (socket);
80 * gtk_container_add (GTK_CONTAINER (parent), socket);
81 *
82 * // The following call is only necessary if one of
83 * // the ancestors of the socket is not yet visible.
84 * gtk_widget_realize (socket);
85 * g_print ("The ID of the sockets window is %#x\n",
86 * gtk_socket_get_id (socket));
87 * ]|
88 *
89 * Note that if you pass the window ID of the socket to another
90 * process that will create a plug in the socket, you must make
91 * sure that the socket widget is not destroyed until that plug
92 * is created. Violating this rule will cause unpredictable
93 * consequences, the most likely consequence being that the plug
94 * will appear as a separate toplevel window. You can check if
95 * the plug has been created by using gtk_socket_get_plug_window().
96 * If it returns a non-%NULL value, then the plug has been
97 * successfully created inside of the socket.
98 *
99 * When GTK+ is notified that the embedded window has been destroyed,
100 * then it will destroy the socket as well. You should always,
101 * therefore, be prepared for your sockets to be destroyed at any
102 * time when the main event loop is running. To prevent this from
103 * happening, you can connect to the #GtkSocket::plug-removed signal.
104 *
105 * The communication between a #GtkSocket and a #GtkPlug follows the
106 * [XEmbed Protocol](http://www.freedesktop.org/Standards/xembed-spec).
107 * This protocol has also been implemented in other toolkits, e.g. Qt,
108 * allowing the same level of integration when embedding a Qt widget
109 * in GTK or vice versa.
110 *
111 * The #GtkPlug and #GtkSocket widgets are only available when GTK+
112 * is compiled for the X11 platform and %GDK_WINDOWING_X11 is defined.
113 * They can only be used on a #GdkX11Display. To use #GtkPlug and
114 * #GtkSocket, you need to include the `gtk/gtkx.h` header.
115 */
116
117 /* Forward declararations */
118
119 static void gtk_socket_finalize (GObject *object);
120 static void gtk_socket_notify (GObject *object,
121 GParamSpec *pspec);
122 static void gtk_socket_realize (GtkWidget *widget);
123 static void gtk_socket_unrealize (GtkWidget *widget);
124 static void gtk_socket_get_preferred_width (GtkWidget *widget,
125 gint *minimum,
126 gint *natural);
127 static void gtk_socket_get_preferred_height (GtkWidget *widget,
128 gint *minimum,
129 gint *natural);
130 static void gtk_socket_size_allocate (GtkWidget *widget,
131 GtkAllocation *allocation);
132 static void gtk_socket_hierarchy_changed (GtkWidget *widget,
133 GtkWidget *old_toplevel);
134 static void gtk_socket_grab_notify (GtkWidget *widget,
135 gboolean was_grabbed);
136 static gboolean gtk_socket_key_event (GtkWidget *widget,
137 GdkEventKey *event);
138 static gboolean gtk_socket_focus (GtkWidget *widget,
139 GtkDirectionType direction);
140 static void gtk_socket_remove (GtkContainer *container,
141 GtkWidget *widget);
142 static void gtk_socket_forall (GtkContainer *container,
143 gboolean include_internals,
144 GtkCallback callback,
145 gpointer callback_data);
146 static void gtk_socket_add_window (GtkSocket *socket,
147 Window xid,
148 gboolean need_reparent);
149 static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
150 GdkEvent *event,
151 gpointer data);
152
153 static gboolean xembed_get_info (GdkWindow *gdk_window,
154 unsigned long *version,
155 unsigned long *flags);
156
157 static void _gtk_socket_accessible_embed (GtkWidget *socket,
158 GdkWindow *window);
159
160 /* From Tk */
161 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
162
163
164 /* Local data */
165
166 typedef struct
167 {
168 guint accel_key;
169 GdkModifierType accel_mods;
170 } GrabbedKey;
171
172 enum {
173 PLUG_ADDED,
174 PLUG_REMOVED,
175 LAST_SIGNAL
176 };
177
178 static guint socket_signals[LAST_SIGNAL] = { 0 };
179
G_DEFINE_TYPE_WITH_PRIVATE(GtkSocket,gtk_socket,GTK_TYPE_CONTAINER)180 G_DEFINE_TYPE_WITH_PRIVATE (GtkSocket, gtk_socket, GTK_TYPE_CONTAINER)
181
182 static void
183 gtk_socket_finalize (GObject *object)
184 {
185 GtkSocket *socket = GTK_SOCKET (object);
186 GtkSocketPrivate *priv = socket->priv;
187
188 g_object_unref (priv->accel_group);
189
190 G_OBJECT_CLASS (gtk_socket_parent_class)->finalize (object);
191 }
192
193 static gboolean
gtk_socket_draw(GtkWidget * widget,cairo_t * cr)194 gtk_socket_draw (GtkWidget *widget,
195 cairo_t *cr)
196 {
197 gtk_render_background (gtk_widget_get_style_context (widget), cr,
198 0, 0,
199 gtk_widget_get_allocated_width (widget),
200 gtk_widget_get_allocated_height (widget));
201
202 return GTK_WIDGET_CLASS (gtk_socket_parent_class)->draw (widget, cr);
203 }
204
205 static void
gtk_socket_class_init(GtkSocketClass * class)206 gtk_socket_class_init (GtkSocketClass *class)
207 {
208 GtkWidgetClass *widget_class;
209 GtkContainerClass *container_class;
210 GObjectClass *gobject_class;
211
212 gobject_class = (GObjectClass *) class;
213 widget_class = (GtkWidgetClass*) class;
214 container_class = (GtkContainerClass*) class;
215
216 gobject_class->finalize = gtk_socket_finalize;
217 gobject_class->notify = gtk_socket_notify;
218
219 widget_class->realize = gtk_socket_realize;
220 widget_class->unrealize = gtk_socket_unrealize;
221 widget_class->get_preferred_width = gtk_socket_get_preferred_width;
222 widget_class->get_preferred_height = gtk_socket_get_preferred_height;
223 widget_class->size_allocate = gtk_socket_size_allocate;
224 widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
225 widget_class->grab_notify = gtk_socket_grab_notify;
226 widget_class->key_press_event = gtk_socket_key_event;
227 widget_class->key_release_event = gtk_socket_key_event;
228 widget_class->focus = gtk_socket_focus;
229 widget_class->draw = gtk_socket_draw;
230
231 /* We don't want to show_all the in-process plug, if any.
232 */
233 widget_class->show_all = gtk_widget_show;
234
235 container_class->remove = gtk_socket_remove;
236 container_class->forall = gtk_socket_forall;
237
238 /**
239 * GtkSocket::plug-added:
240 * @socket_: the object which received the signal
241 *
242 * This signal is emitted when a client is successfully
243 * added to the socket.
244 */
245 socket_signals[PLUG_ADDED] =
246 g_signal_new (I_("plug-added"),
247 G_OBJECT_CLASS_TYPE (class),
248 G_SIGNAL_RUN_LAST,
249 G_STRUCT_OFFSET (GtkSocketClass, plug_added),
250 NULL, NULL,
251 NULL,
252 G_TYPE_NONE, 0);
253
254 /**
255 * GtkSocket::plug-removed:
256 * @socket_: the object which received the signal
257 *
258 * This signal is emitted when a client is removed from the socket.
259 * The default action is to destroy the #GtkSocket widget, so if you
260 * want to reuse it you must add a signal handler that returns %TRUE.
261 *
262 * Returns: %TRUE to stop other handlers from being invoked.
263 */
264 socket_signals[PLUG_REMOVED] =
265 g_signal_new (I_("plug-removed"),
266 G_OBJECT_CLASS_TYPE (class),
267 G_SIGNAL_RUN_LAST,
268 G_STRUCT_OFFSET (GtkSocketClass, plug_removed),
269 _gtk_boolean_handled_accumulator, NULL,
270 _gtk_marshal_BOOLEAN__VOID,
271 G_TYPE_BOOLEAN, 0);
272
273
274 gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SOCKET_ACCESSIBLE);
275 }
276
277 static void
gtk_socket_init(GtkSocket * socket)278 gtk_socket_init (GtkSocket *socket)
279 {
280 GtkSocketPrivate *priv;
281
282 priv = gtk_socket_get_instance_private (socket);
283 socket->priv = priv;
284
285 priv->request_width = 0;
286 priv->request_height = 0;
287 priv->current_width = 0;
288 priv->current_height = 0;
289
290 priv->plug_window = NULL;
291 priv->plug_widget = NULL;
292 priv->focus_in = FALSE;
293 priv->have_size = FALSE;
294 priv->need_map = FALSE;
295 priv->active = FALSE;
296
297 priv->accel_group = gtk_accel_group_new ();
298 g_object_set_data (G_OBJECT (priv->accel_group), I_("gtk-socket"), socket);
299 }
300
301 /**
302 * gtk_socket_new:
303 *
304 * Create a new empty #GtkSocket.
305 *
306 * Returns: the new #GtkSocket.
307 **/
308 GtkWidget*
gtk_socket_new(void)309 gtk_socket_new (void)
310 {
311 GtkSocket *socket;
312
313 socket = g_object_new (GTK_TYPE_SOCKET, NULL);
314
315 return GTK_WIDGET (socket);
316 }
317
318 /**
319 * gtk_socket_add_id:
320 * @socket_: a #GtkSocket
321 * @window: the Window of a client participating in the XEMBED protocol.
322 *
323 * Adds an XEMBED client, such as a #GtkPlug, to the #GtkSocket. The
324 * client may be in the same process or in a different process.
325 *
326 * To embed a #GtkPlug in a #GtkSocket, you can either create the
327 * #GtkPlug with `gtk_plug_new (0)`, call
328 * gtk_plug_get_id() to get the window ID of the plug, and then pass that to the
329 * gtk_socket_add_id(), or you can call gtk_socket_get_id() to get the
330 * window ID for the socket, and call gtk_plug_new() passing in that
331 * ID.
332 *
333 * The #GtkSocket must have already be added into a toplevel window
334 * before you can make this call.
335 **/
336 void
gtk_socket_add_id(GtkSocket * socket,Window window)337 gtk_socket_add_id (GtkSocket *socket,
338 Window window)
339 {
340 g_return_if_fail (GTK_IS_SOCKET (socket));
341 g_return_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)));
342
343 if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
344 gtk_widget_realize (GTK_WIDGET (socket));
345
346 gtk_socket_add_window (socket, window, TRUE);
347 }
348
349 /**
350 * gtk_socket_get_id:
351 * @socket_: a #GtkSocket.
352 *
353 * Gets the window ID of a #GtkSocket widget, which can then
354 * be used to create a client embedded inside the socket, for
355 * instance with gtk_plug_new().
356 *
357 * The #GtkSocket must have already be added into a toplevel window
358 * before you can make this call.
359 *
360 * Returns: the window ID for the socket
361 **/
362 Window
gtk_socket_get_id(GtkSocket * socket)363 gtk_socket_get_id (GtkSocket *socket)
364 {
365 g_return_val_if_fail (GTK_IS_SOCKET (socket), 0);
366 g_return_val_if_fail (_gtk_widget_get_anchored (GTK_WIDGET (socket)), 0);
367
368 if (!gtk_widget_get_realized (GTK_WIDGET (socket)))
369 gtk_widget_realize (GTK_WIDGET (socket));
370
371 return GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (socket)));
372 }
373
374 /**
375 * gtk_socket_get_plug_window:
376 * @socket_: a #GtkSocket.
377 *
378 * Retrieves the window of the plug. Use this to check if the plug has
379 * been created inside of the socket.
380 *
381 * Returns: (nullable) (transfer none): the window of the plug if
382 * available, or %NULL
383 *
384 * Since: 2.14
385 **/
386 GdkWindow*
gtk_socket_get_plug_window(GtkSocket * socket)387 gtk_socket_get_plug_window (GtkSocket *socket)
388 {
389 g_return_val_if_fail (GTK_IS_SOCKET (socket), NULL);
390
391 return socket->priv->plug_window;
392 }
393
394 static void
gtk_socket_realize(GtkWidget * widget)395 gtk_socket_realize (GtkWidget *widget)
396 {
397 GtkAllocation allocation;
398 GdkWindow *window;
399 GdkWindowAttr attributes;
400 XWindowAttributes xattrs;
401 gint attributes_mask;
402 GdkScreen *screen;
403
404 gtk_widget_set_realized (widget, TRUE);
405
406 screen = gtk_widget_get_screen (widget);
407 if (!GDK_IS_X11_SCREEN (screen))
408 g_warning ("GtkSocket: only works under X11");
409
410 gtk_widget_get_allocation (widget, &allocation);
411
412 attributes.window_type = GDK_WINDOW_CHILD;
413 attributes.x = allocation.x;
414 attributes.y = allocation.y;
415 attributes.width = allocation.width;
416 attributes.height = allocation.height;
417 attributes.wclass = GDK_INPUT_OUTPUT;
418 attributes.visual = gtk_widget_get_visual (widget);
419 attributes.event_mask = GDK_FOCUS_CHANGE_MASK;
420
421 attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
422
423 window = gdk_window_new (gtk_widget_get_parent_window (widget),
424 &attributes, attributes_mask);
425 gtk_widget_set_window (widget, window);
426 gtk_widget_register_window (widget, window);
427
428 XGetWindowAttributes (GDK_WINDOW_XDISPLAY (window),
429 GDK_WINDOW_XID (window),
430 &xattrs);
431
432 /* Sooooo, it turns out that mozilla, as per the gtk2xt code selects
433 for input on the socket with a mask of 0x0fffff (for god knows why)
434 which includes ButtonPressMask causing a BadAccess if someone else
435 also selects for this. As per the client-side windows merge we always
436 normally selects for button press so we can emulate it on client
437 side children that selects for button press. However, we don't need
438 this for GtkSocket, so we unselect it here, fixing the crashes in
439 firefox. */
440 XSelectInput (GDK_WINDOW_XDISPLAY (window),
441 GDK_WINDOW_XID (window),
442 (xattrs.your_event_mask & ~ButtonPressMask) |
443 SubstructureNotifyMask | SubstructureRedirectMask);
444
445 gdk_window_add_filter (window,
446 gtk_socket_filter_func,
447 widget);
448
449 /* We sync here so that we make sure that if the XID for
450 * our window is passed to another application, SubstructureRedirectMask
451 * will be set by the time the other app creates its window.
452 */
453 gdk_display_sync (gtk_widget_get_display (widget));
454 }
455
456 /**
457 * gtk_socket_end_embedding:
458 * @socket: a #GtkSocket
459 *
460 * Called to end the embedding of a plug in the socket.
461 */
462 static void
gtk_socket_end_embedding(GtkSocket * socket)463 gtk_socket_end_embedding (GtkSocket *socket)
464 {
465 GtkSocketPrivate *private = socket->priv;
466
467 g_object_unref (private->plug_window);
468 private->plug_window = NULL;
469 private->current_width = 0;
470 private->current_height = 0;
471 private->resize_count = 0;
472
473 gtk_accel_group_disconnect (private->accel_group, NULL);
474 }
475
476 static void
gtk_socket_unrealize(GtkWidget * widget)477 gtk_socket_unrealize (GtkWidget *widget)
478 {
479 GtkSocket *socket = GTK_SOCKET (widget);
480 GtkSocketPrivate *private = socket->priv;
481
482 gtk_widget_set_realized (widget, FALSE);
483
484 if (private->plug_widget)
485 {
486 _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
487 }
488 else if (private->plug_window)
489 {
490 gtk_socket_end_embedding (socket);
491 }
492
493 GTK_WIDGET_CLASS (gtk_socket_parent_class)->unrealize (widget);
494 }
495
496 static void
gtk_socket_size_request(GtkSocket * socket)497 gtk_socket_size_request (GtkSocket *socket)
498 {
499 GtkSocketPrivate *private = socket->priv;
500 GdkDisplay *display;
501 XSizeHints hints;
502 long supplied;
503 int scale;
504
505 display = gtk_widget_get_display (GTK_WIDGET (socket));
506 gdk_x11_display_error_trap_push (display);
507
508 private->request_width = 1;
509 private->request_height = 1;
510 scale = gtk_widget_get_scale_factor (GTK_WIDGET(socket));
511
512 if (XGetWMNormalHints (GDK_WINDOW_XDISPLAY (private->plug_window),
513 GDK_WINDOW_XID (private->plug_window),
514 &hints, &supplied))
515 {
516 if (hints.flags & PMinSize)
517 {
518 private->request_width = MAX (hints.min_width / scale, 1);
519 private->request_height = MAX (hints.min_height / scale, 1);
520 }
521 else if (hints.flags & PBaseSize)
522 {
523 private->request_width = MAX (hints.base_width / scale, 1);
524 private->request_height = MAX (hints.base_height / scale, 1);
525 }
526 }
527 private->have_size = TRUE;
528
529 gdk_x11_display_error_trap_pop_ignored (display);
530 }
531
532 static void
gtk_socket_get_preferred_width(GtkWidget * widget,gint * minimum,gint * natural)533 gtk_socket_get_preferred_width (GtkWidget *widget,
534 gint *minimum,
535 gint *natural)
536 {
537 GtkSocket *socket = GTK_SOCKET (widget);
538 GtkSocketPrivate *private = socket->priv;
539
540 if (private->plug_widget)
541 {
542 gtk_widget_get_preferred_width (private->plug_widget, minimum, natural);
543 }
544 else
545 {
546 if (private->is_mapped && !private->have_size && private->plug_window)
547 gtk_socket_size_request (socket);
548
549 if (private->is_mapped && private->have_size)
550 *minimum = *natural = MAX (private->request_width, 1);
551 else
552 *minimum = *natural = 1;
553 }
554 }
555
556 static void
gtk_socket_get_preferred_height(GtkWidget * widget,gint * minimum,gint * natural)557 gtk_socket_get_preferred_height (GtkWidget *widget,
558 gint *minimum,
559 gint *natural)
560 {
561 GtkSocket *socket = GTK_SOCKET (widget);
562 GtkSocketPrivate *private = socket->priv;
563
564 if (private->plug_widget)
565 {
566 gtk_widget_get_preferred_height (private->plug_widget, minimum, natural);
567 }
568 else
569 {
570 if (private->is_mapped && !private->have_size && private->plug_window)
571 gtk_socket_size_request (socket);
572
573 if (private->is_mapped && private->have_size)
574 *minimum = *natural = MAX (private->request_height, 1);
575 else
576 *minimum = *natural = 1;
577 }
578 }
579
580 static void
gtk_socket_send_configure_event(GtkSocket * socket)581 gtk_socket_send_configure_event (GtkSocket *socket)
582 {
583 GtkAllocation allocation;
584 XConfigureEvent xconfigure;
585 GdkDisplay *display;
586 int x, y, scale;
587
588 g_return_if_fail (socket->priv->plug_window != NULL);
589
590 memset (&xconfigure, 0, sizeof (xconfigure));
591 xconfigure.type = ConfigureNotify;
592
593 xconfigure.event = GDK_WINDOW_XID (socket->priv->plug_window);
594 xconfigure.window = GDK_WINDOW_XID (socket->priv->plug_window);
595
596 /* The ICCCM says that synthetic events should have root relative
597 * coordinates. We still aren't really ICCCM compliant, since
598 * we don't send events when the real toplevel is moved.
599 */
600 display = gdk_window_get_display (socket->priv->plug_window);
601 gdk_x11_display_error_trap_push (display);
602 gdk_window_get_origin (socket->priv->plug_window, &x, &y);
603 gdk_x11_display_error_trap_pop_ignored (display);
604
605 gtk_widget_get_allocation (GTK_WIDGET(socket), &allocation);
606 scale = gtk_widget_get_scale_factor (GTK_WIDGET(socket));
607 xconfigure.x = x * scale;
608 xconfigure.y = y * scale;
609 xconfigure.width = allocation.width * scale;
610 xconfigure.height = allocation.height * scale;
611
612 xconfigure.border_width = 0;
613 xconfigure.above = None;
614 xconfigure.override_redirect = False;
615
616 gdk_x11_display_error_trap_push (display);
617 XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
618 GDK_WINDOW_XID (socket->priv->plug_window),
619 False, NoEventMask, (XEvent *)&xconfigure);
620 gdk_x11_display_error_trap_pop_ignored (display);
621 }
622
623 static void
gtk_socket_size_allocate(GtkWidget * widget,GtkAllocation * allocation)624 gtk_socket_size_allocate (GtkWidget *widget,
625 GtkAllocation *allocation)
626 {
627 GtkSocket *socket = GTK_SOCKET (widget);
628 GtkSocketPrivate *private = socket->priv;
629
630 gtk_widget_set_allocation (widget, allocation);
631 if (gtk_widget_get_realized (widget))
632 {
633 gdk_window_move_resize (gtk_widget_get_window (widget),
634 allocation->x, allocation->y,
635 allocation->width, allocation->height);
636
637 if (private->plug_widget)
638 {
639 GtkAllocation child_allocation;
640
641 child_allocation.x = 0;
642 child_allocation.y = 0;
643 child_allocation.width = allocation->width;
644 child_allocation.height = allocation->height;
645
646 gtk_widget_size_allocate (private->plug_widget, &child_allocation);
647 }
648 else if (private->plug_window)
649 {
650 GdkDisplay *display = gdk_window_get_display (private->plug_window);
651
652 gdk_x11_display_error_trap_push (display);
653
654 if (allocation->width != private->current_width ||
655 allocation->height != private->current_height)
656 {
657 gdk_window_move_resize (private->plug_window,
658 0, 0,
659 allocation->width, allocation->height);
660 if (private->resize_count)
661 private->resize_count--;
662
663 GTK_NOTE (PLUGSOCKET,
664 g_message ("GtkSocket - allocated: %d %d",
665 allocation->width, allocation->height));
666 private->current_width = allocation->width;
667 private->current_height = allocation->height;
668 }
669
670 if (private->need_map)
671 {
672 gdk_window_show (private->plug_window);
673 private->need_map = FALSE;
674 }
675
676 while (private->resize_count)
677 {
678 gtk_socket_send_configure_event (socket);
679 private->resize_count--;
680 GTK_NOTE (PLUGSOCKET,
681 g_message ("GtkSocket - sending synthetic configure: %d %d",
682 allocation->width, allocation->height));
683 }
684
685 gdk_x11_display_error_trap_pop_ignored (display);
686 }
687 }
688 }
689
690 static void
gtk_socket_send_key_event(GtkSocket * socket,GdkEvent * gdk_event,gboolean mask_key_presses)691 gtk_socket_send_key_event (GtkSocket *socket,
692 GdkEvent *gdk_event,
693 gboolean mask_key_presses)
694 {
695 XKeyEvent xkey;
696 GdkScreen *screen = gdk_window_get_screen (socket->priv->plug_window);
697
698 memset (&xkey, 0, sizeof (xkey));
699 xkey.type = (gdk_event->type == GDK_KEY_PRESS) ? KeyPress : KeyRelease;
700 xkey.window = GDK_WINDOW_XID (socket->priv->plug_window);
701 xkey.root = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
702 xkey.subwindow = None;
703 xkey.time = gdk_event->key.time;
704 xkey.x = 0;
705 xkey.y = 0;
706 xkey.x_root = 0;
707 xkey.y_root = 0;
708 xkey.state = gdk_event->key.state;
709 xkey.keycode = gdk_event->key.hardware_keycode;
710 xkey.same_screen = True;/* FIXME ? */
711
712 gdk_x11_display_error_trap_push (gdk_window_get_display (socket->priv->plug_window));
713 XSendEvent (GDK_WINDOW_XDISPLAY (socket->priv->plug_window),
714 GDK_WINDOW_XID (socket->priv->plug_window),
715 False,
716 (mask_key_presses ? KeyPressMask : NoEventMask),
717 (XEvent *)&xkey);
718 gdk_x11_display_error_trap_pop_ignored (gdk_window_get_display (socket->priv->plug_window));
719 }
720
721 static gboolean
activate_key(GtkAccelGroup * accel_group,GObject * acceleratable,guint accel_key,GdkModifierType accel_mods,GrabbedKey * grabbed_key)722 activate_key (GtkAccelGroup *accel_group,
723 GObject *acceleratable,
724 guint accel_key,
725 GdkModifierType accel_mods,
726 GrabbedKey *grabbed_key)
727 {
728 GdkEvent *gdk_event = gtk_get_current_event ();
729
730 GtkSocket *socket = g_object_get_data (G_OBJECT (accel_group), "gtk-socket");
731 gboolean retval = FALSE;
732
733 if (gdk_event && gdk_event->type == GDK_KEY_PRESS && socket->priv->plug_window)
734 {
735 gtk_socket_send_key_event (socket, gdk_event, FALSE);
736 retval = TRUE;
737 }
738
739 if (gdk_event)
740 gdk_event_free (gdk_event);
741
742 return retval;
743 }
744
745 static gboolean
find_accel_key(GtkAccelKey * key,GClosure * closure,gpointer data)746 find_accel_key (GtkAccelKey *key,
747 GClosure *closure,
748 gpointer data)
749 {
750 GrabbedKey *grabbed_key = data;
751
752 return (key->accel_key == grabbed_key->accel_key &&
753 key->accel_mods == grabbed_key->accel_mods);
754 }
755
756 /**
757 * gtk_socket_add_grabbed_key:
758 * @socket: a #GtkSocket
759 * @keyval: a key
760 * @modifiers: modifiers for the key
761 *
762 * Called from the GtkSocket platform-specific backend when the
763 * corresponding plug has told the socket to grab a key.
764 */
765 static void
gtk_socket_add_grabbed_key(GtkSocket * socket,guint keyval,GdkModifierType modifiers)766 gtk_socket_add_grabbed_key (GtkSocket *socket,
767 guint keyval,
768 GdkModifierType modifiers)
769 {
770 GClosure *closure;
771 GrabbedKey *grabbed_key;
772
773 grabbed_key = g_new (GrabbedKey, 1);
774
775 grabbed_key->accel_key = keyval;
776 grabbed_key->accel_mods = modifiers;
777
778 if (gtk_accel_group_find (socket->priv->accel_group,
779 find_accel_key,
780 &grabbed_key))
781 {
782 g_warning ("GtkSocket: request to add already present grabbed key %u,%#x",
783 keyval, modifiers);
784 g_free (grabbed_key);
785 return;
786 }
787
788 closure = g_cclosure_new (G_CALLBACK (activate_key), grabbed_key, (GClosureNotify)g_free);
789
790 gtk_accel_group_connect (socket->priv->accel_group, keyval, modifiers, GTK_ACCEL_LOCKED,
791 closure);
792 }
793
794 /**
795 * gtk_socket_remove_grabbed_key:
796 * @socket: a #GtkSocket
797 * @keyval: a key
798 * @modifiers: modifiers for the key
799 *
800 * Called from the GtkSocket backend when the corresponding plug has
801 * told the socket to remove a key grab.
802 */
803 static void
gtk_socket_remove_grabbed_key(GtkSocket * socket,guint keyval,GdkModifierType modifiers)804 gtk_socket_remove_grabbed_key (GtkSocket *socket,
805 guint keyval,
806 GdkModifierType modifiers)
807 {
808 if (!gtk_accel_group_disconnect_key (socket->priv->accel_group, keyval, modifiers))
809 g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x",
810 keyval, modifiers);
811 }
812
813 static void
socket_update_focus_in(GtkSocket * socket)814 socket_update_focus_in (GtkSocket *socket)
815 {
816 GtkSocketPrivate *private = socket->priv;
817 gboolean focus_in = FALSE;
818
819 if (private->plug_window)
820 {
821 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
822
823 if (gtk_widget_is_toplevel (toplevel) &&
824 gtk_window_has_toplevel_focus (GTK_WINDOW (toplevel)) &&
825 gtk_widget_is_focus (GTK_WIDGET (socket)))
826 focus_in = TRUE;
827 }
828
829 if (focus_in != private->focus_in)
830 {
831 private->focus_in = focus_in;
832
833 if (focus_in)
834 _gtk_xembed_send_focus_message (private->plug_window,
835 XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT);
836 else
837 _gtk_xembed_send_message (private->plug_window,
838 XEMBED_FOCUS_OUT, 0, 0, 0);
839 }
840 }
841
842 static void
socket_update_active(GtkSocket * socket)843 socket_update_active (GtkSocket *socket)
844 {
845 GtkSocketPrivate *private = socket->priv;
846 gboolean active = FALSE;
847
848 if (private->plug_window)
849 {
850 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
851
852 if (gtk_widget_is_toplevel (toplevel) &&
853 gtk_window_is_active (GTK_WINDOW (toplevel)))
854 active = TRUE;
855 }
856
857 if (active != private->active)
858 {
859 private->active = active;
860
861 _gtk_xembed_send_message (private->plug_window,
862 active ? XEMBED_WINDOW_ACTIVATE : XEMBED_WINDOW_DEACTIVATE,
863 0, 0, 0);
864 }
865 }
866
867 static void
gtk_socket_hierarchy_changed(GtkWidget * widget,GtkWidget * old_toplevel)868 gtk_socket_hierarchy_changed (GtkWidget *widget,
869 GtkWidget *old_toplevel)
870 {
871 GtkSocket *socket = GTK_SOCKET (widget);
872 GtkSocketPrivate *private = socket->priv;
873 GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
874
875 if (toplevel && !GTK_IS_WINDOW (toplevel))
876 toplevel = NULL;
877
878 if (toplevel != private->toplevel)
879 {
880 if (private->toplevel)
881 {
882 gtk_window_remove_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
883 g_signal_handlers_disconnect_by_func (private->toplevel,
884 socket_update_focus_in,
885 socket);
886 g_signal_handlers_disconnect_by_func (private->toplevel,
887 socket_update_active,
888 socket);
889 }
890
891 private->toplevel = toplevel;
892
893 if (toplevel)
894 {
895 gtk_window_add_accel_group (GTK_WINDOW (private->toplevel), private->accel_group);
896 g_signal_connect_swapped (private->toplevel, "notify::has-toplevel-focus",
897 G_CALLBACK (socket_update_focus_in), socket);
898 g_signal_connect_swapped (private->toplevel, "notify::is-active",
899 G_CALLBACK (socket_update_active), socket);
900 }
901
902 socket_update_focus_in (socket);
903 socket_update_active (socket);
904 }
905 }
906
907 static void
gtk_socket_grab_notify(GtkWidget * widget,gboolean was_grabbed)908 gtk_socket_grab_notify (GtkWidget *widget,
909 gboolean was_grabbed)
910 {
911 GtkSocket *socket = GTK_SOCKET (widget);
912
913 if (!socket->priv->same_app)
914 _gtk_xembed_send_message (socket->priv->plug_window,
915 was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
916 0, 0, 0);
917 }
918
919 static gboolean
gtk_socket_key_event(GtkWidget * widget,GdkEventKey * event)920 gtk_socket_key_event (GtkWidget *widget,
921 GdkEventKey *event)
922 {
923 GtkSocket *socket = GTK_SOCKET (widget);
924 GtkSocketPrivate *private = socket->priv;
925
926 if (gtk_widget_has_focus (widget) && private->plug_window && !private->plug_widget)
927 {
928 gtk_socket_send_key_event (socket, (GdkEvent *) event, FALSE);
929
930 return TRUE;
931 }
932 else
933 return FALSE;
934 }
935
936 static void
gtk_socket_notify(GObject * object,GParamSpec * pspec)937 gtk_socket_notify (GObject *object,
938 GParamSpec *pspec)
939 {
940 if (strcmp (pspec->name, "is-focus") == 0)
941 socket_update_focus_in (GTK_SOCKET (object));
942
943 if (G_OBJECT_CLASS (gtk_socket_parent_class)->notify)
944 G_OBJECT_CLASS (gtk_socket_parent_class)->notify (object, pspec);
945 }
946
947 /**
948 * gtk_socket_claim_focus:
949 * @socket: a #GtkSocket
950 * @send_event: huh?
951 *
952 * Claims focus for the socket. XXX send_event?
953 */
954 static void
gtk_socket_claim_focus(GtkSocket * socket,gboolean send_event)955 gtk_socket_claim_focus (GtkSocket *socket,
956 gboolean send_event)
957 {
958 GtkWidget *widget = GTK_WIDGET (socket);
959 GtkSocketPrivate *private = socket->priv;
960
961 if (!send_event)
962 private->focus_in = TRUE; /* Otherwise, our notify handler will send FOCUS_IN */
963
964 /* Oh, the trickery... */
965
966 gtk_widget_set_can_focus (widget, TRUE);
967 gtk_widget_grab_focus (widget);
968 gtk_widget_set_can_focus (widget, FALSE);
969 }
970
971 static gboolean
gtk_socket_focus(GtkWidget * widget,GtkDirectionType direction)972 gtk_socket_focus (GtkWidget *widget,
973 GtkDirectionType direction)
974 {
975 GtkSocket *socket = GTK_SOCKET (widget);
976 GtkSocketPrivate *private = socket->priv;
977
978 if (private->plug_widget)
979 return gtk_widget_child_focus (private->plug_widget, direction);
980
981 if (!gtk_widget_is_focus (widget))
982 {
983 gint detail = -1;
984
985 switch (direction)
986 {
987 case GTK_DIR_UP:
988 case GTK_DIR_LEFT:
989 case GTK_DIR_TAB_BACKWARD:
990 detail = XEMBED_FOCUS_LAST;
991 break;
992 case GTK_DIR_DOWN:
993 case GTK_DIR_RIGHT:
994 case GTK_DIR_TAB_FORWARD:
995 detail = XEMBED_FOCUS_FIRST;
996 break;
997 }
998
999 _gtk_xembed_send_focus_message (private->plug_window, XEMBED_FOCUS_IN, detail);
1000 gtk_socket_claim_focus (socket, FALSE);
1001
1002 return TRUE;
1003 }
1004 else
1005 return FALSE;
1006 }
1007
1008 static void
gtk_socket_remove(GtkContainer * container,GtkWidget * child)1009 gtk_socket_remove (GtkContainer *container,
1010 GtkWidget *child)
1011 {
1012 GtkSocket *socket = GTK_SOCKET (container);
1013 GtkSocketPrivate *private = socket->priv;
1014
1015 g_return_if_fail (child == private->plug_widget);
1016
1017 _gtk_plug_remove_from_socket (GTK_PLUG (private->plug_widget), socket);
1018 }
1019
1020 static void
gtk_socket_forall(GtkContainer * container,gboolean include_internals,GtkCallback callback,gpointer callback_data)1021 gtk_socket_forall (GtkContainer *container,
1022 gboolean include_internals,
1023 GtkCallback callback,
1024 gpointer callback_data)
1025 {
1026 GtkSocket *socket = GTK_SOCKET (container);
1027 GtkSocketPrivate *private = socket->priv;
1028
1029 if (private->plug_widget)
1030 (* callback) (private->plug_widget, callback_data);
1031 }
1032
1033 /**
1034 * gtk_socket_add_window:
1035 * @socket: a #GtkSocket
1036 * @xid: the native identifier for a window
1037 * @need_reparent: whether the socket’s plug’s window needs to be
1038 * reparented to the socket
1039 *
1040 * Adds a window to a GtkSocket.
1041 */
1042 static void
gtk_socket_add_window(GtkSocket * socket,Window xid,gboolean need_reparent)1043 gtk_socket_add_window (GtkSocket *socket,
1044 Window xid,
1045 gboolean need_reparent)
1046 {
1047 GtkWidget *widget = GTK_WIDGET (socket);
1048 GdkDisplay *display = gtk_widget_get_display (widget);
1049 gpointer user_data = NULL;
1050 GtkSocketPrivate *private = socket->priv;
1051 unsigned long version;
1052 unsigned long flags;
1053
1054 if (GDK_IS_X11_DISPLAY (display))
1055 private->plug_window = gdk_x11_window_lookup_for_display (display, xid);
1056 else
1057 private->plug_window = NULL;
1058
1059 if (private->plug_window)
1060 {
1061 g_object_ref (private->plug_window);
1062 gdk_window_get_user_data (private->plug_window, &user_data);
1063 }
1064
1065 if (user_data) /* A widget's window in this process */
1066 {
1067 GtkWidget *child_widget = user_data;
1068
1069 if (!GTK_IS_PLUG (child_widget))
1070 {
1071 g_warning (G_STRLOC ": Can't add non-GtkPlug to GtkSocket");
1072 private->plug_window = NULL;
1073 gdk_x11_display_error_trap_pop_ignored (display);
1074
1075 return;
1076 }
1077
1078 _gtk_plug_add_to_socket (GTK_PLUG (child_widget), socket);
1079 }
1080 else /* A foreign window */
1081 {
1082 GdkDragProtocol protocol;
1083
1084 gdk_x11_display_error_trap_push (display);
1085
1086 if (!private->plug_window)
1087 {
1088 if (GDK_IS_X11_DISPLAY (display))
1089 private->plug_window = gdk_x11_window_foreign_new_for_display (display, xid);
1090 if (!private->plug_window) /* was deleted before we could get it */
1091 {
1092 gdk_x11_display_error_trap_pop_ignored (display);
1093 return;
1094 }
1095 }
1096
1097 XSelectInput (GDK_DISPLAY_XDISPLAY (display),
1098 GDK_WINDOW_XID (private->plug_window),
1099 StructureNotifyMask | PropertyChangeMask);
1100
1101 if (gdk_x11_display_error_trap_pop (display))
1102 {
1103 g_object_unref (private->plug_window);
1104 private->plug_window = NULL;
1105 return;
1106 }
1107
1108 /* OK, we now will reliably get destroy notification on socket->plug_window */
1109
1110 gdk_x11_display_error_trap_push (display);
1111
1112 if (need_reparent)
1113 {
1114 gdk_window_hide (private->plug_window); /* Shouldn't actually be necessary for XEMBED, but just in case */
1115 gdk_window_reparent (private->plug_window,
1116 gtk_widget_get_window (widget),
1117 0, 0);
1118 }
1119
1120 private->have_size = FALSE;
1121
1122 private->xembed_version = -1;
1123 if (xembed_get_info (private->plug_window, &version, &flags))
1124 {
1125 private->xembed_version = MIN (GTK_XEMBED_PROTOCOL_VERSION, version);
1126 private->is_mapped = (flags & XEMBED_MAPPED) != 0;
1127 }
1128 else
1129 {
1130 /* FIXME, we should probably actually check the state before we started */
1131 private->is_mapped = TRUE;
1132 }
1133
1134 private->need_map = private->is_mapped;
1135
1136 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1137 protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1138 if (protocol)
1139 gtk_drag_dest_set_proxy (widget, private->plug_window, protocol, TRUE);
1140 G_GNUC_END_IGNORE_DEPRECATIONS
1141
1142 gdk_x11_display_error_trap_pop_ignored (display);
1143
1144 gdk_window_add_filter (private->plug_window,
1145 gtk_socket_filter_func,
1146 socket);
1147
1148 #ifdef HAVE_XFIXES
1149 gdk_x11_display_error_trap_push (display);
1150 XFixesChangeSaveSet (GDK_DISPLAY_XDISPLAY (display),
1151 GDK_WINDOW_XID (private->plug_window),
1152 SetModeInsert, SaveSetRoot, SaveSetUnmap);
1153 gdk_x11_display_error_trap_pop_ignored (display);
1154 #endif
1155 _gtk_xembed_send_message (private->plug_window,
1156 XEMBED_EMBEDDED_NOTIFY, 0,
1157 GDK_WINDOW_XID (gtk_widget_get_window (widget)),
1158 private->xembed_version);
1159
1160 socket_update_active (socket);
1161 socket_update_focus_in (socket);
1162
1163 gtk_widget_queue_resize (GTK_WIDGET (socket));
1164
1165 _gtk_socket_accessible_embed (GTK_WIDGET (socket), private->plug_window);
1166 }
1167
1168 if (private->plug_window)
1169 g_signal_emit (socket, socket_signals[PLUG_ADDED], 0);
1170 }
1171
1172 /**
1173 * gtk_socket_handle_map_request:
1174 * @socket: a #GtkSocket
1175 *
1176 * Called from the GtkSocket backend when the plug has been mapped.
1177 */
1178 static void
gtk_socket_handle_map_request(GtkSocket * socket)1179 gtk_socket_handle_map_request (GtkSocket *socket)
1180 {
1181 GtkSocketPrivate *private = socket->priv;
1182 if (!private->is_mapped)
1183 {
1184 private->is_mapped = TRUE;
1185 private->need_map = TRUE;
1186
1187 gtk_widget_queue_resize (GTK_WIDGET (socket));
1188 }
1189 }
1190
1191 /**
1192 * gtk_socket_unmap_notify:
1193 * @socket: a #GtkSocket
1194 *
1195 * Called from the GtkSocket backend when the plug has been unmapped ???
1196 */
1197 static void
gtk_socket_unmap_notify(GtkSocket * socket)1198 gtk_socket_unmap_notify (GtkSocket *socket)
1199 {
1200 GtkSocketPrivate *private = socket->priv;
1201 if (private->is_mapped)
1202 {
1203 private->is_mapped = FALSE;
1204 gtk_widget_queue_resize (GTK_WIDGET (socket));
1205 }
1206 }
1207
1208 /**
1209 * gtk_socket_advance_toplevel_focus:
1210 * @socket: a #GtkSocket
1211 * @direction: a direction
1212 *
1213 * Called from the GtkSocket backend when the corresponding plug
1214 * has told the socket to move the focus.
1215 */
1216 static void
gtk_socket_advance_toplevel_focus(GtkSocket * socket,GtkDirectionType direction)1217 gtk_socket_advance_toplevel_focus (GtkSocket *socket,
1218 GtkDirectionType direction)
1219 {
1220 GtkBin *bin;
1221 GtkWindow *window;
1222 GtkContainer *container;
1223 GtkWidget *child;
1224 GtkWidget *focus_widget;
1225 GtkWidget *toplevel;
1226 GtkWidget *old_focus_child;
1227 GtkWidget *parent;
1228
1229 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
1230 if (!toplevel)
1231 return;
1232
1233 if (!gtk_widget_is_toplevel (toplevel) || GTK_IS_PLUG (toplevel))
1234 {
1235 gtk_widget_child_focus (toplevel,direction);
1236 return;
1237 }
1238
1239 container = GTK_CONTAINER (toplevel);
1240 window = GTK_WINDOW (toplevel);
1241 bin = GTK_BIN (toplevel);
1242
1243 /* This is a copy of gtk_window_focus(), modified so that we
1244 * can detect wrap-around.
1245 */
1246 old_focus_child = gtk_container_get_focus_child (container);
1247
1248 if (old_focus_child)
1249 {
1250 if (gtk_widget_child_focus (old_focus_child, direction))
1251 return;
1252
1253 /* We are allowed exactly one wrap-around per sequence of focus
1254 * events
1255 */
1256 if (_gtk_xembed_get_focus_wrapped ())
1257 return;
1258 else
1259 _gtk_xembed_set_focus_wrapped ();
1260 }
1261
1262 focus_widget = gtk_window_get_focus (window);
1263 if (window)
1264 {
1265 /* Wrapped off the end, clear the focus setting for the toplevel */
1266 parent = gtk_widget_get_parent (focus_widget);
1267 while (parent)
1268 {
1269 gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
1270 parent = gtk_widget_get_parent (parent);
1271 }
1272
1273 gtk_window_set_focus (GTK_WINDOW (container), NULL);
1274 }
1275
1276 /* Now try to focus the first widget in the window */
1277 child = gtk_bin_get_child (bin);
1278 if (child)
1279 {
1280 if (gtk_widget_child_focus (child, direction))
1281 return;
1282 }
1283 }
1284
1285 static gboolean
xembed_get_info(GdkWindow * window,unsigned long * version,unsigned long * flags)1286 xembed_get_info (GdkWindow *window,
1287 unsigned long *version,
1288 unsigned long *flags)
1289 {
1290 GdkDisplay *display = gdk_window_get_display (window);
1291 Atom xembed_info_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO");
1292 Atom type;
1293 int format;
1294 unsigned long nitems, bytes_after;
1295 unsigned char *data;
1296 unsigned long *data_long;
1297 int status;
1298
1299 gdk_x11_display_error_trap_push (display);
1300 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1301 GDK_WINDOW_XID (window),
1302 xembed_info_atom,
1303 0, 2, False,
1304 xembed_info_atom, &type, &format,
1305 &nitems, &bytes_after, &data);
1306 gdk_x11_display_error_trap_pop_ignored (display);
1307
1308 if (status != Success)
1309 return FALSE; /* Window vanished? */
1310
1311 if (type == None) /* No info property */
1312 return FALSE;
1313
1314 if (type != xembed_info_atom)
1315 {
1316 g_warning ("_XEMBED_INFO property has wrong type");
1317 return FALSE;
1318 }
1319
1320 if (nitems < 2)
1321 {
1322 g_warning ("_XEMBED_INFO too short");
1323 XFree (data);
1324 return FALSE;
1325 }
1326
1327 data_long = (unsigned long *)data;
1328 if (version)
1329 *version = data_long[0];
1330 if (flags)
1331 *flags = data_long[1] & XEMBED_MAPPED;
1332
1333 XFree (data);
1334 return TRUE;
1335 }
1336
1337 static void
handle_xembed_message(GtkSocket * socket,XEmbedMessageType message,glong detail,glong data1,glong data2,guint32 time)1338 handle_xembed_message (GtkSocket *socket,
1339 XEmbedMessageType message,
1340 glong detail,
1341 glong data1,
1342 glong data2,
1343 guint32 time)
1344 {
1345 GTK_NOTE (PLUGSOCKET,
1346 g_message ("GtkSocket: %s received", _gtk_xembed_message_name (message)));
1347
1348 switch (message)
1349 {
1350 case XEMBED_EMBEDDED_NOTIFY:
1351 case XEMBED_WINDOW_ACTIVATE:
1352 case XEMBED_WINDOW_DEACTIVATE:
1353 case XEMBED_MODALITY_ON:
1354 case XEMBED_MODALITY_OFF:
1355 case XEMBED_FOCUS_IN:
1356 case XEMBED_FOCUS_OUT:
1357 g_warning ("GtkSocket: Invalid _XEMBED message %s received", _gtk_xembed_message_name (message));
1358 break;
1359
1360 case XEMBED_REQUEST_FOCUS:
1361 gtk_socket_claim_focus (socket, TRUE);
1362 break;
1363
1364 case XEMBED_FOCUS_NEXT:
1365 case XEMBED_FOCUS_PREV:
1366 gtk_socket_advance_toplevel_focus (socket,
1367 (message == XEMBED_FOCUS_NEXT ?
1368 GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
1369 break;
1370
1371 case XEMBED_GTK_GRAB_KEY:
1372 gtk_socket_add_grabbed_key (socket, data1, data2);
1373 break;
1374 case XEMBED_GTK_UNGRAB_KEY:
1375 gtk_socket_remove_grabbed_key (socket, data1, data2);
1376 break;
1377
1378 case XEMBED_GRAB_KEY:
1379 case XEMBED_UNGRAB_KEY:
1380 break;
1381
1382 default:
1383 GTK_NOTE (PLUGSOCKET,
1384 g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %d", message));
1385 break;
1386 }
1387 }
1388
1389 static void
_gtk_socket_accessible_embed(GtkWidget * socket,GdkWindow * window)1390 _gtk_socket_accessible_embed (GtkWidget *socket, GdkWindow *window)
1391 {
1392 GdkDisplay *display = gdk_window_get_display (window);
1393 Atom net_at_spi_path_atom = gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_AT_SPI_PATH");
1394 Atom type;
1395 int format;
1396 unsigned long nitems, bytes_after;
1397 unsigned char *data;
1398 int status;
1399
1400 gdk_x11_display_error_trap_push (display);
1401 status = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
1402 GDK_WINDOW_XID (window),
1403 net_at_spi_path_atom,
1404 0, INT_MAX / 4, False,
1405 net_at_spi_path_atom, &type, &format,
1406 &nitems, &bytes_after, &data);
1407 gdk_x11_display_error_trap_pop_ignored (display);
1408
1409 if (status != Success)
1410 return; /* Window vanished? */
1411
1412 if (type == None) /* No info property */
1413 return;
1414
1415 if (type != net_at_spi_path_atom)
1416 {
1417 g_warning ("_XEMBED_AT_SPI_PATH property has wrong type");
1418 return;
1419 }
1420
1421 if (nitems == 0)
1422 {
1423 g_warning ("_XEMBED_AT_SPI_PATH too short");
1424 XFree (data);
1425 return;
1426 }
1427
1428 if (nitems > INT_MAX)
1429 {
1430 g_warning ("_XEMBED_AT_SPI_PATH too long");
1431 XFree (data);
1432 return;
1433 }
1434
1435 gtk_socket_accessible_embed (GTK_SOCKET_ACCESSIBLE (gtk_widget_get_accessible (socket)), (gchar*) data);
1436 XFree (data);
1437
1438 return;
1439 }
1440
1441 static GdkFilterReturn
gtk_socket_filter_func(GdkXEvent * gdk_xevent,GdkEvent * event,gpointer data)1442 gtk_socket_filter_func (GdkXEvent *gdk_xevent,
1443 GdkEvent *event,
1444 gpointer data)
1445 {
1446 GtkSocket *socket;
1447 GtkWidget *widget;
1448 GdkDisplay *display;
1449 XEvent *xevent;
1450 GtkSocketPrivate *private;
1451
1452 GdkFilterReturn return_val;
1453
1454 socket = GTK_SOCKET (data);
1455 private = socket->priv;
1456
1457 return_val = GDK_FILTER_CONTINUE;
1458
1459 if (private->plug_widget)
1460 return return_val;
1461
1462 widget = GTK_WIDGET (socket);
1463 xevent = (XEvent *)gdk_xevent;
1464 display = gtk_widget_get_display (widget);
1465
1466 switch (xevent->type)
1467 {
1468 case ClientMessage:
1469 if (xevent->xclient.message_type == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED"))
1470 {
1471 _gtk_xembed_push_message (xevent);
1472 handle_xembed_message (socket,
1473 xevent->xclient.data.l[1],
1474 xevent->xclient.data.l[2],
1475 xevent->xclient.data.l[3],
1476 xevent->xclient.data.l[4],
1477 xevent->xclient.data.l[0]);
1478 _gtk_xembed_pop_message ();
1479
1480 return_val = GDK_FILTER_REMOVE;
1481 }
1482 break;
1483
1484 case CreateNotify:
1485 {
1486 XCreateWindowEvent *xcwe = &xevent->xcreatewindow;
1487
1488 if (!private->plug_window)
1489 {
1490 gtk_socket_add_window (socket, xcwe->window, FALSE);
1491
1492 if (private->plug_window)
1493 {
1494 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window created"));
1495 }
1496 }
1497
1498 return_val = GDK_FILTER_REMOVE;
1499
1500 break;
1501 }
1502
1503 case ConfigureRequest:
1504 {
1505 XConfigureRequestEvent *xcre = &xevent->xconfigurerequest;
1506
1507 if (!private->plug_window)
1508 gtk_socket_add_window (socket, xcre->window, FALSE);
1509
1510 if (private->plug_window)
1511 {
1512 if (xcre->value_mask & (CWWidth | CWHeight))
1513 {
1514 GTK_NOTE (PLUGSOCKET,
1515 g_message ("GtkSocket - configure request: %d %d",
1516 private->request_width,
1517 private->request_height));
1518
1519 private->resize_count++;
1520 gtk_widget_queue_resize (widget);
1521 }
1522 else if (xcre->value_mask & (CWX | CWY))
1523 {
1524 gtk_socket_send_configure_event (socket);
1525 }
1526 /* Ignore stacking requests. */
1527
1528 return_val = GDK_FILTER_REMOVE;
1529 }
1530 break;
1531 }
1532
1533 case DestroyNotify:
1534 {
1535 XDestroyWindowEvent *xdwe = &xevent->xdestroywindow;
1536
1537 /* Note that we get destroy notifies both from SubstructureNotify on
1538 * our window and StructureNotify on socket->plug_window
1539 */
1540 if (private->plug_window && (xdwe->window == GDK_WINDOW_XID (private->plug_window)))
1541 {
1542 gboolean result;
1543
1544 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - destroy notify"));
1545
1546 gdk_window_destroy_notify (private->plug_window);
1547 gtk_socket_end_embedding (socket);
1548
1549 g_object_ref (widget);
1550 g_signal_emit_by_name (widget, "plug-removed", &result);
1551 if (!result)
1552 gtk_widget_destroy (widget);
1553 g_object_unref (widget);
1554
1555 return_val = GDK_FILTER_REMOVE;
1556 }
1557 break;
1558 }
1559
1560 case FocusIn:
1561 if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
1562 {
1563 gtk_socket_claim_focus (socket, TRUE);
1564 }
1565 return_val = GDK_FILTER_REMOVE;
1566 break;
1567 case FocusOut:
1568 return_val = GDK_FILTER_REMOVE;
1569 break;
1570 case MapRequest:
1571 if (!private->plug_window)
1572 {
1573 gtk_socket_add_window (socket, xevent->xmaprequest.window, FALSE);
1574 }
1575
1576 if (private->plug_window)
1577 {
1578 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Map Request"));
1579
1580 gtk_socket_handle_map_request (socket);
1581 return_val = GDK_FILTER_REMOVE;
1582 }
1583 break;
1584 case PropertyNotify:
1585 if (private->plug_window &&
1586 xevent->xproperty.window == GDK_WINDOW_XID (private->plug_window))
1587 {
1588 GdkDragProtocol protocol;
1589
1590 if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "WM_NORMAL_HINTS"))
1591 {
1592 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - received PropertyNotify for plug's WM_NORMAL_HINTS"));
1593 private->have_size = FALSE;
1594 gtk_widget_queue_resize (widget);
1595 return_val = GDK_FILTER_REMOVE;
1596 }
1597 else if ((xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "XdndAware")) ||
1598 (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_MOTIF_DRAG_RECEIVER_INFO")))
1599 {
1600 gdk_x11_display_error_trap_push (display);
1601 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
1602 protocol = gdk_window_get_drag_protocol (private->plug_window, NULL);
1603 if (protocol)
1604 gtk_drag_dest_set_proxy (GTK_WIDGET (socket),
1605 private->plug_window,
1606 protocol, TRUE);
1607 G_GNUC_END_IGNORE_DEPRECATIONS
1608
1609 gdk_x11_display_error_trap_pop_ignored (display);
1610 return_val = GDK_FILTER_REMOVE;
1611 }
1612 else if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_XEMBED_INFO"))
1613 {
1614 unsigned long flags;
1615
1616 if (xembed_get_info (private->plug_window, NULL, &flags))
1617 {
1618 gboolean was_mapped = private->is_mapped;
1619 gboolean is_mapped = (flags & XEMBED_MAPPED) != 0;
1620
1621 if (was_mapped != is_mapped)
1622 {
1623 if (is_mapped)
1624 gtk_socket_handle_map_request (socket);
1625 else
1626 {
1627 gdk_x11_display_error_trap_push (display);
1628 gdk_window_show (private->plug_window);
1629 gdk_x11_display_error_trap_pop_ignored (display);
1630
1631 gtk_socket_unmap_notify (socket);
1632 }
1633 }
1634 }
1635 return_val = GDK_FILTER_REMOVE;
1636 }
1637 }
1638 break;
1639 case ReparentNotify:
1640 {
1641 GdkWindow *window;
1642 XReparentEvent *xre = &xevent->xreparent;
1643
1644 window = gtk_widget_get_window (widget);
1645
1646 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - ReparentNotify received"));
1647 if (!private->plug_window &&
1648 xre->parent == GDK_WINDOW_XID (window))
1649 {
1650 gtk_socket_add_window (socket, xre->window, FALSE);
1651
1652 if (private->plug_window)
1653 {
1654 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - window reparented"));
1655 }
1656
1657 return_val = GDK_FILTER_REMOVE;
1658 }
1659 else
1660 {
1661 if (private->plug_window &&
1662 xre->window == GDK_WINDOW_XID (private->plug_window) &&
1663 xre->parent != GDK_WINDOW_XID (window))
1664 {
1665 gboolean result;
1666
1667 gtk_socket_end_embedding (socket);
1668
1669 g_object_ref (widget);
1670 g_signal_emit_by_name (widget, "plug-removed", &result);
1671 if (!result)
1672 gtk_widget_destroy (widget);
1673 g_object_unref (widget);
1674
1675 return_val = GDK_FILTER_REMOVE;
1676 }
1677 }
1678
1679 break;
1680 }
1681 case UnmapNotify:
1682 if (private->plug_window &&
1683 xevent->xunmap.window == GDK_WINDOW_XID (private->plug_window))
1684 {
1685 GTK_NOTE (PLUGSOCKET, g_message ("GtkSocket - Unmap notify"));
1686
1687 gtk_socket_unmap_notify (socket);
1688 return_val = GDK_FILTER_REMOVE;
1689 }
1690 break;
1691
1692 }
1693
1694 return return_val;
1695 }
1696