1 /* GTK - The GIMP Toolkit
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GTK+ Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
30 #include "gdkconfig.h"
40 #include <sys/types.h> /* For uid_t, gid_t */
50 #include "gtkaccelmap.h"
52 #include "gtkclipboard.h"
54 #include "gtkversion.h"
56 #include "gtkmodules.h"
58 #include "gtkrecentmanager.h"
59 #include "gtkselection.h"
60 #include "gtksettings.h"
61 #include "gtkwidget.h"
62 #include "gtkwindow.h"
63 #include "gtktooltip.h"
66 #include "gdk/gdkkeysyms.h"
68 #include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */
72 static HMODULE gtk_dll;
75 DllMain (HINSTANCE hinstDLL,
81 case DLL_PROCESS_ATTACH:
82 gtk_dll = (HMODULE) hinstDLL;
89 /* These here before inclusion of gtkprivate.h so that the original
90 * GTK_LIBDIR and GTK_LOCALEDIR definitions are seen. Yeah, this is a
94 _gtk_get_libdir (void)
96 static char *gtk_libdir = NULL;
97 if (gtk_libdir == NULL)
99 gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
100 gchar *slash = strrchr (root, '\\');
101 if (g_ascii_strcasecmp (slash + 1, ".libs") == 0)
102 gtk_libdir = GTK_LIBDIR;
104 gtk_libdir = g_build_filename (root, "lib", NULL);
112 _gtk_get_localedir (void)
114 static char *gtk_localedir = NULL;
115 if (gtk_localedir == NULL)
120 /* GTK_LOCALEDIR ends in either /lib/locale or
121 * /share/locale. Scan for that slash.
123 p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
129 root = g_win32_get_package_installation_directory_of_module (gtk_dll);
130 temp = g_build_filename (root, p, NULL);
133 /* gtk_localedir is passed to bindtextdomain() which isn't
136 gtk_localedir = g_win32_locale_filename_from_utf8 (temp);
139 return gtk_localedir;
144 #include "gtkprivate.h"
146 /* Private type definitions
148 typedef struct _GtkInitFunction GtkInitFunction;
149 typedef struct _GtkQuitFunction GtkQuitFunction;
150 typedef struct _GtkKeySnooperData GtkKeySnooperData;
152 struct _GtkInitFunction
154 GtkFunction function;
158 struct _GtkQuitFunction
162 GtkCallbackMarshal marshal;
163 GtkFunction function;
165 GDestroyNotify destroy;
168 struct _GtkKeySnooperData
170 GtkKeySnoopFunc func;
175 static gint gtk_quit_invoke_function (GtkQuitFunction *quitf);
176 static void gtk_quit_destroy (GtkQuitFunction *quitf);
177 static gint gtk_invoke_key_snoopers (GtkWidget *grab_widget,
180 static GtkWindowGroup *gtk_main_get_window_group (GtkWidget *widget);
182 const guint gtk_major_version = GTK_MAJOR_VERSION;
183 const guint gtk_minor_version = GTK_MINOR_VERSION;
184 const guint gtk_micro_version = GTK_MICRO_VERSION;
185 const guint gtk_binary_age = GTK_BINARY_AGE;
186 const guint gtk_interface_age = GTK_INTERFACE_AGE;
188 static guint gtk_main_loop_level = 0;
189 static gint pre_initialized = FALSE;
190 static gint gtk_initialized = FALSE;
191 static GList *current_events = NULL;
193 static GSList *main_loops = NULL; /* stack of currently executing main loops */
195 static GList *init_functions = NULL; /* A list of init functions.
197 static GList *quit_functions = NULL; /* A list of quit functions.
199 static GSList *key_snoopers = NULL;
201 guint gtk_debug_flags = 0; /* Global GTK debug flag */
203 #ifdef G_ENABLE_DEBUG
204 static const GDebugKey gtk_debug_keys[] = {
205 {"misc", GTK_DEBUG_MISC},
206 {"plugsocket", GTK_DEBUG_PLUGSOCKET},
207 {"text", GTK_DEBUG_TEXT},
208 {"tree", GTK_DEBUG_TREE},
209 {"updates", GTK_DEBUG_UPDATES},
210 {"keybindings", GTK_DEBUG_KEYBINDINGS},
211 {"multihead", GTK_DEBUG_MULTIHEAD},
212 {"modules", GTK_DEBUG_MODULES},
213 {"geometry", GTK_DEBUG_GEOMETRY},
214 {"icontheme", GTK_DEBUG_ICONTHEME},
215 {"printing", GTK_DEBUG_PRINTING},
216 {"builder", GTK_DEBUG_BUILDER},
217 {"size-request", GTK_DEBUG_SIZE_REQUEST},
219 #endif /* G_ENABLE_DEBUG */
223 * @required_major: the required major version.
224 * @required_minor: the required minor version.
225 * @required_micro: the required micro version.
227 * Checks that the GTK+ library in use is compatible with the
228 * given version. Generally you would pass in the constants
229 * #GTK_MAJOR_VERSION, #GTK_MINOR_VERSION, #GTK_MICRO_VERSION
230 * as the three arguments to this function; that produces
231 * a check that the library in use is compatible with
232 * the version of GTK+ the application or module was compiled
235 * Compatibility is defined by two things: first the version
236 * of the running library is newer than the version
237 * @required_major.required_minor.@required_micro. Second
238 * the running library must be binary compatible with the
239 * version @required_major.required_minor.@required_micro
240 * (same major version.)
242 * This function is primarily for GTK+ modules; the module
243 * can call this function to check that it wasn't loaded
244 * into an incompatible version of GTK+. However, such a
245 * a check isn't completely reliable, since the module may be
246 * linked against an old version of GTK+ and calling the
247 * old version of gtk_check_version(), but still get loaded
248 * into an application using a newer version of GTK+.
250 * Return value: %NULL if the GTK+ library is compatible with the
251 * given version, or a string describing the version mismatch.
252 * The returned string is owned by GTK+ and should not be modified
256 gtk_check_version (guint required_major,
257 guint required_minor,
258 guint required_micro)
260 gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
261 gint required_effective_micro = 100 * required_minor + required_micro;
263 if (required_major > GTK_MAJOR_VERSION)
264 return "Gtk+ version too old (major mismatch)";
265 if (required_major < GTK_MAJOR_VERSION)
266 return "Gtk+ version too new (major mismatch)";
267 if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
268 return "Gtk+ version too new (micro mismatch)";
269 if (required_effective_micro > gtk_effective_micro)
270 return "Gtk+ version too old (micro mismatch)";
274 /* This checks to see if the process is running suid or sgid
275 * at the current time. If so, we don't allow GTK+ to be initialized.
276 * This is meant to be a mild check - we only error out if we
277 * can prove the programmer is doing something wrong, not if
278 * they could be doing something wrong. For this reason, we
279 * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
284 /* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
286 uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
287 gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
289 #ifdef HAVE_GETRESUID
290 /* These aren't in the header files, so we prototype them here.
292 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
293 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
295 if (getresuid (&ruid, &euid, &suid) != 0 ||
296 getresgid (&rgid, &egid, &sgid) != 0)
297 #endif /* HAVE_GETRESUID */
299 suid = ruid = getuid ();
300 sgid = rgid = getgid ();
305 if (ruid != euid || ruid != suid ||
306 rgid != egid || rgid != sgid)
308 g_warning ("This process is currently running setuid or setgid.\n"
309 "This is not a supported use of GTK+. You must create a helper\n"
310 "program instead. For further details, see:\n\n"
311 " http://www.gtk.org/setuid.html\n\n"
312 "Refusing to initialize GTK+.");
322 _gtk_get_datadir (void)
324 static char *gtk_datadir = NULL;
325 if (gtk_datadir == NULL)
327 gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
328 gtk_datadir = g_build_filename (root, "share", NULL);
336 _gtk_get_sysconfdir (void)
338 static char *gtk_sysconfdir = NULL;
339 if (gtk_sysconfdir == NULL)
341 gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
342 gtk_sysconfdir = g_build_filename (root, "etc", NULL);
346 return gtk_sysconfdir;
350 _gtk_get_data_prefix (void)
352 static char *gtk_data_prefix = NULL;
353 if (gtk_data_prefix == NULL)
354 gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
356 return gtk_data_prefix;
359 #endif /* G_OS_WIN32 */
361 static gboolean do_setlocale = TRUE;
364 * gtk_disable_setlocale:
366 * Prevents gtk_init(), gtk_init_check(), gtk_init_with_args() and
367 * gtk_parse_args() from automatically
368 * calling <literal>setlocale (LC_ALL, "")</literal>. You would
369 * want to use this function if you wanted to set the locale for
370 * your program to something other than the user's locale, or if
371 * you wanted to set different values for different locale categories.
373 * Most programs should not need to call this function.
376 gtk_disable_setlocale (void)
379 g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
381 do_setlocale = FALSE;
384 #ifdef G_PLATFORM_WIN32
385 #undef gtk_init_check
388 static GString *gtk_modules_string = NULL;
389 static gboolean g_fatal_warnings = FALSE;
391 #ifdef G_ENABLE_DEBUG
393 gtk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
395 gtk_debug_flags |= g_parse_debug_string (value,
397 G_N_ELEMENTS (gtk_debug_keys));
403 gtk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
405 gtk_debug_flags &= ~g_parse_debug_string (value,
407 G_N_ELEMENTS (gtk_debug_keys));
411 #endif /* G_ENABLE_DEBUG */
414 gtk_arg_module_cb (const char *key, const char *value, gpointer user_data)
418 if (gtk_modules_string)
419 g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
421 gtk_modules_string = g_string_new (NULL);
423 g_string_append (gtk_modules_string, value);
429 static const GOptionEntry gtk_args[] = {
430 { "gtk-module", 0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_module_cb,
431 /* Description of --gtk-module=MODULES in --help output */ N_("Load additional GTK+ modules"),
432 /* Placeholder in --gtk-module=MODULES in --help output */ N_("MODULES") },
433 { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings,
434 /* Description of --g-fatal-warnings in --help output */ N_("Make all warnings fatal"), NULL },
435 #ifdef G_ENABLE_DEBUG
436 { "gtk-debug", 0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_debug_cb,
437 /* Description of --gtk-debug=FLAGS in --help output */ N_("GTK+ debugging flags to set"),
438 /* Placeholder in --gtk-debug=FLAGS in --help output */ N_("FLAGS") },
439 { "gtk-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_no_debug_cb,
440 /* Description of --gtk-no-debug=FLAGS in --help output */ N_("GTK+ debugging flags to unset"),
441 /* Placeholder in --gtk-no-debug=FLAGS in --help output */ N_("FLAGS") },
448 static char *iso639_to_check = NULL;
449 static char *iso3166_to_check = NULL;
450 static char *script_to_check = NULL;
451 static gboolean setlocale_called = FALSE;
454 enum_locale_proc (LPTSTR locale)
462 lcid = strtoul (locale, &endptr, 16);
463 if (*endptr == '\0' &&
464 GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
465 GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
467 if (strcmp (iso639, iso639_to_check) == 0 &&
468 ((iso3166_to_check != NULL &&
469 strcmp (iso3166, iso3166_to_check) == 0) ||
470 (iso3166_to_check == NULL &&
471 SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
473 char language[100], country[100];
476 if (script_to_check != NULL)
478 /* If lcid is the "other" script for this language,
479 * return TRUE, i.e. continue looking.
481 if (strcmp (script_to_check, "Latn") == 0)
483 switch (LANGIDFROMLCID (lcid))
485 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
487 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
489 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
491 case MAKELANGID (LANG_SERBIAN, 0x07):
492 /* Serbian in Bosnia and Herzegovina, Cyrillic */
496 else if (strcmp (script_to_check, "Cyrl") == 0)
498 switch (LANGIDFROMLCID (lcid))
500 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
502 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
504 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
506 case MAKELANGID (LANG_SERBIAN, 0x06):
507 /* Serbian in Bosnia and Herzegovina, Latin */
513 SetThreadLocale (lcid);
515 if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
516 GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
518 strcpy (locale, language);
519 strcat (locale, "_");
520 strcat (locale, country);
522 if (setlocale (LC_ALL, locale) != NULL)
523 setlocale_called = TRUE;
536 setlocale_initialization (void)
538 static gboolean initialized = FALSE;
547 /* If some of the POSIXish environment variables are set, set
548 * the Win32 thread locale correspondingly.
550 char *p = getenv ("LC_ALL");
557 if (strcmp (p, "C") == 0)
558 SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
561 /* Check if one of the supported locales match the
562 * environment variable. If so, use that locale.
565 iso3166_to_check = strchr (iso639_to_check, '_');
566 if (iso3166_to_check != NULL)
568 *iso3166_to_check++ = '\0';
570 script_to_check = strchr (iso3166_to_check, '@');
571 if (script_to_check != NULL)
572 *script_to_check++ = '\0';
574 /* Handle special cases. */
576 /* The standard code for Serbia and Montenegro was
577 * "CS", but MSFT uses for some reason "SP". By now
578 * (October 2006), SP has split into two, "RS" and
579 * "ME", but don't bother trying to handle those
580 * yet. Do handle the even older "YU", though.
582 if (strcmp (iso3166_to_check, "CS") == 0 ||
583 strcmp (iso3166_to_check, "YU") == 0)
584 iso3166_to_check = "SP";
588 script_to_check = strchr (iso639_to_check, '@');
589 if (script_to_check != NULL)
590 *script_to_check++ = '\0';
591 /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
592 if (strcmp (iso639_to_check, "sr") == 0)
593 iso3166_to_check = "SP";
596 EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
600 if (!setlocale_called)
601 setlocale (LC_ALL, "");
603 if (!setlocale (LC_ALL, ""))
604 g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
610 check_mixed_deps (void)
615 module = g_module_open (NULL, 0);
617 if (g_module_symbol (module, "gtk_progress_get_type", &func))
619 g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
622 g_module_close (module);
626 do_pre_parse_initialization (int *argc,
629 const gchar *env_string;
634 pre_initialized = TRUE;
638 gdk_pre_parse_libgtk_only ();
639 gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
641 #ifdef G_ENABLE_DEBUG
642 env_string = g_getenv ("GTK_DEBUG");
643 if (env_string != NULL)
645 gtk_debug_flags = g_parse_debug_string (env_string,
647 G_N_ELEMENTS (gtk_debug_keys));
650 #endif /* G_ENABLE_DEBUG */
652 env_string = g_getenv ("GTK_MODULES");
654 gtk_modules_string = g_string_new (env_string);
658 gettext_initialization (void)
660 setlocale_initialization ();
663 bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
664 bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
665 # ifdef HAVE_BIND_TEXTDOMAIN_CODESET
666 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
667 bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
673 do_post_parse_initialization (int *argc,
679 gettext_initialization ();
682 signal (SIGPIPE, SIG_IGN);
685 if (g_fatal_warnings)
687 GLogLevelFlags fatal_mask;
689 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
690 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
691 g_log_set_always_fatal (fatal_mask);
694 if (gtk_debug_flags & GTK_DEBUG_UPDATES)
695 gdk_window_set_debug_updates (TRUE);
698 /* Translate to default:RTL if you want your widgets
699 * to be RTL, otherwise translate to default:LTR.
700 * Do *not* translate it to "predefinito:LTR", if it
701 * it isn't default:LTR or default:RTL it will not work
703 char *e = _("default:LTR");
704 if (strcmp (e, "default:RTL")==0)
705 gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
706 else if (strcmp (e, "default:LTR"))
707 g_warning ("Whoever translated default:LTR did so wrongly.\n");
710 /* do what the call to gtk_type_init() used to do */
713 _gtk_accel_map_init ();
716 /* Set the 'initialized' flag.
718 gtk_initialized = TRUE;
720 /* load gtk modules */
721 if (gtk_modules_string)
723 _gtk_modules_init (argc, argv, gtk_modules_string->str);
724 g_string_free (gtk_modules_string, TRUE);
728 _gtk_modules_init (argc, argv, NULL);
735 gboolean open_default_display;
739 pre_parse_hook (GOptionContext *context,
744 do_pre_parse_initialization (NULL, NULL);
750 post_parse_hook (GOptionContext *context,
755 OptionGroupInfo *info = data;
758 do_post_parse_initialization (NULL, NULL);
760 if (info->open_default_display)
762 if (gdk_display_open_default_libgtk_only () == NULL)
764 const char *display_name = gdk_get_display_arg_name ();
767 G_OPTION_ERROR_FAILED,
768 _("Cannot open display: %s"),
769 display_name ? display_name : "" );
780 * gtk_get_option_group:
781 * @open_default_display: whether to open the default display
782 * when parsing the commandline arguments
784 * Returns a #GOptionGroup for the commandline arguments recognized
785 * by GTK+ and GDK. You should add this group to your #GOptionContext
786 * with g_option_context_add_group(), if you are using
787 * g_option_context_parse() to parse your commandline arguments.
789 * Returns: a #GOptionGroup for the commandline arguments recognized
795 gtk_get_option_group (gboolean open_default_display)
798 OptionGroupInfo *info;
800 gettext_initialization ();
802 info = g_new0 (OptionGroupInfo, 1);
803 info->open_default_display = open_default_display;
805 group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
806 g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
808 gdk_add_option_entries_libgtk_only (group);
809 g_option_group_add_entries (group, gtk_args);
810 g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
816 * gtk_init_with_args:
817 * @argc: a pointer to the number of command line arguments.
818 * @argv: a pointer to the array of command line arguments.
819 * @parameter_string: a string which is displayed in
820 * the first line of <option>--help</option> output, after
821 * <literal><replaceable>programname</replaceable> [OPTION...]</literal>
822 * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
823 * describing the options of your program
824 * @translation_domain: a translation domain to use for translating
825 * the <option>--help</option> output for the options in @entries
826 * with gettext(), or %NULL
827 * @error: a return location for errors
829 * This function does the same work as gtk_init_check().
830 * Additionally, it allows you to add your own commandline options,
831 * and it automatically generates nicely formatted
832 * <option>--help</option> output. Note that your program will
833 * be terminated after writing out the help output.
835 * Returns: %TRUE if the GUI has been successfully initialized,
841 gtk_init_with_args (gint *argc,
843 const gchar *parameter_string,
844 const GOptionEntry *entries,
845 const gchar *translation_domain,
848 GOptionContext *context;
849 GOptionGroup *gtk_group;
853 return gdk_display_open_default_libgtk_only () != NULL;
855 gettext_initialization ();
857 if (!check_setugid ())
860 gtk_group = gtk_get_option_group (TRUE);
862 context = g_option_context_new (parameter_string);
863 g_option_context_add_group (context, gtk_group);
866 g_option_context_add_main_entries (context, entries, translation_domain);
867 retval = g_option_context_parse (context, argc, argv, error);
869 g_option_context_free (context);
877 * @argc: (inout): a pointer to the number of command line arguments.
878 * @argv: (array) (inout): a pointer to the array of command line arguments.
880 * Parses command line arguments, and initializes global
881 * attributes of GTK+, but does not actually open a connection
882 * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
884 * Any arguments used by GTK+ or GDK are removed from the array and
885 * @argc and @argv are updated accordingly.
887 * You shouldn't call this function explicitely if you are using
888 * gtk_init(), or gtk_init_check().
890 * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
893 gtk_parse_args (int *argc,
896 GOptionContext *option_context;
897 GOptionGroup *gtk_group;
898 GError *error = NULL;
903 gettext_initialization ();
905 if (!check_setugid ())
908 option_context = g_option_context_new (NULL);
909 g_option_context_set_ignore_unknown_options (option_context, TRUE);
910 g_option_context_set_help_enabled (option_context, FALSE);
911 gtk_group = gtk_get_option_group (FALSE);
912 g_option_context_set_main_group (option_context, gtk_group);
913 if (!g_option_context_parse (option_context, argc, argv, &error))
915 g_warning ("%s", error->message);
916 g_error_free (error);
919 g_option_context_free (option_context);
924 #ifdef G_PLATFORM_WIN32
925 #undef gtk_init_check
930 * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
931 * main() function. Changed if any arguments were handled.
932 * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
933 * Any parameters understood by gtk_init() are stripped before return.
935 * This function does the same work as gtk_init() with only
936 * a single change: It does not terminate the program if the GUI can't be
937 * initialized. Instead it returns %FALSE on failure.
939 * This way the application can fall back to some other means of communication
940 * with the user - for example a curses or command line interface.
942 * Return value: %TRUE if the GUI has been successfully initialized,
946 gtk_init_check (int *argc,
949 if (!gtk_parse_args (argc, argv))
952 return gdk_display_open_default_libgtk_only () != NULL;
955 #ifdef G_PLATFORM_WIN32
961 * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
962 * main() function. Changed if any arguments were handled.
963 * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
964 * Any parameters understood by gtk_init() are stripped before return.
966 * Call this function before using any other GTK+ functions in your GUI
967 * applications. It will initialize everything needed to operate the
968 * toolkit and parses some standard command line options. @argc and
969 * @argv are adjusted accordingly so your own code will
970 * never see those standard arguments.
972 * Note that there are some alternative ways to initialize GTK+:
973 * if you are calling gtk_parse_args(), gtk_init_check(),
974 * gtk_init_with_args() or g_option_context_parse() with
975 * the option group returned by gtk_get_option_group(), you
976 * <emphasis>don't</emphasis> have to call gtk_init().
979 * This function will terminate your program if it was unable to initialize
980 * the GUI for some reason. If you want your program to fall back to a
981 * textual interface you want to call gtk_init_check() instead.
985 * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
986 * during initialization, to ignore SIGPIPE signals, since these are
987 * almost never wanted in graphical applications. If you do need to
988 * handle SIGPIPE for some reason, reset the handler after gtk_init(),
989 * but notice that other libraries (e.g. libdbus or gvfs) might do
994 gtk_init (int *argc, char ***argv)
996 if (!gtk_init_check (argc, argv))
998 const char *display_name_arg = gdk_get_display_arg_name ();
999 if (display_name_arg == NULL)
1000 display_name_arg = getenv("DISPLAY");
1001 g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
1006 #ifdef G_PLATFORM_WIN32
1009 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
1011 if (sizeof_GtkWindow != sizeof (GtkWindow))
1012 g_error ("Incompatible build!\n"
1013 "The code using GTK+ thinks GtkWindow is of different\n"
1014 "size than it actually is in this build of GTK+.\n"
1015 "On Windows, this probably means that you have compiled\n"
1016 "your code with gcc without the -mms-bitfields switch,\n"
1017 "or that you are using an unsupported compiler.");
1020 /* In GTK+ 2.0 the GtkWindow struct actually is the same size in
1021 * gcc-compiled code on Win32 whether compiled with -fnative-struct or
1022 * not. Unfortunately this wan't noticed until after GTK+ 2.0.1. So,
1023 * from GTK+ 2.0.2 on, check some other struct, too, where the use of
1024 * -fnative-struct still matters. GtkBox is one such.
1027 check_sizeof_GtkBox (size_t sizeof_GtkBox)
1029 if (sizeof_GtkBox != sizeof (GtkBox))
1030 g_error ("Incompatible build!\n"
1031 "The code using GTK+ thinks GtkBox is of different\n"
1032 "size than it actually is in this build of GTK+.\n"
1033 "On Windows, this probably means that you have compiled\n"
1034 "your code with gcc without the -mms-bitfields switch,\n"
1035 "or that you are using an unsupported compiler.");
1038 /* These two functions might get more checks added later, thus pass
1039 * in the number of extra args.
1042 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1044 check_sizeof_GtkWindow (sizeof_GtkWindow);
1045 if (num_checks >= 2)
1046 check_sizeof_GtkBox (sizeof_GtkBox);
1047 gtk_init (argc, argv);
1051 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1053 check_sizeof_GtkWindow (sizeof_GtkWindow);
1054 if (num_checks >= 2)
1055 check_sizeof_GtkBox (sizeof_GtkBox);
1056 return gtk_init_check (argc, argv);
1064 * Initializes internationalization support for GTK+. gtk_init()
1065 * automatically does this, so there is typically no point
1066 * in calling this function.
1068 * If you are calling this function because you changed the locale
1069 * after GTK+ is was initialized, then calling this function
1070 * may help a bit. (Note, however, that changing the locale
1071 * after GTK+ is initialized may produce inconsistent results and
1072 * is not really supported.)
1074 * In detail - sets the current locale according to the
1075 * program environment. This is the same as calling the C library function
1076 * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the
1077 * locale specific setup of the windowing system used by GDK.
1079 * Returns: a string corresponding to the locale set, typically in the
1080 * form lang_COUNTRY, where lang is an ISO-639 language code, and
1081 * COUNTRY is an ISO-3166 country code. On Unix, this form matches the
1082 * result of the setlocale(); it is also used on other machines, such as
1083 * Windows, where the C library returns a different result. The string is
1084 * owned by GTK+ and should not be modified or freed.
1087 gtk_set_locale (void)
1089 return gdk_set_locale ();
1093 * _gtk_get_lc_ctype:
1095 * Return the Unix-style locale string for the language currently in
1096 * effect. On Unix systems, this is the return value from
1097 * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
1098 * affect this through the environment variables LC_ALL, LC_CTYPE or
1099 * LANG (checked in that order). The locale strings typically is in
1100 * the form lang_COUNTRY, where lang is an ISO-639 language code, and
1101 * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
1102 * Swedish as written in Finland or pt_BR for Portuguese as written in
1105 * On Windows, the C library doesn't use any such environment
1106 * variables, and setting them won't affect the behaviour of functions
1107 * like ctime(). The user sets the locale through the Regional Options
1108 * in the Control Panel. The C library (in the setlocale() function)
1109 * does not use country and language codes, but country and language
1110 * names spelled out in English.
1111 * However, this function does check the above environment
1112 * variables, and does return a Unix-style locale string based on
1113 * either said environment variables or the thread's current locale.
1115 * Return value: a dynamically allocated string, free with g_free().
1119 _gtk_get_lc_ctype (void)
1122 /* Somebody might try to set the locale for this process using the
1123 * LANG or LC_ environment variables. The Microsoft C library
1124 * doesn't know anything about them. You set the locale in the
1125 * Control Panel. Setting these env vars won't have any affect on
1126 * locale-dependent C library functions like ctime(). But just for
1127 * kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes
1128 * it easier to test GTK and Pango in various default languages, you
1129 * don't have to clickety-click in the Control Panel, you can simply
1130 * start the program with LC_ALL=something on the command line.)
1134 p = getenv ("LC_ALL");
1136 return g_strdup (p);
1138 p = getenv ("LC_CTYPE");
1140 return g_strdup (p);
1142 p = getenv ("LANG");
1144 return g_strdup (p);
1146 return g_win32_getlocale ();
1148 return g_strdup (setlocale (LC_CTYPE, NULL));
1153 * gtk_get_default_language:
1155 * Returns the #PangoLanguage for the default language currently in
1156 * effect. (Note that this can change over the life of an
1157 * application.) The default language is derived from the current
1158 * locale. It determines, for example, whether GTK+ uses the
1159 * right-to-left or left-to-right text direction.
1161 * This function is equivalent to pango_language_get_default(). See
1162 * that function for details.
1164 * Return value: the default language as a #PangoLanguage, must not be
1168 gtk_get_default_language (void)
1170 return pango_language_get_default ();
1178 GtkInitFunction *init;
1181 gtk_main_loop_level++;
1183 loop = g_main_loop_new (NULL, TRUE);
1184 main_loops = g_slist_prepend (main_loops, loop);
1186 tmp_list = functions = init_functions;
1187 init_functions = NULL;
1191 init = tmp_list->data;
1192 tmp_list = tmp_list->next;
1194 (* init->function) (init->data);
1197 g_list_free (functions);
1199 if (g_main_loop_is_running (main_loops->data))
1201 GDK_THREADS_LEAVE ();
1202 g_main_loop_run (loop);
1203 GDK_THREADS_ENTER ();
1209 GList *reinvoke_list = NULL;
1210 GtkQuitFunction *quitf;
1212 while (quit_functions)
1214 quitf = quit_functions->data;
1216 tmp_list = quit_functions;
1217 quit_functions = g_list_remove_link (quit_functions, quit_functions);
1218 g_list_free_1 (tmp_list);
1220 if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
1221 gtk_quit_invoke_function (quitf))
1223 reinvoke_list = g_list_prepend (reinvoke_list, quitf);
1227 gtk_quit_destroy (quitf);
1234 work = g_list_last (reinvoke_list);
1236 quit_functions->prev = work;
1237 work->next = quit_functions;
1238 quit_functions = work;
1244 main_loops = g_slist_remove (main_loops, loop);
1246 g_main_loop_unref (loop);
1248 gtk_main_loop_level--;
1250 if (gtk_main_loop_level == 0)
1252 /* Try storing all clipboard data we have */
1253 _gtk_clipboard_store_all ();
1255 /* Synchronize the recent manager singleton */
1256 _gtk_recent_manager_sync ();
1261 gtk_main_level (void)
1263 return gtk_main_loop_level;
1267 gtk_main_quit (void)
1269 g_return_if_fail (main_loops != NULL);
1271 g_main_loop_quit (main_loops->data);
1275 gtk_events_pending (void)
1279 GDK_THREADS_LEAVE ();
1280 result = g_main_context_pending (NULL);
1281 GDK_THREADS_ENTER ();
1287 gtk_main_iteration (void)
1289 GDK_THREADS_LEAVE ();
1290 g_main_context_iteration (NULL, TRUE);
1291 GDK_THREADS_ENTER ();
1294 return !g_main_loop_is_running (main_loops->data);
1300 gtk_main_iteration_do (gboolean blocking)
1302 GDK_THREADS_LEAVE ();
1303 g_main_context_iteration (NULL, blocking);
1304 GDK_THREADS_ENTER ();
1307 return !g_main_loop_is_running (main_loops->data);
1312 /* private libgtk to libgdk interfaces
1314 gboolean gdk_device_grab_info_libgtk_only (GdkDisplay *display,
1316 GdkWindow **grab_window,
1317 gboolean *owner_events);
1320 rewrite_events_translate (GdkWindow *old_window,
1321 GdkWindow *new_window,
1325 gint old_origin_x, old_origin_y;
1326 gint new_origin_x, new_origin_y;
1328 gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1329 gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1331 *x += old_origin_x - new_origin_x;
1332 *y += old_origin_y - new_origin_y;
1336 rewrite_event_for_window (GdkEvent *event,
1337 GdkWindow *new_window)
1339 event = gdk_event_copy (event);
1341 switch (event->type)
1344 rewrite_events_translate (event->any.window,
1346 &event->scroll.x, &event->scroll.y);
1348 case GDK_BUTTON_PRESS:
1349 case GDK_2BUTTON_PRESS:
1350 case GDK_3BUTTON_PRESS:
1351 case GDK_BUTTON_RELEASE:
1352 rewrite_events_translate (event->any.window,
1354 &event->button.x, &event->button.y);
1356 case GDK_MOTION_NOTIFY:
1357 rewrite_events_translate (event->any.window,
1359 &event->motion.x, &event->motion.y);
1362 case GDK_KEY_RELEASE:
1363 case GDK_PROXIMITY_IN:
1364 case GDK_PROXIMITY_OUT:
1371 g_object_unref (event->any.window);
1372 event->any.window = g_object_ref (new_window);
1377 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1378 * then what X11 does is deliver the event normally if it was going to this
1379 * client, otherwise, delivers it in terms of the grab window. This function
1380 * rewrites events to the effect that events going to the same window group
1381 * are delivered normally, otherwise, the event is delivered in terms of the
1385 rewrite_event_for_grabs (GdkEvent *event)
1387 GdkWindow *grab_window;
1388 GtkWidget *event_widget, *grab_widget;
1389 gpointer grab_widget_ptr;
1390 gboolean owner_events;
1391 GdkDisplay *display;
1394 switch (event->type)
1397 case GDK_BUTTON_PRESS:
1398 case GDK_2BUTTON_PRESS:
1399 case GDK_3BUTTON_PRESS:
1400 case GDK_BUTTON_RELEASE:
1401 case GDK_MOTION_NOTIFY:
1402 case GDK_PROXIMITY_IN:
1403 case GDK_PROXIMITY_OUT:
1405 case GDK_KEY_RELEASE:
1406 display = gdk_drawable_get_display (event->any.window);
1407 device = gdk_event_get_device (event);
1409 if (!gdk_device_grab_info_libgtk_only (display, device, &grab_window, &owner_events) ||
1417 event_widget = gtk_get_event_widget (event);
1418 gdk_window_get_user_data (grab_window, &grab_widget_ptr);
1419 grab_widget = grab_widget_ptr;
1422 gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1423 return rewrite_event_for_window (event, grab_window);
1429 gtk_main_do_event (GdkEvent *event)
1431 GtkWidget *event_widget;
1432 GtkWidget *grab_widget = NULL;
1433 GtkWindowGroup *window_group;
1434 GdkEvent *rewritten_event = NULL;
1438 if (event->type == GDK_SETTING)
1440 _gtk_settings_handle_event (&event->setting);
1444 if (event->type == GDK_OWNER_CHANGE)
1446 _gtk_clipboard_handle_event (&event->owner_change);
1450 /* Find the widget which got the event. We store the widget
1451 * in the user_data field of GdkWindow's.
1452 * Ignore the event if we don't have a widget for it, except
1453 * for GDK_PROPERTY_NOTIFY events which are handled specialy.
1454 * Though this happens rarely, bogus events can occour
1455 * for e.g. destroyed GdkWindows.
1457 event_widget = gtk_get_event_widget (event);
1460 /* To handle selection INCR transactions, we select
1461 * PropertyNotify events on the requestor window and create
1462 * a corresponding (fake) GdkWindow so that events get
1463 * here. There won't be a widget though, so we have to handle
1466 if (event->type == GDK_PROPERTY_NOTIFY)
1467 _gtk_selection_incr_event (event->any.window,
1473 /* If pointer or keyboard grabs are in effect, munge the events
1474 * so that each window group looks like a separate app.
1476 rewritten_event = rewrite_event_for_grabs (event);
1477 if (rewritten_event)
1479 event = rewritten_event;
1480 event_widget = gtk_get_event_widget (event);
1483 window_group = gtk_main_get_window_group (event_widget);
1484 device = gdk_event_get_device (event);
1486 /* check whether there is a (device) grab in effect...
1489 grab_widget = gtk_window_group_get_current_device_grab (window_group, device);
1491 if (!grab_widget && window_group->grabs)
1492 grab_widget = window_group->grabs->data;
1494 /* If the grab widget is an ancestor of the event widget
1495 * then we send the event to the original event widget.
1496 * This is the key to implementing modality.
1499 (gtk_widget_is_sensitive (event_widget) &&
1500 gtk_widget_is_ancestor (event_widget, grab_widget)))
1501 grab_widget = event_widget;
1503 /* If the widget receiving events is actually blocked by another device GTK+ grab */
1505 _gtk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
1507 if (rewritten_event)
1508 gdk_event_free (rewritten_event);
1513 /* Push the event onto a stack of current events for
1514 * gtk_current_event_get().
1516 current_events = g_list_prepend (current_events, event);
1518 /* Not all events get sent to the grabbing widget.
1519 * The delete, destroy, expose, focus change and resize
1520 * events still get sent to the event widget because
1521 * 1) these events have no meaning for the grabbing widget
1522 * and 2) redirecting these events to the grabbing widget
1523 * could cause the display to be messed up.
1525 * Drag events are also not redirected, since it isn't
1526 * clear what the semantics of that would be.
1528 switch (event->type)
1534 g_object_ref (event_widget);
1535 if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1536 !gtk_widget_event (event_widget, event))
1537 gtk_widget_destroy (event_widget);
1538 g_object_unref (event_widget);
1542 /* Unexpected GDK_DESTROY from the outside, ignore for
1543 * child windows, handle like a GDK_DELETE for toplevels
1545 if (!event_widget->parent)
1547 g_object_ref (event_widget);
1548 if (!gtk_widget_event (event_widget, event) &&
1549 gtk_widget_get_realized (event_widget))
1550 gtk_widget_destroy (event_widget);
1551 g_object_unref (event_widget);
1556 if (event->any.window && gtk_widget_get_double_buffered (event_widget))
1558 gdk_window_begin_paint_region (event->any.window, event->expose.region);
1559 gtk_widget_send_expose (event_widget, event);
1560 gdk_window_end_paint (event->any.window);
1564 /* The app may paint with a previously allocated cairo_t,
1565 which will draw directly to the window. We can't catch cairo
1566 drap operatoins to automatically flush the window, thus we
1567 need to explicitly flush any outstanding moves or double
1569 gdk_window_flush (event->any.window);
1570 gtk_widget_send_expose (event_widget, event);
1574 case GDK_PROPERTY_NOTIFY:
1576 case GDK_FOCUS_CHANGE:
1580 case GDK_SELECTION_CLEAR:
1581 case GDK_SELECTION_REQUEST:
1582 case GDK_SELECTION_NOTIFY:
1583 case GDK_CLIENT_EVENT:
1584 case GDK_VISIBILITY_NOTIFY:
1585 case GDK_WINDOW_STATE:
1586 case GDK_GRAB_BROKEN:
1588 gtk_widget_event (event_widget, event);
1592 case GDK_BUTTON_PRESS:
1593 case GDK_2BUTTON_PRESS:
1594 case GDK_3BUTTON_PRESS:
1595 gtk_propagate_event (grab_widget, event);
1599 case GDK_KEY_RELEASE:
1602 if (gtk_invoke_key_snoopers (grab_widget, event))
1605 /* Catch alt press to enable auto-mnemonics;
1606 * menus are handled elsewhere
1608 if ((event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R) &&
1609 !GTK_IS_MENU_SHELL (grab_widget))
1611 gboolean auto_mnemonics;
1613 g_object_get (gtk_widget_get_settings (grab_widget),
1614 "gtk-auto-mnemonics", &auto_mnemonics, NULL);
1618 gboolean mnemonics_visible;
1621 mnemonics_visible = (event->type == GDK_KEY_PRESS);
1623 window = gtk_widget_get_toplevel (grab_widget);
1625 if (GTK_IS_WINDOW (window))
1626 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
1629 /* else fall through */
1630 case GDK_MOTION_NOTIFY:
1631 case GDK_BUTTON_RELEASE:
1632 case GDK_PROXIMITY_IN:
1633 case GDK_PROXIMITY_OUT:
1634 gtk_propagate_event (grab_widget, event);
1637 case GDK_ENTER_NOTIFY:
1638 _gtk_widget_set_device_window (event_widget,
1639 gdk_event_get_device (event),
1641 if (gtk_widget_is_sensitive (grab_widget))
1642 gtk_widget_event (grab_widget, event);
1645 case GDK_LEAVE_NOTIFY:
1646 _gtk_widget_set_device_window (event_widget,
1647 gdk_event_get_device (event),
1649 if (gtk_widget_is_sensitive (grab_widget))
1650 gtk_widget_event (grab_widget, event);
1653 case GDK_DRAG_STATUS:
1654 case GDK_DROP_FINISHED:
1655 _gtk_drag_source_handle_event (event_widget, event);
1657 case GDK_DRAG_ENTER:
1658 case GDK_DRAG_LEAVE:
1659 case GDK_DRAG_MOTION:
1660 case GDK_DROP_START:
1661 _gtk_drag_dest_handle_event (event_widget, event);
1664 g_assert_not_reached ();
1668 if (event->type == GDK_ENTER_NOTIFY
1669 || event->type == GDK_LEAVE_NOTIFY
1670 || event->type == GDK_BUTTON_PRESS
1671 || event->type == GDK_2BUTTON_PRESS
1672 || event->type == GDK_3BUTTON_PRESS
1673 || event->type == GDK_KEY_PRESS
1674 || event->type == GDK_DRAG_ENTER
1675 || event->type == GDK_GRAB_BROKEN
1676 || event->type == GDK_MOTION_NOTIFY
1677 || event->type == GDK_SCROLL)
1679 _gtk_tooltip_handle_event (event);
1682 tmp_list = current_events;
1683 current_events = g_list_remove_link (current_events, tmp_list);
1684 g_list_free_1 (tmp_list);
1686 if (rewritten_event)
1687 gdk_event_free (rewritten_event);
1702 static GtkWindowGroup *
1703 gtk_main_get_window_group (GtkWidget *widget)
1705 GtkWidget *toplevel = NULL;
1708 toplevel = gtk_widget_get_toplevel (widget);
1710 if (GTK_IS_WINDOW (toplevel))
1711 return gtk_window_get_group (GTK_WINDOW (toplevel));
1713 return gtk_window_get_group (NULL);
1718 GtkWidget *old_grab_widget;
1719 GtkWidget *new_grab_widget;
1720 gboolean was_grabbed;
1721 gboolean is_grabbed;
1723 GList *notified_windows;
1728 synth_crossing_for_grab_notify (GtkWidget *from,
1730 GrabNotifyInfo *info,
1732 GdkCrossingMode mode)
1736 GdkDevice *device = devices->data;
1737 GdkWindow *from_window, *to_window;
1739 /* Do not propagate events more than once to
1740 * the same windows if non-multidevice aware.
1746 from_window = _gtk_widget_get_device_window (from, device);
1749 !gdk_window_get_support_multidevice (from_window) &&
1750 g_list_find (info->notified_windows, from_window))
1758 to_window = _gtk_widget_get_device_window (to, device);
1761 !gdk_window_get_support_multidevice (to_window) &&
1762 g_list_find (info->notified_windows, to_window))
1766 if (from_window || to_window)
1768 _gtk_widget_synthesize_crossing ((from_window) ? from : NULL,
1769 (to_window) ? to : NULL,
1773 info->notified_windows = g_list_prepend (info->notified_windows, from_window);
1776 info->notified_windows = g_list_prepend (info->notified_windows, to_window);
1779 devices = devices->next;
1784 gtk_grab_notify_foreach (GtkWidget *child,
1787 GrabNotifyInfo *info = data;
1788 gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1791 was_grabbed = info->was_grabbed;
1792 is_grabbed = info->is_grabbed;
1794 info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1795 info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1797 was_shadowed = info->old_grab_widget && !info->was_grabbed;
1798 is_shadowed = info->new_grab_widget && !info->is_grabbed;
1800 g_object_ref (child);
1802 if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1803 gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1806 _gtk_widget_get_device_window (child, info->device))
1808 /* Device specified and is on widget */
1809 devices = g_list_prepend (NULL, info->device);
1812 devices = _gtk_widget_list_devices (child);
1816 GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
1817 if (!was_shadowed && devices &&
1818 gtk_widget_is_sensitive (child))
1819 synth_crossing_for_grab_notify (child, info->new_grab_widget,
1821 GDK_CROSSING_GTK_GRAB);
1825 GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
1826 if (was_shadowed && devices &&
1827 gtk_widget_is_sensitive (child))
1828 synth_crossing_for_grab_notify (info->old_grab_widget, child,
1830 info->from_grab ? GDK_CROSSING_GTK_GRAB :
1831 GDK_CROSSING_GTK_UNGRAB);
1834 if (was_shadowed != is_shadowed)
1835 _gtk_widget_grab_notify (child, was_shadowed);
1837 g_object_unref (child);
1838 g_list_free (devices);
1840 info->was_grabbed = was_grabbed;
1841 info->is_grabbed = is_grabbed;
1845 gtk_grab_notify (GtkWindowGroup *group,
1847 GtkWidget *old_grab_widget,
1848 GtkWidget *new_grab_widget,
1852 GrabNotifyInfo info = { 0 };
1854 if (old_grab_widget == new_grab_widget)
1857 info.old_grab_widget = old_grab_widget;
1858 info.new_grab_widget = new_grab_widget;
1859 info.from_grab = from_grab;
1860 info.device = device;
1862 g_object_ref (group);
1864 toplevels = gtk_window_list_toplevels ();
1865 g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1869 GtkWindow *toplevel = toplevels->data;
1870 toplevels = g_list_delete_link (toplevels, toplevels);
1872 info.was_grabbed = FALSE;
1873 info.is_grabbed = FALSE;
1875 if (group == gtk_window_get_group (toplevel))
1876 gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1877 g_object_unref (toplevel);
1880 g_list_free (info.notified_windows);
1881 g_object_unref (group);
1885 gtk_grab_add (GtkWidget *widget)
1887 GtkWindowGroup *group;
1888 GtkWidget *old_grab_widget;
1890 g_return_if_fail (widget != NULL);
1892 if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
1894 _gtk_widget_set_has_grab (widget, TRUE);
1896 group = gtk_main_get_window_group (widget);
1899 old_grab_widget = (GtkWidget *)group->grabs->data;
1901 old_grab_widget = NULL;
1903 g_object_ref (widget);
1904 group->grabs = g_slist_prepend (group->grabs, widget);
1906 gtk_grab_notify (group, NULL, old_grab_widget, widget, TRUE);
1911 gtk_grab_get_current (void)
1913 GtkWindowGroup *group;
1915 group = gtk_main_get_window_group (NULL);
1918 return GTK_WIDGET (group->grabs->data);
1923 gtk_grab_remove (GtkWidget *widget)
1925 GtkWindowGroup *group;
1926 GtkWidget *new_grab_widget;
1928 g_return_if_fail (widget != NULL);
1930 if (gtk_widget_has_grab (widget))
1932 _gtk_widget_set_has_grab (widget, FALSE);
1934 group = gtk_main_get_window_group (widget);
1935 group->grabs = g_slist_remove (group->grabs, widget);
1938 new_grab_widget = (GtkWidget *)group->grabs->data;
1940 new_grab_widget = NULL;
1942 gtk_grab_notify (group, NULL, widget, new_grab_widget, FALSE);
1944 g_object_unref (widget);
1949 * gtk_device_grab_add:
1950 * @widget: a #GtkWidget
1951 * @device: a #GtkDevice to grab on.
1952 * @block_others: %TRUE to prevent other devices to interact with @widget.
1954 * Adds a GTK+ grab on @device, so all the events on @device and its
1955 * associated pointer or keyboard (if any) are delivered to @widget.
1956 * If the @block_others parameter is %TRUE, any other devices will be
1957 * unable to interact with @widget during the grab.
1962 gtk_device_grab_add (GtkWidget *widget,
1964 gboolean block_others)
1966 GtkWindowGroup *group;
1967 GtkWidget *old_grab_widget;
1969 g_return_if_fail (GTK_IS_WIDGET (widget));
1970 g_return_if_fail (GDK_IS_DEVICE (device));
1972 group = gtk_main_get_window_group (widget);
1973 old_grab_widget = gtk_window_group_get_current_device_grab (group, device);
1975 if (old_grab_widget != widget)
1976 _gtk_window_group_add_device_grab (group, widget, device, block_others);
1978 gtk_grab_notify (group, device, old_grab_widget, widget, TRUE);
1982 * gtk_device_grab_remove:
1983 * @widget: a #GtkWidget
1984 * @device: a #GdkDevice
1986 * Removes a device grab from the given widget. You have to pair calls
1987 * to gtk_device_grab_add() and gtk_device_grab_remove().
1992 gtk_device_grab_remove (GtkWidget *widget,
1995 GtkWindowGroup *group;
1996 GtkWidget *new_grab_widget;
1998 g_return_if_fail (GTK_IS_WIDGET (widget));
1999 g_return_if_fail (GDK_IS_DEVICE (device));
2001 group = gtk_main_get_window_group (widget);
2002 _gtk_window_group_remove_device_grab (group, widget, device);
2003 new_grab_widget = gtk_window_group_get_current_device_grab (group, device);
2005 gtk_grab_notify (group, device, widget, new_grab_widget, FALSE);
2009 gtk_init_add (GtkFunction function,
2012 GtkInitFunction *init;
2014 init = g_new (GtkInitFunction, 1);
2015 init->function = function;
2018 init_functions = g_list_prepend (init_functions, init);
2022 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
2025 GtkKeySnooperData *data;
2026 static guint snooper_id = 1;
2028 g_return_val_if_fail (snooper != NULL, 0);
2030 data = g_new (GtkKeySnooperData, 1);
2031 data->func = snooper;
2032 data->func_data = func_data;
2033 data->id = snooper_id++;
2034 key_snoopers = g_slist_prepend (key_snoopers, data);
2040 gtk_key_snooper_remove (guint snooper_id)
2042 GtkKeySnooperData *data = NULL;
2045 slist = key_snoopers;
2049 if (data->id == snooper_id)
2052 slist = slist->next;
2057 key_snoopers = g_slist_remove (key_snoopers, data);
2063 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
2067 gint return_val = FALSE;
2069 slist = key_snoopers;
2070 while (slist && !return_val)
2072 GtkKeySnooperData *data;
2075 slist = slist->next;
2076 return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
2083 gtk_quit_add_full (guint main_level,
2084 GtkFunction function,
2085 GtkCallbackMarshal marshal,
2087 GDestroyNotify destroy)
2089 static guint quit_id = 1;
2090 GtkQuitFunction *quitf;
2092 g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
2094 quitf = g_slice_new (GtkQuitFunction);
2096 quitf->id = quit_id++;
2097 quitf->main_level = main_level;
2098 quitf->function = function;
2099 quitf->marshal = marshal;
2101 quitf->destroy = destroy;
2103 quit_functions = g_list_prepend (quit_functions, quitf);
2109 gtk_quit_destroy (GtkQuitFunction *quitf)
2112 quitf->destroy (quitf->data);
2113 g_slice_free (GtkQuitFunction, quitf);
2117 gtk_quit_destructor (GtkObject **object_p)
2120 gtk_object_destroy (*object_p);
2127 gtk_quit_add_destroy (guint main_level,
2130 GtkObject **object_p;
2132 g_return_if_fail (main_level > 0);
2133 g_return_if_fail (GTK_IS_OBJECT (object));
2135 object_p = g_new (GtkObject*, 1);
2137 g_signal_connect (object,
2139 G_CALLBACK (gtk_widget_destroyed),
2141 gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
2145 gtk_quit_add (guint main_level,
2146 GtkFunction function,
2149 return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2153 gtk_quit_remove (guint id)
2155 GtkQuitFunction *quitf;
2158 tmp_list = quit_functions;
2161 quitf = tmp_list->data;
2163 if (quitf->id == id)
2165 quit_functions = g_list_remove_link (quit_functions, tmp_list);
2166 g_list_free (tmp_list);
2167 gtk_quit_destroy (quitf);
2172 tmp_list = tmp_list->next;
2177 gtk_quit_remove_by_data (gpointer data)
2179 GtkQuitFunction *quitf;
2182 tmp_list = quit_functions;
2185 quitf = tmp_list->data;
2187 if (quitf->data == data)
2189 quit_functions = g_list_remove_link (quit_functions, tmp_list);
2190 g_list_free (tmp_list);
2191 gtk_quit_destroy (quitf);
2196 tmp_list = tmp_list->next;
2201 * gtk_get_current_event:
2203 * Obtains a copy of the event currently being processed by GTK+. For
2204 * example, if you get a "clicked" signal from #GtkButton, the current
2205 * event will be the #GdkEventButton that triggered the "clicked"
2206 * signal. The returned event must be freed with gdk_event_free().
2207 * If there is no current event, the function returns %NULL.
2209 * Return value: a copy of the current event, or %NULL if no current event.
2212 gtk_get_current_event (void)
2215 return gdk_event_copy (current_events->data);
2221 * gtk_get_current_event_time:
2223 * If there is a current event and it has a timestamp, return that
2224 * timestamp, otherwise return %GDK_CURRENT_TIME.
2226 * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2229 gtk_get_current_event_time (void)
2232 return gdk_event_get_time (current_events->data);
2234 return GDK_CURRENT_TIME;
2238 * gtk_get_current_event_state:
2239 * @state: a location to store the state of the current event
2241 * If there is a current event and it has a state field, place
2242 * that state field in @state and return %TRUE, otherwise return
2245 * Return value: %TRUE if there was a current event and it had a state field
2248 gtk_get_current_event_state (GdkModifierType *state)
2250 g_return_val_if_fail (state != NULL, FALSE);
2253 return gdk_event_get_state (current_events->data, state);
2262 * gtk_get_current_event_device:
2264 * If there is a current event and it has a device, return that
2265 * device, otherwise return %NULL.
2267 * Returns: a #GdkDevice, or %NULL
2270 gtk_get_current_event_device (void)
2273 return gdk_event_get_device (current_events->data);
2279 * gtk_get_event_widget:
2280 * @event: a #GdkEvent
2282 * If @event is %NULL or the event was not associated with any widget,
2283 * returns %NULL, otherwise returns the widget that received the event
2286 * Return value: the widget that originally received @event, or %NULL
2289 gtk_get_event_widget (GdkEvent *event)
2292 gpointer widget_ptr;
2295 if (event && event->any.window &&
2296 (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2298 gdk_window_get_user_data (event->any.window, &widget_ptr);
2299 widget = widget_ptr;
2306 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2308 if (!quitf->marshal)
2309 return quitf->function (quitf->data);
2313 gint ret_val = FALSE;
2315 args[0].name = NULL;
2316 args[0].type = G_TYPE_BOOLEAN;
2317 args[0].d.pointer_data = &ret_val;
2318 ((GtkCallbackMarshal) quitf->marshal) (NULL,
2326 * gtk_propagate_event:
2327 * @widget: a #GtkWidget
2330 * Sends an event to a widget, propagating the event to parent widgets
2331 * if the event remains unhandled. Events received by GTK+ from GDK
2332 * normally begin in gtk_main_do_event(). Depending on the type of
2333 * event, existence of modal dialogs, grabs, etc., the event may be
2334 * propagated; if so, this function is used. gtk_propagate_event()
2335 * calls gtk_widget_event() on each widget it decides to send the
2336 * event to. So gtk_widget_event() is the lowest-level function; it
2337 * simply emits the "event" and possibly an event-specific signal on a
2338 * widget. gtk_propagate_event() is a bit higher-level, and
2339 * gtk_main_do_event() is the highest level.
2341 * All that said, you most likely don't want to use any of these
2342 * functions; synthesizing events is rarely needed. Consider asking on
2343 * the mailing list for better ways to achieve your goals. For
2344 * example, use gdk_window_invalidate_rect() or
2345 * gtk_widget_queue_draw() instead of making up expose events.
2349 gtk_propagate_event (GtkWidget *widget,
2354 g_return_if_fail (GTK_IS_WIDGET (widget));
2355 g_return_if_fail (event != NULL);
2357 handled_event = FALSE;
2359 g_object_ref (widget);
2361 if ((event->type == GDK_KEY_PRESS) ||
2362 (event->type == GDK_KEY_RELEASE))
2364 /* Only send key events within Window widgets to the Window
2365 * The Window widget will in turn pass the
2366 * key event on to the currently focused widget
2371 window = gtk_widget_get_toplevel (widget);
2372 if (GTK_IS_WINDOW (window))
2374 /* If there is a grab within the window, give the grab widget
2375 * a first crack at the key event
2377 if (widget != window && gtk_widget_has_grab (widget))
2378 handled_event = gtk_widget_event (widget, event);
2382 window = gtk_widget_get_toplevel (widget);
2383 if (GTK_IS_WINDOW (window))
2385 if (gtk_widget_is_sensitive (window))
2386 gtk_widget_event (window, event);
2390 handled_event = TRUE; /* don't send to widget */
2394 /* Other events get propagated up the widget tree
2395 * so that parents can see the button and motion
2396 * events of the children.
2404 /* Scroll events are special cased here because it
2405 * feels wrong when scrolling a GtkViewport, say,
2406 * to have children of the viewport eat the scroll
2409 if (!gtk_widget_is_sensitive (widget))
2410 handled_event = event->type != GDK_SCROLL;
2412 handled_event = gtk_widget_event (widget, event);
2414 tmp = widget->parent;
2415 g_object_unref (widget);
2419 if (!handled_event && widget)
2420 g_object_ref (widget);
2426 g_object_unref (widget);
2430 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2431 GValue *return_accu,
2432 const GValue *handler_return,
2435 gboolean continue_emission;
2436 gboolean signal_handled;
2438 signal_handled = g_value_get_boolean (handler_return);
2439 g_value_set_boolean (return_accu, signal_handled);
2440 continue_emission = !signal_handled;
2442 return continue_emission;