1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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.
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.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* By Owen Taylor <otaylor@gtk.org> 98/4/4 */
22 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
23 * file for a list of people on the GTK+ Team. See the ChangeLog
24 * files for a list of changes. These files are distributed with
25 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
29 #include "gtkmarshal.h"
31 #include "gtkprivate.h"
33 #include "gdk/gdkkeysyms.h"
38 static void gtk_plug_class_init (GtkPlugClass *klass);
39 static void gtk_plug_init (GtkPlug *plug);
40 static void gtk_plug_realize (GtkWidget *widget);
41 static void gtk_plug_unrealize (GtkWidget *widget);
42 static void gtk_plug_show (GtkWidget *widget);
43 static void gtk_plug_hide (GtkWidget *widget);
44 static void gtk_plug_map (GtkWidget *widget);
45 static void gtk_plug_unmap (GtkWidget *widget);
46 static void gtk_plug_size_allocate (GtkWidget *widget,
47 GtkAllocation *allocation);
48 static gboolean gtk_plug_key_press_event (GtkWidget *widget,
50 static void gtk_plug_forward_key_press (GtkPlug *plug,
52 static void gtk_plug_set_focus (GtkWindow *window,
54 static gboolean gtk_plug_focus (GtkWidget *widget,
55 GtkDirectionType direction);
56 static void gtk_plug_check_resize (GtkContainer *container);
58 static void gtk_plug_accel_entries_changed (GtkWindow *window);
60 static GdkFilterReturn gtk_plug_filter_func (GdkXEvent *gdk_xevent,
64 static void gtk_plug_free_grabbed_keys (GHashTable *key_table);
65 static void handle_modality_off (GtkPlug *plug);
66 static void send_xembed_message (GtkPlug *plug,
72 static void xembed_set_info (GdkWindow *window,
76 #define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
78 static GtkWindowClass *parent_class = NULL;
79 static GtkBinClass *bin_class = NULL;
86 static guint plug_signals[LAST_SIGNAL] = { 0 };
91 static GtkType plug_type = 0;
95 static const GTypeInfo plug_info =
97 sizeof (GtkPlugClass),
99 NULL, /* base_finalize */
100 (GClassInitFunc) gtk_plug_class_init,
101 NULL, /* class_finalize */
102 NULL, /* class_data */
104 16, /* n_preallocs */
105 (GInstanceInitFunc) gtk_plug_init,
108 plug_type = g_type_register_static (GTK_TYPE_WINDOW, "GtkPlug", &plug_info, 0);
115 gtk_plug_class_init (GtkPlugClass *class)
117 GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
118 GtkWindowClass *window_class = (GtkWindowClass *)class;
119 GtkContainerClass *container_class = (GtkContainerClass *)class;
121 parent_class = gtk_type_class (GTK_TYPE_WINDOW);
122 bin_class = gtk_type_class (GTK_TYPE_BIN);
124 widget_class->realize = gtk_plug_realize;
125 widget_class->unrealize = gtk_plug_unrealize;
126 widget_class->key_press_event = gtk_plug_key_press_event;
128 widget_class->show = gtk_plug_show;
129 widget_class->hide = gtk_plug_hide;
130 widget_class->map = gtk_plug_map;
131 widget_class->unmap = gtk_plug_unmap;
132 widget_class->size_allocate = gtk_plug_size_allocate;
134 widget_class->focus = gtk_plug_focus;
136 container_class->check_resize = gtk_plug_check_resize;
138 window_class->set_focus = gtk_plug_set_focus;
140 window_class->accel_entries_changed = gtk_plug_accel_entries_changed;
143 plug_signals[EMBEDDED] =
144 g_signal_new ("embedded",
145 G_OBJECT_CLASS_TYPE (class),
147 G_STRUCT_OFFSET (GtkPlugClass, embedded),
149 gtk_marshal_VOID__VOID,
154 gtk_plug_init (GtkPlug *plug)
158 window = GTK_WINDOW (plug);
160 window->type = GTK_WINDOW_TOPLEVEL;
164 gtk_plug_set_is_child (GtkPlug *plug,
167 g_assert (!GTK_WIDGET (plug)->parent);
171 if (plug->modality_window)
172 handle_modality_off (plug);
174 if (plug->modality_group)
176 gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
177 g_object_unref (plug->modality_group);
178 plug->modality_group = NULL;
181 GTK_WIDGET_UNSET_FLAGS (plug, GTK_TOPLEVEL);
182 gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_PARENT);
184 _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), GTK_WIDGET (plug));
188 plug->modality_group = gtk_window_group_new ();
189 gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug));
191 GTK_WIDGET_SET_FLAGS (plug, GTK_TOPLEVEL);
192 gtk_container_set_resize_mode (GTK_CONTAINER (plug), GTK_RESIZE_QUEUE);
194 _gtk_widget_propagate_hierarchy_changed (GTK_WIDGET (plug), NULL);
199 * _gtk_plug_add_to_socket:
201 * @socket: a #GtkSocket
203 * Add a plug to a socket within the same application.
206 _gtk_plug_add_to_socket (GtkPlug *plug,
211 g_return_if_fail (GTK_IS_PLUG (plug));
212 g_return_if_fail (GTK_IS_SOCKET (socket));
213 g_return_if_fail (GTK_WIDGET_REALIZED (socket));
215 widget = GTK_WIDGET (plug);
217 gtk_plug_set_is_child (plug, TRUE);
218 plug->same_app = TRUE;
219 socket->plug_widget = widget;
221 if (GTK_WIDGET_REALIZED (widget))
222 gdk_window_reparent (widget->window, plug->socket_window, 0, 0);
224 gtk_widget_set_parent (widget, GTK_WIDGET (socket));
226 g_signal_emit_by_name (G_OBJECT (socket), "plug_added", 0);
230 * _gtk_plug_add_to_socket:
232 * @socket: a #GtkSocket
234 * Remove a plug from a socket within the same application.
237 _gtk_plug_remove_from_socket (GtkPlug *plug,
243 gboolean widget_was_visible;
245 g_return_if_fail (GTK_IS_PLUG (plug));
246 g_return_if_fail (GTK_IS_SOCKET (socket));
247 g_return_if_fail (GTK_WIDGET_REALIZED (plug));
249 widget = GTK_WIDGET (plug);
252 g_object_ref (socket);
254 widget_was_visible = GTK_WIDGET_VISIBLE (plug);
256 gdk_window_hide (widget->window);
257 gdk_window_reparent (widget->window, GDK_ROOT_PARENT (), 0, 0);
259 GTK_PRIVATE_SET_FLAG (plug, GTK_IN_REPARENT);
260 gtk_widget_unparent (GTK_WIDGET (plug));
261 GTK_PRIVATE_UNSET_FLAG (plug, GTK_IN_REPARENT);
263 socket->plug_widget = NULL;
264 socket->plug_window = NULL;
265 socket->same_app = FALSE;
267 plug->same_app = FALSE;
268 plug->socket_window = FALSE;
270 gtk_plug_set_is_child (plug, FALSE);
272 g_signal_emit_by_name (G_OBJECT (socket), "plug_removed", &result);
274 gtk_widget_destroy (GTK_WIDGET (socket));
276 event.any.type = GDK_DELETE;
277 event.any.window = g_object_ref (widget->window);
278 event.any.send_event = FALSE;
280 if (!gtk_widget_event (widget, &event))
281 gtk_widget_destroy (widget);
283 g_object_unref (event.any.window);
284 g_object_unref (plug);
286 if (widget_was_visible && GTK_WIDGET_VISIBLE (socket))
287 gtk_widget_queue_resize (GTK_WIDGET (socket));
289 g_object_unref (socket);
293 gtk_plug_construct (GtkPlug *plug,
294 GdkNativeWindow socket_id)
298 gpointer user_data = NULL;
300 plug->socket_window = gdk_window_lookup (socket_id);
302 if (plug->socket_window)
303 gdk_window_get_user_data (plug->socket_window, &user_data);
305 plug->socket_window = gdk_window_foreign_new (socket_id);
309 if (GTK_IS_SOCKET (user_data))
310 _gtk_plug_add_to_socket (plug, user_data);
313 g_warning (G_STRLOC "Can't create GtkPlug as child of non-GtkSocket");
314 plug->socket_window = NULL;
318 if (plug->socket_window)
319 g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0);
324 gtk_plug_new (GdkNativeWindow socket_id)
328 plug = GTK_PLUG (gtk_type_new (GTK_TYPE_PLUG));
329 gtk_plug_construct (plug, socket_id);
330 return GTK_WIDGET (plug);
337 * Gets the window ID of a #GtkPlug widget, which can then
338 * be used to embed this window inside another window, for
339 * instance with gtk_socket_add_id().
341 * Return value: the window ID for the plug
344 gtk_plug_get_id (GtkPlug *plug)
346 g_return_val_if_fail (GTK_IS_PLUG (plug), 0);
348 if (!GTK_WIDGET_REALIZED (plug))
349 gtk_widget_realize (GTK_WIDGET (plug));
351 return GDK_WINDOW_XWINDOW (GTK_WIDGET (plug)->window);
355 gtk_plug_unrealize (GtkWidget *widget)
359 g_return_if_fail (GTK_IS_PLUG (widget));
361 plug = GTK_PLUG (widget);
363 if (plug->socket_window != NULL)
365 gdk_window_set_user_data (plug->socket_window, NULL);
366 gdk_window_unref (plug->socket_window);
367 plug->socket_window = NULL;
372 if (plug->modality_window)
373 handle_modality_off (plug);
375 gtk_window_group_remove_window (plug->modality_group, GTK_WINDOW (plug));
376 g_object_unref (plug->modality_group);
379 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
380 (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
384 gtk_plug_realize (GtkWidget *widget)
388 GdkWindowAttr attributes;
389 gint attributes_mask;
391 g_return_if_fail (GTK_IS_PLUG (widget));
393 GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
394 window = GTK_WINDOW (widget);
395 plug = GTK_PLUG (widget);
397 attributes.window_type = GDK_WINDOW_CHILD; /* XXX GDK_WINDOW_PLUG ? */
398 attributes.title = window->title;
399 attributes.wmclass_name = window->wmclass_name;
400 attributes.wmclass_class = window->wmclass_class;
401 attributes.width = widget->allocation.width;
402 attributes.height = widget->allocation.height;
403 attributes.wclass = GDK_INPUT_OUTPUT;
405 /* this isn't right - we should match our parent's visual/colormap.
406 * though that will require handling "foreign" colormaps */
407 attributes.visual = gtk_widget_get_visual (widget);
408 attributes.colormap = gtk_widget_get_colormap (widget);
409 attributes.event_mask = gtk_widget_get_events (widget);
410 attributes.event_mask |= (GDK_EXPOSURE_MASK |
412 GDK_ENTER_NOTIFY_MASK |
413 GDK_LEAVE_NOTIFY_MASK |
414 GDK_FOCUS_CHANGE_MASK |
417 attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP;
418 attributes_mask |= (window->title ? GDK_WA_TITLE : 0);
419 attributes_mask |= (window->wmclass_name ? GDK_WA_WMCLASS : 0);
421 if (GTK_WIDGET_TOPLEVEL (widget))
423 attributes.window_type = GDK_WINDOW_TOPLEVEL;
425 gdk_error_trap_push ();
426 widget->window = gdk_window_new (plug->socket_window,
427 &attributes, attributes_mask);
429 if (gdk_error_trap_pop ()) /* Uh-oh */
431 gdk_error_trap_push ();
432 gdk_window_destroy (widget->window);
434 gdk_error_trap_pop ();
435 widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
438 gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget);
440 plug->modality_group = gtk_window_group_new ();
441 gtk_window_group_add_window (plug->modality_group, window);
443 xembed_set_info (widget->window, 0);
446 widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
448 gdk_window_set_user_data (widget->window, window);
450 widget->style = gtk_style_attach (widget->style, widget->window);
451 gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
455 gtk_plug_show (GtkWidget *widget)
457 if (GTK_WIDGET_TOPLEVEL (widget))
458 GTK_WIDGET_CLASS (parent_class)->show (widget);
460 GTK_WIDGET_CLASS (bin_class)->show (widget);
464 gtk_plug_hide (GtkWidget *widget)
466 if (GTK_WIDGET_TOPLEVEL (widget))
467 GTK_WIDGET_CLASS (parent_class)->hide (widget);
469 GTK_WIDGET_CLASS (bin_class)->hide (widget);
472 /* From gdkinternals.h */
473 void gdk_synthesize_window_state (GdkWindow *window,
474 GdkWindowState unset_flags,
475 GdkWindowState set_flags);
478 gtk_plug_map (GtkWidget *widget)
480 if (GTK_WIDGET_TOPLEVEL (widget))
482 GtkBin *bin = GTK_BIN (widget);
484 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
487 GTK_WIDGET_VISIBLE (bin->child) &&
488 !GTK_WIDGET_MAPPED (bin->child))
489 gtk_widget_map (bin->child);
491 xembed_set_info (widget->window, XEMBED_MAPPED);
493 gdk_synthesize_window_state (widget->window,
494 GDK_WINDOW_STATE_WITHDRAWN,
498 GTK_WIDGET_CLASS (bin_class)->map (widget);
502 gtk_plug_unmap (GtkWidget *widget)
504 if (GTK_WIDGET_TOPLEVEL (widget))
506 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
508 gdk_window_hide (widget->window);
509 xembed_set_info (widget->window, 0);
511 gdk_synthesize_window_state (widget->window,
513 GDK_WINDOW_STATE_WITHDRAWN);
516 GTK_WIDGET_CLASS (bin_class)->unmap (widget);
520 gtk_plug_size_allocate (GtkWidget *widget,
521 GtkAllocation *allocation)
523 if (GTK_WIDGET_TOPLEVEL (widget))
524 GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
527 GtkBin *bin = GTK_BIN (widget);
529 if (GTK_WIDGET_REALIZED (widget))
530 gdk_window_move_resize (widget->window,
531 allocation->x, allocation->y,
532 allocation->width, allocation->height);
534 if (bin->child && GTK_WIDGET_VISIBLE (bin->child))
536 GtkAllocation child_allocation;
538 child_allocation.x = child_allocation.y = GTK_CONTAINER (widget)->border_width;
539 child_allocation.width =
540 MAX (1, (gint)allocation->width - child_allocation.x * 2);
541 child_allocation.height =
542 MAX (1, (gint)allocation->height - child_allocation.y * 2);
544 gtk_widget_size_allocate (bin->child, &child_allocation);
551 gtk_plug_key_press_event (GtkWidget *widget,
554 if (!GTK_WINDOW (widget)->has_focus)
556 gtk_plug_forward_key_press (GTK_PLUG (widget), event);
560 return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
564 gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
568 xevent.xkey.type = KeyPress;
569 xevent.xkey.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
570 xevent.xkey.window = GDK_WINDOW_XWINDOW (plug->socket_window);
571 xevent.xkey.root = GDK_ROOT_WINDOW (); /* FIXME */
572 xevent.xkey.time = event->time;
573 /* FIXME, the following might cause big problems for
577 xevent.xkey.x_root = 0;
578 xevent.xkey.y_root = 0;
579 xevent.xkey.state = event->state;
580 xevent.xkey.keycode = XKeysymToKeycode(GDK_DISPLAY(),
582 xevent.xkey.same_screen = TRUE; /* FIXME ? */
584 gdk_error_trap_push ();
585 XSendEvent (GDK_DISPLAY (),
586 GDK_WINDOW_XWINDOW (plug->socket_window),
587 False, NoEventMask, &xevent);
589 gdk_error_trap_pop ();
593 gtk_plug_set_focus (GtkWindow *window,
596 GtkPlug *plug = GTK_PLUG (window);
598 GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus);
600 /* Ask for focus from embedder
603 if (focus && !window->has_focus)
608 xevent.xfocus.type = FocusIn;
609 xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
610 xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
611 xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
612 xevent.xfocus.detail = FALSE; /* Don't force */
614 gdk_error_trap_push ();
615 XSendEvent (GDK_DISPLAY (),
616 GDK_WINDOW_XWINDOW (plug->socket_window),
617 False, NoEventMask, &xevent);
619 gdk_error_trap_pop ();
622 send_xembed_message (plug, XEMBED_REQUEST_FOCUS, 0, 0, 0,
623 gtk_get_current_event_time ());
631 guint accelerator_key;
632 GdkModifierType accelerator_mods;
636 grabbed_key_hash (gconstpointer a)
638 const GrabbedKey *key = a;
641 h = key->accelerator_key << 16;
642 h ^= key->accelerator_key >> 16;
643 h ^= key->accelerator_mods;
649 grabbed_key_equal (gconstpointer a, gconstpointer b)
651 const GrabbedKey *keya = a;
652 const GrabbedKey *keyb = b;
654 return (keya->accelerator_key == keyb->accelerator_key &&
655 keya->accelerator_mods == keyb->accelerator_mods);
659 add_grabbed_keys (gpointer key, gpointer val, gpointer data)
661 GrabbedKey *grabbed_key = key;
662 GtkPlug *plug = data;
664 if (!plug->grabbed_keys ||
665 !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
667 send_xembed_message (plug, XEMBED_GRAB_KEY, 0,
668 grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
669 gtk_get_current_event_time ());
674 remove_grabbed_keys (gpointer key, gpointer val, gpointer data)
676 GrabbedKey *grabbed_key = key;
677 GtkPlug *plug = data;
679 if (!plug->grabbed_keys ||
680 !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
682 send_xembed_message (plug, XEMBED_UNGRAB_KEY, 0,
683 grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
684 gtk_get_current_event_time ());
689 gtk_plug_free_grabbed_keys (GHashTable *key_table)
691 g_hash_table_foreach (key_table, (GHFunc)g_free, NULL);
692 g_hash_table_destroy (key_table);
696 gtk_plug_accel_entries_changed (GtkWindow *window)
698 GHashTable *new_grabbed_keys, *old_grabbed_keys;
699 GSList *accel_groups, *tmp_list;
700 GtkPlug *plug = GTK_PLUG (window);
702 new_grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
704 accel_groups = gtk_accel_groups_from_object (G_OBJECT (window));
706 tmp_list = accel_groups;
710 GtkAccelGroup *accel_group = tmp_list->data;
712 GtkAccelEntry *entries;
714 gtk_accel_group_get_entries (accel_group, &entries, &n_entries);
716 for (i = 0; i < n_entries; i++)
721 if (gdk_keymap_get_entries_for_keyval (NULL, entries[i].accelerator_key, &keys, &n_keys))
723 GrabbedKey *key = g_new (GrabbedKey, 1);
725 key->accelerator_key = keys[0].keycode;
726 key->accelerator_mods = entries[i].accelerator_mods;
728 g_hash_table_insert (new_grabbed_keys, key, key);
734 tmp_list = tmp_list->next;
737 g_hash_table_foreach (new_grabbed_keys, add_grabbed_keys, plug);
739 old_grabbed_keys = plug->grabbed_keys;
740 plug->grabbed_keys = new_grabbed_keys;
742 if (old_grabbed_keys)
744 g_hash_table_foreach (old_grabbed_keys, remove_grabbed_keys, plug);
745 gtk_plug_free_grabbed_keys (old_grabbed_keys);
752 gtk_plug_focus (GtkWidget *widget,
753 GtkDirectionType direction)
755 GtkBin *bin = GTK_BIN (widget);
756 GtkPlug *plug = GTK_PLUG (widget);
757 GtkWindow *window = GTK_WINDOW (widget);
758 GtkContainer *container = GTK_CONTAINER (widget);
759 GtkWidget *old_focus_child = container->focus_child;
762 /* We override GtkWindow's behavior, since we don't want wrapping here.
766 if (gtk_widget_child_focus (old_focus_child, direction))
769 if (window->focus_widget)
771 /* Wrapped off the end, clear the focus setting for the toplevel */
772 parent = window->focus_widget->parent;
775 gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
776 parent = GTK_WIDGET (parent)->parent;
779 gtk_window_set_focus (GTK_WINDOW (container), NULL);
781 if (!GTK_CONTAINER (window)->focus_child)
789 case GTK_DIR_TAB_BACKWARD:
790 message = XEMBED_FOCUS_PREV;
794 case GTK_DIR_TAB_FORWARD:
795 message = XEMBED_FOCUS_NEXT;
799 send_xembed_message (plug, message, 0, 0, 0,
800 gtk_get_current_event_time ());
803 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
805 gdk_error_trap_push ();
806 XSetInputFocus (GDK_DISPLAY (),
807 GDK_WINDOW_XWINDOW (plug->socket_window),
808 RevertToParent, event->time);
810 gdk_error_trap_pop ();
812 gtk_plug_forward_key_press (plug, event);
821 /* Try to focus the first widget in the window */
823 if (gtk_widget_child_focus (bin->child, direction))
831 gtk_plug_check_resize (GtkContainer *container)
833 if (GTK_WIDGET_TOPLEVEL (container))
834 GTK_CONTAINER_CLASS (parent_class)->check_resize (container);
836 GTK_CONTAINER_CLASS (bin_class)->check_resize (container);
840 send_xembed_message (GtkPlug *plug,
847 if (plug->socket_window)
851 xevent.xclient.window = GDK_WINDOW_XWINDOW (plug->socket_window);
852 xevent.xclient.type = ClientMessage;
853 xevent.xclient.message_type = gdk_atom_intern ("_XEMBED", FALSE);
854 xevent.xclient.format = 32;
855 xevent.xclient.data.l[0] = time;
856 xevent.xclient.data.l[1] = message;
857 xevent.xclient.data.l[2] = detail;
858 xevent.xclient.data.l[3] = data1;
859 xevent.xclient.data.l[4] = data2;
861 gdk_error_trap_push ();
862 XSendEvent (GDK_DISPLAY (),
863 GDK_WINDOW_XWINDOW (plug->socket_window),
864 False, NoEventMask, &xevent);
866 gdk_error_trap_pop ();
871 focus_first_last (GtkPlug *plug,
872 GtkDirectionType direction)
874 GtkWindow *window = GTK_WINDOW (plug);
877 if (window->focus_widget)
879 parent = window->focus_widget->parent;
882 gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
883 parent = GTK_WIDGET (parent)->parent;
886 gtk_window_set_focus (GTK_WINDOW (plug), NULL);
889 gtk_widget_child_focus (GTK_WIDGET (plug), direction);
893 handle_modality_on (GtkPlug *plug)
895 if (!plug->modality_window)
897 plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
898 gtk_window_group_add_window (plug->modality_group, GTK_WINDOW (plug->modality_window));
899 gtk_grab_add (plug->modality_window);
904 handle_modality_off (GtkPlug *plug)
906 if (plug->modality_window)
908 gtk_widget_destroy (plug->modality_window);
909 plug->modality_window = NULL;
914 xembed_set_info (GdkWindow *gdk_window,
917 Display *display = GDK_WINDOW_XDISPLAY (gdk_window);
918 Window window = GDK_WINDOW_XWINDOW (gdk_window);
919 unsigned long buffer[2];
921 Atom xembed_info_atom = gdk_atom_intern ("_XEMBED_INFO", FALSE);
923 buffer[1] = 0; /* Protocol version */
926 XChangeProperty (display, window,
927 xembed_info_atom, xembed_info_atom, 32,
929 (unsigned char *)buffer, 2);
933 handle_xembed_message (GtkPlug *plug,
940 GTK_NOTE (PLUGSOCKET,
941 g_message ("Message of type %ld received", message));
945 case XEMBED_EMBEDDED_NOTIFY:
947 case XEMBED_WINDOW_ACTIVATE:
949 g_message ("GtkPlug: ACTIVATE received"));
951 case XEMBED_WINDOW_DEACTIVATE:
953 g_message ("GtkPlug: DEACTIVATE received"));
956 case XEMBED_MODALITY_ON:
957 handle_modality_on (plug);
959 case XEMBED_MODALITY_OFF:
960 handle_modality_off (plug);
963 case XEMBED_FOCUS_IN:
966 case XEMBED_FOCUS_FIRST:
967 focus_first_last (plug, GTK_DIR_TAB_FORWARD);
969 case XEMBED_FOCUS_LAST:
970 focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
972 case XEMBED_FOCUS_CURRENT:
976 case XEMBED_FOCUS_OUT:
980 event.focus_change.type = GDK_FOCUS_CHANGE;
981 event.focus_change.window = GTK_WIDGET (plug)->window;
982 event.focus_change.send_event = TRUE;
983 event.focus_change.in = (message == XEMBED_FOCUS_IN);
985 gtk_widget_event (GTK_WIDGET (plug), &event);
990 case XEMBED_REQUEST_FOCUS:
991 case XEMBED_FOCUS_NEXT:
992 case XEMBED_FOCUS_PREV:
993 case XEMBED_GRAB_KEY:
994 case XEMBED_UNGRAB_KEY:
995 g_warning ("GtkPlug: Invalid _XEMBED message of type %ld received", message);
1000 g_message ("GtkPlug: Ignoring unknown _XEMBED message of type %ld", message));
1005 static GdkFilterReturn
1006 gtk_plug_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
1008 GtkPlug *plug = GTK_PLUG (data);
1009 XEvent *xevent = (XEvent *)gdk_xevent;
1011 GdkFilterReturn return_val;
1013 return_val = GDK_FILTER_CONTINUE;
1015 switch (xevent->type)
1018 if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
1020 handle_xembed_message (plug,
1021 xevent->xclient.data.l[1],
1022 xevent->xclient.data.l[2],
1023 xevent->xclient.data.l[3],
1024 xevent->xclient.data.l[4],
1025 xevent->xclient.data.l[0]);
1028 return GDK_FILTER_REMOVE;
1030 else if (xevent->xclient.message_type == gdk_atom_intern ("WM_DELETE_WINDOW", FALSE))
1032 /* We filter these out because we take being reparented back to the
1033 * root window as the reliable end of the embedding protocol
1036 return GDK_FILTER_REMOVE;
1039 case ReparentNotify:
1041 XReparentEvent *xre = &xevent->xreparent;
1042 gboolean was_embedded = plug->socket_window != NULL;
1044 return_val = GDK_FILTER_REMOVE;
1046 g_object_ref (plug);
1050 /* End of embedding protocol for previous socket */
1052 /* FIXME: race if we remove from another socket and
1053 * then add to a local window before we get notification
1054 * Probably need check in _gtk_plug_add_to_socket
1057 if (xre->parent != GDK_WINDOW_XWINDOW (plug->socket_window))
1059 GtkWidget *widget = GTK_WIDGET (plug);
1061 gdk_window_set_user_data (plug->socket_window, NULL);
1062 gdk_window_unref (plug->socket_window);
1063 plug->socket_window = NULL;
1065 /* Emit a delete window, as if the user attempted
1066 * to close the toplevel. Simple as to how we
1067 * handle WM_DELETE_WINDOW, if it isn't handled
1068 * we destroy the widget. BUt only do this if
1069 * we are being reparented to the root window.
1070 * Moving from one embedder to another should
1071 * be invisible to the app.
1074 if (xre->parent == GDK_ROOT_WINDOW())
1078 event.any.type = GDK_DELETE;
1079 event.any.window = g_object_ref (widget->window);
1080 event.any.send_event = FALSE;
1082 if (!gtk_widget_event (widget, &event))
1083 gtk_widget_destroy (widget);
1085 g_object_unref (event.any.window);
1092 if (xre->parent != GDK_ROOT_WINDOW ())
1094 /* Start of embedding protocol */
1096 plug->socket_window = gdk_window_lookup (xre->parent);
1097 if (plug->socket_window)
1099 gpointer user_data = NULL;
1100 gdk_window_get_user_data (plug->socket_window, &user_data);
1104 g_warning (G_STRLOC "Plug reparented unexpectedly into window in the same process");
1105 plug->socket_window = NULL;
1109 g_object_ref (plug->socket_window);
1113 plug->socket_window = gdk_window_foreign_new (xre->parent);
1114 if (!plug->socket_window) /* Already gone */
1118 /* FIXME: Add grabbed keys here */
1121 g_signal_emit (G_OBJECT (plug), plug_signals[EMBEDDED], 0);
1124 g_object_unref (plug);
1130 return GDK_FILTER_CONTINUE;