]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Fix #149547, Markus Lausser:
[~andy/gtk] / gtk / gtkmain.c
index e3477d1c99969f266dabd71699bc9a48c9d7f818..55df71e992c22c3611a881e583df3993ae4cbea3 100644 (file)
@@ -24,6 +24,8 @@
  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
  */
 
+#include <config.h>
+
 #include "gdkconfig.h"
 
 #include <locale.h>
 
 #include <pango/pango-utils.h> /* For pango_split_file_list */
 
+#include "gtkalias.h"
+#include "gtkintl.h"
+
 #include "gtkaccelmap.h"
 #include "gtkbox.h"
+#include "gtkclipboard.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 "config.h"
 #include "gtkdebug.h"
-#include "gtkintl.h"
 
 /* Private type definitions
  */
@@ -172,6 +175,40 @@ static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey
 
 #endif /* G_ENABLE_DEBUG */
 
+/**
+ * gtk_check_version:
+ * @required_major: the required major version.
+ * @required_minor: the required major version.
+ * @required_micro: the required major version.
+ * 
+ * Checks that the GTK+ library in use is compatible with the
+ * given version. Generally you would pass in the constants
+ * #GTK_MAJOR_VERSION, #GTK_MINOR_VERSION, #GTK_MICRO_VERSION
+ * as the three arguments to this function; that produces
+ * a check that the library in use is compatible with
+ * the version of GTK+ the application or module was compiled
+ * against.
+ *
+ * Compatibility is defined by two things: first the version
+ * of the running library is newer than the version
+ * @required_major.required_minor.@required_micro. Second
+ * the running library must be binary compatible with the
+ * version @required_major.required_minor.@required_micro
+ * (same major version.)
+ *
+ * This function is primarily for GTK+ modules; the module
+ * can call this function to check that it wasn't loaded
+ * into an incompatible version of GTK+. However, such a
+ * a check isn't completely reliable, since the module may be
+ * linked against an old version of GTK+ and calling the
+ * old version of gtk_check_version(), but still get loaded
+ * into an application using a newer version of GTK+.
+ *
+ * Return value: %NULL if the GTK+ library is compatible with the
+ *   given version, or a string describing the version mismatch.
+ *   The returned string is owned by GTK+ and should not be modified
+ *   or freed.
+ **/
 gchar*
 gtk_check_version (guint required_major,
                   guint required_minor,
@@ -240,6 +277,17 @@ check_setugid (void)
 
 G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
 
+const gchar *
+_gtk_get_datadir (void)
+{
+  static char *gtk_datadir = NULL;
+  if (gtk_datadir == NULL)
+    gtk_datadir = g_win32_get_package_installation_subdirectory
+      (GETTEXT_PACKAGE, dll_name, "share");
+
+  return gtk_datadir;
+}
+
 const gchar *
 _gtk_get_libdir (void)
 {
@@ -413,8 +461,8 @@ module_build_la_path (const gchar *directory,
  * @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.
+ * Looks for a dynamically loadable 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().
@@ -562,7 +610,9 @@ gtk_disable_setlocale (void)
   do_setlocale = FALSE;
 }
 
+#ifdef G_PLATFORM_WIN32
 #undef gtk_init_check
+#endif
 
 static void
 default_display_notify_cb (GdkDisplayManager *display_manager)
@@ -610,15 +660,15 @@ display_opened_cb (GdkDisplayManager *display_manager,
 }
 
 /**
- * gdk_parse_args:
- * @argc: the number of command line arguments.
- * @argv: the array of command line arguments.
+ * gtk_parse_args:
+ * @argc: a pointer to the number of command line arguments.
+ * @argv: a pointer to 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
+ * 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
@@ -792,8 +842,10 @@ gtk_parse_args (int    *argc,
 
 #ifdef ENABLE_NLS
   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
+  bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+  bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
 #    endif
 #endif  
 
@@ -842,16 +894,16 @@ gtk_parse_args (int    *argc,
   return TRUE;
 }
 
+#ifdef G_PLATFORM_WIN32
 #undef gtk_init_check
+#endif
 
 /**
  * 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.
+ *   main() function. Changed if any arguments were handled.
+ * @argv: Address of the <parameter>argv</parameter> parameter of main(). 
+ *   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 
@@ -867,40 +919,26 @@ 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;
+  return gdk_display_open_default_libgtk_only () != NULL;
 }
 
+#ifdef G_PLATFORM_WIN32
 #undef gtk_init
+#endif
 
 /**
  * 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.
+ *   main() function. Changed if any arguments were handled.
+ * @argv: Address of the <parameter>argv</parameter> parameter of main(). 
+ *   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 
+ * 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.
  *
@@ -915,13 +953,13 @@ gtk_init (int *argc, char ***argv)
 {
   if (!gtk_init_check (argc, argv))
     {
-      char *display_name_arg = gdk_get_display_arg_name ();
+      const 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)
@@ -931,8 +969,9 @@ 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,\n"
-            "or that you are using an unsupported compiler.");
+            "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
@@ -949,8 +988,9 @@ check_sizeof_GtkBox (size_t sizeof_GtkBox)
             "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 switch,\n"
-            "or that you are using an unsupported compiler.");
+            "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
@@ -979,9 +1019,7 @@ gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof
 void
 gtk_exit (gint errorcode)
 {
-  /* Only if "gtk" has been initialized should we de-initialize.
-   */
-  gdk_exit (errorcode);
+  exit (errorcode);
 }
 
 
@@ -1003,25 +1041,91 @@ gtk_exit (gint errorcode)
  * <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 <function>setlocale()</function>.
+ * Returns: a string corresponding to the locale set, typically in the
+ * form lang_COUNTRY, where lang is an ISO-639 language code, and
+ * COUNTRY is an ISO-3166 country code. On Unix, this form matches the
+ * result of the setlocale(); it is also used on other machines, such as 
+ * Windows, where the C library returns a different result. The string is 
+ * owned by GTK+ and should not be modified or freed.
  **/
-gchar*
+gchar *
 gtk_set_locale (void)
 {
   return gdk_set_locale ();
 }
 
+/**
+ * _gtk_get_lc_ctype:
+ *
+ * Return the Unix-style locale string for the language currently in
+ * effect. On Unix systems, this is the return value from
+ * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
+ * affect this through the environment variables LC_ALL, LC_CTYPE or
+ * LANG (checked in that order). The locale strings typically is in
+ * the form lang_COUNTRY, where lang is an ISO-639 language code, and
+ * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
+ * Swedish as written in Finland or pt_BR for Portuguese as written in
+ * Brazil.
+ * 
+ * On Windows, the C library doesn't use any such environment
+ * variables, and setting them won't affect the behaviour of functions
+ * like ctime(). The user sets the locale through the Regional Options 
+ * in the Control Panel. The C library (in the setlocale() function) 
+ * does not use country and language codes, but country and language 
+ * names spelled out in English. 
+ * However, this function does check the above environment
+ * variables, and does return a Unix-style locale string based on
+ * either said environment variables or the thread's current locale.
+ *
+ * Return value: a dynamically allocated string, free with g_free().
+ */
+
+gchar *
+_gtk_get_lc_ctype (void)
+{
+#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, LC_CTYPE and LANG 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.)
+   */
+  gchar *p;
+
+  p = getenv ("LC_ALL");
+  if (p != NULL)
+    return g_strdup (p);
+
+  p = getenv ("LC_CTYPE");
+  if (p != NULL)
+    return g_strdup (p);
+
+  p = getenv ("LANG");
+  if (p != NULL)
+    return g_strdup (p);
+
+  return g_win32_getlocale ();
+#else
+  return g_strdup (setlocale (LC_CTYPE, NULL));
+#endif
+}
+
 /**
  * gtk_get_default_language:
  *
- * Returns the ISO language code for the default language currently in
+ * Returns the #PangoLanguage for the default language currently in
  * effect. (Note that this can change over the life of an
  * application.)  The default language is derived from the current
  * locale. It determines, for example, whether GTK+ uses the
- * right-to-left or left-to-right text direction.
+ * right-to-left or left-to-right text direction. See
+ * _gtk_get_lc_ctype() for notes on behaviour on Windows.
  * 
- * Return value: the default language as an allocated string, must be freed
+ * Return value: the default language as a #PangoLanguage, must not be
+ * freed
  **/
 PangoLanguage *
 gtk_get_default_language (void)
@@ -1030,7 +1134,7 @@ gtk_get_default_language (void)
   PangoLanguage *result;
   gchar *p;
   
-  lang = g_strdup (setlocale (LC_CTYPE, NULL));
+  lang = _gtk_get_lc_ctype ();
   p = strchr (lang, '.');
   if (p)
     *p = '\0';
@@ -1054,7 +1158,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;
@@ -1070,10 +1174,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 ();
     }
@@ -1117,7 +1221,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--;
 }
@@ -1133,16 +1237,16 @@ 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
+gboolean
 gtk_events_pending (void)
 {
   gboolean result;
   
   GDK_THREADS_LEAVE ();  
-  result = g_main_pending ();
+  result = g_main_context_pending (NULL);
   GDK_THREADS_ENTER ();
 
   return result;
@@ -1152,11 +1256,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;
 }
@@ -1165,11 +1269,11 @@ 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;
 }
@@ -1336,6 +1440,18 @@ gtk_main_do_event (GdkEvent *event)
   if (next_event)
     gdk_event_free (next_event);
 
+  if (event->type == GDK_SETTING)
+    {
+      _gtk_settings_handle_event (&event->setting);
+      return;
+    }
+
+  if (event->type == GDK_OWNER_CHANGE)
+    {
+      _gtk_clipboard_handle_event (&event->owner_change);
+      return;
+    }
+
   /* Find the widget which got the event. We store the widget
    *  in the user_data field of GdkWindow's.
    *  Ignore the event if we don't have a widget for it, except
@@ -1353,10 +1469,8 @@ gtk_main_do_event (GdkEvent *event)
           * them specially
           */
       if (event->type == GDK_PROPERTY_NOTIFY)
-       gtk_selection_incr_event (event->any.window,
-                                 &event->property);
-      else if (event->type == GDK_SETTING)
-       _gtk_settings_handle_event (&event->setting);
+       _gtk_selection_incr_event (event->any.window,
+                                  &event->property);
 
       return;
     }
@@ -1413,11 +1527,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:
@@ -1426,11 +1540,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;
       
@@ -1581,14 +1695,14 @@ gtk_grab_notify_foreach (GtkWidget *child,
 
   if (was_grabbed != is_grabbed)
     {
-      g_object_ref (G_OBJECT (child));
-      
-      gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
+      g_object_ref (child);
+
+      _gtk_widget_grab_notify (child, was_grabbed);
       
       if (GTK_IS_CONTAINER (child))
        gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
       
-      g_object_unref (G_OBJECT (child));
+      g_object_unref (child);
     }
 }
 
@@ -1647,7 +1761,7 @@ 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);
 
       gtk_grab_notify (group, widget, FALSE);
@@ -1680,7 +1794,7 @@ 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);
 
       gtk_grab_notify (group, widget, TRUE);
     }
@@ -1718,7 +1832,7 @@ gtk_key_snooper_install (GtkKeySnoopFunc snooper,
 }
 
 void
-gtk_key_snooper_remove (guint           snooper_id)
+gtk_key_snooper_remove (guint snooper_id)
 {
   GtkKeySnooperData *data = NULL;
   GSList *slist;
@@ -1734,7 +1848,10 @@ gtk_key_snooper_remove (guint             snooper_id)
       data = NULL;
     }
   if (data)
-    key_snoopers = g_slist_remove (key_snoopers, data);
+    {
+      key_snoopers = g_slist_remove (key_snoopers, data);
+      g_free (data);
+    }
 }
 
 static gint
@@ -1816,10 +1933,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);
 }
 
@@ -1947,7 +2064,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      
@@ -2022,7 +2139,7 @@ gtk_invoke_idle_timeout (gpointer data)
   GtkArg args[1];
   gint ret_val = FALSE;
   args[0].name = NULL;
-  args[0].type = GTK_TYPE_BOOL;
+  args[0].type = G_TYPE_BOOLEAN;
   args[0].d.pointer_data = &ret_val;
   closure->marshal (NULL, closure->data,  0, args);
   return ret_val;
@@ -2036,13 +2153,13 @@ gtk_invoke_input (gpointer          data,
   GtkClosure *closure = data;
 
   GtkArg args[3];
-  args[0].type = GTK_TYPE_INT;
+  args[0].type = G_TYPE_INT;
   args[0].name = NULL;
   GTK_VALUE_INT (args[0]) = source;
   args[1].type = GDK_TYPE_INPUT_CONDITION;
   args[1].name = NULL;
   GTK_VALUE_FLAGS (args[1]) = condition;
-  args[2].type = GTK_TYPE_NONE;
+  args[2].type = G_TYPE_NONE;
   args[2].name = NULL;
 
   closure->marshal (NULL, closure->data, 2, args);
@@ -2142,7 +2259,7 @@ gtk_quit_invoke_function (GtkQuitFunction *quitf)
       gint ret_val = FALSE;
 
       args[0].name = NULL;
-      args[0].type = GTK_TYPE_BOOL;
+      args[0].type = G_TYPE_BOOLEAN;
       args[0].d.pointer_data = &ret_val;
       ((GtkCallbackMarshal) quitf->marshal) (NULL,
                                             quitf->data,
@@ -2185,7 +2302,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))
@@ -2229,21 +2346,30 @@ gtk_propagate_event (GtkWidget *widget,
       while (TRUE)
        {
          GtkWidget *tmp;
-         
-         handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
+
+         /* Scroll events are special cased here because it
+          * feels wrong when scrolling a GtkViewport, say,
+          * to have children of the viewport eat the scroll
+          * event
+          */
+         if (!GTK_WIDGET_IS_SENSITIVE (widget))
+           handled_event = event->type != GDK_SCROLL;
+         else
+           handled_event = 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