]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkmain.c
Support added for building using a GNU toolchain on Win32,
[~andy/gtk] / gtk / gtkmain.c
index 949aab3c4749df4fee7d95b90d88af2178fced9d..fa558da93a7656d68e4c5ea5cf18209d86fcabad 100644 (file)
  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  */
+
+/*
+ * Modified by the GTK+ Team and others 1997-1999.  See the AUTHORS
+ * file for a list of people on the GTK+ Team.  See the ChangeLog
+ * files for a list of changes.  These files are distributed with
+ * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
+ */
+
+#include "gdkx.h"              /* For GDK_WINDOWING */
+
+#if GDK_WINDOWING == GDK_WINDOWING_X11
 #include <X11/Xlocale.h>       /* so we get the right setlocale */
+#else
+#include <locale.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <gmodule.h>
 #include "gtkbutton.h"
 #include "gtkdnd.h"
-#include "gtkfeatures.h"
+#include "gtkcompat.h"
 #include "gtkhscrollbar.h"
 #include "gtkhseparator.h"
 #include "gtkmain.h"
 #include "gtkpreview.h"
 #include "gtkrc.h"
+#include "gtkscrolledwindow.h"
 #include "gtkselection.h"
 #include "gtksignal.h"
 #include "gtktable.h"
@@ -85,8 +100,6 @@ static gint  gtk_quit_invoke_function         (GtkQuitFunction    *quitf);
 static void  gtk_quit_destroy           (GtkQuitFunction    *quitf);
 static gint  gtk_invoke_key_snoopers    (GtkWidget          *grab_widget,
                                          GdkEvent           *event);
-static void  gtk_propagate_event        (GtkWidget          *widget,
-                                         GdkEvent           *event);
 
 static void     gtk_destroy_closure      (gpointer            data);
 static gboolean gtk_invoke_idle_timeout  (gpointer            data);
@@ -133,14 +146,13 @@ static GdkColormap *gtk_colormap;    /* The colormap to be used in creating new
 
 guint gtk_debug_flags = 0;                /* Global GTK debug flag */
 
-GMutex *gtk_threads_mutex = NULL;          /* Global GTK lock */
-
 #ifdef G_ENABLE_DEBUG
 static const GDebugKey gtk_debug_keys[] = {
   {"objects", GTK_DEBUG_OBJECTS},
   {"misc", GTK_DEBUG_MISC},
   {"signals", GTK_DEBUG_SIGNALS},
-  {"dnd", GTK_DEBUG_DND}
+  {"dnd", GTK_DEBUG_DND},
+  {"plugsocket", GTK_DEBUG_PLUGSOCKET}
 };
 
 static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
@@ -153,41 +165,48 @@ gtk_check_version (guint required_major,
                   guint required_micro)
 {
   if (required_major > GTK_MAJOR_VERSION)
-    return "Gtk+ version to old (major mismatch)";
+    return "Gtk+ version too old (major mismatch)";
   if (required_major < GTK_MAJOR_VERSION)
-    return "Gtk+ version to new (major mismatch)";
+    return "Gtk+ version too new (major mismatch)";
   if (required_minor > GTK_MINOR_VERSION)
-    return "Gtk+ version to old (minor mismatch)";
+    return "Gtk+ version too old (minor mismatch)";
   if (required_minor < GTK_MINOR_VERSION)
-    return "Gtk+ version to new (minor mismatch)";
+    return "Gtk+ version too new (minor mismatch)";
   if (required_micro < GTK_MICRO_VERSION - GTK_BINARY_AGE)
-    return "Gtk+ version to new (micro mismatch)";
+    return "Gtk+ version too new (micro mismatch)";
   if (required_micro > GTK_MICRO_VERSION)
-    return "Gtk+ version to old (micro mismatch)";
+    return "Gtk+ version too old (micro mismatch)";
   return NULL;
 }
 
+#ifdef __EMX__
+static gchar *add_dll_suffix(gchar *module_name)
+{
+    gchar *suffix = strrchr(module_name, '.');
+    
+    if (!suffix || stricmp(suffix, ".dll"))
+    {
+       gchar *old = module_name;
+         
+       module_name = g_strconcat (module_name, ".dll", NULL);
+       g_free (old);
+    }
+    return (module_name);
+}
+#endif
 
-void
-gtk_init (int   *argc,
-         char ***argv)
+gboolean
+gtk_init_check (int     *argc,
+               char   ***argv)
 {
+  extern void gtk_object_post_arg_parsing_init (void);
   GSList *gtk_modules = NULL;
   GSList *slist;
   gchar *env_string = NULL;
 
   if (gtk_initialized)
-    return;
-
-  /* There is some argument for putting this in a separate
-   * function ... but I don't think that it is much
-   * of a restriction to require that GTK+ be used
-   * single threaded until gtk_init().
-   */
+    return TRUE;
 
-  if (g_thread_supported ())
-    gtk_threads_mutex = g_mutex_new ();
-  
 #if    0
   g_set_error_handler (gtk_error);
   g_set_warning_handler (gtk_warning);
@@ -198,7 +217,8 @@ gtk_init (int        *argc,
   /* Initialize "gdk". We pass along the 'argc' and 'argv'
    *  parameters as they contain information that GDK uses
    */
-  gdk_init (argc, argv);
+  if (!gdk_init_check (argc, argv))
+    return FALSE;
 
   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
   
@@ -218,7 +238,11 @@ gtk_init (int       *argc,
     {
       gchar **modules, **as;
 
-      modules = g_strsplit (env_string, ":", -1);
+#ifndef __EMX__
+      modules = g_strsplit (env_string, G_SEARCHPATH_SEPARATOR_S, -1);
+#else
+      modules = g_strsplit (env_string, ";", -1);
+#endif
       for (as = modules; *as; as++)
        {
          if (**as)
@@ -335,16 +359,17 @@ gtk_init (int      *argc,
       
       module_name = slist->data;
       slist->data = NULL;
-      if (!(module_name[0] == '/' ||
-           (module_name[0] == 'l' &&
-            module_name[1] == 'i' &&
-            module_name[2] == 'b')))
+#ifndef __EMX__
+      if (!g_path_is_absolute (module_name))
        {
          gchar *old = module_name;
          
-         module_name = g_strconcat ("lib", module_name, ".so", NULL);
+         module_name = g_module_build_path (NULL, module_name);
          g_free (old);
        }
+#else
+      module_name = add_dll_suffix(module_name);
+#endif
       if (g_module_supported ())
        {
          module = g_module_open (module_name, G_MODULE_BIND_LAZY);
@@ -376,7 +401,7 @@ gtk_init (int        *argc,
     }
 
 #ifdef ENABLE_NLS
-  bindtextdomain("gtk+",GTK_LOCALEDIR);
+  bindtextdomain("gtk+", GTK_LOCALEDIR);
 #endif  
 
   /* Initialize the default visual and colormap to be
@@ -387,6 +412,7 @@ gtk_init (int        *argc,
   gtk_colormap = gdk_colormap_get_system ();
 
   gtk_type_init ();
+  gtk_object_post_arg_parsing_init ();
   gtk_signal_init ();
   gtk_rc_init ();
   
@@ -412,6 +438,27 @@ gtk_init (int       *argc,
        }
     }
   g_slist_free (gtk_modules);
+  
+#ifndef NATIVE_WIN32
+  /* No use warning on Win32, there aren't any non-devel versions anyhow... */
+  g_warning (""              "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;
+}
+void
+gtk_init (int *argc, char ***argv)
+{
+  if (!gtk_init_check (argc, argv))
+    {
+      g_warning ("cannot open display: %s", gdk_get_display ());
+      exit(1);
+    }
 }
 
 void
@@ -437,12 +484,13 @@ gtk_main (void)
   GList *tmp_list;
   GList *functions;
   GtkInitFunction *init;
-
   GMainLoop *loop;
-  GSList *tmp_node;
 
   gtk_main_loop_level++;
   
+  loop = g_main_new (TRUE);
+  main_loops = g_slist_prepend (main_loops, loop);
+
   tmp_list = functions = init_functions;
   init_functions = NULL;
   
@@ -455,19 +503,14 @@ gtk_main (void)
       g_free (init);
     }
   g_list_free (functions);
-  
-  loop = g_main_new ();
-  main_loops = g_slist_prepend (main_loops, loop);
 
-  GTK_THREADS_LEAVE ();
-  g_main_run (loop);
-  GTK_THREADS_ENTER ();
-  
-  g_main_destroy (loop);
-
-  tmp_node = main_loops;
-  main_loops = g_slist_remove_link (main_loops, main_loops);
-  g_slist_free_1 (tmp_node);
+  if (g_main_is_running (main_loops->data))
+    {
+      GDK_THREADS_LEAVE ();
+      g_main_run (loop);
+      GDK_THREADS_ENTER ();
+      gdk_flush ();
+    }
 
   if (quit_functions)
     {
@@ -501,8 +544,14 @@ gtk_main (void)
          work->next = quit_functions;
          quit_functions = work;
        }
+
+      gdk_flush ();
     }
              
+  main_loops = g_slist_remove (main_loops, loop);
+
+  g_main_destroy (loop);
+
   gtk_main_loop_level--;
 }
 
@@ -515,6 +564,8 @@ gtk_main_level (void)
 void
 gtk_main_quit (void)
 {
+  g_return_if_fail (main_loops != NULL);
+
   g_main_quit (main_loops->data);
 }
 
@@ -527,13 +578,23 @@ gtk_events_pending (void)
 gint 
 gtk_main_iteration (void)
 {
-  return g_main_iteration (TRUE);
+  g_main_iteration (TRUE);
+
+  if (main_loops)
+    return !g_main_is_running (main_loops->data);
+  else
+    return TRUE;
 }
 
 gint 
 gtk_main_iteration_do (gboolean blocking)
 {
-  return g_main_iteration (blocking);
+  g_main_iteration (blocking);
+
+  if (main_loops)
+    return !g_main_is_running (main_loops->data);
+  else
+    return TRUE;
 }
 
 void 
@@ -546,7 +607,7 @@ gtk_main_do_event (GdkEvent *event)
 
   /* If there are any events pending then get the next one.
    */
-  next_event = gdk_event_get ();
+  next_event = gdk_event_peek ();
   
   /* Try to compress enter/leave notify events. These event
    *  pairs occur when the mouse is dragged quickly across
@@ -564,16 +625,17 @@ gtk_main_do_event (GdkEvent *event)
        (next_event->type != event->type) &&
        (next_event->any.window == event->any.window))
       {
+       /* Throw both the peeked copy and the queued copy away 
+        */
+       gdk_event_free (next_event);
+       next_event = gdk_event_get ();
        gdk_event_free (next_event);
-       next_event = NULL;
        
        return;
       }
-  
 
   if (next_event)
-    gdk_event_put (next_event);
-  next_event = NULL;
+    gdk_event_free (next_event);
 
   /* Find the widget which got the event. We store the widget
    *  in the user_data field of GdkWindow's.
@@ -621,7 +683,7 @@ gtk_main_do_event (GdkEvent *event)
     {
       grab_widget = event_widget;
     }
-  
+
   /* Not all events get sent to the grabbing widget.
    * The delete, destroy, expose, focus change and resize
    *  events still get sent to the event widget because
@@ -667,7 +729,49 @@ gtk_main_do_event (GdkEvent *event)
     case GDK_VISIBILITY_NOTIFY:
       gtk_widget_event (event_widget, event);
       break;
-      
+
+    case GDK_BUTTON_PRESS:
+    case GDK_2BUTTON_PRESS:
+    case GDK_3BUTTON_PRESS:
+    /* We treat button 4-5 specially, assume we have
+     * a MS-style scrollwheel mouse, and try to find
+     * a plausible widget to scroll. We also trap
+     * button 4-5 double and triple clicks here, since
+     * they will be generated if the user scrolls quickly.
+     */
+      if ((grab_widget == event_widget) &&
+         (event->button.button == 4 || event->button.button == 5))
+       {
+         GtkWidget *range = NULL;
+         GtkWidget *scrollwin;
+         
+         if (GTK_IS_RANGE (event_widget))
+           range = event_widget;
+         else
+           {
+             scrollwin = gtk_widget_get_ancestor (event_widget,
+                                                  GTK_TYPE_SCROLLED_WINDOW);
+             if (scrollwin)
+               range = GTK_SCROLLED_WINDOW (scrollwin)->vscrollbar;
+           }
+         
+         if (range && GTK_WIDGET_VISIBLE (range))
+           {
+             if (event->type == GDK_BUTTON_PRESS)
+               {
+                 GtkAdjustment *adj = GTK_RANGE (range)->adjustment;
+                 gfloat new_value = adj->value + ((event->button.button == 4) ? 
+                                                  -adj->page_increment / 2: 
+                                                   adj->page_increment / 2);
+                 new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
+                 gtk_adjustment_set_value (adj, new_value);
+               }
+             break;
+           }
+       }
+      gtk_propagate_event (grab_widget, event);
+      break;
+
     case GDK_KEY_PRESS:
     case GDK_KEY_RELEASE:
       if (key_snoopers)
@@ -677,9 +781,6 @@ gtk_main_do_event (GdkEvent *event)
        }
       /* else fall through */
     case GDK_MOTION_NOTIFY:
-    case GDK_BUTTON_PRESS:
-    case GDK_2BUTTON_PRESS:
-    case GDK_3BUTTON_PRESS:
     case GDK_BUTTON_RELEASE:
     case GDK_PROXIMITY_IN:
     case GDK_PROXIMITY_OUT:
@@ -997,15 +1098,6 @@ gtk_timeout_add (guint32     interval,
   return g_timeout_add_full (0, interval, function, data, NULL);
 }
 
-guint
-gtk_timeout_add_interp (guint32                   interval,
-                       GtkCallbackMarshal function,
-                       gpointer           data,
-                       GtkDestroyNotify   destroy)
-{
-  return gtk_timeout_add_full (interval, NULL, function, data, destroy);
-}
-
 void
 gtk_timeout_remove (guint tag)
 {
@@ -1052,14 +1144,6 @@ gtk_idle_add_priority    (gint               priority,
   return g_idle_add_full (priority, function, data, NULL);
 }
 
-guint
-gtk_idle_add_interp  (GtkCallbackMarshal   marshal,
-                     gpointer             data,
-                     GtkDestroyNotify     destroy)
-{
-  return gtk_idle_add_full (GTK_PRIORITY_DEFAULT, NULL, marshal, data, destroy);
-}
-
 void
 gtk_idle_remove (guint tag)
 {
@@ -1069,7 +1153,8 @@ gtk_idle_remove (guint tag)
 void
 gtk_idle_remove_by_data (gpointer data)
 {
-  g_source_remove_by_user_data (data);
+  if (!g_idle_remove_by_data (data))
+    g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
 }
 
 guint
@@ -1201,13 +1286,14 @@ gtk_quit_invoke_function (GtkQuitFunction *quitf)
     }
 }
 
-static void
+void
 gtk_propagate_event (GtkWidget *widget,
                     GdkEvent  *event)
 {
   gint handled_event;
   
   g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_WIDGET (widget));
   g_return_if_fail (event != NULL);
   
   handled_event = FALSE;
@@ -1222,7 +1308,7 @@ gtk_propagate_event (GtkWidget *widget,
        */
       GtkWidget *window;
 
-      window = gtk_widget_get_ancestor (widget, gtk_window_get_type ());
+      window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
       if (window)
         {
          if (GTK_WIDGET_IS_SENSITIVE (window))
@@ -1248,18 +1334,6 @@ gtk_propagate_event (GtkWidget *widget,
     }
 }
 
-void
-gtk_threads_enter ()
-{
-  GTK_THREADS_ENTER ();
-}
-
-void
-gtk_threads_leave ()
-{
-  GTK_THREADS_LEAVE ();
-}
-
 #if 0
 static void
 gtk_error (gchar *str)