]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Don't insert mnemonics for stock items (#72918, reported by Mikael
[~andy/gtk] / gtk / gtkmain.c
index 9eeebb7ed4bd1a152c888fa52200d91c22ffbced..fead858f0f0db6128b32371cf5b2de3c67b725c1 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 "gtkbox.h"
 #include "gtkdnd.h"
 #include "gtkversion.h"
 #include "gtkmain.h"
 #include "gtkrc.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
-#include "gtksignal.h"
 #include "gtkwidget.h"
 #include "gtkwindow.h"
 #include "gtkprivate.h"
-#include "gdk/gdki18n.h"
 #include "config.h"
 #include "gtkdebug.h"
 #include "gtkintl.h"
@@ -63,6 +69,7 @@ typedef struct _GtkInitFunction                GtkInitFunction;
 typedef struct _GtkQuitFunction                 GtkQuitFunction;
 typedef struct _GtkClosure              GtkClosure;
 typedef struct _GtkKeySnooperData       GtkKeySnooperData;
+typedef struct _GtkModuleInfo            GtkModuleInfo;
 
 struct _GtkInitFunction
 {
@@ -94,7 +101,12 @@ struct _GtkKeySnooperData
   guint id;
 };
 
-static void  gtk_exit_func              (void);
+struct _GtkModuleInfo
+{
+  GtkModuleInitFunc init_func;
+  GtkModuleDisplayInitFunc display_init_func;
+};
+
 static gint  gtk_quit_invoke_function   (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy           (GtkQuitFunction    *quitf);
 static gint  gtk_invoke_key_snoopers    (GtkWidget          *grab_widget,
@@ -121,6 +133,13 @@ const guint gtk_micro_version = GTK_MICRO_VERSION;
 const guint gtk_binary_age = GTK_BINARY_AGE;
 const guint gtk_interface_age = GTK_INTERFACE_AGE;
 
+static GSList *gtk_modules;
+
+/* Saved argc,argv for delayed module initialization
+ */
+static gint    gtk_argc = 0;
+static gchar **gtk_argv = NULL;
+
 static guint gtk_main_loop_level = 0;
 static gint gtk_initialized = FALSE;
 static GList *current_events = NULL;
@@ -135,13 +154,6 @@ static GMemChunk *quit_mem_chunk = NULL;
 
 static GSList *key_snoopers = NULL;
 
-static GdkVisual *gtk_visual;             /* The visual to be used in creating new
-                                           *  widgets.
-                                           */
-static GdkColormap *gtk_colormap;         /* The colormap to be used in creating new
-                                           *  widgets.
-                                           */
-
 guint gtk_debug_flags = 0;                /* Global GTK debug flag */
 
 #ifdef G_ENABLE_DEBUG
@@ -150,7 +162,9 @@ 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},
+  {"multihead", GTK_DEBUG_MULTIHEAD}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -162,23 +176,20 @@ gtk_check_version (guint required_major,
                   guint required_minor,
                   guint required_micro)
 {
+  gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
+  gint required_effective_micro = 100 * required_minor + required_micro;
+
   if (required_major > GTK_MAJOR_VERSION)
     return "Gtk+ version too old (major mismatch)";
   if (required_major < GTK_MAJOR_VERSION)
     return "Gtk+ version too new (major mismatch)";
-  if (required_minor > GTK_MINOR_VERSION)
-    return "Gtk+ version too old (minor mismatch)";
-  if (required_minor < GTK_MINOR_VERSION)
-    return "Gtk+ version too new (minor mismatch)";
-  if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
+  if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
     return "Gtk+ version too new (micro mismatch)";
-  if (required_micro > GTK_MICRO_VERSION)
+  if (required_effective_micro > gtk_effective_micro)
     return "Gtk+ version too old (micro mismatch)";
   return NULL;
 }
 
-#undef gtk_init_check
-
 /* This checks to see if the process is running suid or sgid
  * at the current time. If so, we don't allow GTK+ to be initialized.
  * This is meant to be a mild check - we only error out if we
@@ -224,73 +235,242 @@ 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
+    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
-    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", "modules", NULL);
+    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+                               default_dir, NULL);
 
-  module_path = g_strconcat (module_path ? module_path : "",
-                            module_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 (default_dir);
   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;
+
+  for (path = paths; *path; path++)
+    count++;
+
+  result = g_new (gchar *, count * 4 + 1);
+
+  count = 0;
+  for (path = get_module_path (); *path; path++)
+    {
+      gint use_version, use_host;
+      
+      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;
+         }
+    }
+
+  result[count++] = NULL;
+
+  return result;
+}
+
+/* Like g_module_path, but use .la as the suffix
+ */
+static gchar*
+module_build_la_path (const gchar *directory,
+                     const gchar *module_name)
+{
+       gchar *filename;
+       gchar *result;
+       
+       if (strncmp (module_name, "lib", 3) == 0)
+               filename = (gchar *)module_name;
+       else
+               filename =  g_strconcat ("lib", module_name, ".la", NULL);
+
+       if (directory && *directory)
+               result = g_build_filename (directory, filename, NULL);
+       else
+               result = g_strdup (filename);
+
+       if (filename != module_name)
+               g_free (filename);
+
+       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_module_open (name, G_MODULE_BIND_LAZY);
+    return g_strdup (name);
 
-  for (i = 0; module_path[i]; i++)
+  paths = _gtk_get_module_path (type);
+  for (path = paths; *path; path++)
     {
-      gchar *version_directory;
+      gchar *tmp_name;
 
-      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))
+      tmp_name = g_module_build_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
        {
-         g_free (module_name);
-         return g_module_open (module_name, G_MODULE_BIND_LAZY);
+         module_name = tmp_name;
+         goto found;
        }
-      
-      g_free (module_name);
+      g_free(tmp_name);
 
-      module_name = g_module_build_path (module_path[i], name);
-      
-      if (g_file_test (module_name, G_FILE_TEST_EXISTS))
+      tmp_name = module_build_la_path (*path, name);
+      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
        {
-         g_free (module_name);
-         return g_module_open (module_name, G_MODULE_BIND_LAZY);
+         module_name = tmp_name;
+         goto found;
        }
-
-      g_free (module_name);
+      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);
+ found:
+  g_strfreev (paths);
+  return module_name;
+}
+
+static GModule *
+find_module (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);
 
@@ -298,24 +478,30 @@ find_module (gchar      **module_path,
 }
 
 static GSList *
-load_module (GSList      *gtk_modules,
-            gchar      **module_path,
+load_module (GSList      *module_list,
             const gchar *name)
 {
   GtkModuleInitFunc modinit_func = NULL;
+  GtkModuleInfo *info;
   GModule *module = NULL;
   
   if (g_module_supported ())
     {
-      module = find_module (module_path, name);
+      module = find_module (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))
+         if (!g_slist_find (module_list, (gconstpointer) modinit_func))
            {
              g_module_make_resident (module);
-             gtk_modules = g_slist_prepend (gtk_modules, modinit_func);
+             info = g_new (GtkModuleInfo, 1);
+
+             info->init_func = modinit_func;
+             g_module_symbol (module, "gtk_module_display_init",
+                              (gpointer *) &info->display_init_func);
+             
+             module_list = g_slist_prepend (module_list, info);
            }
          else
            {
@@ -333,36 +519,120 @@ load_module (GSList      *gtk_modules,
        g_module_close (module);
     }
   
-  return gtk_modules;
+  return module_list;
 }
 
 static GSList *
 load_modules (const char *module_str)
 {
-  gchar **module_path = get_module_path ();
   gchar **module_names = pango_split_file_list (module_str);
-  GSList *gtk_modules = NULL;
+  GSList *module_list = NULL;
   gint i;
   
   for (i = 0; module_names[i]; i++)
-    gtk_modules = load_module (gtk_modules, module_path, module_names[i]);
+    module_list = load_module (module_list, module_names[i]);
   
-  gtk_modules = g_slist_reverse (gtk_modules);
+  module_list = g_slist_reverse (module_list);
   
   g_strfreev (module_names);
-  g_strfreev (module_path);
 
-  return gtk_modules;
+  return module_list;
 }
 
+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;
+}
+
+#undef gtk_init_check
+
+static void
+default_display_notify_cb (GdkDisplayManager *display_manager)
+{
+  GSList *slist;
+
+  /* Initialize non-multihead-aware modules when the
+   * default display is first set to a non-NULL value.
+   */
+  static gboolean initialized = FALSE;
+
+  if (!gdk_display_get_default () || initialized)
+    return;
+
+  initialized = TRUE;
+
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+       {
+         GtkModuleInfo *info = slist->data;
+
+         if (!info->display_init_func)
+           info->init_func (&gtk_argc, &gtk_argv);
+       }
+    }
+}
+
+static void
+display_opened_cb (GdkDisplayManager *display_manager,
+                  GdkDisplay        *display)
+{
+  GSList *slist;
+  
+  for (slist = gtk_modules; slist; slist = slist->next)
+    {
+      if (slist->data)
+       {
+         GtkModuleInfo *info = slist->data;
+
+         if (info->display_init_func)
+           info->display_init_func (display);
+       }
+    }
+}
+
+/**
+ * gdk_parse_args:
+ * @argc: the number of command line arguments.
+ * @argv: the array of command line arguments.
+ * 
+ * Parses command line arguments, and initializes global
+ * attributes of GTK+, but does not actually open a connection
+ * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
+ *
+ * Any arguments used by GTK or GDK are removed from the array and
+ * @argc and @argv are updated accordingly.
+ *
+ * You shouldn't call this function explicitely if you are using
+ * gtk_init(), or gtk_init_check().
+ *
+ * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
+ **/
 gboolean
-gtk_init_check (int     *argc,
-               char   ***argv)
+gtk_parse_args (int    *argc,
+               char ***argv)
 {
   GString *gtk_modules_string = NULL;
-  GSList *gtk_modules = NULL;
   GSList *slist;
-  gchar *env_string;
+  GdkDisplayManager *display_manager;
+  const gchar *env_string;
 
   if (gtk_initialized)
     return TRUE;
@@ -376,17 +646,18 @@ gtk_init_check (int        *argc,
   g_set_message_handler (gtk_message);
   g_set_print_handler (gtk_print);
 #endif
-  
-  /* Initialize "gdk". We pass along the 'argc' and 'argv'
-   *  parameters as they contain information that GDK uses
-   */
-  if (!gdk_init_check (argc, argv))
-    return FALSE;
 
+  if (do_setlocale)
+    {
+      if (!setlocale (LC_ALL, ""))
+       g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
+    }
+
+  gdk_parse_args (argc, argv);
   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,
@@ -396,7 +667,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);
 
@@ -501,6 +772,11 @@ gtk_init_check (int         *argc,
              *argc -= k;
            }
        }
+
+      gtk_argv = g_malloc ((gtk_argc + 1) * sizeof (char*));
+      for (i = 0; i < gtk_argc; i++)
+       gtk_argv[i] = g_strdup ((*argv)[i]);
+      gtk_argv[gtk_argc] = NULL;
     }
 
   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
@@ -514,19 +790,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-%d.%d.dll", GTK_MAJOR_VERSION, GTK_MINOR_VERSION),
-                                                                  "locale"));
-  }
-#endif
 #endif  
 
   {
@@ -543,65 +810,117 @@ gtk_init_check (int       *argc,
     }
   }
 
-  /* Initialize the default visual and colormap to be
-   *  used in creating widgets. (We want to use the system
-   *  defaults so as to be nice to the colormap).
-   */
-  gtk_visual = gdk_visual_get_system ();
-  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;
 
-  /* initialize gtk modules
+  display_manager = gdk_display_manager_get ();
+  g_signal_connect (display_manager, "notify::default-display",
+                   G_CALLBACK (default_display_notify_cb), NULL);
+  g_signal_connect (display_manager, "display-opened",
+                   G_CALLBACK (display_opened_cb), NULL);
+
+  /* initialize multhead aware gtk modules; for other modules,
+   * we wait until we have a display open;
    */
   for (slist = gtk_modules; slist; slist = slist->next)
     {
       if (slist->data)
        {
-         GtkModuleInitFunc modinit;
-         
-         modinit = slist->data;
-         modinit (argc, argv);
+         GtkModuleInfo *info = slist->data;
+
+         if (info->display_init_func)
+           info->init_func (argc, argv);
        }
     }
-  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 retrived 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;
 }
 
+#undef gtk_init_check
+
+/**
+ * gtk_init_check:
+ * @argc: Address of the <parameter>argc</parameter> parameter of your 
+ *   <function>main()</function> function. Changed if any arguments were 
+ *   handled.
+ * @argv: Address of the <parameter>argv</parameter> parameter of 
+ *   <function>main()</function>. Any parameters understood by gtk_init() 
+ *   are stripped before return.
+ * 
+ * This function does the same work as gtk_init() with only 
+ * a single change: It does not terminate the program if the GUI can't be 
+ * initialized. Instead it returns %FALSE on failure.
+ *
+ * This way the application can fall back to some other means of communication 
+ * with the user - for example a curses or command line interface.
+ * 
+ * Return value: %TRUE if the GUI has been successfully initialized, 
+ *               %FALSE otherwise.
+ **/
+gboolean
+gtk_init_check (int     *argc,
+               char   ***argv)
+{
+  GdkDisplay *display;
+  
+  if (!gtk_parse_args (argc, argv))
+    return FALSE;
+
+  if (gdk_display_get_default ())
+    return TRUE;
+
+  display = gdk_display_open (gdk_get_display_arg_name ());
+
+  if (display)
+    {
+      gdk_display_manager_set_default_display (gdk_display_manager_get (),
+                                              display);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
 #undef gtk_init
 
+/**
+ * gtk_init:
+ * @argc: Address of the <parameter>argc</parameter> parameter of your 
+ *   <function>main()</function> function. Changed if any arguments were 
+ *   handled.
+ * @argv: Address of the <parameter>argv</parameter> parameter of 
+ *   <function>main()</function>. Any parameters understood by gtk_init() 
+ *   are stripped before return.
+ * 
+ * Call this function before using any other GTK+ functions in your GUI
+ * applications.  It will initialize everything needed to operate the toolkit and
+ * parses some standard command line options. @argc and 
+ * @argv are adjusted accordingly so your own code will 
+ * never see those standard arguments.
+ *
+ * <note><para>
+ * This function will terminate your program if it was unable to initialize 
+ * the GUI for some reason. If you want your program to fall back to a 
+ * textual interface you want to call gtk_init_check() instead.
+ * </para></note>
+ **/
 void
 gtk_init (int *argc, char ***argv)
 {
   if (!gtk_init_check (argc, argv))
     {
-      g_warning ("cannot open display: %s", gdk_get_display ());
+      char *display_name_arg = gdk_get_display_arg_name ();
+      g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : " ");
       exit (1);
     }
 }
 
-#ifdef G_OS_WIN32
+#ifdef G_PLATFORM_WIN32
 
 static void
 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
@@ -611,23 +930,48 @@ check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
             "The code using GTK+ thinks GtkWindow is of different\n"
              "size than it actually is in this build of GTK+.\n"
             "On Windows, this probably means that you have compiled\n"
-            "your code with gcc without the -fnative-struct switch.");
+            "your code with gcc without the -fnative-struct\n"
+            "(or -mms-bitfields) switch, or that you are using\n"
+            "an unsupported compiler.");
+}
+
+/* In GTK+ 2.0 the GtkWindow struct actually is the same size in
+ * gcc-compiled code on Win32 whether compiled with -fnative-struct or
+ * not. Unfortunately this wan't noticed until after GTK+ 2.0.1. So,
+ * from GTK+ 2.0.2 on, check some other struct, too, where the use of
+ * -fnative-struct still matters. GtkBox is one such.
+ */
+static void
+check_sizeof_GtkBox (size_t sizeof_GtkBox)
+{
+  if (sizeof_GtkBox != sizeof (GtkBox))
+    g_error ("Incompatible build!\n"
+            "The code using GTK+ thinks GtkBox is of different\n"
+             "size than it actually is in this build of GTK+.\n"
+            "On Windows, this probably means that you have compiled\n"
+            "your code with gcc without the -fnative-struct\n"
+            "(or -mms-bitfields) switch, or that you are using\n"
+            "an unsupported compiler.");
 }
 
 /* These two functions might get more checks added later, thus pass
  * in the number of extra args.
  */
 void
-gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
+gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
 {
   check_sizeof_GtkWindow (sizeof_GtkWindow);
+  if (num_checks >= 2)
+    check_sizeof_GtkBox (sizeof_GtkBox);
   gtk_init (argc, argv);
 }
 
 gboolean
-gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
+gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
 {
   check_sizeof_GtkWindow (sizeof_GtkWindow);
+  if (num_checks >= 2)
+    check_sizeof_GtkBox (sizeof_GtkBox);
   return gtk_init_check (argc, argv);
 }
 
@@ -638,9 +982,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);
 }
 
@@ -648,17 +989,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)
@@ -684,7 +1031,37 @@ gtk_get_default_language (void)
   PangoLanguage *result;
   gchar *p;
   
+#ifdef G_OS_WIN32
+  /* Somebody might try to set the locale for this process using the
+   * LANG or LC_ environment variables. The Microsoft C library
+   * doesn't know anything about them. You set the locale in the
+   * Control Panel. Setting these env vars won't have any affect on
+   * locale-dependent C library functions like ctime. But just for
+   * kicks, do obey LC_ALL, LANG and LC_CTYPE in GTK. (This also makes
+   * it easier to test GTK and Pango in various default languages, you
+   * don't have to clickety-click in the Control Panel, you can simply
+   * start the program with LC_ALL=something on the command line.)
+   */
+  p = getenv ("LC_ALL");
+  if (p != NULL)
+    lang = g_strdup (p);
+  else
+    {
+      p = getenv ("LANG");
+      if (p != NULL)
+       lang = g_strdup (p);
+      else
+       {
+         p = getenv ("LC_CTYPE");
+         if (p != NULL)
+           lang = g_strdup (p);
+         else
+           lang = g_win32_getlocale ();
+       }
+    }
+#else
   lang = g_strdup (setlocale (LC_CTYPE, NULL));
+#endif
   p = strchr (lang, '.');
   if (p)
     *p = '\0';
@@ -708,7 +1085,7 @@ gtk_main (void)
 
   gtk_main_loop_level++;
   
-  loop = g_main_new (TRUE);
+  loop = g_main_loop_new (NULL, TRUE);
   main_loops = g_slist_prepend (main_loops, loop);
 
   tmp_list = functions = init_functions;
@@ -724,10 +1101,10 @@ gtk_main (void)
     }
   g_list_free (functions);
 
-  if (g_main_is_running (main_loops->data))
+  if (g_main_loop_is_running (main_loops->data))
     {
       GDK_THREADS_LEAVE ();
-      g_main_run (loop);
+      g_main_loop_run (loop);
       GDK_THREADS_ENTER ();
       gdk_flush ();
     }
@@ -771,7 +1148,7 @@ gtk_main (void)
              
   main_loops = g_slist_remove (main_loops, loop);
 
-  g_main_destroy (loop);
+  g_main_loop_unref (loop);
 
   gtk_main_loop_level--;
 }
@@ -787,7 +1164,7 @@ gtk_main_quit (void)
 {
   g_return_if_fail (main_loops != NULL);
 
-  g_main_quit (main_loops->data);
+  g_main_loop_quit (main_loops->data);
 }
 
 gint
@@ -796,7 +1173,7 @@ gtk_events_pending (void)
   gboolean result;
   
   GDK_THREADS_LEAVE ();  
-  result = g_main_pending ();
+  result = g_main_context_pending (NULL);
   GDK_THREADS_ENTER ();
 
   return result;
@@ -806,11 +1183,11 @@ gboolean
 gtk_main_iteration (void)
 {
   GDK_THREADS_LEAVE ();
-  g_main_iteration (TRUE);
+  g_main_context_iteration (NULL, TRUE);
   GDK_THREADS_ENTER ();
 
   if (main_loops)
-    return !g_main_is_running (main_loops->data);
+    return !g_main_loop_is_running (main_loops->data);
   else
     return TRUE;
 }
@@ -819,15 +1196,135 @@ gboolean
 gtk_main_iteration_do (gboolean blocking)
 {
   GDK_THREADS_LEAVE ();
-  g_main_iteration (blocking);
+  g_main_context_iteration (NULL, blocking);
   GDK_THREADS_ENTER ();
 
   if (main_loops)
-    return !g_main_is_running (main_loops->data);
+    return !g_main_loop_is_running (main_loops->data);
   else
     return TRUE;
 }
 
+/* private libgtk to libgdk interfaces
+ */
+gboolean gdk_pointer_grab_info_libgtk_only  (GdkDisplay *display,
+                                            GdkWindow **grab_window,
+                                            gboolean   *owner_events);
+gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
+                                            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 += old_origin_x - new_origin_x;
+  *y += old_origin_y - new_origin_y;
+}
+
+static 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;
+  GdkDisplay *display;
+
+  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:
+      display = gdk_drawable_get_display (event->proximity.window);
+      if (!gdk_pointer_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
+         !owner_events)
+       return NULL;
+      break;
+
+    case GDK_KEY_PRESS:
+    case GDK_KEY_RELEASE:
+      display = gdk_drawable_get_display (event->key.window);
+      if (!gdk_keyboard_grab_info_libgtk_only (display, &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)
 {
@@ -835,6 +1332,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.
@@ -886,21 +1384,31 @@ gtk_main_do_event (GdkEvent *event)
           * them specially
           */
       if (event->type == GDK_PROPERTY_NOTIFY)
-       gtk_selection_incr_event (event->any.window,
-                                 &event->property);
+       _gtk_selection_incr_event (event->any.window,
+                                  &event->property);
       else if (event->type == GDK_SETTING)
        _gtk_settings_handle_event (&event->setting);
 
       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)
@@ -936,11 +1444,11 @@ gtk_main_do_event (GdkEvent *event)
       break;
       
     case GDK_DELETE:
-      gtk_widget_ref (event_widget);
+      g_object_ref (event_widget);
       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
          !gtk_widget_event (event_widget, event))
        gtk_widget_destroy (event_widget);
-      gtk_widget_unref (event_widget);
+      g_object_unref (event_widget);
       break;
       
     case GDK_DESTROY:
@@ -949,11 +1457,11 @@ gtk_main_do_event (GdkEvent *event)
        */
       if (!event_widget->parent)
        {
-         gtk_widget_ref (event_widget);
+         g_object_ref (event_widget);
          if (!gtk_widget_event (event_widget, event) &&
              GTK_WIDGET_REALIZED (event_widget))
            gtk_widget_destroy (event_widget);
-         gtk_widget_unref (event_widget);
+         g_object_unref (event_widget);
        }
       break;
       
@@ -1008,9 +1516,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;
       
@@ -1042,6 +1554,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
@@ -1072,27 +1587,39 @@ 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);
-
+      g_object_ref (child);
+      
+      g_signal_emit_by_name (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));
+      g_object_unref (child);
     }
 }
 
@@ -1104,8 +1631,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);
@@ -1118,7 +1653,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);
     }
@@ -1143,11 +1678,10 @@ gtk_grab_add (GtkWidget *widget)
 
       was_grabbed = (group->grabs != NULL);
       
-      gtk_widget_ref (widget);
+      g_object_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);
     }
 }
 
@@ -1177,10 +1711,9 @@ gtk_grab_remove (GtkWidget *widget)
       group = gtk_main_get_window_group (widget);
       group->grabs = g_slist_remove (group->grabs, widget);
       
-      gtk_widget_unref (widget);
+      g_object_unref (widget);
 
-      if (!group->grabs)
-       gtk_grab_notify (group, widget, TRUE);
+      gtk_grab_notify (group, widget, TRUE);
     }
 }
 
@@ -1314,10 +1847,10 @@ gtk_quit_add_destroy (guint              main_level,
 
   object_p = g_new (GtkObject*, 1);
   *object_p = object;
-  gtk_signal_connect (object,
-                     "destroy",
-                     GTK_SIGNAL_FUNC (gtk_widget_destroyed),
-                     object_p);
+  g_signal_connect (object,
+                   "destroy",
+                   G_CALLBACK (gtk_widget_destroyed),
+                   object_p);
   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
 }
 
@@ -1445,7 +1978,7 @@ guint
 gtk_idle_add (GtkFunction function,
              gpointer    data)
 {
-  return g_idle_add_full (GTK_PRIORITY_DEFAULT, function, data, NULL);
+  return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
 }
 
 guint      
@@ -1629,16 +2162,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)
 {
@@ -1693,7 +2216,7 @@ gtk_propagate_event (GtkWidget *widget,
   
   handled_event = FALSE;
 
-  gtk_widget_ref (widget);
+  g_object_ref (widget);
       
   if ((event->type == GDK_KEY_PRESS) ||
       (event->type == GDK_KEY_RELEASE))
@@ -1740,18 +2263,18 @@ gtk_propagate_event (GtkWidget *widget,
          
          handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
          tmp = widget->parent;
-         gtk_widget_unref (widget);
+         g_object_unref (widget);
 
          widget = tmp;
          
          if (!handled_event && widget)
-           gtk_widget_ref (widget);
+           g_object_ref (widget);
          else
            break;
        }
     }
   else
-    gtk_widget_unref (widget);
+    g_object_unref (widget);
 }
 
 #if 0