summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwen Taylor <otaylor@redhat.com>2001-04-19 20:36:46 +0000
committerOwen Taylor <otaylor@src.gnome.org>2001-04-19 20:36:46 +0000
commitbf660df987e2eb2ac2f1f885178e0bbdb7d560b0 (patch)
tree5d135018addc3f99e185ce572150e9d8693f46ed
parente13ec2098affda07023d073a5527f0e61bb24058 (diff)
downloadgdk-pixbuf-bf660df987e2eb2ac2f1f885178e0bbdb7d560b0.tar.gz
File containing #defines for XEMBED protocol.
Thu Apr 19 16:11:07 2001 Owen Taylor <otaylor@redhat.com> * gtk/Makefile.am xembed.h: File containing #defines for XEMBED protocol. * gtk/gtkplug.[ch] gtk/gtksocket.[ch]: - Change protocol from old plug/socket specific protocol to XEMBED draft - Various fixes to work with GTK+-2.0 Still quite a bit of work to do here to handle initiation from the socket side (as specified by XEMBED), to handle the more advanced features of XEMBED, and to figure out a good way to handle same-app embedding with less overhead than using full XEMBED.
-rw-r--r--gtk/Makefile.am1
-rw-r--r--gtk/gtkplug.c813
-rw-r--r--gtk/gtksocket.c486
-rw-r--r--gtk/gtksocket.h3
-rw-r--r--gtk/gtkwindow.c52
-rw-r--r--gtk/gtkwindow.h1
-rw-r--r--gtk/xembed.h19
7 files changed, 939 insertions, 436 deletions
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index cbb5ef42b..509b8ecd5 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -359,6 +359,7 @@ gtk_c_sources = @STRIP_BEGIN@ \
gtkwindow-decorate.c \
fnmatch.c \
fnmatch.h \
+ xembed.h \
@STRIP_END@
# we use our own built_sources variable rules to avoid automake's
diff --git a/gtk/gtkplug.c b/gtk/gtkplug.c
index 420b53a8c..78d9d5128 100644
--- a/gtk/gtkplug.c
+++ b/gtk/gtkplug.c
@@ -25,34 +25,39 @@
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-#include "gdkconfig.h"
-#include "gdkprivate.h"
-
-#if defined (GDK_WINDOWING_X11)
-#include "x11/gdkx.h"
-#elif defined (GDK_WINDOWING_WIN32)
-#include "win32/gdkwin32.h"
-#elif defined (GDK_WINDOWING_NANOX)
-#include "nanox/gdkprivate-nanox.h"
-#elif defined (GDK_WINDOWING_FB)
-#include "linux-fb/gdkfb.h"
-#endif
-
-#include "gdk/gdkkeysyms.h"
+#include "gtkmain.h"
#include "gtkplug.h"
-static void gtk_plug_class_init (GtkPlugClass *klass);
-static void gtk_plug_init (GtkPlug *plug);
+#include "gdk/gdkkeysyms.h"
+#include "x11/gdkx.h"
-static void gtk_plug_realize (GtkWidget *widget);
-static void gtk_plug_unrealize (GtkWidget *widget);
-static gint gtk_plug_key_press_event (GtkWidget *widget,
- GdkEventKey *event);
-static void gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event);
-static gint gtk_plug_focus_in_event (GtkWidget *widget, GdkEventFocus *event);
-static gint gtk_plug_focus_out_event (GtkWidget *widget, GdkEventFocus *event);
-static void gtk_plug_set_focus (GtkWindow *window,
- GtkWidget *focus);
+#include "xembed.h"
+
+static void gtk_plug_class_init (GtkPlugClass *klass);
+static void gtk_plug_init (GtkPlug *plug);
+static void gtk_plug_realize (GtkWidget *widget);
+static void gtk_plug_unrealize (GtkWidget *widget);
+static gboolean gtk_plug_key_press_event (GtkWidget *widget,
+ GdkEventKey *event);
+static void gtk_plug_forward_key_press (GtkPlug *plug,
+ GdkEventKey *event);
+static void gtk_plug_set_focus (GtkWindow *window,
+ GtkWidget *focus);
+static gboolean gtk_plug_focus (GtkContainer *container,
+ GtkDirectionType direction);
+static void gtk_plug_accel_entries_changed (GtkWindow *window);
+static GdkFilterReturn gtk_plug_filter_func (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+
+static void gtk_plug_free_grabbed_keys (GHashTable *key_table);
+static void handle_modality_off (GtkPlug *plug);
+static void send_xembed_message (GtkPlug *plug,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time);
/* From Tk */
#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
@@ -88,21 +93,22 @@ gtk_plug_get_type ()
static void
gtk_plug_class_init (GtkPlugClass *class)
{
- GtkWidgetClass *widget_class;
- GtkWindowClass *window_class;
-
- widget_class = (GtkWidgetClass *)class;
- window_class = (GtkWindowClass *)class;
+ GtkWidgetClass *widget_class = (GtkWidgetClass *)class;
+ GtkContainerClass *container_class = (GtkContainerClass *)class;
+ GtkWindowClass *window_class = (GtkWindowClass *)class;
parent_class = gtk_type_class (GTK_TYPE_WINDOW);
widget_class->realize = gtk_plug_realize;
widget_class->unrealize = gtk_plug_unrealize;
widget_class->key_press_event = gtk_plug_key_press_event;
- widget_class->focus_in_event = gtk_plug_focus_in_event;
- widget_class->focus_out_event = gtk_plug_focus_out_event;
+
+ container_class->focus = gtk_plug_focus;
window_class->set_focus = gtk_plug_set_focus;
+#if 0
+ window_class->accel_entries_changed = gtk_plug_accel_entries_changed;
+#endif
}
static void
@@ -114,18 +120,25 @@ gtk_plug_init (GtkPlug *plug)
window->type = GTK_WINDOW_TOPLEVEL;
window->auto_shrink = TRUE;
+
+#if 0
+ gtk_window_set_grab_group (window, window);
+#endif
}
void
gtk_plug_construct (GtkPlug *plug, GdkNativeWindow socket_id)
{
- plug->socket_window = gdk_window_lookup (socket_id);
- plug->same_app = TRUE;
-
- if (plug->socket_window == NULL)
+ if (socket_id)
{
- plug->socket_window = gdk_window_foreign_new (socket_id);
- plug->same_app = FALSE;
+ plug->socket_window = gdk_window_lookup (socket_id);
+ plug->same_app = TRUE;
+
+ if (plug->socket_window == NULL)
+ {
+ plug->socket_window = gdk_window_foreign_new (socket_id);
+ plug->same_app = FALSE;
+ }
}
}
@@ -156,6 +169,11 @@ gtk_plug_unrealize (GtkWidget *widget)
plug->socket_window = NULL;
}
+#if 0
+ if (plug->modality_window)
+ handle_modality_off (plug);
+#endif
+
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
@@ -212,132 +230,31 @@ gtk_plug_realize (GtkWidget *widget)
widget->window = gdk_window_new (NULL, &attributes, attributes_mask);
}
- GDK_WINDOW_TYPE (window) = GDK_WINDOW_TOPLEVEL;
+ GDK_WINDOW_TYPE (widget->window) = GDK_WINDOW_TOPLEVEL;
gdk_window_set_user_data (widget->window, window);
widget->style = gtk_style_attach (widget->style, widget->window);
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
+
+ gdk_window_add_filter (widget->window, gtk_plug_filter_func, widget);
}
-static gint
+static gboolean
gtk_plug_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
- GtkWindow *window;
- GtkPlug *plug;
- GtkDirectionType direction = 0;
- gint return_val;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- window = GTK_WINDOW (widget);
- plug = GTK_PLUG (widget);
-
- if (!GTK_WIDGET_HAS_FOCUS(widget))
+ if (!GTK_WINDOW (widget)->has_focus)
{
- gtk_plug_forward_key_press (plug, event);
+ gtk_plug_forward_key_press (GTK_PLUG (widget), event);
return TRUE;
}
-
- return_val = FALSE;
- if (window->focus_widget)
- return_val = gtk_widget_event (window->focus_widget, (GdkEvent*) event);
-
-#if 0
- if (!return_val && gtk_window_check_accelerator (window, event->keyval, event->state))
- return_val = TRUE;
-#endif
-
- if (!return_val)
- {
- switch (event->keyval)
- {
- case GDK_space:
- if (window->focus_widget)
- {
- gtk_widget_activate (window->focus_widget);
- return_val = TRUE;
- }
- break;
- case GDK_Return:
- case GDK_KP_Enter:
- if (window->default_widget &&
- (!window->focus_widget ||
- !GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget)))
- {
- gtk_widget_activate (window->default_widget);
- return_val = TRUE;
- }
- else if (window->focus_widget)
- {
- gtk_widget_activate (window->focus_widget);
- return_val = TRUE;
- }
- break;
- case GDK_Up:
- case GDK_Down:
- case GDK_Left:
- case GDK_Right:
- case GDK_Tab:
- switch (event->keyval)
- {
- case GDK_Up:
- direction = GTK_DIR_UP;
- break;
- case GDK_Down:
- direction = GTK_DIR_DOWN;
- break;
- case GDK_Left:
- direction = GTK_DIR_LEFT;
- break;
- case GDK_Right:
- direction = GTK_DIR_RIGHT;
- break;
- case GDK_Tab:
- if (event->state & GDK_SHIFT_MASK)
- direction = GTK_DIR_TAB_BACKWARD;
- else
- direction = GTK_DIR_TAB_FORWARD;
- break;
- default :
- direction = GTK_DIR_UP; /* never reached, but makes compiler happy */
- }
-
- gtk_container_focus (GTK_CONTAINER (widget), direction);
-
- if (!GTK_CONTAINER (window)->focus_child)
- {
- gtk_window_set_focus (GTK_WINDOW (widget), NULL);
-
- gdk_error_trap_push ();
-#ifdef GDK_WINDOWING_X11
- XSetInputFocus (GDK_DISPLAY (),
- GDK_WINDOW_XWINDOW (plug->socket_window),
- RevertToParent, event->time);
-#elif defined (GDK_WINDOWING_WIN32)
- SetFocus (GDK_WINDOW_HWND (plug->socket_window));
-#endif
- gdk_flush ();
- gdk_error_trap_pop ();
-
- gtk_plug_forward_key_press (plug, event);
- }
-
- return_val = TRUE;
-
- break;
- }
- }
-
- return return_val;
+ else
+ return GTK_WIDGET_CLASS (parent_class)->key_press_event (widget, event);
}
static void
gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
{
-#ifdef GDK_WINDOWING_X11
XEvent xevent;
xevent.xkey.type = KeyPress;
@@ -362,261 +279,280 @@ gtk_plug_forward_key_press (GtkPlug *plug, GdkEventKey *event)
False, NoEventMask, &xevent);
gdk_flush ();
gdk_error_trap_pop ();
-#elif defined (GDK_WINDOWING_WIN32)
- /* This is pretty bogus, and not tested at all. */
- WPARAM wParam;
- LPARAM lParam;
- gboolean no_WM_CHAR = TRUE;
-
- lParam = 0;
- switch (event->keyval)
- {
- case GDK_Cancel:
- wParam = VK_CANCEL; break;
- case GDK_BackSpace:
- wParam = VK_BACK; break;
- case GDK_Tab:
- wParam = VK_TAB; break;
- case GDK_Clear:
- wParam = VK_CLEAR; break;
- case GDK_Return:
- wParam = VK_RETURN; break;
- case GDK_Shift_L:
- wParam = VK_SHIFT; break;
- case GDK_Control_L:
- wParam = VK_CONTROL; break;
- case GDK_Control_R:
- wParam = VK_CONTROL; lParam |= 0x01000000; break;
- case GDK_Alt_L:
- wParam = VK_MENU; break;
- case GDK_Alt_R:
- wParam = VK_MENU; lParam |= 0x01000000; break;
- case GDK_Pause:
- wParam = VK_PAUSE; break;
- case GDK_Caps_Lock:
- wParam = VK_CAPITAL; break;
- case GDK_Escape:
- wParam = VK_ESCAPE; break;
- case GDK_Prior:
- wParam = VK_PRIOR; break;
- case GDK_Next:
- wParam = VK_NEXT; break;
- case GDK_End:
- wParam = VK_END; break;
- case GDK_Home:
- wParam = VK_HOME; break;
- case GDK_Left:
- wParam = VK_LEFT; break;
- case GDK_Up:
- wParam = VK_UP; break;
- case GDK_Right:
- wParam = VK_RIGHT; break;
- case GDK_Down:
- wParam = VK_DOWN; break;
- case GDK_Select:
- wParam = VK_SELECT; break;
- case GDK_Print:
- wParam = VK_PRINT; break;
- case GDK_Execute:
- wParam = VK_EXECUTE; break;
- case GDK_Insert:
- wParam = VK_INSERT; break;
- case GDK_Delete:
- wParam = VK_DELETE; break;
- case GDK_Help:
- wParam = VK_HELP; break;
- case GDK_KP_0:
- wParam = VK_NUMPAD0; break;
- case GDK_KP_1:
- wParam = VK_NUMPAD1; break;
- case GDK_KP_2:
- wParam = VK_NUMPAD2; break;
- case GDK_KP_3:
- wParam = VK_NUMPAD3; break;
- case GDK_KP_4:
- wParam = VK_NUMPAD4; break;
- case GDK_KP_5:
- wParam = VK_NUMPAD5; break;
- case GDK_KP_6:
- wParam = VK_NUMPAD6; break;
- case GDK_KP_7:
- wParam = VK_NUMPAD7; break;
- case GDK_KP_8:
- wParam = VK_NUMPAD8; break;
- case GDK_KP_9:
- wParam = VK_NUMPAD9; break;
- case GDK_KP_Multiply:
- wParam = VK_MULTIPLY; break;
- case GDK_KP_Add:
- wParam = VK_ADD; break;
- case GDK_KP_Separator:
- wParam = VK_SEPARATOR; break;
- case GDK_KP_Subtract:
- wParam = VK_SUBTRACT; break;
- case GDK_KP_Decimal:
- wParam = VK_DECIMAL; break;
- case GDK_KP_Divide:
- wParam = VK_DIVIDE; break;
- case GDK_F1:
- wParam = VK_F1; break;
- case GDK_F2:
- wParam = VK_F2; break;
- case GDK_F3:
- wParam = VK_F3; break;
- case GDK_F4:
- wParam = VK_F4; break;
- case GDK_F5:
- wParam = VK_F5; break;
- case GDK_F6:
- wParam = VK_F6; break;
- case GDK_F7:
- wParam = VK_F7; break;
- case GDK_F8:
- wParam = VK_F8; break;
- case GDK_F9:
- wParam = VK_F9; break;
- case GDK_F10:
- wParam = VK_F10; break;
- case GDK_F11:
- wParam = VK_F11; break;
- case GDK_F12:
- wParam = VK_F12; break;
- case GDK_F13:
- wParam = VK_F13; break;
- case GDK_F14:
- wParam = VK_F14; break;
- case GDK_F15:
- wParam = VK_F15; break;
- case GDK_F16:
- wParam = VK_F16; break;
- default:
- wParam = event->keyval;
- no_WM_CHAR = FALSE;
- break;
- }
-
- PostMessage (GDK_WINDOW_HWND (plug->socket_window),
- WM_KEYDOWN, wParam, lParam);
- if (!no_WM_CHAR)
- PostMessage (GDK_WINDOW_HWND (plug->socket_window),
- WM_CHAR, wParam, lParam);
- PostMessage (GDK_WINDOW_HWND (plug->socket_window),
- WM_KEYUP, wParam, lParam);
-#endif
}
-/* Copied from Window, Ughh */
-
-static gint
-gtk_plug_focus_in_event (GtkWidget *widget,
- GdkEventFocus *event)
+static void
+gtk_plug_set_focus (GtkWindow *window,
+ GtkWidget *focus)
{
- GtkWindow *window;
- GdkEventFocus fevent;
-
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
+ GtkPlug *plug = GTK_PLUG (window);
- /* It appears spurious focus in events can occur when
- * the window is hidden. So we'll just check to see if
- * the window is visible before actually handling the
- * event
+ GTK_WINDOW_CLASS (parent_class)->set_focus (window, focus);
+
+ /* Ask for focus from embedder
*/
- if (GTK_WIDGET_VISIBLE (widget))
+
+ if (focus && !window->has_focus)
{
- GTK_OBJECT_SET_FLAGS (widget, GTK_HAS_FOCUS);
- window = GTK_WINDOW (widget);
- if (window->focus_widget && !GTK_WIDGET_HAS_FOCUS (window->focus_widget))
- {
- fevent.type = GDK_FOCUS_CHANGE;
- fevent.window = window->focus_widget->window;
- fevent.in = TRUE;
+#if 0
+ XEvent xevent;
- gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
- }
- }
+ xevent.xfocus.type = FocusIn;
+ xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
+ xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
+ xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
+ xevent.xfocus.detail = FALSE; /* Don't force */
- return FALSE;
+ gdk_error_trap_push ();
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (plug->socket_window),
+ False, NoEventMask, &xevent);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+#endif
+
+ send_xembed_message (plug, XEMBED_REQUEST_FOCUS, 0, 0, 0,
+ gtk_get_current_event_time ());
+ }
}
-static gint
-gtk_plug_focus_out_event (GtkWidget *widget,
- GdkEventFocus *event)
+#if 0
+
+typedef struct
{
- GtkWindow *window;
- GdkEventFocus fevent;
+ guint accelerator_key;
+ GdkModifierType accelerator_mods;
+} GrabbedKey;
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_PLUG (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
+static guint
+grabbed_key_hash (gconstpointer a)
+{
+ const GrabbedKey *key = a;
+ guint h;
+
+ h = key->accelerator_key << 16;
+ h ^= key->accelerator_key >> 16;
+ h ^= key->accelerator_mods;
- GTK_OBJECT_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+ return h;
+}
- window = GTK_WINDOW (widget);
+static gboolean
+grabbed_key_equal (gconstpointer a, gconstpointer b)
+{
+ const GrabbedKey *keya = a;
+ const GrabbedKey *keyb = b;
- if (window->focus_widget && GTK_WIDGET_HAS_FOCUS (window->focus_widget))
- {
- fevent.type = GDK_FOCUS_CHANGE;
- fevent.window = window->focus_widget->window;
- fevent.in = FALSE;
+ return (keya->accelerator_key == keyb->accelerator_key &&
+ keya->accelerator_mods == keyb->accelerator_mods);
+}
- gtk_widget_event (window->focus_widget, (GdkEvent*) &fevent);
+static void
+add_grabbed_keys (gpointer key, gpointer val, gpointer data)
+{
+ GrabbedKey *grabbed_key = key;
+ GtkPlug *plug = data;
+
+ if (!plug->grabbed_keys ||
+ !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
+ {
+ send_xembed_message (plug, XEMBED_GRAB_KEY, 0,
+ grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
+ gtk_get_current_event_time ());
}
+}
- return FALSE;
+static void
+remove_grabbed_keys (gpointer key, gpointer val, gpointer data)
+{
+ GrabbedKey *grabbed_key = key;
+ GtkPlug *plug = data;
+
+ if (!plug->grabbed_keys ||
+ !g_hash_table_lookup (plug->grabbed_keys, grabbed_key))
+ {
+ send_xembed_message (plug, XEMBED_UNGRAB_KEY, 0,
+ grabbed_key->accelerator_key, grabbed_key->accelerator_mods,
+ gtk_get_current_event_time ());
+ }
}
static void
-gtk_plug_set_focus (GtkWindow *window,
- GtkWidget *focus)
+gtk_plug_free_grabbed_keys (GHashTable *key_table)
{
- GtkPlug *plug;
- GdkEventFocus event;
+ g_hash_table_foreach (key_table, (GHFunc)g_free, NULL);
+ g_hash_table_destroy (key_table);
+}
- g_return_if_fail (window != NULL);
- g_return_if_fail (GTK_IS_PLUG (window));
+static void
+gtk_plug_accel_entries_changed (GtkWindow *window)
+{
+ GHashTable *new_grabbed_keys, *old_grabbed_keys;
+ GSList *accel_groups, *tmp_list;
+ GtkPlug *plug = GTK_PLUG (window);
- plug = GTK_PLUG (window);
+ new_grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
- if (focus && !GTK_WIDGET_CAN_FOCUS (focus))
- return;
+ accel_groups = gtk_accel_groups_from_object (GTK_OBJECT (window));
+
+ tmp_list = accel_groups;
- if (window->focus_widget != focus)
+ while (tmp_list)
{
- if (window->focus_widget)
- {
- event.type = GDK_FOCUS_CHANGE;
- event.window = window->focus_widget->window;
- event.in = FALSE;
+ GtkAccelGroup *accel_group = tmp_list->data;
+ gint i, n_entries;
+ GtkAccelEntry *entries;
+
+ gtk_accel_group_get_entries (accel_group, &entries, &n_entries);
- gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ for (i = 0; i < n_entries; i++)
+ {
+ GdkKeymapKey *keys;
+ gint n_keys;
+
+ if (gdk_keymap_get_entries_for_keyval (NULL, entries[i].accelerator_key, &keys, &n_keys))
+ {
+ GrabbedKey *key = g_new (GrabbedKey, 1);
+
+ key->accelerator_key = keys[0].keycode;
+ key->accelerator_mods = entries[i].accelerator_mods;
+
+ g_hash_table_insert (new_grabbed_keys, key, key);
+
+ g_free (keys);
+ }
}
+
+ tmp_list = tmp_list->next;
+ }
+
+ g_hash_table_foreach (new_grabbed_keys, add_grabbed_keys, plug);
- window->focus_widget = focus;
+ old_grabbed_keys = plug->grabbed_keys;
+ plug->grabbed_keys = new_grabbed_keys;
+
+ if (old_grabbed_keys)
+ {
+ g_hash_table_foreach (old_grabbed_keys, remove_grabbed_keys, plug);
+ gtk_plug_free_grabbed_keys (old_grabbed_keys);
+ }
+
+}
+#endif
+
+static gboolean
+gtk_plug_focus (GtkContainer *container,
+ GtkDirectionType direction)
+{
+ GtkBin *bin = GTK_BIN (container);
+ GtkPlug *plug = GTK_PLUG (container);
+ GtkWindow *window = GTK_WINDOW (container);
+ GtkWidget *old_focus_child = container->focus_child;
+ GtkWidget *parent;
+
+ /* We override GtkWindow's behavior, since we don't want wrapping here.
+ */
+ if (old_focus_child)
+ {
+ if (GTK_IS_CONTAINER (old_focus_child) &&
+ GTK_WIDGET_DRAWABLE (old_focus_child) &&
+ GTK_WIDGET_IS_SENSITIVE (old_focus_child) &&
+ gtk_container_focus (GTK_CONTAINER (old_focus_child), direction))
+ return TRUE;
if (window->focus_widget)
{
- event.type = GDK_FOCUS_CHANGE;
- event.window = window->focus_widget->window;
- event.in = TRUE;
+ /* Wrapped off the end, clear the focus setting for the toplevel */
+ parent = window->focus_widget->parent;
+ while (parent)
+ {
+ gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
+ parent = GTK_WIDGET (parent)->parent;
+ }
+
+ gtk_window_set_focus (GTK_WINDOW (container), NULL);
- gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ if (!GTK_CONTAINER (window)->focus_child)
+ {
+ gint message = -1;
+
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ case GTK_DIR_LEFT:
+ case GTK_DIR_TAB_BACKWARD:
+ message = XEMBED_FOCUS_PREV;
+ break;
+ case GTK_DIR_DOWN:
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_TAB_FORWARD:
+ message = XEMBED_FOCUS_NEXT;
+ break;
+ }
+
+ send_xembed_message (plug, message, 0, 0, 0,
+ gtk_get_current_event_time ());
+
+#if 0
+ gtk_window_set_focus (GTK_WINDOW (widget), NULL);
+
+ gdk_error_trap_push ();
+ XSetInputFocus (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (plug->socket_window),
+ RevertToParent, event->time);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+
+ gtk_plug_forward_key_press (plug, event);
+#endif
+ }
+ }
+
+ return FALSE;
+ }
+ else
+ {
+ /* Try to focus the first widget in the window */
+ if (GTK_WIDGET_DRAWABLE (bin->child) &&
+ GTK_WIDGET_IS_SENSITIVE (bin->child))
+ {
+ if (GTK_IS_CONTAINER (bin->child))
+ {
+ if (gtk_container_focus (GTK_CONTAINER (bin->child), direction))
+ return TRUE;
+ }
+ else if (GTK_WIDGET_CAN_FOCUS (bin->child))
+ {
+ gtk_widget_grab_focus (bin->child);
+ return TRUE;
+ }
}
}
- /* Ask for focus from parent */
+ return FALSE;
+}
- if (focus && !GTK_WIDGET_HAS_FOCUS(window))
+static void
+send_xembed_message (GtkPlug *plug,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time)
+{
+ if (plug->socket_window)
{
-#ifdef GDK_WINDOWING_X11
XEvent xevent;
- xevent.xfocus.type = FocusIn;
- xevent.xfocus.display = GDK_WINDOW_XDISPLAY (GTK_WIDGET(plug)->window);
- xevent.xfocus.window = GDK_WINDOW_XWINDOW (plug->socket_window);
- xevent.xfocus.mode = EMBEDDED_APP_WANTS_FOCUS;
- xevent.xfocus.detail = FALSE; /* Don't force */
+ xevent.xclient.window = GDK_WINDOW_XWINDOW (plug->socket_window);
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.message_type = gdk_atom_intern ("_XEMBED", FALSE);
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = time;
+ xevent.xclient.data.l[1] = message;
+ xevent.xclient.data.l[2] = detail;
+ xevent.xclient.data.l[3] = data1;
+ xevent.xclient.data.l[4] = data2;
gdk_error_trap_push ();
XSendEvent (gdk_display,
@@ -624,8 +560,157 @@ gtk_plug_set_focus (GtkWindow *window,
False, NoEventMask, &xevent);
gdk_flush ();
gdk_error_trap_pop ();
-#elif defined (GDK_WINDOWING_WIN32)
- /* XXX Not implemented */
-#endif
}
}
+
+static void
+focus_first_last (GtkPlug *plug,
+ GtkDirectionType direction)
+{
+ GtkWindow *window = GTK_WINDOW (plug);
+ GtkWidget *parent;
+
+ if (window->focus_widget)
+ {
+ parent = window->focus_widget->parent;
+ while (parent)
+ {
+ gtk_container_set_focus_child (GTK_CONTAINER (parent), NULL);
+ parent = GTK_WIDGET (parent)->parent;
+ }
+
+ gtk_window_set_focus (GTK_WINDOW (plug), NULL);
+ }
+
+ gtk_container_focus (GTK_CONTAINER (plug), direction);
+}
+
+static void
+handle_modality_on (GtkPlug *plug)
+{
+#if 0
+ if (!plug->modality_window)
+ {
+ plug->modality_window = gtk_window_new (GTK_WINDOW_POPUP);
+ gtk_window_set_grab_group (GTK_WINDOW (plug->modality_window), GTK_WINDOW (plug));
+ gtk_grab_add (plug->modality_window);
+ }
+#endif
+}
+
+static void
+handle_modality_off (GtkPlug *plug)
+{
+#if 0
+ if (plug->modality_window)
+ {
+ gtk_grab_remove (plug->modality_window);
+ gtk_widget_destroy (plug->modality_window);
+ plug->modality_window = NULL;
+ }
+#endif
+}
+
+static void
+handle_xembed_message (GtkPlug *plug,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time)
+{
+ GTK_NOTE (PLUGSOCKET,
+ g_message ("Message of type %ld received", message));
+
+ switch (message)
+ {
+ case XEMBED_EMBEDDED_NOTIFY:
+ break;
+ case XEMBED_WINDOW_ACTIVATE:
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkPlug: ACTIVATE received"));
+ break;
+ case XEMBED_WINDOW_DEACTIVATE:
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkPlug: DEACTIVATE received"));
+ break;
+
+ case XEMBED_MODALITY_ON:
+ handle_modality_on (plug);
+ break;
+ case XEMBED_MODALITY_OFF:
+ handle_modality_off (plug);
+ break;
+
+ case XEMBED_FOCUS_IN:
+ switch (detail)
+ {
+ case XEMBED_FOCUS_FIRST:
+ focus_first_last (plug, GTK_DIR_TAB_FORWARD);
+ break;
+ case XEMBED_FOCUS_LAST:
+ focus_first_last (plug, GTK_DIR_TAB_BACKWARD);
+ break;
+ case XEMBED_FOCUS_CURRENT:
+ /* fall through */;
+ }
+
+ case XEMBED_FOCUS_OUT:
+ {
+ GdkEvent event;
+
+ event.focus_change.type = GDK_FOCUS_CHANGE;
+ event.focus_change.window = GTK_WIDGET (plug)->window;
+ event.focus_change.send_event = TRUE;
+ event.focus_change.in = (message == XEMBED_FOCUS_IN);
+
+ gtk_widget_event (GTK_WIDGET (plug), &event);
+
+ break;
+ }
+
+ case XEMBED_REQUEST_FOCUS:
+ case XEMBED_FOCUS_NEXT:
+ case XEMBED_FOCUS_PREV:
+ case XEMBED_GRAB_KEY:
+ case XEMBED_UNGRAB_KEY:
+ g_warning ("GtkPlug: Invalid _XEMBED message of type %ld received", message);
+ break;
+
+ default:
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkPlug: Ignoring unknown _XEMBED message of type %ld", message));
+ break;
+ }
+}
+
+static GdkFilterReturn
+gtk_plug_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
+{
+ GtkPlug *plug = GTK_PLUG (data);
+ XEvent *xevent = (XEvent *)gdk_xevent;
+
+ GdkFilterReturn return_val;
+
+ return_val = GDK_FILTER_CONTINUE;
+
+ switch (xevent->type)
+ {
+ case ClientMessage:
+ if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
+ {
+ handle_xembed_message (plug,
+ xevent->xclient.data.l[1],
+ xevent->xclient.data.l[2],
+ xevent->xclient.data.l[3],
+ xevent->xclient.data.l[4],
+ xevent->xclient.data.l[0]);
+
+
+ return GDK_FILTER_REMOVE;
+ }
+ break;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
diff --git a/gtk/gtksocket.c b/gtk/gtksocket.c
index 648cedc48..1f905b796 100644
--- a/gtk/gtksocket.c
+++ b/gtk/gtksocket.c
@@ -36,34 +36,49 @@
#endif
#include "gdk/gdkkeysyms.h"
+#include "gtkmain.h"
#include "gtkwindow.h"
#include "gtksignal.h"
#include "gtksocket.h"
#include "gtkdnd.h"
+#include "xembed.h"
+
#ifdef GDK_WINDOWING_X11
/* Forward declararations */
-static void gtk_socket_class_init (GtkSocketClass *klass);
-static void gtk_socket_init (GtkSocket *socket);
-static void gtk_socket_realize (GtkWidget *widget);
-static void gtk_socket_unrealize (GtkWidget *widget);
-static void gtk_socket_size_request (GtkWidget *widget,
- GtkRequisition *requisition);
-static void gtk_socket_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
-static gint gtk_socket_focus_in_event (GtkWidget *widget,
- GdkEventFocus *event);
-static void gtk_socket_claim_focus (GtkSocket *socket);
-static gint gtk_socket_focus_out_event (GtkWidget *widget,
- GdkEventFocus *event);
-static void gtk_socket_send_configure_event (GtkSocket *socket);
-static gint gtk_socket_focus (GtkContainer *container,
- GtkDirectionType direction);
-static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
- GdkEvent *event,
- gpointer data);
+static void gtk_socket_class_init (GtkSocketClass *klass);
+static void gtk_socket_init (GtkSocket *socket);
+static void gtk_socket_realize (GtkWidget *widget);
+static void gtk_socket_unrealize (GtkWidget *widget);
+static void gtk_socket_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void gtk_socket_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void gtk_socket_hierarchy_changed (GtkWidget *widget);
+static void gtk_socket_grab_notify (GtkWidget *widget,
+ gboolean was_grabbed);
+static gboolean gtk_socket_key_press_event (GtkWidget *widget,
+ GdkEventKey *event);
+static gboolean gtk_socket_focus_in_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_claim_focus (GtkSocket *socket);
+static gboolean gtk_socket_focus_out_event (GtkWidget *widget,
+ GdkEventFocus *event);
+static void gtk_socket_send_configure_event (GtkSocket *socket);
+static gboolean gtk_socket_focus (GtkContainer *container,
+ GtkDirectionType direction);
+static GdkFilterReturn gtk_socket_filter_func (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer data);
+
+static void send_xembed_message (GtkSocket *socket,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time);
/* From Tk */
#define EMBEDDED_APP_WANTS_FOCUS NotifyNormal+20
@@ -101,11 +116,9 @@ gtk_socket_get_type (void)
static void
gtk_socket_class_init (GtkSocketClass *class)
{
- GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkContainerClass *container_class;
- object_class = (GtkObjectClass*) class;
widget_class = (GtkWidgetClass*) class;
container_class = (GtkContainerClass*) class;
@@ -115,6 +128,11 @@ gtk_socket_class_init (GtkSocketClass *class)
widget_class->unrealize = gtk_socket_unrealize;
widget_class->size_request = gtk_socket_size_request;
widget_class->size_allocate = gtk_socket_size_allocate;
+ widget_class->hierarchy_changed = gtk_socket_hierarchy_changed;
+#if 0
+ widget_class->grab_notify = gtk_socket_grab_notify;
+#endif
+ widget_class->key_press_event = gtk_socket_key_press_event;
widget_class->focus_in_event = gtk_socket_focus_in_event;
widget_class->focus_out_event = gtk_socket_focus_out_event;
@@ -141,7 +159,7 @@ gtk_socket_new (void)
{
GtkSocket *socket;
- socket = gtk_type_new (GTK_TYPE_SOCKET);
+ socket = g_object_new (GTK_TYPE_SOCKET, NULL);
return GTK_WIDGET (socket);
}
@@ -271,8 +289,19 @@ gtk_socket_unrealize (GtkWidget *widget)
if (toplevel && GTK_IS_WINDOW (toplevel))
gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel),
GDK_WINDOW_XWINDOW (socket->plug_window));
+
+ socket->plug_window = NULL;
}
+#if 0
+ if (socket->grabbed_keys)
+ {
+ g_hash_table_foreach (socket->grabbed_keys, (GHFunc)g_free, NULL);
+ g_hash_table_destroy (socket->grabbed_keys);
+ socket->grabbed_keys = NULL;
+ }
+#endif
+
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
@@ -383,35 +412,256 @@ gtk_socket_size_allocate (GtkWidget *widget,
}
}
-static gint
-gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
+#if 0
+
+typedef struct
{
- GtkSocket *socket;
- g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
- socket = GTK_SOCKET (widget);
+ guint accelerator_key;
+ GdkModifierType accelerator_mods;
+} GrabbedKey;
+
+static guint
+grabbed_key_hash (gconstpointer a)
+{
+ const GrabbedKey *key = a;
+ guint h;
+
+ h = key->accelerator_key << 16;
+ h ^= key->accelerator_key >> 16;
+ h ^= key->accelerator_mods;
- if (socket->focus_in && socket->plug_window)
+ return h;
+}
+
+static gboolean
+grabbed_key_equal (gconstpointer a, gconstpointer b)
+{
+ const GrabbedKey *keya = a;
+ const GrabbedKey *keyb = b;
+
+ return (keya->accelerator_key == keyb->accelerator_key &&
+ keya->accelerator_mods == keyb->accelerator_mods);
+}
+
+static void
+add_grabbed_key (GtkSocket *socket,
+ guint hardware_keycode,
+ GdkModifierType mods)
+{
+ GrabbedKey key;
+ GrabbedKey *new_key;
+ GrabbedKey *found_key;
+
+ if (socket->grabbed_keys)
{
+ key.accelerator_key = hardware_keycode;
+ key.accelerator_mods = mods;
+
+ found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
+
+ if (found_key)
+ {
+ g_warning ("GtkSocket: request to add already present grabbed key %u,%#x\n",
+ hardware_keycode, mods);
+ return;
+ }
+ }
+
+ if (!socket->grabbed_keys)
+ socket->grabbed_keys = g_hash_table_new (grabbed_key_hash, grabbed_key_equal);
+
+ new_key = g_new (GrabbedKey, 1);
+
+ new_key->accelerator_key = hardware_keycode;
+ new_key->accelerator_mods = mods;
+
+ g_hash_table_insert (socket->grabbed_keys, new_key, new_key);
+}
+
+static void
+remove_grabbed_key (GtkSocket *socket,
+ guint hardware_keycode,
+ GdkModifierType mods)
+{
+ GrabbedKey key;
+ GrabbedKey *found_key = NULL;
+
+ if (socket->grabbed_keys)
+ {
+ key.accelerator_key = hardware_keycode;
+ key.accelerator_mods = mods;
+
+ found_key = g_hash_table_lookup (socket->grabbed_keys, &key);
+ }
+
+ if (found_key)
+ {
+ g_hash_table_remove (socket->grabbed_keys, &key);
+ g_free (found_key);
+ }
+ else
+ g_warning ("GtkSocket: request to remove non-present grabbed key %u,%#x\n",
+ hardware_keycode, mods);
+}
+
+static gboolean
+toplevel_key_press_handler (GtkWidget *toplevel,
+ GdkEventKey *event,
+ GtkSocket *socket)
+{
+ GrabbedKey search_key;
+
+ search_key.accelerator_key = event->hardware_keycode;
+ search_key.accelerator_mods = event->state;
+
+ if (socket->grabbed_keys &&
+ g_hash_table_lookup (socket->grabbed_keys, &search_key))
+ {
+ gtk_socket_key_press_event (GTK_WIDGET (socket), event);
+ gtk_signal_emit_stop_by_name (GTK_OBJECT (toplevel), "key_press_event");
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+#endif
+
+static void
+toplevel_focus_in_handler (GtkWidget *toplevel,
+ GdkEventFocus *event,
+ GtkSocket *socket)
+{
+ /* It appears spurious focus in events can occur when
+ * the window is hidden. So we'll just check to see if
+ * the window is visible before actually handling the
+ * event. (Comment from gtkwindow.c)
+ */
+ if (GTK_WIDGET_VISIBLE (toplevel))
+ send_xembed_message (socket, XEMBED_WINDOW_ACTIVATE, 0, 0, 0,
+ gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
+}
+
+static void
+toplevel_focus_out_handler (GtkWidget *toplevel,
+ GdkEventFocus *event,
+ GtkSocket *socket)
+{
+ send_xembed_message (socket, XEMBED_WINDOW_DEACTIVATE, 0, 0, 0,
+ gtk_get_current_event_time ()); /* Will be GDK_CURRENT_TIME */
+}
+
+static void
+gtk_socket_hierarchy_changed (GtkWidget *widget)
+{
+ GtkSocket *socket = GTK_SOCKET (widget);
+ GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
+
+ if (toplevel && !GTK_IS_WINDOW (toplevel))
+ toplevel = NULL;
+
+ if (toplevel != socket->toplevel)
+ {
+ if (socket->toplevel)
+ {
+#if 0
+ gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
+#endif
+ gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
+ gtk_signal_disconnect_by_func (GTK_OBJECT (socket->toplevel), GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
+ }
+
+ socket->toplevel = toplevel;
+
+ if (toplevel)
+ {
+#if 0
+ gtk_signal_connect (GTK_OBJECT (socket->toplevel), "key_press_event",
+ GTK_SIGNAL_FUNC (toplevel_key_press_handler), socket);
+#endif
+ gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_in_event",
+ GTK_SIGNAL_FUNC (toplevel_focus_in_handler), socket);
+ gtk_signal_connect (GTK_OBJECT (socket->toplevel), "focus_out_event",
+ GTK_SIGNAL_FUNC (toplevel_focus_out_handler), socket);
+ }
+ }
+}
+
+static void
+gtk_socket_grab_notify (GtkWidget *widget,
+ gboolean was_grabbed)
+{
+ send_xembed_message (GTK_SOCKET (widget),
+ was_grabbed ? XEMBED_MODALITY_OFF : XEMBED_MODALITY_ON,
+ 0, 0, 0, gtk_get_current_event_time ());
+}
+
+static gboolean
+gtk_socket_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkSocket *socket = GTK_SOCKET (widget);
+
+ if (socket->plug_window)
+ {
+ XEvent xevent;
+
+ xevent.xkey.type = KeyPress;
+ xevent.xkey.display = GDK_WINDOW_XDISPLAY (event->window);
+ xevent.xkey.window = GDK_WINDOW_XWINDOW (socket->plug_window);
+ xevent.xkey.root = GDK_ROOT_WINDOW ();
+ xevent.xkey.time = event->time;
+ /* FIXME, the following might cause problems for non-GTK apps */
+ xevent.xkey.x = 0;
+ xevent.xkey.y = 0;
+ xevent.xkey.x_root = 0;
+ xevent.xkey.y_root = 0;
+ xevent.xkey.state = event->state;
+ xevent.xkey.keycode = event->hardware_keycode;
+ xevent.xkey.same_screen = TRUE; /* FIXME ? */
+
gdk_error_trap_push ();
- XSetInputFocus (GDK_DISPLAY (),
- GDK_WINDOW_XWINDOW (socket->plug_window),
- RevertToParent, GDK_CURRENT_TIME);
- gdk_flush();
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ False, NoEventMask, &xevent);
+ gdk_flush ();
gdk_error_trap_pop ();
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+gtk_socket_focus_in_event (GtkWidget *widget, GdkEventFocus *event)
+{
+ GtkSocket *socket = GTK_SOCKET (widget);
+
+ if (!GTK_WIDGET_HAS_FOCUS (widget))
+ {
+ GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_FOCUS);
+
+ if (socket->plug_window)
+ {
+ send_xembed_message (socket, XEMBED_FOCUS_IN, XEMBED_FOCUS_CURRENT, 0, 0,
+ gtk_get_current_event_time ());
+ }
}
return TRUE;
}
-static gint
+static gboolean
gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
{
- GtkWidget *toplevel;
- GtkSocket *socket;
+ GtkSocket *socket = GTK_SOCKET (widget);
- g_return_val_if_fail (GTK_IS_SOCKET (widget), FALSE);
- socket = GTK_SOCKET (widget);
+ GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_FOCUS);
+#if 0
+ GtkWidget *toplevel;
toplevel = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
if (toplevel)
@@ -421,8 +671,16 @@ gtk_socket_focus_out_event (GtkWidget *widget, GdkEventFocus *event)
RevertToParent, CurrentTime); /* FIXME? */
}
- socket->focus_in = FALSE;
+#endif
+
+ if (socket->plug_window)
+ {
+ send_xembed_message (socket, XEMBED_FOCUS_OUT, 0, 0, 0,
+ gtk_get_current_event_time ());
+ }
+ socket->focus_in = FALSE;
+
return TRUE;
}
@@ -442,24 +700,55 @@ gtk_socket_claim_focus (GtkSocket *socket)
* it as an app... (and see _focus_in ()) */
if (socket->plug_window)
{
+#if 0
gdk_error_trap_push ();
XSetInputFocus (GDK_DISPLAY (),
GDK_WINDOW_XWINDOW (socket->plug_window),
RevertToParent, GDK_CURRENT_TIME);
gdk_flush ();
gdk_error_trap_pop ();
+#endif
}
}
-static gint
+static gboolean
gtk_socket_focus (GtkContainer *container, GtkDirectionType direction)
{
GtkSocket *socket;
+ gint detail = -1;
g_return_val_if_fail (GTK_IS_SOCKET (container), FALSE);
socket = GTK_SOCKET (container);
+ if (!GTK_WIDGET_HAS_FOCUS (container))
+ {
+ switch (direction)
+ {
+ case GTK_DIR_UP:
+ case GTK_DIR_LEFT:
+ case GTK_DIR_TAB_BACKWARD:
+ detail = XEMBED_FOCUS_LAST;
+ break;
+ case GTK_DIR_DOWN:
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_TAB_FORWARD:
+ detail = XEMBED_FOCUS_FIRST;
+ break;
+ }
+
+ send_xembed_message (socket, XEMBED_FOCUS_IN, detail, 0, 0,
+ gtk_get_current_event_time ());
+
+ GTK_WIDGET_SET_FLAGS (container, GTK_HAS_FOCUS);
+ gtk_widget_grab_focus (GTK_WIDGET (container));
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+
+#if 0
if (!socket->focus_in && socket->plug_window)
{
XEvent xevent;
@@ -517,6 +806,7 @@ gtk_socket_focus (GtkContainer *container, GtkDirectionType direction)
{
return FALSE;
}
+#endif
}
static void
@@ -587,6 +877,98 @@ gtk_socket_add_window (GtkSocket *socket, GdkNativeWindow xid)
{
gtk_window_add_embedded_xid (GTK_WINDOW (toplevel), xid);
}
+
+ gtk_widget_queue_resize (GTK_WIDGET (socket));
+ }
+}
+
+
+static void
+send_xembed_message (GtkSocket *socket,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time)
+{
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkSocket: Sending XEMBED message of type %d", message));
+
+ if (socket->plug_window)
+ {
+ XEvent xevent;
+
+ xevent.xclient.window = GDK_WINDOW_XWINDOW (socket->plug_window);
+ xevent.xclient.type = ClientMessage;
+ xevent.xclient.message_type = gdk_atom_intern ("_XEMBED", FALSE);
+ xevent.xclient.format = 32;
+ xevent.xclient.data.l[0] = time;
+ xevent.xclient.data.l[1] = message;
+ xevent.xclient.data.l[2] = detail;
+ xevent.xclient.data.l[3] = data1;
+ xevent.xclient.data.l[4] = data2;
+
+ gdk_error_trap_push ();
+ XSendEvent (gdk_display,
+ GDK_WINDOW_XWINDOW (socket->plug_window),
+ False, NoEventMask, &xevent);
+ gdk_flush ();
+ gdk_error_trap_pop ();
+ }
+}
+
+static void
+handle_xembed_message (GtkSocket *socket,
+ glong message,
+ glong detail,
+ glong data1,
+ glong data2,
+ guint32 time)
+{
+ switch (message)
+ {
+ case XEMBED_EMBEDDED_NOTIFY:
+ case XEMBED_WINDOW_ACTIVATE:
+ case XEMBED_WINDOW_DEACTIVATE:
+ case XEMBED_MODALITY_ON:
+ case XEMBED_MODALITY_OFF:
+ case XEMBED_FOCUS_IN:
+ case XEMBED_FOCUS_OUT:
+ g_warning ("GtkSocket: Invalid _XEMBED message of type %ld received", message);
+ break;
+
+ case XEMBED_REQUEST_FOCUS:
+ gtk_socket_claim_focus (socket);
+ break;
+
+ case XEMBED_FOCUS_NEXT:
+ case XEMBED_FOCUS_PREV:
+ {
+ GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
+ if (toplevel && GTK_IS_CONTAINER (toplevel))
+ {
+ gtk_container_focus (GTK_CONTAINER (toplevel),
+ (message == XEMBED_FOCUS_NEXT ?
+ GTK_DIR_TAB_FORWARD : GTK_DIR_TAB_BACKWARD));
+ }
+ break;
+ }
+
+ case XEMBED_GRAB_KEY:
+#if 0
+ add_grabbed_key (socket, data1, data2);
+#endif
+ break;
+ case XEMBED_UNGRAB_KEY:
+#if 0
+ remove_grabbed_key (socket, data1, data2);
+#endif
+ break;
+
+ default:
+ GTK_NOTE(PLUGSOCKET,
+ g_message ("GtkSocket: Ignoring unknown _XEMBED message of type %ld", message));
+ break;
}
}
@@ -631,8 +1013,6 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
g_message ("GtkSocket - window created with size: %d %d",
socket->request_width,
socket->request_height));
-
- gtk_widget_queue_resize (widget);
}
return_val = GDK_FILTER_REMOVE;
@@ -688,6 +1068,7 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (socket));
if (toplevel && GTK_IS_WINDOW (toplevel))
gtk_window_remove_embedded_xid (GTK_WINDOW (toplevel), xdwe->window);
+
gdk_window_destroy_notify (socket->plug_window);
gtk_widget_destroy (widget);
@@ -696,8 +1077,8 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
return_val = GDK_FILTER_REMOVE;
}
break;
- }
-
+ }
+
case FocusIn:
if (xevent->xfocus.mode == EMBEDDED_APP_WANTS_FOCUS)
{
@@ -731,7 +1112,7 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
{
GTK_NOTE(PLUGSOCKET,
g_message ("GtkSocket - Map Request"));
-
+
gdk_error_trap_push ();
gdk_window_show (socket->plug_window);
gdk_flush ();
@@ -759,8 +1140,23 @@ gtk_socket_filter_func (GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data)
}
return_val = GDK_FILTER_REMOVE;
}
+ break;
+ case ClientMessage:
+ if (xevent->xclient.message_type == gdk_atom_intern ("_XEMBED", FALSE))
+ {
+ handle_xembed_message (socket,
+ xevent->xclient.data.l[1],
+ xevent->xclient.data.l[2],
+ xevent->xclient.data.l[3],
+ xevent->xclient.data.l[4],
+ xevent->xclient.data.l[0]);
+
+
+ return_val = GDK_FILTER_REMOVE;
+ }
+ break;
}
-
+
return return_val;
}
diff --git a/gtk/gtksocket.h b/gtk/gtksocket.h
index 4d354a096..d6dc92d71 100644
--- a/gtk/gtksocket.h
+++ b/gtk/gtksocket.h
@@ -58,6 +58,9 @@ struct _GtkSocket
guint focus_in : 1;
guint have_size : 1;
guint need_map : 1;
+
+ GHashTable *grabbed_keys;
+ GtkWidget *toplevel;
};
struct _GtkSocketClass
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index e03cc71fd..52654dab0 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -2248,13 +2248,9 @@ static gint
gtk_window_focus_in_event (GtkWidget *widget,
GdkEventFocus *event)
{
- GtkWindow *window;
+ GtkWindow *window = GTK_WINDOW (widget);
GdkEventFocus fevent;
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
/* It appears spurious focus in events can occur when
* the window is hidden. So we'll just check to see if
* the window is visible before actually handling the
@@ -2262,7 +2258,8 @@ gtk_window_focus_in_event (GtkWidget *widget,
*/
if (GTK_WIDGET_VISIBLE (widget))
{
- window = GTK_WINDOW (widget);
+ window->has_focus = TRUE;
+
if (window->focus_widget &&
window->focus_widget != widget &&
!GTK_WIDGET_HAS_FOCUS (window->focus_widget))
@@ -2282,14 +2279,11 @@ static gint
gtk_window_focus_out_event (GtkWidget *widget,
GdkEventFocus *event)
{
- GtkWindow *window;
+ GtkWindow *window = GTK_WINDOW (widget);
GdkEventFocus fevent;
- g_return_val_if_fail (widget != NULL, FALSE);
- g_return_val_if_fail (GTK_IS_WINDOW (widget), FALSE);
- g_return_val_if_fail (event != NULL, FALSE);
-
- window = GTK_WINDOW (widget);
+ window->has_focus = FALSE;
+
if (window->focus_widget &&
window->focus_widget != widget &&
GTK_WIDGET_HAS_FOCUS (window->focus_widget))
@@ -2456,32 +2450,29 @@ gtk_window_real_set_focus (GtkWindow *window,
if (window->focus_widget)
{
- event.type = GDK_FOCUS_CHANGE;
- event.window = window->focus_widget->window;
- event.in = FALSE;
-
if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
(window->focus_widget != window->default_widget))
{
GTK_WIDGET_UNSET_FLAGS (window->focus_widget, GTK_HAS_DEFAULT);
- /* if any widget had the default set there should be
- a default_widget, but might not so this is a sanity
- check */
+
if (window->default_widget)
GTK_WIDGET_SET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
}
-
- gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+
+ if (window->has_focus)
+ {
+ event.type = GDK_FOCUS_CHANGE;
+ event.window = window->focus_widget->window;
+ event.in = FALSE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ }
}
window->focus_widget = focus;
if (window->focus_widget)
{
- event.type = GDK_FOCUS_CHANGE;
- event.window = window->focus_widget->window;
- event.in = TRUE;
-
if (GTK_WIDGET_RECEIVES_DEFAULT (window->focus_widget) &&
(window->focus_widget != window->default_widget))
{
@@ -2491,8 +2482,15 @@ gtk_window_real_set_focus (GtkWindow *window,
if (window->default_widget)
GTK_WIDGET_UNSET_FLAGS (window->default_widget, GTK_HAS_DEFAULT);
}
-
- gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+
+ if (window->has_focus)
+ {
+ event.type = GDK_FOCUS_CHANGE;
+ event.window = window->focus_widget->window;
+ event.in = TRUE;
+
+ gtk_widget_event (window->focus_widget, (GdkEvent*) &event);
+ }
}
if (window->default_widget &&
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 868891729..76584d80d 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -70,6 +70,7 @@ struct _GtkWindow
GtkWindowType type : 4;
guint has_user_ref_count : 1;
+ guint has_focus : 1;
guint allow_shrink : 1;
guint allow_grow : 1;
guint auto_shrink : 1;
diff --git a/gtk/xembed.h b/gtk/xembed.h
new file mode 100644
index 000000000..5c4e35d77
--- /dev/null
+++ b/gtk/xembed.h
@@ -0,0 +1,19 @@
+/* XEMBED messages */
+#define XEMBED_EMBEDDED_NOTIFY 0
+#define XEMBED_WINDOW_ACTIVATE 1
+#define XEMBED_WINDOW_DEACTIVATE 2
+#define XEMBED_REQUEST_FOCUS 3
+#define XEMBED_FOCUS_IN 4
+#define XEMBED_FOCUS_OUT 5
+#define XEMBED_FOCUS_NEXT 6
+#define XEMBED_FOCUS_PREV 7
+#define XEMBED_GRAB_KEY 8
+#define XEMBED_UNGRAB_KEY 9
+#define XEMBED_MODALITY_ON 10
+#define XEMBED_MODALITY_OFF 11
+
+/* Details for XEMBED_FOCUS_IN: */
+#define XEMBED_FOCUS_CURRENT 0
+#define XEMBED_FOCUS_FIRST 1
+#define XEMBED_FOCUS_LAST 2
+