]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Robustify tracking of pointer grab window.
[~andy/gtk] / gtk / gtkmain.c
index 180e29d08200695ab7387955cea79a9618fe3a61..c38607a39cc66b9c588f0da5291268224d4f9b3d 100644 (file)
 #include <gmodule.h>
 #ifdef G_OS_UNIX
 #include <unistd.h>
+#include <sys/types.h>         /* For uid_t, gid_t */
+#endif
+#ifdef G_OS_WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
 #endif
 
 #include <pango/pango-utils.h> /* For pango_split_file_list */
 
+#include "gtkaccelmap.h"
 #include "gtkdnd.h"
 #include "gtkversion.h"
 #include "gtkmain.h"
@@ -52,7 +59,6 @@
 #include "gtkwidget.h"
 #include "gtkwindow.h"
 #include "gtkprivate.h"
-#include "gdk/gdki18n.h"
 #include "config.h"
 #include "gtkdebug.h"
 #include "gtkintl.h"
@@ -94,7 +100,6 @@ struct _GtkKeySnooperData
   guint id;
 };
 
-static void  gtk_exit_func              (void);
 static gint  gtk_quit_invoke_function   (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy           (GtkQuitFunction    *quitf);
 static gint  gtk_invoke_key_snoopers    (GtkWidget          *grab_widget,
@@ -150,7 +155,8 @@ static const GDebugKey gtk_debug_keys[] = {
   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
   {"text", GTK_DEBUG_TEXT},
   {"tree", GTK_DEBUG_TREE},
-  {"updates", GTK_DEBUG_UPDATES}
+  {"updates", GTK_DEBUG_UPDATES},
+  {"keybindings", GTK_DEBUG_KEYBINDINGS}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -224,81 +230,211 @@ check_setugid (void)
   return TRUE;
 }
 
+#ifdef G_OS_WIN32
+
+G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
+
+const gchar *
+_gtk_get_libdir (void)
+{
+  static char *gtk_libdir = NULL;
+  if (gtk_libdir == NULL)
+    gtk_libdir = g_win32_get_package_installation_subdirectory
+      (GETTEXT_PACKAGE, dll_name, "lib");
+
+  return gtk_libdir;
+}
+
+const gchar *
+_gtk_get_localedir (void)
+{
+  static char *gtk_localedir = NULL;
+  if (gtk_localedir == NULL)
+    gtk_localedir = g_win32_get_package_installation_subdirectory
+      (GETTEXT_PACKAGE, dll_name, "lib\\locale");
+
+  return gtk_localedir;
+}
+
+const gchar *
+_gtk_get_sysconfdir (void)
+{
+  static char *gtk_sysconfdir = NULL;
+  if (gtk_sysconfdir == NULL)
+    gtk_sysconfdir = g_win32_get_package_installation_subdirectory
+      (GETTEXT_PACKAGE, dll_name, "etc");
+
+  return gtk_sysconfdir;
+}
+
+const gchar *
+_gtk_get_data_prefix (void)
+{
+  static char *gtk_data_prefix = NULL;
+  if (gtk_data_prefix == NULL)
+    gtk_data_prefix = g_win32_get_package_installation_directory
+      (GETTEXT_PACKAGE, dll_name);
+
+  return gtk_data_prefix;
+}
+
+#endif /* G_OS_WIN32 */
+
 static gchar **
 get_module_path (void)
 {
-  gchar *module_path = g_getenv ("GTK_MODULE_PATH");
-  gchar *exe_prefix = g_getenv("GTK_EXE_PREFIX");
-  gchar **result;
+  const gchar *module_path_env;
+  const gchar *exe_prefix;
+  const gchar *home_dir;
+  gchar *home_gtk_dir = NULL;
+  gchar *module_path;
   gchar *default_dir;
+  static gchar **result = NULL;
+
+  if (result)
+    return result;
+
+  home_dir = g_get_home_dir();
+  if (home_dir)
+    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);
+
+  module_path_env = g_getenv ("GTK_PATH");
+  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
 
   if (exe_prefix)
-    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", "modules", NULL);
+    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
   else
-    {
-#ifndef G_OS_WIN32
-      default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", "modules", NULL);
-#else
-      default_dir = g_build_filename (get_gtk_win32_directory (""), "modules", NULL);
-#endif
-    }
-  module_path = g_strconcat (module_path ? module_path : "",
-                            module_path ? G_SEARCHPATH_SEPARATOR_S : "",
-                            default_dir, NULL);
-
-  result = pango_split_file_list (module_path);
+    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);
+
+  if (module_path_env && home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               module_path_env, home_gtk_dir, default_dir, NULL);
+  else if (module_path_env)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               module_path_env, default_dir, NULL);
+  else if (home_gtk_dir)
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               home_gtk_dir, default_dir, NULL);
+  else
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               default_dir, NULL);
 
+  g_free (home_gtk_dir);
   g_free (default_dir);
+
+  result = pango_split_file_list (module_path);
   g_free (module_path);
 
   return result;
 }
 
-static GModule *
-find_module (gchar      **module_path,
-            const gchar *name)
+/**
+ * _gtk_get_module_path:
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Determines the search path for a particular type of module.
+ * 
+ * Return value: the search path for the module type. Free with g_strfreev().
+ **/
+gchar **
+_gtk_get_module_path (const gchar *type)
 {
-  GModule *module;
-  gchar *module_name;
-  gint i;
+  gchar **paths = get_module_path();
+  gchar **path;
+  gchar **result;
+  gint count = 0;
 
-  if (g_path_is_absolute (name))
-    return g_module_open (name, G_MODULE_BIND_LAZY);
+  for (path = paths; *path; path++)
+    count++;
 
-  for (i = 0; module_path[i]; i++)
-    {
-      gchar *version_directory;
+  result = g_new (gchar *, count * 4 + 1);
 
-#ifndef G_OS_WIN32 /* ignoring GTK_BINARY_VERSION elsewhere too */
-      version_directory = g_build_filename (module_path[i], GTK_BINARY_VERSION, NULL);
-      module_name = g_module_build_path (version_directory, name);
-      g_free (version_directory);
-      
-      if (g_file_test (module_name, G_FILE_TEST_EXISTS))
-       {
-         g_free (module_name);
-         return g_module_open (module_name, G_MODULE_BIND_LAZY);
-       }
+  count = 0;
+  for (path = get_module_path (); *path; path++)
+    {
+      gint use_version, use_host;
       
-      g_free (module_name);
-#endif
+      for (use_version = TRUE; use_version >= FALSE; use_version--)
+       for (use_host = TRUE; use_host >= FALSE; use_host--)
+         {
+           gchar *tmp_dir;
+           
+           if (use_version && use_host)
+             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
+           else if (use_version)
+             tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
+           else if (use_host)
+             tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
+           else
+             tmp_dir = g_build_filename (*path, type, NULL);
+
+           result[count++] = tmp_dir;
+         }
+    }
 
-      module_name = g_module_build_path (module_path[i], name);
-      
-      if (g_file_test (module_name, G_FILE_TEST_EXISTS))
+  result[count++] = NULL;
+
+  return result;
+}
+
+/**
+ * _gtk_find_module:
+ * @name: the name of the module
+ * @type: the type of the module, for instance 'modules', 'engines', immodules'
+ * 
+ * Looks for a dynamically module named @name of type @type in the standard GTK+
+ *  module search path.
+ * 
+ * Return value: the pathname to the found module, or %NULL if it wasn't found.
+ *  Free with g_free().
+ **/
+gchar *
+_gtk_find_module (const gchar *name,
+                 const gchar *type)
+{
+  gchar **paths;
+  gchar **path;
+  gchar *module_name = NULL;
+
+  if (g_path_is_absolute (name))
+    return g_strdup (name);
+
+  paths = _gtk_get_module_path (type);
+  for (path = paths; *path; path++)
+    {
+      gchar *tmp_name = g_module_build_path (*path, name);
+           
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
        {
-         module = g_module_open (module_name, G_MODULE_BIND_LAZY);
-         g_free (module_name);
-         return module;
+         module_name = tmp_name;
+         goto found;
        }
-
-      g_free (module_name);
+      else
+       g_free(tmp_name);
     }
 
-  /* As last resort, try loading without an absolute path (using system
-   * library path)
-   */
-  module_name = g_module_build_path (NULL, name);
+  g_strfreev (paths);
+
+ found:
+  return module_name;
+}
+
+static GModule *
+find_module (gchar      **module_path,
+            const gchar *name)
+{
+  GModule *module;
+  gchar *module_name;
+
+  module_name = _gtk_find_module (name, "modules");
+  if (!module_name)
+    {
+      /* As last resort, try loading without an absolute path (using system
+       * library path)
+       */
+      module_name = g_module_build_path (NULL, name);
+    }
+  
   module = g_module_open (module_name, G_MODULE_BIND_LAZY);
   g_free(module_name);
 
@@ -317,7 +453,7 @@ load_module (GSList      *gtk_modules,
     {
       module = find_module (module_path, name);
       if (module &&
-         g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) &&
+         g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
          modinit_func)
        {
          if (!g_slist_find (gtk_modules, modinit_func))
@@ -363,6 +499,28 @@ load_modules (const char *module_str)
   return gtk_modules;
 }
 
+static gboolean do_setlocale = TRUE;
+
+/**
+ * gtk_disable_setlocale:
+ * 
+ * Prevents gtk_init() and gtk_init_check() from automatically
+ * calling <literal>setlocale (LC_ALL, "")</literal>. You would 
+ * want to use this function if you wanted to set the locale for 
+ * your program to something other than the user's locale, or if 
+ * you wanted to set different values for different locale categories.
+ *
+ * Most programs should not need to call this function.
+ **/
+void
+gtk_disable_setlocale (void)
+{
+  if (gtk_initialized)
+    g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
+    
+  do_setlocale = FALSE;
+}
+
 gboolean
 gtk_init_check (int     *argc,
                char   ***argv)
@@ -370,7 +528,7 @@ gtk_init_check (int  *argc,
   GString *gtk_modules_string = NULL;
   GSList *gtk_modules = NULL;
   GSList *slist;
-  gchar *env_string;
+  const gchar *env_string;
 
   if (gtk_initialized)
     return TRUE;
@@ -384,6 +542,12 @@ gtk_init_check (int         *argc,
   g_set_message_handler (gtk_message);
   g_set_print_handler (gtk_print);
 #endif
+
+  if (do_setlocale)
+    {
+      if (!setlocale (LC_ALL, ""))
+       g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
+    }
   
   /* Initialize "gdk". We pass along the 'argc' and 'argv'
    *  parameters as they contain information that GDK uses
@@ -394,7 +558,7 @@ gtk_init_check (int  *argc,
   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
   
 #ifdef G_ENABLE_DEBUG
-  env_string = getenv ("GTK_DEBUG");
+  env_string = g_getenv ("GTK_DEBUG");
   if (env_string != NULL)
     {
       gtk_debug_flags = g_parse_debug_string (env_string,
@@ -404,7 +568,7 @@ gtk_init_check (int  *argc,
     }
 #endif /* G_ENABLE_DEBUG */
 
-  env_string = getenv ("GTK_MODULES");
+  env_string = g_getenv ("GTK_MODULES");
   if (env_string)
     gtk_modules_string = g_string_new (env_string);
 
@@ -522,19 +686,10 @@ gtk_init_check (int        *argc,
     }
 
 #ifdef ENABLE_NLS
-#  ifndef G_OS_WIN32
   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 #    endif
-#  else /* !G_OS_WIN32 */
-  {
-    bindtextdomain (GETTEXT_PACKAGE,
-                   g_win32_get_package_installation_subdirectory (GETTEXT_PACKAGE,
-                                                                  g_strdup_printf ("gtk-win32-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION),
-                                                                  "locale"));
-  }
-#endif
 #endif  
 
   {
@@ -559,13 +714,9 @@ gtk_init_check (int         *argc,
   gtk_colormap = gdk_colormap_get_system ();
 
   gtk_type_init (0);
+  _gtk_accel_map_init ();  
   _gtk_rc_init ();
   
-  
-  /* Register an exit function to make sure we are able to cleanup.
-   */
-  g_atexit (gtk_exit_func);
-  
   /* Set the 'initialized' flag.
    */
   gtk_initialized = TRUE;
@@ -584,16 +735,6 @@ gtk_init_check (int         *argc,
     }
   g_slist_free (gtk_modules);
   
-#ifndef G_OS_WIN32
-  /* No use warning on Win32, there aren't any non-devel versions anyhow... */
-  g_message (""              "YOU ARE USING THE DEVEL BRANCH 1.3.x OF GTK+ WHICH IS CURRENTLY\n"
-            "                UNDER HEAVY DEVELOPMENT AND FREQUENTLY INTRODUCES INSTABILITIES.\n"
-            "                if you don't know why you are getting this, you probably want to\n"
-            "                use the stable branch which can be retrieved from\n"
-            "                ftp://ftp.gtk.org/pub/gtk/v1.2/ or via CVS with\n"
-            "                cvs checkout -r glib-1-2 glib; cvs checkout -r gtk-1-2 gtk+");
-#endif
-
   return TRUE;
 }
 
@@ -646,9 +787,6 @@ gtk_exit (gint errorcode)
 {
   /* Only if "gtk" has been initialized should we de-initialize.
    */
-  /* de-initialisation is done by the gtk_exit_funct(),
-   * no need to do this here (Alex J.)
-   */
   gdk_exit (errorcode);
 }
 
@@ -656,17 +794,23 @@ gtk_exit (gint errorcode)
 /**
  * gtk_set_locale:
  *
+ * Initializes internationalization support for GTK+. gtk_init()
+ * automatically does this, so there is typically no point
+ * in calling this function.
  *
- * Initializes internationalization support for GTK+.  You
- * should call this function before gtk_init() if your application
- * supports internationalization.
+ * If you are calling this function because you changed the locale
+ * after GTK+ is was initialized, then calling this function
+ * may help a bit. (Note, however, that changing the locale
+ * after GTK+ is initialized may produce inconsistent results and
+ * is not really supported.)
  * 
- *  (In gory detail - sets the current locale according to the
- * program environment. This is the same as calling the libc function
- * setlocale (LC_ALL, "") but also takes care of the locale specific
- * setup of the windowing system used by GDK.)
+ * In detail - sets the current locale according to the
+ * program environment. This is the same as calling the C library function
+ * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
+ * locale specific setup of the windowing system used by GDK.
  * 
- * Return value: a string corresponding to the locale set, as with the C library function setlocale()
+ * Return value: a string corresponding to the locale set, as with the
+ * C library function <function>setlocale()</function>.
  **/
 gchar*
 gtk_set_locale (void)
@@ -836,6 +980,121 @@ gtk_main_iteration_do (gboolean blocking)
     return TRUE;
 }
 
+/* private libgtk to libgdk interfaces
+ */
+gboolean gdk_pointer_grab_info_libgtk_only  (GdkWindow **grab_window,
+                                            gboolean   *owner_events);
+gboolean gdk_keyboard_grab_info_libgtk_only (GdkWindow **grab_window,
+                                            gboolean   *owner_events);
+
+static void
+rewrite_events_translate (GdkWindow *old_window,
+                         GdkWindow *new_window,
+                         gdouble   *x,
+                         gdouble   *y)
+{
+  gint old_origin_x, old_origin_y;
+  gint new_origin_x, new_origin_y;
+
+  gdk_window_get_origin        (old_window, &old_origin_x, &old_origin_y);
+  gdk_window_get_origin        (new_window, &new_origin_x, &new_origin_y);
+
+  *x += new_origin_x - old_origin_x;
+  *y += new_origin_y - old_origin_y;
+}
+
+GdkEvent *
+rewrite_event_for_window (GdkEvent  *event,
+                         GdkWindow *new_window)
+{
+  event = gdk_event_copy (event);
+
+  switch (event->type)
+    {
+    case GDK_SCROLL:
+      rewrite_events_translate (event->any.window,
+                               new_window,
+                               &event->scroll.x, &event->scroll.y);
+      break;
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+      rewrite_events_translate (event->any.window,
+                               new_window,
+                               &event->button.x, &event->button.y);
+      break;
+    case GDK_MOTION_NOTIFY:
+      rewrite_events_translate (event->any.window,
+                               new_window,
+                               &event->motion.x, &event->motion.y);
+      break;
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+      break;
+
+    default:
+      return event;
+    }
+
+  g_object_unref (event->any.window);
+  event->any.window = g_object_ref (new_window);
+
+  return event;
+}
+
+/* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
+ * then what X11 does is deliver the event normally if it was going to this
+ * client, otherwise, delivers it in terms of the grab window. This function
+ * rewrites events to the effect that events going to the same window group
+ * are delivered normally, otherwise, the event is delivered in terms of the
+ * grab window.
+ */
+static GdkEvent *
+rewrite_event_for_grabs (GdkEvent *event)
+{
+  GdkWindow *grab_window;
+  GtkWidget *event_widget, *grab_widget;;
+  gboolean owner_events;
+
+  switch (event->type)
+    {
+    case GDK_SCROLL:
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    case GDK_BUTTON_RELEASE:
+    case GDK_MOTION_NOTIFY:
+    case GDK_PROXIMITY_IN:
+    case GDK_PROXIMITY_OUT:
+      if (!gdk_pointer_grab_info_libgtk_only (&grab_window, &owner_events) ||
+         !owner_events)
+       return NULL;
+      break;
+
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      if (!gdk_keyboard_grab_info_libgtk_only (&grab_window, &owner_events) ||
+         !owner_events)
+       return NULL;
+      break;
+
+    default:
+      return NULL;
+    }
+
+  event_widget = gtk_get_event_widget (event);
+  gdk_window_get_user_data (grab_window, (void**) &grab_widget);
+
+  if (grab_widget &&
+      gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
+    return rewrite_event_for_window (event, grab_window);
+  else
+    return NULL;
+}
+
 void 
 gtk_main_do_event (GdkEvent *event)
 {
@@ -843,6 +1102,7 @@ gtk_main_do_event (GdkEvent *event)
   GtkWidget *grab_widget;
   GtkWindowGroup *window_group;
   GdkEvent *next_event;
+  GdkEvent *rewritten_event = NULL;
   GList *tmp_list;
 
   /* If there are any events pending then get the next one.
@@ -901,14 +1161,24 @@ gtk_main_do_event (GdkEvent *event)
 
       return;
     }
+
+  /* If pointer or keyboard grabs are in effect, munge the events
+   * so that each window group looks like a separate app.
+   */
+  rewritten_event = rewrite_event_for_grabs (event);
+  if (rewritten_event)
+    {
+      event = rewritten_event;
+      event_widget = gtk_get_event_widget (event);
+    }
   
+  window_group = gtk_main_get_window_group (event_widget);
+
   /* Push the event onto a stack of current events for
    * gtk_current_event_get().
    */
   current_events = g_list_prepend (current_events, event);
 
-  window_group = gtk_main_get_window_group (event_widget);
-  
   /* If there is a grab in effect...
    */
   if (window_group->grabs)
@@ -1016,9 +1286,13 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_ENTER_NOTIFY:
       if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
        {
+         g_object_ref (event_widget);
+         
          gtk_widget_event (grab_widget, event);
          if (event_widget == grab_widget)
            GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
+         
+         g_object_unref (event_widget);
        }
       break;
       
@@ -1050,6 +1324,9 @@ gtk_main_do_event (GdkEvent *event)
   tmp_list = current_events;
   current_events = g_list_remove_link (current_events, tmp_list);
   g_list_free_1 (tmp_list);
+
+  if (rewritten_event)
+    gdk_event_free (rewritten_event);
 }
 
 gboolean
@@ -1080,25 +1357,37 @@ gtk_main_get_window_group (GtkWidget   *widget)
 
 typedef struct
 {
-  gboolean was_grabbed;
-  GtkWidget *grab_widget;
+  GtkWidget *old_grab_widget;
+  GtkWidget *new_grab_widget;
 } GrabNotifyInfo;
 
+static gboolean
+check_is_grabbed (GtkWidget *widget,
+                 GtkWidget *grab_widget)
+{
+  if (grab_widget)
+    return !(widget == grab_widget || gtk_widget_is_ancestor (widget, grab_widget));
+  else
+    return FALSE;
+}
+
 static void
 gtk_grab_notify_foreach (GtkWidget *child,
                         gpointer   data)
                         
 {
   GrabNotifyInfo *info = data;
+  gboolean was_grabbed = check_is_grabbed (child, info->old_grab_widget);
+  gboolean is_grabbed = check_is_grabbed (child, info->new_grab_widget);
 
-  if (child != info->grab_widget)
+  if (was_grabbed != is_grabbed)
     {
       g_object_ref (G_OBJECT (child));
-
-      gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", info->was_grabbed);
-
+      
+      gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
+      
       if (GTK_IS_CONTAINER (child))
-       gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
+       gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
       
       g_object_unref (G_OBJECT (child));
     }
@@ -1112,8 +1401,16 @@ gtk_grab_notify (GtkWindowGroup *group,
   GList *toplevels;
   GrabNotifyInfo info;
 
-  info.grab_widget = grab_widget;
-  info.was_grabbed = was_grabbed;
+  if (was_grabbed)
+    {
+      info.old_grab_widget = grab_widget;
+      info.new_grab_widget = group->grabs ? group->grabs->data : NULL;
+    }
+  else
+    {
+      info.old_grab_widget = (group->grabs && group->grabs->next) ? group->grabs->next->data : NULL;
+      info.new_grab_widget = grab_widget;
+    }
 
   g_object_ref (group);
   g_object_ref (grab_widget);
@@ -1126,7 +1423,7 @@ gtk_grab_notify (GtkWindowGroup *group,
       GtkWindow *toplevel = toplevels->data;
       toplevels = g_list_delete_link (toplevels, toplevels);
 
-      if (group == toplevel->group)
+      if (group == _gtk_window_get_group (toplevel))
        gtk_container_foreach (GTK_CONTAINER (toplevel), gtk_grab_notify_foreach, &info);
       g_object_unref (toplevel);
     }
@@ -1154,8 +1451,7 @@ gtk_grab_add (GtkWidget *widget)
       gtk_widget_ref (widget);
       group->grabs = g_slist_prepend (group->grabs, widget);
 
-      if (!was_grabbed)
-       gtk_grab_notify (group, widget, FALSE);
+      gtk_grab_notify (group, widget, FALSE);
     }
 }
 
@@ -1187,8 +1483,7 @@ gtk_grab_remove (GtkWidget *widget)
       
       gtk_widget_unref (widget);
 
-      if (!group->grabs)
-       gtk_grab_notify (group, widget, TRUE);
+      gtk_grab_notify (group, widget, TRUE);
     }
 }
 
@@ -1637,16 +1932,6 @@ gtk_get_event_widget (GdkEvent *event)
   return widget;
 }
 
-static void
-gtk_exit_func (void)
-{
-  if (gtk_initialized)
-    {
-      gtk_initialized = FALSE;
-    }
-}
-
-
 static gint
 gtk_quit_invoke_function (GtkQuitFunction *quitf)
 {