]> Pileus Git - ~andy/gtk/commitdiff
File containing #defines for XEMBED protocol.
authorOwen Taylor <otaylor@redhat.com>
Thu, 19 Apr 2001 20:36:46 +0000 (20:36 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Thu, 19 Apr 2001 20:36:46 +0000 (20:36 +0000)
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.

gtk/Makefile.am
gtk/gtkplug.c
gtk/gtksocket.c
gtk/gtksocket.h
gtk/gtkwindow.c
gtk/gtkwindow.h
gtk/xembed.h [new file with mode: 0644]

index cbb5ef42b3bb0550b5d5058900dba4e06446855f..509b8ecd5fca1bac31f530f63c4c27849bcd1ba3 100644 (file)
@@ -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
index 420b53a8c6444bb38e157678416dac573d8940af..78d9d5128fe1e3009e224149df6d7e7079dd5c1c 100644 (file)
  * 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;
+}
index 648cedc48170f025113f883a9cbc4a554b45e3b6..1f905b796c7d7e2b20014ef7cdca520d3c589590 100644 (file)
 #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;
 }
 
index 4d354a0969a7bfe1e3ca4ffc3d5db1a185451e7f..d6dc92d7104728c392bf94cb76fbf030461b2abe 100644 (file)
@@ -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
index e03cc71fd38204a6ae40b2993f7d32af8c1dc051..52654dab0864ef63561e05afa6af17693fb754ee 100644 (file)
@@ -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 &&
index 8688917297795e887038db1aa90dbc4f00aa854e..76584d80de30efec23e324e442ae130d4c60def1 100644 (file)
@@ -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 (file)
index 0000000..5c4e35d
--- /dev/null
@@ -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
+