X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmain.c;h=fead858f0f0db6128b32371cf5b2de3c67b725c1;hb=a9fd75f871c0d9b0887531c5a33bd392aaa68ac6;hp=9eeebb7ed4bd1a152c888fa52200d91c22ffbced;hpb=69915aa7104beebdcfbc6d42592481843069c403;p=~andy%2Fgtk diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 9eeebb7ed..fead858f0 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -38,21 +38,27 @@ #include #ifdef G_OS_UNIX #include +#include /* For uid_t, gid_t */ +#endif +#ifdef G_OS_WIN32 +#define STRICT +#include +#undef STRICT #endif #include /* 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 setlocale (LC_ALL, ""). 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 (>k_argc, >k_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 argc parameter of your + * main() function. Changed if any arguments were + * handled. + * @argv: Address of the argv 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 + * 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 argc parameter of your + * main() function. Changed if any arguments were + * handled. + * @argv: Address of the argv 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 + * @argv are adjusted accordingly so your own code will + * never see those standard arguments. + * + * + * 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. + * + **/ 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 + * setlocale (LC_ALL, "") 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 setlocale(). **/ 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