]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Don't add attributes with empty ranges. (fixes #101564 and #80637)
[~andy/gtk] / gtk / gtkmain.c
index eb33e039f227c035b8fe286099fadf1fd0388df0..10b5f276cbbdeb73eb2e02ed8b61b75e8359810e 100644 (file)
@@ -56,7 +56,6 @@
 #include "gtkrc.h"
 #include "gtkselection.h"
 #include "gtksettings.h"
-#include "gtksignal.h"
 #include "gtkwidget.h"
 #include "gtkwindow.h"
 #include "gtkprivate.h"
@@ -70,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
 {
@@ -101,6 +101,12 @@ struct _GtkKeySnooperData
   guint id;
 };
 
+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,
@@ -127,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;
@@ -163,17 +176,16 @@ 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;
 }
@@ -466,10 +478,11 @@ find_module (const gchar *name)
 }
 
 static GSList *
-load_module (GSList      *gtk_modules,
+load_module (GSList      *module_list,
             const gchar *name)
 {
   GtkModuleInitFunc modinit_func = NULL;
+  GtkModuleInfo *info;
   GModule *module = NULL;
   
   if (g_module_supported ())
@@ -479,11 +492,16 @@ load_module (GSList      *gtk_modules,
          g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
          modinit_func)
        {
-         if (!g_slist_find (gtk_modules, (gconstpointer) modinit_func))
+         if (!g_slist_find (module_list, (gconstpointer) modinit_func))
            {
              g_module_make_resident (module);
-             gtk_modules = g_slist_prepend (gtk_modules,
-                                            (gpointer) 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
            {
@@ -501,24 +519,24 @@ 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_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_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);
 
-  return gtk_modules;
+  return module_list;
 }
 
 static gboolean do_setlocale = TRUE;
@@ -545,13 +563,75 @@ gtk_disable_setlocale (void)
 
 #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;
+  GdkDisplayManager *display_manager;
   const gchar *env_string;
 
   if (gtk_initialized)
@@ -572,13 +652,8 @@ gtk_init_check (int         *argc,
       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
-   */
-  if (!gdk_init_check (argc, argv))
-    return FALSE;
 
+  gdk_parse_args (argc, argv);
   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
   
 #ifdef G_ENABLE_DEBUG
@@ -697,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)
@@ -738,37 +818,95 @@ gtk_init_check (int        *argc,
    */
   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 = (GtkModuleInitFunc) slist->data;
-         modinit (argc, argv);
+         GtkModuleInfo *info = slist->data;
+
+         if (info->display_init_func)
+           info->init_func (argc, argv);
        }
     }
-  g_slist_free (gtk_modules);
   
   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)
+{
+  if (!gtk_parse_args (argc, argv))
+    return FALSE;
+
+  return gdk_display_open_default_libgtk_only () != NULL;
+}
+
 #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))
     {
-      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)
@@ -778,8 +916,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
@@ -796,8 +935,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
@@ -826,9 +966,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);
 }
 
 
@@ -877,7 +1015,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';
@@ -901,7 +1069,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;
@@ -917,10 +1085,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 ();
     }
@@ -964,7 +1132,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--;
 }
@@ -980,7 +1148,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
@@ -989,7 +1157,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;
@@ -999,11 +1167,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;
 }
@@ -1012,11 +1180,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;
 }
@@ -1183,6 +1351,12 @@ 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;
+    }
+
   /* 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
@@ -1200,10 +1374,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;
     }
@@ -1260,11 +1432,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:
@@ -1273,11 +1445,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;
       
@@ -1428,14 +1600,14 @@ gtk_grab_notify_foreach (GtkWidget *child,
 
   if (was_grabbed != is_grabbed)
     {
-      g_object_ref (G_OBJECT (child));
+      g_object_ref (child);
       
-      gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
+      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);
       
-      g_object_unref (G_OBJECT (child));
+      g_object_unref (child);
     }
 }
 
@@ -1494,7 +1666,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);
@@ -1527,7 +1699,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);
     }
@@ -1663,10 +1835,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);
 }
 
@@ -1794,7 +1966,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      
@@ -1869,7 +2041,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;
@@ -1883,13 +2055,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);
@@ -1989,7 +2161,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,
@@ -2032,7 +2204,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))
@@ -2079,18 +2251,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