1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
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.
8  *
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.
13  *
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.
18  */
19 
20 /*
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/.
25  */
26 
27 #include "config.h"
28 
29 #include "gtkmain.h"
30 
31 #include <glib.h>
32 #include "gdkconfig.h"
33 
34 #include <locale.h>
35 
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #include <sys/types.h>		/* For uid_t, gid_t */
43 
44 #ifdef G_OS_WIN32
45 #define STRICT
46 #include <windows.h>
47 #undef STRICT
48 #endif
49 
50 #include "gtkintl.h"
51 
52 #include "gtkaccelmap.h"
53 #include "gtkbox.h"
54 #include "gtkclipboard.h"
55 #include "gtkdnd.h"
56 #include "gtkversion.h"
57 #include "gtkmodules.h"
58 #include "gtkrc.h"
59 #include "gtkrecentmanager.h"
60 #include "gtkselection.h"
61 #include "gtksettings.h"
62 #include "gtkwidget.h"
63 #include "gtkwindow.h"
64 #include "gtktooltip.h"
65 #include "gtkdebug.h"
66 #include "gtkalias.h"
67 #include "gtkmenu.h"
68 #include "gdk/gdkkeysyms.h"
69 
70 #include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */
71 
72 #ifdef G_OS_WIN32
73 
74 static HMODULE gtk_dll;
75 
76 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)77 DllMain (HINSTANCE hinstDLL,
78 	 DWORD     fdwReason,
79 	 LPVOID    lpvReserved)
80 {
81   switch (fdwReason)
82     {
83     case DLL_PROCESS_ATTACH:
84       gtk_dll = (HMODULE) hinstDLL;
85       break;
86     }
87 
88   return TRUE;
89 }
90 
91 /* These here before inclusion of gtkprivate.h so that the original
92  * GTK_LIBDIR and GTK_LOCALEDIR definitions are seen. Yeah, this is a
93  * bit sucky.
94  */
95 const gchar *
_gtk_get_libdir(void)96 _gtk_get_libdir (void)
97 {
98   static char *gtk_libdir = NULL;
99   if (gtk_libdir == NULL)
100     {
101       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
102       gchar *slash = root ? strrchr (root, '\\') : NULL;
103       if (slash != NULL &&
104           g_ascii_strcasecmp (slash + 1, ".libs") == 0)
105 	gtk_libdir = GTK_LIBDIR;
106       else
107 	gtk_libdir = g_build_filename (root, "lib", NULL);
108       g_free (root);
109     }
110 
111   return gtk_libdir;
112 }
113 
114 const gchar *
_gtk_get_localedir(void)115 _gtk_get_localedir (void)
116 {
117   static char *gtk_localedir = NULL;
118   if (gtk_localedir == NULL)
119     {
120       const gchar *p;
121       gchar *root, *temp;
122 
123       /* GTK_LOCALEDIR ends in either /lib/locale or
124        * /share/locale. Scan for that slash.
125        */
126       p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
127       while (*--p != '/')
128 	;
129       while (*--p != '/')
130 	;
131 
132       root = g_win32_get_package_installation_directory_of_module (gtk_dll);
133       temp = g_build_filename (root, p, NULL);
134       g_free (root);
135 
136       /* gtk_localedir is passed to bindtextdomain() which isn't
137        * UTF-8-aware.
138        */
139       gtk_localedir = g_win32_locale_filename_from_utf8 (temp);
140       g_free (temp);
141     }
142   return gtk_localedir;
143 }
144 
145 #endif
146 
147 #include "gtkprivate.h"
148 
149 /* Private type definitions
150  */
151 typedef struct _GtkInitFunction		 GtkInitFunction;
152 typedef struct _GtkQuitFunction		 GtkQuitFunction;
153 typedef struct _GtkClosure	         GtkClosure;
154 typedef struct _GtkKeySnooperData	 GtkKeySnooperData;
155 
156 struct _GtkInitFunction
157 {
158   GtkFunction function;
159   gpointer data;
160 };
161 
162 struct _GtkQuitFunction
163 {
164   guint id;
165   guint main_level;
166   GtkCallbackMarshal marshal;
167   GtkFunction function;
168   gpointer data;
169   GDestroyNotify destroy;
170 };
171 
172 struct _GtkClosure
173 {
174   GtkCallbackMarshal marshal;
175   gpointer data;
176   GDestroyNotify destroy;
177 };
178 
179 struct _GtkKeySnooperData
180 {
181   GtkKeySnoopFunc func;
182   gpointer func_data;
183   guint id;
184 };
185 
186 static gint  gtk_quit_invoke_function	 (GtkQuitFunction    *quitf);
187 static void  gtk_quit_destroy		 (GtkQuitFunction    *quitf);
188 static gint  gtk_invoke_key_snoopers	 (GtkWidget	     *grab_widget,
189 					  GdkEvent	     *event);
190 
191 static void     gtk_destroy_closure      (gpointer            data);
192 static gboolean gtk_invoke_idle_timeout  (gpointer            data);
193 static void     gtk_invoke_input         (gpointer            data,
194 					  gint                source,
195 					  GdkInputCondition   condition);
196 
197 #if 0
198 static void  gtk_error			 (gchar		     *str);
199 static void  gtk_warning		 (gchar		     *str);
200 static void  gtk_message		 (gchar		     *str);
201 static void  gtk_print			 (gchar		     *str);
202 #endif
203 
204 static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);
205 
206 const guint gtk_major_version = GTK_MAJOR_VERSION;
207 const guint gtk_minor_version = GTK_MINOR_VERSION;
208 const guint gtk_micro_version = GTK_MICRO_VERSION;
209 const guint gtk_binary_age = GTK_BINARY_AGE;
210 const guint gtk_interface_age = GTK_INTERFACE_AGE;
211 
212 static guint gtk_main_loop_level = 0;
213 static gint pre_initialized = FALSE;
214 static gint gtk_initialized = FALSE;
215 static GList *current_events = NULL;
216 
217 static GSList *main_loops = NULL;      /* stack of currently executing main loops */
218 
219 static GList *init_functions = NULL;	   /* A list of init functions.
220 					    */
221 static GList *quit_functions = NULL;	   /* A list of quit functions.
222 					    */
223 static GSList *key_snoopers = NULL;
224 
225 guint gtk_debug_flags = 0;		   /* Global GTK debug flag */
226 
227 #ifdef G_ENABLE_DEBUG
228 static const GDebugKey gtk_debug_keys[] = {
229   {"misc", GTK_DEBUG_MISC},
230   {"plugsocket", GTK_DEBUG_PLUGSOCKET},
231   {"text", GTK_DEBUG_TEXT},
232   {"tree", GTK_DEBUG_TREE},
233   {"updates", GTK_DEBUG_UPDATES},
234   {"keybindings", GTK_DEBUG_KEYBINDINGS},
235   {"multihead", GTK_DEBUG_MULTIHEAD},
236   {"modules", GTK_DEBUG_MODULES},
237   {"geometry", GTK_DEBUG_GEOMETRY},
238   {"icontheme", GTK_DEBUG_ICONTHEME},
239   {"printing", GTK_DEBUG_PRINTING},
240   {"builder", GTK_DEBUG_BUILDER}
241 };
242 #endif /* G_ENABLE_DEBUG */
243 
244 /**
245  * gtk_check_version:
246  * @required_major: the required major version.
247  * @required_minor: the required minor version.
248  * @required_micro: the required micro version.
249  *
250  * Checks that the GTK+ library in use is compatible with the
251  * given version. Generally you would pass in the constants
252  * #GTK_MAJOR_VERSION, #GTK_MINOR_VERSION, #GTK_MICRO_VERSION
253  * as the three arguments to this function; that produces
254  * a check that the library in use is compatible with
255  * the version of GTK+ the application or module was compiled
256  * against.
257  *
258  * Compatibility is defined by two things: first the version
259  * of the running library is newer than the version
260  * @required_major.required_minor.@required_micro. Second
261  * the running library must be binary compatible with the
262  * version @required_major.required_minor.@required_micro
263  * (same major version.)
264  *
265  * This function is primarily for GTK+ modules; the module
266  * can call this function to check that it wasn't loaded
267  * into an incompatible version of GTK+. However, such a
268  * a check isn't completely reliable, since the module may be
269  * linked against an old version of GTK+ and calling the
270  * old version of gtk_check_version(), but still get loaded
271  * into an application using a newer version of GTK+.
272  *
273  * Return value: %NULL if the GTK+ library is compatible with the
274  *   given version, or a string describing the version mismatch.
275  *   The returned string is owned by GTK+ and should not be modified
276  *   or freed.
277  **/
278 const gchar*
gtk_check_version(guint required_major,guint required_minor,guint required_micro)279 gtk_check_version (guint required_major,
280 		   guint required_minor,
281 		   guint required_micro)
282 {
283   gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
284   gint required_effective_micro = 100 * required_minor + required_micro;
285 
286   if (required_major > GTK_MAJOR_VERSION)
287     return "Gtk+ version too old (major mismatch)";
288   if (required_major < GTK_MAJOR_VERSION)
289     return "Gtk+ version too new (major mismatch)";
290   if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
291     return "Gtk+ version too new (micro mismatch)";
292   if (required_effective_micro > gtk_effective_micro)
293     return "Gtk+ version too old (micro mismatch)";
294   return NULL;
295 }
296 
297 /* This checks to see if the process is running suid or sgid
298  * at the current time. If so, we don't allow GTK+ to be initialized.
299  * This is meant to be a mild check - we only error out if we
300  * can prove the programmer is doing something wrong, not if
301  * they could be doing something wrong. For this reason, we
302  * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
303  */
304 static gboolean
check_setugid(void)305 check_setugid (void)
306 {
307 /* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
308 #ifndef G_OS_WIN32
309   uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
310   gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
311 
312 #ifdef HAVE_GETRESUID
313   /* These aren't in the header files, so we prototype them here.
314    */
315   int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
316   int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
317 
318   if (getresuid (&ruid, &euid, &suid) != 0 ||
319       getresgid (&rgid, &egid, &sgid) != 0)
320 #endif /* HAVE_GETRESUID */
321     {
322       suid = ruid = getuid ();
323       sgid = rgid = getgid ();
324       euid = geteuid ();
325       egid = getegid ();
326     }
327 
328   if (ruid != euid || ruid != suid ||
329       rgid != egid || rgid != sgid)
330     {
331       g_warning ("This process is currently running setuid or setgid.\n"
332 		 "This is not a supported use of GTK+. You must create a helper\n"
333 		 "program instead. For further details, see:\n\n"
334 		 "    http://www.gtk.org/setuid.html\n\n"
335 		 "Refusing to initialize GTK+.");
336       exit (1);
337     }
338 #endif
339   return TRUE;
340 }
341 
342 #ifdef G_OS_WIN32
343 
344 const gchar *
_gtk_get_datadir(void)345 _gtk_get_datadir (void)
346 {
347   static char *gtk_datadir = NULL;
348   if (gtk_datadir == NULL)
349     {
350       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
351       gtk_datadir = g_build_filename (root, "share", NULL);
352       g_free (root);
353     }
354 
355   return gtk_datadir;
356 }
357 
358 const gchar *
_gtk_get_sysconfdir(void)359 _gtk_get_sysconfdir (void)
360 {
361   static char *gtk_sysconfdir = NULL;
362   if (gtk_sysconfdir == NULL)
363     {
364       gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
365       gtk_sysconfdir = g_build_filename (root, "etc", NULL);
366       g_free (root);
367     }
368 
369   return gtk_sysconfdir;
370 }
371 
372 const gchar *
_gtk_get_data_prefix(void)373 _gtk_get_data_prefix (void)
374 {
375   static char *gtk_data_prefix = NULL;
376   if (gtk_data_prefix == NULL)
377     gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
378 
379   return gtk_data_prefix;
380 }
381 
382 #endif /* G_OS_WIN32 */
383 
384 static gboolean do_setlocale = TRUE;
385 
386 /**
387  * gtk_disable_setlocale:
388  *
389  * Prevents gtk_init(), gtk_init_check(), gtk_init_with_args() and
390  * gtk_parse_args() from automatically
391  * calling <literal>setlocale (LC_ALL, "")</literal>. You would
392  * want to use this function if you wanted to set the locale for
393  * your program to something other than the user's locale, or if
394  * you wanted to set different values for different locale categories.
395  *
396  * Most programs should not need to call this function.
397  **/
398 void
gtk_disable_setlocale(void)399 gtk_disable_setlocale (void)
400 {
401   if (pre_initialized)
402     g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
403 
404   do_setlocale = FALSE;
405 }
406 
407 #ifdef G_PLATFORM_WIN32
408 #undef gtk_init_check
409 #endif
410 
411 static GString *gtk_modules_string = NULL;
412 static gboolean g_fatal_warnings = FALSE;
413 
414 #ifdef G_ENABLE_DEBUG
415 static gboolean
gtk_arg_debug_cb(const char * key,const char * value,gpointer user_data)416 gtk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
417 {
418   gtk_debug_flags |= g_parse_debug_string (value,
419 					   gtk_debug_keys,
420 					   G_N_ELEMENTS (gtk_debug_keys));
421 
422   return TRUE;
423 }
424 
425 static gboolean
gtk_arg_no_debug_cb(const char * key,const char * value,gpointer user_data)426 gtk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
427 {
428   gtk_debug_flags &= ~g_parse_debug_string (value,
429 					    gtk_debug_keys,
430 					    G_N_ELEMENTS (gtk_debug_keys));
431 
432   return TRUE;
433 }
434 #endif /* G_ENABLE_DEBUG */
435 
436 static gboolean
gtk_arg_module_cb(const char * key,const char * value,gpointer user_data)437 gtk_arg_module_cb (const char *key, const char *value, gpointer user_data)
438 {
439   if (value && *value)
440     {
441       if (gtk_modules_string)
442 	g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
443       else
444 	gtk_modules_string = g_string_new (NULL);
445 
446       g_string_append (gtk_modules_string, value);
447     }
448 
449   return TRUE;
450 }
451 
452 static const GOptionEntry gtk_args[] = {
453   { "gtk-module",       0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_module_cb,
454     /* Description of --gtk-module=MODULES in --help output */ N_("Load additional GTK+ modules"),
455     /* Placeholder in --gtk-module=MODULES in --help output */ N_("MODULES") },
456   { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings,
457     /* Description of --g-fatal-warnings in --help output */   N_("Make all warnings fatal"), NULL },
458 #ifdef G_ENABLE_DEBUG
459   { "gtk-debug",        0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_debug_cb,
460     /* Description of --gtk-debug=FLAGS in --help output */    N_("GTK+ debugging flags to set"),
461     /* Placeholder in --gtk-debug=FLAGS in --help output */    N_("FLAGS") },
462   { "gtk-no-debug",     0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_no_debug_cb,
463     /* Description of --gtk-no-debug=FLAGS in --help output */ N_("GTK+ debugging flags to unset"),
464     /* Placeholder in --gtk-no-debug=FLAGS in --help output */ N_("FLAGS") },
465 #endif
466   { NULL }
467 };
468 
469 #ifdef G_OS_WIN32
470 
471 static char *iso639_to_check = NULL;
472 static char *iso3166_to_check = NULL;
473 static char *script_to_check = NULL;
474 static gboolean setlocale_called = FALSE;
475 
476 static BOOL CALLBACK
enum_locale_proc(LPTSTR locale)477 enum_locale_proc (LPTSTR locale)
478 {
479   LCID lcid;
480   char iso639[10];
481   char iso3166[10];
482   char *endptr;
483 
484 
485   lcid = strtoul (locale, &endptr, 16);
486   if (*endptr == '\0' &&
487       GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
488       GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
489     {
490       if (strcmp (iso639, iso639_to_check) == 0 &&
491 	  ((iso3166_to_check != NULL &&
492 	    strcmp (iso3166, iso3166_to_check) == 0) ||
493 	   (iso3166_to_check == NULL &&
494 	    SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
495 	{
496 	  char language[100], country[100];
497 	  char locale[300];
498 
499 	  if (script_to_check != NULL)
500 	    {
501 	      /* If lcid is the "other" script for this language,
502 	       * return TRUE, i.e. continue looking.
503 	       */
504 	      if (strcmp (script_to_check, "Latn") == 0)
505 		{
506 		  switch (LANGIDFROMLCID (lcid))
507 		    {
508 		    case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
509 		      return TRUE;
510 		    case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
511 		      return TRUE;
512 		    case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
513 		      return TRUE;
514 		    case MAKELANGID (LANG_SERBIAN, 0x07):
515 		      /* Serbian in Bosnia and Herzegovina, Cyrillic */
516 		      return TRUE;
517 		    }
518 		}
519 	      else if (strcmp (script_to_check, "Cyrl") == 0)
520 		{
521 		  switch (LANGIDFROMLCID (lcid))
522 		    {
523 		    case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
524 		      return TRUE;
525 		    case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
526 		      return TRUE;
527 		    case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
528 		      return TRUE;
529 		    case MAKELANGID (LANG_SERBIAN, 0x06):
530 		      /* Serbian in Bosnia and Herzegovina, Latin */
531 		      return TRUE;
532 		    }
533 		}
534 	    }
535 
536 	  SetThreadLocale (lcid);
537 
538 	  if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
539 	      GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
540 	    {
541 	      strcpy (locale, language);
542 	      strcat (locale, "_");
543 	      strcat (locale, country);
544 
545 	      if (setlocale (LC_ALL, locale) != NULL)
546 		setlocale_called = TRUE;
547 	    }
548 
549 	  return FALSE;
550 	}
551     }
552 
553   return TRUE;
554 }
555 
556 #endif
557 
558 static void
setlocale_initialization(void)559 setlocale_initialization (void)
560 {
561   static gboolean initialized = FALSE;
562 
563   if (initialized)
564     return;
565   initialized = TRUE;
566 
567   if (do_setlocale)
568     {
569 #ifdef G_OS_WIN32
570       /* If some of the POSIXish environment variables are set, set
571        * the Win32 thread locale correspondingly.
572        */
573       char *p = getenv ("LC_ALL");
574       if (p == NULL)
575 	p = getenv ("LANG");
576 
577       if (p != NULL)
578 	{
579 	  p = g_strdup (p);
580 	  if (strcmp (p, "C") == 0)
581 	    SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
582 	  else
583 	    {
584 	      /* Check if one of the supported locales match the
585 	       * environment variable. If so, use that locale.
586 	       */
587 	      iso639_to_check = p;
588 	      iso3166_to_check = strchr (iso639_to_check, '_');
589 	      if (iso3166_to_check != NULL)
590 		{
591 		  *iso3166_to_check++ = '\0';
592 
593 		  script_to_check = strchr (iso3166_to_check, '@');
594 		  if (script_to_check != NULL)
595 		    *script_to_check++ = '\0';
596 
597 		  /* Handle special cases. */
598 
599 		  /* The standard code for Serbia and Montenegro was
600 		   * "CS", but MSFT uses for some reason "SP". By now
601 		   * (October 2006), SP has split into two, "RS" and
602 		   * "ME", but don't bother trying to handle those
603 		   * yet. Do handle the even older "YU", though.
604 		   */
605 		  if (strcmp (iso3166_to_check, "CS") == 0 ||
606 		      strcmp (iso3166_to_check, "YU") == 0)
607 		    iso3166_to_check = "SP";
608 		}
609 	      else
610 		{
611 		  script_to_check = strchr (iso639_to_check, '@');
612 		  if (script_to_check != NULL)
613 		    *script_to_check++ = '\0';
614 		  /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
615 		  if (strcmp (iso639_to_check, "sr") == 0)
616 		    iso3166_to_check = "SP";
617 		}
618 
619 	      EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
620 	    }
621 	  g_free (p);
622 	}
623       if (!setlocale_called)
624 	setlocale (LC_ALL, "");
625 #else
626       if (!setlocale (LC_ALL, ""))
627 	g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
628 #endif
629     }
630 }
631 
632 /* Return TRUE if module_to_check causes version conflicts.
633  * If module_to_check is NULL, check the main module.
634  */
635 gboolean
_gtk_module_has_mixed_deps(GModule * module_to_check)636 _gtk_module_has_mixed_deps (GModule *module_to_check)
637 {
638   GModule *module;
639   gpointer func;
640   gboolean result;
641 
642   if (!module_to_check)
643     module = g_module_open (NULL, 0);
644   else
645     module = module_to_check;
646 
647   if (g_module_symbol (module, "gtk_widget_device_is_shadowed", &func))
648     result = TRUE;
649   else
650     result = FALSE;
651 
652   if (!module_to_check)
653     g_module_close (module);
654 
655   return result;
656 }
657 
658 static void
do_pre_parse_initialization(int * argc,char *** argv)659 do_pre_parse_initialization (int    *argc,
660 			     char ***argv)
661 {
662   const gchar *env_string;
663 
664 #if	0
665   g_set_error_handler (gtk_error);
666   g_set_warning_handler (gtk_warning);
667   g_set_message_handler (gtk_message);
668   g_set_print_handler (gtk_print);
669 #endif
670 
671   if (pre_initialized)
672     return;
673 
674   pre_initialized = TRUE;
675 
676   if (_gtk_module_has_mixed_deps (NULL))
677     g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
678 
679   gdk_pre_parse_libgtk_only ();
680   gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
681 
682 #ifdef G_ENABLE_DEBUG
683   env_string = g_getenv ("GTK_DEBUG");
684   if (env_string != NULL)
685     {
686       gtk_debug_flags = g_parse_debug_string (env_string,
687 					      gtk_debug_keys,
688 					      G_N_ELEMENTS (gtk_debug_keys));
689       env_string = NULL;
690     }
691 #endif	/* G_ENABLE_DEBUG */
692 
693   env_string = g_getenv ("GTK2_MODULES");
694   if (env_string)
695     gtk_modules_string = g_string_new (env_string);
696 
697   env_string = g_getenv ("GTK_MODULES");
698   if (env_string)
699     {
700       if (gtk_modules_string)
701         g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
702       else
703         gtk_modules_string = g_string_new (NULL);
704 
705       g_string_append (gtk_modules_string, env_string);
706     }
707 }
708 
709 static void
gettext_initialization(void)710 gettext_initialization (void)
711 {
712   setlocale_initialization ();
713 
714 #ifdef ENABLE_NLS
715   bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
716   bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
717 #    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
718   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
719   bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
720 #    endif
721 #endif
722 }
723 
724 static void
do_post_parse_initialization(int * argc,char *** argv)725 do_post_parse_initialization (int    *argc,
726 			      char ***argv)
727 {
728   if (gtk_initialized)
729     return;
730 
731   gettext_initialization ();
732 
733 #ifdef SIGPIPE
734   signal (SIGPIPE, SIG_IGN);
735 #endif
736 
737   if (g_fatal_warnings)
738     {
739       GLogLevelFlags fatal_mask;
740 
741       fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
742       fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
743       g_log_set_always_fatal (fatal_mask);
744     }
745 
746   if (gtk_debug_flags & GTK_DEBUG_UPDATES)
747     gdk_window_set_debug_updates (TRUE);
748 
749   {
750   /* Translate to default:RTL if you want your widgets
751    * to be RTL, otherwise translate to default:LTR.
752    * Do *not* translate it to "predefinito:LTR", if it
753    * it isn't default:LTR or default:RTL it will not work
754    */
755     char *e = _("default:LTR");
756     if (strcmp (e, "default:RTL")==0)
757       gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
758     else if (strcmp (e, "default:LTR"))
759       g_warning ("Whoever translated default:LTR did so wrongly.\n");
760   }
761 
762   /* do what the call to gtk_type_init() used to do */
763   g_type_init ();
764 
765   _gtk_accel_map_init ();
766   _gtk_rc_init ();
767 
768   /* Set the 'initialized' flag.
769    */
770   gtk_initialized = TRUE;
771 
772   /* load gtk modules */
773   if (gtk_modules_string)
774     {
775       _gtk_modules_init (argc, argv, gtk_modules_string->str);
776       g_string_free (gtk_modules_string, TRUE);
777     }
778   else
779     {
780       _gtk_modules_init (argc, argv, NULL);
781     }
782 }
783 
784 
785 typedef struct
786 {
787   gboolean open_default_display;
788 } OptionGroupInfo;
789 
790 static gboolean
pre_parse_hook(GOptionContext * context,GOptionGroup * group,gpointer data,GError ** error)791 pre_parse_hook (GOptionContext *context,
792 		GOptionGroup   *group,
793 		gpointer	data,
794 		GError        **error)
795 {
796   do_pre_parse_initialization (NULL, NULL);
797 
798   return TRUE;
799 }
800 
801 static gboolean
post_parse_hook(GOptionContext * context,GOptionGroup * group,gpointer data,GError ** error)802 post_parse_hook (GOptionContext *context,
803 		 GOptionGroup   *group,
804 		 gpointer	data,
805 		 GError        **error)
806 {
807   OptionGroupInfo *info = data;
808 
809 
810   do_post_parse_initialization (NULL, NULL);
811 
812   if (info->open_default_display)
813     {
814       if (gdk_display_open_default_libgtk_only () == NULL)
815 	{
816 	  const char *display_name = gdk_get_display_arg_name ();
817 	  g_set_error (error,
818 		       G_OPTION_ERROR,
819 		       G_OPTION_ERROR_FAILED,
820 		       _("Cannot open display: %s"),
821 		       display_name ? display_name : "" );
822 
823 	  return FALSE;
824 	}
825     }
826 
827   return TRUE;
828 }
829 
830 
831 /**
832  * gtk_get_option_group:
833  * @open_default_display: whether to open the default display
834  *    when parsing the commandline arguments
835  *
836  * Returns a #GOptionGroup for the commandline arguments recognized
837  * by GTK+ and GDK. You should add this group to your #GOptionContext
838  * with g_option_context_add_group(), if you are using
839  * g_option_context_parse() to parse your commandline arguments.
840  *
841  * Returns: a #GOptionGroup for the commandline arguments recognized
842  *   by GTK+
843  *
844  * Since: 2.6
845  */
846 GOptionGroup *
gtk_get_option_group(gboolean open_default_display)847 gtk_get_option_group (gboolean open_default_display)
848 {
849   GOptionGroup *group;
850   OptionGroupInfo *info;
851 
852   gettext_initialization ();
853 
854   info = g_new0 (OptionGroupInfo, 1);
855   info->open_default_display = open_default_display;
856 
857   group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
858   g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
859 
860   gdk_add_option_entries_libgtk_only (group);
861   g_option_group_add_entries (group, gtk_args);
862   g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
863 
864   return group;
865 }
866 
867 /**
868  * gtk_init_with_args:
869  * @argc: a pointer to the number of command line arguments.
870  * @argv: (inout) (array length=argc): a pointer to the array of
871  *    command line arguments.
872  * @parameter_string: a string which is displayed in
873  *    the first line of <option>--help</option> output, after
874  *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
875  * @entries: (array zero-terminated=1):  a %NULL-terminated array
876  *    of #GOptionEntry<!-- -->s describing the options of your program
877  * @translation_domain: a translation domain to use for translating
878  *    the <option>--help</option> output for the options in @entries
879  *    and the @parameter_string with gettext(), or %NULL
880  * @error: a return location for errors
881  *
882  * This function does the same work as gtk_init_check().
883  * Additionally, it allows you to add your own commandline options,
884  * and it automatically generates nicely formatted
885  * <option>--help</option> output. Note that your program will
886  * be terminated after writing out the help output.
887  *
888  * Returns: %TRUE if the GUI has been successfully initialized,
889  *               %FALSE otherwise.
890  *
891  * Since: 2.6
892  */
893 gboolean
gtk_init_with_args(int * argc,char *** argv,const char * parameter_string,GOptionEntry * entries,const char * translation_domain,GError ** error)894 gtk_init_with_args (int            *argc,
895 		    char         ***argv,
896 		    const char     *parameter_string,
897 		    GOptionEntry   *entries,
898 		    const char     *translation_domain,
899 		    GError        **error)
900 {
901   GOptionContext *context;
902   GOptionGroup *gtk_group;
903   gboolean retval;
904 
905   if (gtk_initialized)
906     return gdk_display_open_default_libgtk_only () != NULL;
907 
908   gettext_initialization ();
909 
910   if (!check_setugid ())
911     return FALSE;
912 
913   gtk_group = gtk_get_option_group (TRUE);
914 
915   context = g_option_context_new (parameter_string);
916   g_option_context_add_group (context, gtk_group);
917 
918   g_option_context_set_translation_domain (context, translation_domain);
919 
920   if (entries)
921     g_option_context_add_main_entries (context, entries, translation_domain);
922   retval = g_option_context_parse (context, argc, argv, error);
923 
924   g_option_context_free (context);
925 
926   return retval;
927 }
928 
929 
930 /**
931  * gtk_parse_args:
932  * @argc: (inout): a pointer to the number of command line arguments
933  * @argv: (array length=argc) (inout): a pointer to the array of
934  *     command line arguments
935  *
936  * Parses command line arguments, and initializes global
937  * attributes of GTK+, but does not actually open a connection
938  * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
939  *
940  * Any arguments used by GTK+ or GDK are removed from the array and
941  * @argc and @argv are updated accordingly.
942  *
943  * There is no need to call this function explicitely if you are using
944  * gtk_init(), or gtk_init_check().
945  *
946  * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
947  **/
948 gboolean
gtk_parse_args(int * argc,char *** argv)949 gtk_parse_args (int    *argc,
950 		char ***argv)
951 {
952   GOptionContext *option_context;
953   GOptionGroup *gtk_group;
954   GError *error = NULL;
955 
956   if (gtk_initialized)
957     return TRUE;
958 
959   gettext_initialization ();
960 
961   if (!check_setugid ())
962     return FALSE;
963 
964   option_context = g_option_context_new (NULL);
965   g_option_context_set_ignore_unknown_options (option_context, TRUE);
966   g_option_context_set_help_enabled (option_context, FALSE);
967   gtk_group = gtk_get_option_group (FALSE);
968   g_option_context_set_main_group (option_context, gtk_group);
969   if (!g_option_context_parse (option_context, argc, argv, &error))
970     {
971       g_warning ("%s", error->message);
972       g_error_free (error);
973     }
974 
975   g_option_context_free (option_context);
976 
977   return TRUE;
978 }
979 
980 #ifdef G_PLATFORM_WIN32
981 #undef gtk_init_check
982 #endif
983 
984 /**
985  * gtk_init_check:
986  * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
987  *   main() function. Changed if any arguments were handled.
988  * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
989  *   Any parameters understood by gtk_init() are stripped before return.
990  *
991  * This function does the same work as gtk_init() with only
992  * a single change: It does not terminate the program if the GUI can't be
993  * initialized. Instead it returns %FALSE on failure.
994  *
995  * This way the application can fall back to some other means of communication
996  * with the user - for example a curses or command line interface.
997  *
998  * Return value: %TRUE if the GUI has been successfully initialized,
999  *               %FALSE otherwise.
1000  **/
1001 gboolean
gtk_init_check(int * argc,char *** argv)1002 gtk_init_check (int	 *argc,
1003 		char   ***argv)
1004 {
1005   if (!gtk_parse_args (argc, argv))
1006     return FALSE;
1007 
1008   return gdk_display_open_default_libgtk_only () != NULL;
1009 }
1010 
1011 #ifdef G_PLATFORM_WIN32
1012 #undef gtk_init
1013 #endif
1014 
1015 /**
1016  * gtk_init:
1017  * @argc: (inout): Address of the <parameter>argc</parameter> parameter of
1018  *     your main() function. Changed if any arguments were handled
1019  * @argv: (array length=argc) (inout) (allow-none): Address of the
1020  *     <parameter>argv</parameter> parameter of main(). Any options
1021  *     understood by GTK+ are stripped before return.
1022  *
1023  * Call this function before using any other GTK+ functions in your GUI
1024  * applications.  It will initialize everything needed to operate the
1025  * toolkit and parses some standard command line options.
1026  *
1027  * @argc and @argv are adjusted accordingly so your own code will
1028  * never see those standard arguments.
1029  *
1030  * Note that there are some alternative ways to initialize GTK+:
1031  * if you are calling gtk_parse_args(), gtk_init_check(),
1032  * gtk_init_with_args() or g_option_context_parse() with
1033  * the option group returned by gtk_get_option_group(),
1034  * you <emphasis>don't</emphasis> have to call gtk_init().
1035  *
1036  * <note><para>
1037  * This function will terminate your program if it was unable to
1038  * initialize the windowing system for some reason. If you want
1039  * your program to fall back to a textual interface you want to
1040  * call gtk_init_check() instead.
1041  * </para></note>
1042  *
1043  * <note><para>
1044  * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
1045  * during initialization, to ignore SIGPIPE signals, since these are
1046  * almost never wanted in graphical applications. If you do need to
1047  * handle SIGPIPE for some reason, reset the handler after gtk_init(),
1048  * but notice that other libraries (e.g. libdbus or gvfs) might do
1049  * similar things.
1050  * </para></note>
1051  */
1052 void
gtk_init(int * argc,char *** argv)1053 gtk_init (int *argc, char ***argv)
1054 {
1055   if (!gtk_init_check (argc, argv))
1056     {
1057       const char *display_name_arg = gdk_get_display_arg_name ();
1058       if (display_name_arg == NULL)
1059         display_name_arg = getenv("DISPLAY");
1060       g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
1061       exit (1);
1062     }
1063 }
1064 
1065 #ifdef G_PLATFORM_WIN32
1066 
1067 static void
check_sizeof_GtkWindow(size_t sizeof_GtkWindow)1068 check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
1069 {
1070   if (sizeof_GtkWindow != sizeof (GtkWindow))
1071     g_error ("Incompatible build!\n"
1072 	     "The code using GTK+ thinks GtkWindow is of different\n"
1073              "size than it actually is in this build of GTK+.\n"
1074 	     "On Windows, this probably means that you have compiled\n"
1075 	     "your code with gcc without the -mms-bitfields switch,\n"
1076 	     "or that you are using an unsupported compiler.");
1077 }
1078 
1079 /* In GTK+ 2.0 the GtkWindow struct actually is the same size in
1080  * gcc-compiled code on Win32 whether compiled with -fnative-struct or
1081  * not. Unfortunately this wan't noticed until after GTK+ 2.0.1. So,
1082  * from GTK+ 2.0.2 on, check some other struct, too, where the use of
1083  * -fnative-struct still matters. GtkBox is one such.
1084  */
1085 static void
check_sizeof_GtkBox(size_t sizeof_GtkBox)1086 check_sizeof_GtkBox (size_t sizeof_GtkBox)
1087 {
1088   if (sizeof_GtkBox != sizeof (GtkBox))
1089     g_error ("Incompatible build!\n"
1090 	     "The code using GTK+ thinks GtkBox is of different\n"
1091              "size than it actually is in this build of GTK+.\n"
1092 	     "On Windows, this probably means that you have compiled\n"
1093 	     "your code with gcc without the -mms-bitfields switch,\n"
1094 	     "or that you are using an unsupported compiler.");
1095 }
1096 
1097 /* These two functions might get more checks added later, thus pass
1098  * in the number of extra args.
1099  */
1100 void
gtk_init_abi_check(int * argc,char *** argv,int num_checks,size_t sizeof_GtkWindow,size_t sizeof_GtkBox)1101 gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1102 {
1103   check_sizeof_GtkWindow (sizeof_GtkWindow);
1104   if (num_checks >= 2)
1105     check_sizeof_GtkBox (sizeof_GtkBox);
1106   gtk_init (argc, argv);
1107 }
1108 
1109 gboolean
gtk_init_check_abi_check(int * argc,char *** argv,int num_checks,size_t sizeof_GtkWindow,size_t sizeof_GtkBox)1110 gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
1111 {
1112   check_sizeof_GtkWindow (sizeof_GtkWindow);
1113   if (num_checks >= 2)
1114     check_sizeof_GtkBox (sizeof_GtkBox);
1115   return gtk_init_check (argc, argv);
1116 }
1117 
1118 #endif
1119 
1120 void
gtk_exit(gint errorcode)1121 gtk_exit (gint errorcode)
1122 {
1123   exit (errorcode);
1124 }
1125 
1126 
1127 /**
1128  * gtk_set_locale:
1129  *
1130  * Initializes internationalization support for GTK+. gtk_init()
1131  * automatically does this, so there is typically no point
1132  * in calling this function.
1133  *
1134  * If you are calling this function because you changed the locale
1135  * after GTK+ is was initialized, then calling this function
1136  * may help a bit. (Note, however, that changing the locale
1137  * after GTK+ is initialized may produce inconsistent results and
1138  * is not really supported.)
1139  *
1140  * In detail - sets the current locale according to the
1141  * program environment. This is the same as calling the C library function
1142  * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the
1143  * locale specific setup of the windowing system used by GDK.
1144  *
1145  * Returns: a string corresponding to the locale set, typically in the
1146  * form lang_COUNTRY, where lang is an ISO-639 language code, and
1147  * COUNTRY is an ISO-3166 country code. On Unix, this form matches the
1148  * result of the setlocale(); it is also used on other machines, such as
1149  * Windows, where the C library returns a different result. The string is
1150  * owned by GTK+ and should not be modified or freed.
1151  *
1152  * Deprecated: 2.24: Use setlocale() directly
1153  **/
1154 gchar *
gtk_set_locale(void)1155 gtk_set_locale (void)
1156 {
1157   return gdk_set_locale ();
1158 }
1159 
1160 /**
1161  * _gtk_get_lc_ctype:
1162  *
1163  * Return the Unix-style locale string for the language currently in
1164  * effect. On Unix systems, this is the return value from
1165  * <literal>setlocale(LC_CTYPE, NULL)</literal>, and the user can
1166  * affect this through the environment variables LC_ALL, LC_CTYPE or
1167  * LANG (checked in that order). The locale strings typically is in
1168  * the form lang_COUNTRY, where lang is an ISO-639 language code, and
1169  * COUNTRY is an ISO-3166 country code. For instance, sv_FI for
1170  * Swedish as written in Finland or pt_BR for Portuguese as written in
1171  * Brazil.
1172  *
1173  * On Windows, the C library doesn't use any such environment
1174  * variables, and setting them won't affect the behaviour of functions
1175  * like ctime(). The user sets the locale through the Regional Options
1176  * in the Control Panel. The C library (in the setlocale() function)
1177  * does not use country and language codes, but country and language
1178  * names spelled out in English.
1179  * However, this function does check the above environment
1180  * variables, and does return a Unix-style locale string based on
1181  * either said environment variables or the thread's current locale.
1182  *
1183  * Return value: a dynamically allocated string, free with g_free().
1184  */
1185 
1186 gchar *
_gtk_get_lc_ctype(void)1187 _gtk_get_lc_ctype (void)
1188 {
1189 #ifdef G_OS_WIN32
1190   /* Somebody might try to set the locale for this process using the
1191    * LANG or LC_ environment variables. The Microsoft C library
1192    * doesn't know anything about them. You set the locale in the
1193    * Control Panel. Setting these env vars won't have any affect on
1194    * locale-dependent C library functions like ctime(). But just for
1195    * kicks, do obey LC_ALL, LC_CTYPE and LANG in GTK. (This also makes
1196    * it easier to test GTK and Pango in various default languages, you
1197    * don't have to clickety-click in the Control Panel, you can simply
1198    * start the program with LC_ALL=something on the command line.)
1199    */
1200   gchar *p;
1201 
1202   p = getenv ("LC_ALL");
1203   if (p != NULL)
1204     return g_strdup (p);
1205 
1206   p = getenv ("LC_CTYPE");
1207   if (p != NULL)
1208     return g_strdup (p);
1209 
1210   p = getenv ("LANG");
1211   if (p != NULL)
1212     return g_strdup (p);
1213 
1214   return g_win32_getlocale ();
1215 #else
1216   return g_strdup (setlocale (LC_CTYPE, NULL));
1217 #endif
1218 }
1219 
1220 /**
1221  * gtk_get_default_language:
1222  *
1223  * Returns the #PangoLanguage for the default language currently in
1224  * effect. (Note that this can change over the life of an
1225  * application.)  The default language is derived from the current
1226  * locale. It determines, for example, whether GTK+ uses the
1227  * right-to-left or left-to-right text direction.
1228  *
1229  * This function is equivalent to pango_language_get_default().  See
1230  * that function for details.
1231  *
1232  * Return value: the default language as a #PangoLanguage, must not be
1233  * freed
1234  **/
1235 PangoLanguage *
gtk_get_default_language(void)1236 gtk_get_default_language (void)
1237 {
1238   return pango_language_get_default ();
1239 }
1240 
1241 void
gtk_main(void)1242 gtk_main (void)
1243 {
1244   GList *tmp_list;
1245   GList *functions;
1246   GtkInitFunction *init;
1247   GMainLoop *loop;
1248 
1249   gtk_main_loop_level++;
1250 
1251   loop = g_main_loop_new (NULL, TRUE);
1252   main_loops = g_slist_prepend (main_loops, loop);
1253 
1254   tmp_list = functions = init_functions;
1255   init_functions = NULL;
1256 
1257   while (tmp_list)
1258     {
1259       init = tmp_list->data;
1260       tmp_list = tmp_list->next;
1261 
1262       (* init->function) (init->data);
1263       g_free (init);
1264     }
1265   g_list_free (functions);
1266 
1267   if (g_main_loop_is_running (main_loops->data))
1268     {
1269       GDK_THREADS_LEAVE ();
1270       g_main_loop_run (loop);
1271       GDK_THREADS_ENTER ();
1272       gdk_flush ();
1273     }
1274 
1275   if (quit_functions)
1276     {
1277       GList *reinvoke_list = NULL;
1278       GtkQuitFunction *quitf;
1279 
1280       while (quit_functions)
1281 	{
1282 	  quitf = quit_functions->data;
1283 
1284 	  tmp_list = quit_functions;
1285 	  quit_functions = g_list_remove_link (quit_functions, quit_functions);
1286 	  g_list_free_1 (tmp_list);
1287 
1288 	  if ((quitf->main_level && quitf->main_level != gtk_main_loop_level) ||
1289 	      gtk_quit_invoke_function (quitf))
1290 	    {
1291 	      reinvoke_list = g_list_prepend (reinvoke_list, quitf);
1292 	    }
1293 	  else
1294 	    {
1295 	      gtk_quit_destroy (quitf);
1296 	    }
1297 	}
1298       if (reinvoke_list)
1299 	{
1300 	  GList *work;
1301 
1302 	  work = g_list_last (reinvoke_list);
1303 	  if (quit_functions)
1304 	    quit_functions->prev = work;
1305 	  work->next = quit_functions;
1306 	  quit_functions = work;
1307 	}
1308 
1309       gdk_flush ();
1310     }
1311 
1312   main_loops = g_slist_remove (main_loops, loop);
1313 
1314   g_main_loop_unref (loop);
1315 
1316   gtk_main_loop_level--;
1317 
1318   if (gtk_main_loop_level == 0)
1319     {
1320       /* Try storing all clipboard data we have */
1321       _gtk_clipboard_store_all ();
1322 
1323       /* Synchronize the recent manager singleton */
1324       _gtk_recent_manager_sync ();
1325     }
1326 }
1327 
1328 guint
gtk_main_level(void)1329 gtk_main_level (void)
1330 {
1331   return gtk_main_loop_level;
1332 }
1333 
1334 void
gtk_main_quit(void)1335 gtk_main_quit (void)
1336 {
1337   g_return_if_fail (main_loops != NULL);
1338 
1339   g_main_loop_quit (main_loops->data);
1340 }
1341 
1342 gboolean
gtk_events_pending(void)1343 gtk_events_pending (void)
1344 {
1345   gboolean result;
1346 
1347   GDK_THREADS_LEAVE ();
1348   result = g_main_context_pending (NULL);
1349   GDK_THREADS_ENTER ();
1350 
1351   return result;
1352 }
1353 
1354 gboolean
gtk_main_iteration(void)1355 gtk_main_iteration (void)
1356 {
1357   GDK_THREADS_LEAVE ();
1358   g_main_context_iteration (NULL, TRUE);
1359   GDK_THREADS_ENTER ();
1360 
1361   if (main_loops)
1362     return !g_main_loop_is_running (main_loops->data);
1363   else
1364     return TRUE;
1365 }
1366 
1367 gboolean
gtk_main_iteration_do(gboolean blocking)1368 gtk_main_iteration_do (gboolean blocking)
1369 {
1370   GDK_THREADS_LEAVE ();
1371   g_main_context_iteration (NULL, blocking);
1372   GDK_THREADS_ENTER ();
1373 
1374   if (main_loops)
1375     return !g_main_loop_is_running (main_loops->data);
1376   else
1377     return TRUE;
1378 }
1379 
1380 /* private libgtk to libgdk interfaces
1381  */
1382 gboolean gdk_pointer_grab_info_libgtk_only  (GdkDisplay *display,
1383 					     GdkWindow **grab_window,
1384 					     gboolean   *owner_events);
1385 gboolean gdk_keyboard_grab_info_libgtk_only (GdkDisplay *display,
1386 					     GdkWindow **grab_window,
1387 					     gboolean   *owner_events);
1388 
1389 static void
rewrite_events_translate(GdkWindow * old_window,GdkWindow * new_window,gdouble * x,gdouble * y)1390 rewrite_events_translate (GdkWindow *old_window,
1391 			  GdkWindow *new_window,
1392 			  gdouble   *x,
1393 			  gdouble   *y)
1394 {
1395   gint old_origin_x, old_origin_y;
1396   gint new_origin_x, new_origin_y;
1397 
1398   gdk_window_get_origin	(old_window, &old_origin_x, &old_origin_y);
1399   gdk_window_get_origin	(new_window, &new_origin_x, &new_origin_y);
1400 
1401   *x += old_origin_x - new_origin_x;
1402   *y += old_origin_y - new_origin_y;
1403 }
1404 
1405 static GdkEvent *
rewrite_event_for_window(GdkEvent * event,GdkWindow * new_window)1406 rewrite_event_for_window (GdkEvent  *event,
1407 			  GdkWindow *new_window)
1408 {
1409   event = gdk_event_copy (event);
1410 
1411   switch (event->type)
1412     {
1413     case GDK_SCROLL:
1414       rewrite_events_translate (event->any.window,
1415 				new_window,
1416 				&event->scroll.x, &event->scroll.y);
1417       break;
1418     case GDK_BUTTON_PRESS:
1419     case GDK_2BUTTON_PRESS:
1420     case GDK_3BUTTON_PRESS:
1421     case GDK_BUTTON_RELEASE:
1422       rewrite_events_translate (event->any.window,
1423 				new_window,
1424 				&event->button.x, &event->button.y);
1425       break;
1426     case GDK_MOTION_NOTIFY:
1427       rewrite_events_translate (event->any.window,
1428 				new_window,
1429 				&event->motion.x, &event->motion.y);
1430       break;
1431     case GDK_KEY_PRESS:
1432     case GDK_KEY_RELEASE:
1433     case GDK_PROXIMITY_IN:
1434     case GDK_PROXIMITY_OUT:
1435       break;
1436 
1437     default:
1438       return event;
1439     }
1440 
1441   g_object_unref (event->any.window);
1442   event->any.window = g_object_ref (new_window);
1443 
1444   return event;
1445 }
1446 
1447 /* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1448  * then what X11 does is deliver the event normally if it was going to this
1449  * client, otherwise, delivers it in terms of the grab window. This function
1450  * rewrites events to the effect that events going to the same window group
1451  * are delivered normally, otherwise, the event is delivered in terms of the
1452  * grab window.
1453  */
1454 static GdkEvent *
rewrite_event_for_grabs(GdkEvent * event)1455 rewrite_event_for_grabs (GdkEvent *event)
1456 {
1457   GdkWindow *grab_window;
1458   GtkWidget *event_widget, *grab_widget;
1459   gpointer grab_widget_ptr;
1460   gboolean owner_events;
1461   GdkDisplay *display;
1462 
1463   switch (event->type)
1464     {
1465     case GDK_SCROLL:
1466     case GDK_BUTTON_PRESS:
1467     case GDK_2BUTTON_PRESS:
1468     case GDK_3BUTTON_PRESS:
1469     case GDK_BUTTON_RELEASE:
1470     case GDK_MOTION_NOTIFY:
1471     case GDK_PROXIMITY_IN:
1472     case GDK_PROXIMITY_OUT:
1473       display = gdk_window_get_display (event->proximity.window);
1474       if (!gdk_pointer_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1475 	  !owner_events)
1476 	return NULL;
1477       break;
1478 
1479     case GDK_KEY_PRESS:
1480     case GDK_KEY_RELEASE:
1481       display = gdk_window_get_display (event->key.window);
1482       if (!gdk_keyboard_grab_info_libgtk_only (display, &grab_window, &owner_events) ||
1483 	  !owner_events)
1484 	return NULL;
1485       break;
1486 
1487     default:
1488       return NULL;
1489     }
1490 
1491   event_widget = gtk_get_event_widget (event);
1492   gdk_window_get_user_data (grab_window, &grab_widget_ptr);
1493   grab_widget = grab_widget_ptr;
1494 
1495   if (grab_widget &&
1496       gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1497     return rewrite_event_for_window (event, grab_window);
1498   else
1499     return NULL;
1500 }
1501 
1502 void
gtk_main_do_event(GdkEvent * event)1503 gtk_main_do_event (GdkEvent *event)
1504 {
1505   GtkWidget *event_widget;
1506   GtkWidget *grab_widget;
1507   GtkWindowGroup *window_group;
1508   GdkEvent *rewritten_event = NULL;
1509   GList *tmp_list;
1510 
1511   if (event->type == GDK_SETTING)
1512     {
1513       _gtk_settings_handle_event (&event->setting);
1514       return;
1515     }
1516 
1517   if (event->type == GDK_OWNER_CHANGE)
1518     {
1519       _gtk_clipboard_handle_event (&event->owner_change);
1520       return;
1521     }
1522 
1523   /* Find the widget which got the event. We store the widget
1524    *  in the user_data field of GdkWindow's.
1525    *  Ignore the event if we don't have a widget for it, except
1526    *  for GDK_PROPERTY_NOTIFY events which are handled specialy.
1527    *  Though this happens rarely, bogus events can occour
1528    *  for e.g. destroyed GdkWindows.
1529    */
1530   event_widget = gtk_get_event_widget (event);
1531   if (!event_widget)
1532     {
1533       /* To handle selection INCR transactions, we select
1534        * PropertyNotify events on the requestor window and create
1535        * a corresponding (fake) GdkWindow so that events get
1536        * here. There won't be a widget though, so we have to handle
1537 	   * them specially
1538 	   */
1539       if (event->type == GDK_PROPERTY_NOTIFY)
1540 	_gtk_selection_incr_event (event->any.window,
1541 				   &event->property);
1542 
1543       return;
1544     }
1545 
1546   /* If pointer or keyboard grabs are in effect, munge the events
1547    * so that each window group looks like a separate app.
1548    */
1549   rewritten_event = rewrite_event_for_grabs (event);
1550   if (rewritten_event)
1551     {
1552       event = rewritten_event;
1553       event_widget = gtk_get_event_widget (event);
1554     }
1555 
1556   window_group = gtk_main_get_window_group (event_widget);
1557 
1558   /* Push the event onto a stack of current events for
1559    * gtk_current_event_get().
1560    */
1561   current_events = g_list_prepend (current_events, event);
1562 
1563   /* If there is a grab in effect...
1564    */
1565   if (window_group->grabs)
1566     {
1567       grab_widget = window_group->grabs->data;
1568 
1569       /* If the grab widget is an ancestor of the event widget
1570        *  then we send the event to the original event widget.
1571        *  This is the key to implementing modality.
1572        */
1573       if ((gtk_widget_is_sensitive (event_widget) || event->type == GDK_SCROLL) &&
1574 	  gtk_widget_is_ancestor (event_widget, grab_widget))
1575 	grab_widget = event_widget;
1576     }
1577   else
1578     {
1579       grab_widget = event_widget;
1580     }
1581 
1582   /* Not all events get sent to the grabbing widget.
1583    * The delete, destroy, expose, focus change and resize
1584    *  events still get sent to the event widget because
1585    *  1) these events have no meaning for the grabbing widget
1586    *  and 2) redirecting these events to the grabbing widget
1587    *  could cause the display to be messed up.
1588    *
1589    * Drag events are also not redirected, since it isn't
1590    *  clear what the semantics of that would be.
1591    */
1592   switch (event->type)
1593     {
1594     case GDK_NOTHING:
1595       break;
1596 
1597     case GDK_DELETE:
1598       g_object_ref (event_widget);
1599       if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
1600 	  !gtk_widget_event (event_widget, event))
1601 	gtk_widget_destroy (event_widget);
1602       g_object_unref (event_widget);
1603       break;
1604 
1605     case GDK_DESTROY:
1606       /* Unexpected GDK_DESTROY from the outside, ignore for
1607        * child windows, handle like a GDK_DELETE for toplevels
1608        */
1609       if (!event_widget->parent)
1610 	{
1611 	  g_object_ref (event_widget);
1612 	  if (!gtk_widget_event (event_widget, event) &&
1613 	      gtk_widget_get_realized (event_widget))
1614 	    gtk_widget_destroy (event_widget);
1615 	  g_object_unref (event_widget);
1616 	}
1617       break;
1618 
1619     case GDK_EXPOSE:
1620       if (event->any.window && gtk_widget_get_double_buffered (event_widget))
1621 	{
1622 	  gdk_window_begin_paint_region (event->any.window, event->expose.region);
1623 	  gtk_widget_send_expose (event_widget, event);
1624 	  gdk_window_end_paint (event->any.window);
1625 	}
1626       else
1627 	{
1628 	  /* The app may paint with a previously allocated cairo_t,
1629 	     which will draw directly to the window. We can't catch cairo
1630 	     drap operatoins to automatically flush the window, thus we
1631 	     need to explicitly flush any outstanding moves or double
1632 	     buffering */
1633 	  gdk_window_flush (event->any.window);
1634 	  gtk_widget_send_expose (event_widget, event);
1635 	}
1636       break;
1637 
1638     case GDK_PROPERTY_NOTIFY:
1639     case GDK_NO_EXPOSE:
1640     case GDK_FOCUS_CHANGE:
1641     case GDK_CONFIGURE:
1642     case GDK_MAP:
1643     case GDK_UNMAP:
1644     case GDK_SELECTION_CLEAR:
1645     case GDK_SELECTION_REQUEST:
1646     case GDK_SELECTION_NOTIFY:
1647     case GDK_CLIENT_EVENT:
1648     case GDK_VISIBILITY_NOTIFY:
1649     case GDK_WINDOW_STATE:
1650     case GDK_GRAB_BROKEN:
1651     case GDK_DAMAGE:
1652       gtk_widget_event (event_widget, event);
1653       break;
1654 
1655     case GDK_SCROLL:
1656     case GDK_BUTTON_PRESS:
1657     case GDK_2BUTTON_PRESS:
1658     case GDK_3BUTTON_PRESS:
1659       gtk_propagate_event (grab_widget, event);
1660       break;
1661 
1662     case GDK_KEY_PRESS:
1663     case GDK_KEY_RELEASE:
1664       if (key_snoopers)
1665 	{
1666 	  if (gtk_invoke_key_snoopers (grab_widget, event))
1667 	    break;
1668 	}
1669       /* Catch alt press to enable auto-mnemonics;
1670        * menus are handled elsewhere
1671        */
1672       if ((event->key.keyval == GDK_Alt_L || event->key.keyval == GDK_Alt_R) &&
1673           !GTK_IS_MENU_SHELL (grab_widget))
1674         {
1675           gboolean auto_mnemonics;
1676 
1677           g_object_get (gtk_widget_get_settings (grab_widget),
1678                         "gtk-auto-mnemonics", &auto_mnemonics, NULL);
1679 
1680           if (auto_mnemonics)
1681             {
1682               gboolean mnemonics_visible;
1683               GtkWidget *window;
1684 
1685               mnemonics_visible = (event->type == GDK_KEY_PRESS);
1686 
1687               window = gtk_widget_get_toplevel (grab_widget);
1688 
1689               if (GTK_IS_WINDOW (window))
1690                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
1691             }
1692         }
1693       /* else fall through */
1694     case GDK_MOTION_NOTIFY:
1695     case GDK_BUTTON_RELEASE:
1696     case GDK_PROXIMITY_IN:
1697     case GDK_PROXIMITY_OUT:
1698       gtk_propagate_event (grab_widget, event);
1699       break;
1700 
1701     case GDK_ENTER_NOTIFY:
1702       GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
1703       _gtk_widget_set_pointer_window (event_widget, event->any.window);
1704       if (gtk_widget_is_sensitive (grab_widget))
1705 	gtk_widget_event (grab_widget, event);
1706       break;
1707 
1708     case GDK_LEAVE_NOTIFY:
1709       GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
1710       if (gtk_widget_is_sensitive (grab_widget))
1711 	gtk_widget_event (grab_widget, event);
1712       break;
1713 
1714     case GDK_DRAG_STATUS:
1715     case GDK_DROP_FINISHED:
1716       _gtk_drag_source_handle_event (event_widget, event);
1717       break;
1718     case GDK_DRAG_ENTER:
1719     case GDK_DRAG_LEAVE:
1720     case GDK_DRAG_MOTION:
1721     case GDK_DROP_START:
1722       _gtk_drag_dest_handle_event (event_widget, event);
1723       break;
1724     default:
1725       g_assert_not_reached ();
1726       break;
1727     }
1728 
1729   if (event->type == GDK_ENTER_NOTIFY
1730       || event->type == GDK_LEAVE_NOTIFY
1731       || event->type == GDK_BUTTON_PRESS
1732       || event->type == GDK_2BUTTON_PRESS
1733       || event->type == GDK_3BUTTON_PRESS
1734       || event->type == GDK_KEY_PRESS
1735       || event->type == GDK_DRAG_ENTER
1736       || event->type == GDK_GRAB_BROKEN
1737       || event->type == GDK_MOTION_NOTIFY
1738       || event->type == GDK_SCROLL)
1739     {
1740       _gtk_tooltip_handle_event (event);
1741     }
1742 
1743   tmp_list = current_events;
1744   current_events = g_list_remove_link (current_events, tmp_list);
1745   g_list_free_1 (tmp_list);
1746 
1747   if (rewritten_event)
1748     gdk_event_free (rewritten_event);
1749 }
1750 
1751 gboolean
gtk_true(void)1752 gtk_true (void)
1753 {
1754   return TRUE;
1755 }
1756 
1757 gboolean
gtk_false(void)1758 gtk_false (void)
1759 {
1760   return FALSE;
1761 }
1762 
1763 static GtkWindowGroup *
gtk_main_get_window_group(GtkWidget * widget)1764 gtk_main_get_window_group (GtkWidget   *widget)
1765 {
1766   GtkWidget *toplevel = NULL;
1767 
1768   if (widget)
1769     toplevel = gtk_widget_get_toplevel (widget);
1770 
1771   if (GTK_IS_WINDOW (toplevel))
1772     return gtk_window_get_group (GTK_WINDOW (toplevel));
1773   else
1774     return gtk_window_get_group (NULL);
1775 }
1776 
1777 typedef struct
1778 {
1779   GtkWidget *old_grab_widget;
1780   GtkWidget *new_grab_widget;
1781   gboolean   was_grabbed;
1782   gboolean   is_grabbed;
1783   gboolean   from_grab;
1784 } GrabNotifyInfo;
1785 
1786 static void
gtk_grab_notify_foreach(GtkWidget * child,gpointer data)1787 gtk_grab_notify_foreach (GtkWidget *child,
1788 			 gpointer   data)
1789 
1790 {
1791   GrabNotifyInfo *info = data;
1792 
1793   gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
1794 
1795   was_grabbed = info->was_grabbed;
1796   is_grabbed = info->is_grabbed;
1797 
1798   info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
1799   info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
1800 
1801   was_shadowed = info->old_grab_widget && !info->was_grabbed;
1802   is_shadowed = info->new_grab_widget && !info->is_grabbed;
1803 
1804   g_object_ref (child);
1805 
1806   if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
1807     gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
1808 
1809   if (is_shadowed)
1810     {
1811       GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
1812       if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
1813 	  && gtk_widget_is_sensitive (child))
1814 	_gtk_widget_synthesize_crossing (child, info->new_grab_widget,
1815 					 GDK_CROSSING_GTK_GRAB);
1816     }
1817   else
1818     {
1819       GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
1820       if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
1821 	  && gtk_widget_is_sensitive (child))
1822 	_gtk_widget_synthesize_crossing (info->old_grab_widget, child,
1823 					 info->from_grab ? GDK_CROSSING_GTK_GRAB
1824 					 : GDK_CROSSING_GTK_UNGRAB);
1825     }
1826 
1827   if (was_shadowed != is_shadowed)
1828     _gtk_widget_grab_notify (child, was_shadowed);
1829 
1830   g_object_unref (child);
1831 
1832   info->was_grabbed = was_grabbed;
1833   info->is_grabbed = is_grabbed;
1834 }
1835 
1836 static void
gtk_grab_notify(GtkWindowGroup * group,GtkWidget * old_grab_widget,GtkWidget * new_grab_widget,gboolean from_grab)1837 gtk_grab_notify (GtkWindowGroup *group,
1838 		 GtkWidget      *old_grab_widget,
1839 		 GtkWidget      *new_grab_widget,
1840 		 gboolean        from_grab)
1841 {
1842   GList *toplevels;
1843   GrabNotifyInfo info;
1844 
1845   if (old_grab_widget == new_grab_widget)
1846     return;
1847 
1848   info.old_grab_widget = old_grab_widget;
1849   info.new_grab_widget = new_grab_widget;
1850   info.from_grab = from_grab;
1851 
1852   g_object_ref (group);
1853 
1854   toplevels = gtk_window_list_toplevels ();
1855   g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
1856 
1857   while (toplevels)
1858     {
1859       GtkWindow *toplevel = toplevels->data;
1860       toplevels = g_list_delete_link (toplevels, toplevels);
1861 
1862       info.was_grabbed = FALSE;
1863       info.is_grabbed = FALSE;
1864 
1865       if (group == gtk_window_get_group (toplevel))
1866 	gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
1867       g_object_unref (toplevel);
1868     }
1869 
1870   g_object_unref (group);
1871 }
1872 
1873 void
gtk_grab_add(GtkWidget * widget)1874 gtk_grab_add (GtkWidget *widget)
1875 {
1876   GtkWindowGroup *group;
1877   GtkWidget *old_grab_widget;
1878 
1879   g_return_if_fail (widget != NULL);
1880 
1881   if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
1882     {
1883       _gtk_widget_set_has_grab (widget, TRUE);
1884 
1885       group = gtk_main_get_window_group (widget);
1886 
1887       if (group->grabs)
1888 	old_grab_widget = (GtkWidget *)group->grabs->data;
1889       else
1890 	old_grab_widget = NULL;
1891 
1892       g_object_ref (widget);
1893       group->grabs = g_slist_prepend (group->grabs, widget);
1894 
1895       gtk_grab_notify (group, old_grab_widget, widget, TRUE);
1896     }
1897 }
1898 
1899 /**
1900  * gtk_grab_get_current:
1901  *
1902  * Queries the current grab of the default window group.
1903  *
1904  * Return value: (transfer none): The widget which currently
1905  *     has the grab or %NULL if no grab is active
1906  */
1907 GtkWidget*
gtk_grab_get_current(void)1908 gtk_grab_get_current (void)
1909 {
1910   GtkWindowGroup *group;
1911 
1912   group = gtk_main_get_window_group (NULL);
1913 
1914   if (group->grabs)
1915     return GTK_WIDGET (group->grabs->data);
1916   return NULL;
1917 }
1918 
1919 void
gtk_grab_remove(GtkWidget * widget)1920 gtk_grab_remove (GtkWidget *widget)
1921 {
1922   GtkWindowGroup *group;
1923   GtkWidget *new_grab_widget;
1924 
1925   g_return_if_fail (widget != NULL);
1926 
1927   if (gtk_widget_has_grab (widget))
1928     {
1929       _gtk_widget_set_has_grab (widget, FALSE);
1930 
1931       group = gtk_main_get_window_group (widget);
1932       group->grabs = g_slist_remove (group->grabs, widget);
1933 
1934       if (group->grabs)
1935 	new_grab_widget = (GtkWidget *)group->grabs->data;
1936       else
1937 	new_grab_widget = NULL;
1938 
1939       gtk_grab_notify (group, widget, new_grab_widget, FALSE);
1940 
1941       g_object_unref (widget);
1942     }
1943 }
1944 
1945 void
gtk_init_add(GtkFunction function,gpointer data)1946 gtk_init_add (GtkFunction function,
1947 	      gpointer	  data)
1948 {
1949   GtkInitFunction *init;
1950 
1951   init = g_new (GtkInitFunction, 1);
1952   init->function = function;
1953   init->data = data;
1954 
1955   init_functions = g_list_prepend (init_functions, init);
1956 }
1957 
1958 guint
gtk_key_snooper_install(GtkKeySnoopFunc snooper,gpointer func_data)1959 gtk_key_snooper_install (GtkKeySnoopFunc snooper,
1960 			 gpointer	 func_data)
1961 {
1962   GtkKeySnooperData *data;
1963   static guint snooper_id = 1;
1964 
1965   g_return_val_if_fail (snooper != NULL, 0);
1966 
1967   data = g_new (GtkKeySnooperData, 1);
1968   data->func = snooper;
1969   data->func_data = func_data;
1970   data->id = snooper_id++;
1971   key_snoopers = g_slist_prepend (key_snoopers, data);
1972 
1973   return data->id;
1974 }
1975 
1976 void
gtk_key_snooper_remove(guint snooper_id)1977 gtk_key_snooper_remove (guint snooper_id)
1978 {
1979   GtkKeySnooperData *data = NULL;
1980   GSList *slist;
1981 
1982   slist = key_snoopers;
1983   while (slist)
1984     {
1985       data = slist->data;
1986       if (data->id == snooper_id)
1987 	break;
1988 
1989       slist = slist->next;
1990       data = NULL;
1991     }
1992   if (data)
1993     {
1994       key_snoopers = g_slist_remove (key_snoopers, data);
1995       g_free (data);
1996     }
1997 }
1998 
1999 static gint
gtk_invoke_key_snoopers(GtkWidget * grab_widget,GdkEvent * event)2000 gtk_invoke_key_snoopers (GtkWidget *grab_widget,
2001 			 GdkEvent  *event)
2002 {
2003   GSList *slist;
2004   gint return_val = FALSE;
2005 
2006   slist = key_snoopers;
2007   while (slist && !return_val)
2008     {
2009       GtkKeySnooperData *data;
2010 
2011       data = slist->data;
2012       slist = slist->next;
2013       return_val = (*data->func) (grab_widget, (GdkEventKey*) event, data->func_data);
2014     }
2015 
2016   return return_val;
2017 }
2018 
2019 guint
gtk_quit_add_full(guint main_level,GtkFunction function,GtkCallbackMarshal marshal,gpointer data,GDestroyNotify destroy)2020 gtk_quit_add_full (guint		main_level,
2021 		   GtkFunction		function,
2022 		   GtkCallbackMarshal	marshal,
2023 		   gpointer		data,
2024 		   GDestroyNotify	destroy)
2025 {
2026   static guint quit_id = 1;
2027   GtkQuitFunction *quitf;
2028 
2029   g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
2030 
2031   quitf = g_slice_new (GtkQuitFunction);
2032 
2033   quitf->id = quit_id++;
2034   quitf->main_level = main_level;
2035   quitf->function = function;
2036   quitf->marshal = marshal;
2037   quitf->data = data;
2038   quitf->destroy = destroy;
2039 
2040   quit_functions = g_list_prepend (quit_functions, quitf);
2041 
2042   return quitf->id;
2043 }
2044 
2045 static void
gtk_quit_destroy(GtkQuitFunction * quitf)2046 gtk_quit_destroy (GtkQuitFunction *quitf)
2047 {
2048   if (quitf->destroy)
2049     quitf->destroy (quitf->data);
2050   g_slice_free (GtkQuitFunction, quitf);
2051 }
2052 
2053 static gint
gtk_quit_destructor(GtkObject ** object_p)2054 gtk_quit_destructor (GtkObject **object_p)
2055 {
2056   if (*object_p)
2057     gtk_object_destroy (*object_p);
2058   g_free (object_p);
2059 
2060   return FALSE;
2061 }
2062 
2063 void
gtk_quit_add_destroy(guint main_level,GtkObject * object)2064 gtk_quit_add_destroy (guint              main_level,
2065 		      GtkObject         *object)
2066 {
2067   GtkObject **object_p;
2068 
2069   g_return_if_fail (main_level > 0);
2070   g_return_if_fail (GTK_IS_OBJECT (object));
2071 
2072   object_p = g_new (GtkObject*, 1);
2073   *object_p = object;
2074   g_signal_connect (object,
2075 		    "destroy",
2076 		    G_CALLBACK (gtk_widget_destroyed),
2077 		    object_p);
2078   gtk_quit_add (main_level, (GtkFunction) gtk_quit_destructor, object_p);
2079 }
2080 
2081 guint
gtk_quit_add(guint main_level,GtkFunction function,gpointer data)2082 gtk_quit_add (guint	  main_level,
2083 	      GtkFunction function,
2084 	      gpointer	  data)
2085 {
2086   return gtk_quit_add_full (main_level, function, NULL, data, NULL);
2087 }
2088 
2089 void
gtk_quit_remove(guint id)2090 gtk_quit_remove (guint id)
2091 {
2092   GtkQuitFunction *quitf;
2093   GList *tmp_list;
2094 
2095   tmp_list = quit_functions;
2096   while (tmp_list)
2097     {
2098       quitf = tmp_list->data;
2099 
2100       if (quitf->id == id)
2101 	{
2102 	  quit_functions = g_list_remove_link (quit_functions, tmp_list);
2103 	  g_list_free (tmp_list);
2104 	  gtk_quit_destroy (quitf);
2105 
2106 	  return;
2107 	}
2108 
2109       tmp_list = tmp_list->next;
2110     }
2111 }
2112 
2113 void
gtk_quit_remove_by_data(gpointer data)2114 gtk_quit_remove_by_data (gpointer data)
2115 {
2116   GtkQuitFunction *quitf;
2117   GList *tmp_list;
2118 
2119   tmp_list = quit_functions;
2120   while (tmp_list)
2121     {
2122       quitf = tmp_list->data;
2123 
2124       if (quitf->data == data)
2125 	{
2126 	  quit_functions = g_list_remove_link (quit_functions, tmp_list);
2127 	  g_list_free (tmp_list);
2128 	  gtk_quit_destroy (quitf);
2129 
2130 	  return;
2131 	}
2132 
2133       tmp_list = tmp_list->next;
2134     }
2135 }
2136 
2137 guint
gtk_timeout_add_full(guint32 interval,GtkFunction function,GtkCallbackMarshal marshal,gpointer data,GDestroyNotify destroy)2138 gtk_timeout_add_full (guint32		 interval,
2139 		      GtkFunction	 function,
2140 		      GtkCallbackMarshal marshal,
2141 		      gpointer		 data,
2142 		      GDestroyNotify	 destroy)
2143 {
2144   if (marshal)
2145     {
2146       GtkClosure *closure;
2147 
2148       closure = g_new (GtkClosure, 1);
2149       closure->marshal = marshal;
2150       closure->data = data;
2151       closure->destroy = destroy;
2152 
2153       return g_timeout_add_full (0, interval,
2154 				 gtk_invoke_idle_timeout,
2155 				 closure,
2156 				 gtk_destroy_closure);
2157     }
2158   else
2159     return g_timeout_add_full (0, interval, function, data, destroy);
2160 }
2161 
2162 guint
gtk_timeout_add(guint32 interval,GtkFunction function,gpointer data)2163 gtk_timeout_add (guint32     interval,
2164 		 GtkFunction function,
2165 		 gpointer    data)
2166 {
2167   return g_timeout_add_full (0, interval, function, data, NULL);
2168 }
2169 
2170 void
gtk_timeout_remove(guint tag)2171 gtk_timeout_remove (guint tag)
2172 {
2173   g_source_remove (tag);
2174 }
2175 
2176 guint
gtk_idle_add_full(gint priority,GtkFunction function,GtkCallbackMarshal marshal,gpointer data,GDestroyNotify destroy)2177 gtk_idle_add_full (gint			priority,
2178 		   GtkFunction		function,
2179 		   GtkCallbackMarshal	marshal,
2180 		   gpointer		data,
2181 		   GDestroyNotify	destroy)
2182 {
2183   if (marshal)
2184     {
2185       GtkClosure *closure;
2186 
2187       closure = g_new (GtkClosure, 1);
2188       closure->marshal = marshal;
2189       closure->data = data;
2190       closure->destroy = destroy;
2191 
2192       return g_idle_add_full (priority,
2193 			      gtk_invoke_idle_timeout,
2194 			      closure,
2195 			      gtk_destroy_closure);
2196     }
2197   else
2198     return g_idle_add_full (priority, function, data, destroy);
2199 }
2200 
2201 guint
gtk_idle_add(GtkFunction function,gpointer data)2202 gtk_idle_add (GtkFunction function,
2203 	      gpointer	  data)
2204 {
2205   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
2206 }
2207 
2208 guint
gtk_idle_add_priority(gint priority,GtkFunction function,gpointer data)2209 gtk_idle_add_priority (gint        priority,
2210 		       GtkFunction function,
2211 		       gpointer	   data)
2212 {
2213   return g_idle_add_full (priority, function, data, NULL);
2214 }
2215 
2216 void
gtk_idle_remove(guint tag)2217 gtk_idle_remove (guint tag)
2218 {
2219   g_source_remove (tag);
2220 }
2221 
2222 void
gtk_idle_remove_by_data(gpointer data)2223 gtk_idle_remove_by_data (gpointer data)
2224 {
2225   if (!g_idle_remove_by_data (data))
2226     g_warning ("gtk_idle_remove_by_data(%p): no such idle", data);
2227 }
2228 
2229 guint
gtk_input_add_full(gint source,GdkInputCondition condition,GdkInputFunction function,GtkCallbackMarshal marshal,gpointer data,GDestroyNotify destroy)2230 gtk_input_add_full (gint		source,
2231 		    GdkInputCondition	condition,
2232 		    GdkInputFunction	function,
2233 		    GtkCallbackMarshal	marshal,
2234 		    gpointer		data,
2235 		    GDestroyNotify	destroy)
2236 {
2237   if (marshal)
2238     {
2239       GtkClosure *closure;
2240 
2241       closure = g_new (GtkClosure, 1);
2242       closure->marshal = marshal;
2243       closure->data = data;
2244       closure->destroy = destroy;
2245 
2246       return gdk_input_add_full (source,
2247 				 condition,
2248 				 (GdkInputFunction) gtk_invoke_input,
2249 				 closure,
2250 				 (GDestroyNotify) gtk_destroy_closure);
2251     }
2252   else
2253     return gdk_input_add_full (source, condition, function, data, destroy);
2254 }
2255 
2256 void
gtk_input_remove(guint tag)2257 gtk_input_remove (guint tag)
2258 {
2259   g_source_remove (tag);
2260 }
2261 
2262 static void
gtk_destroy_closure(gpointer data)2263 gtk_destroy_closure (gpointer data)
2264 {
2265   GtkClosure *closure = data;
2266 
2267   if (closure->destroy)
2268     (closure->destroy) (closure->data);
2269   g_free (closure);
2270 }
2271 
2272 static gboolean
gtk_invoke_idle_timeout(gpointer data)2273 gtk_invoke_idle_timeout (gpointer data)
2274 {
2275   GtkClosure *closure = data;
2276 
2277   GtkArg args[1];
2278   gint ret_val = FALSE;
2279   args[0].name = NULL;
2280   args[0].type = G_TYPE_BOOLEAN;
2281   args[0].d.pointer_data = &ret_val;
2282   closure->marshal (NULL, closure->data,  0, args);
2283   return ret_val;
2284 }
2285 
2286 static void
gtk_invoke_input(gpointer data,gint source,GdkInputCondition condition)2287 gtk_invoke_input (gpointer	    data,
2288 		  gint		    source,
2289 		  GdkInputCondition condition)
2290 {
2291   GtkClosure *closure = data;
2292 
2293   GtkArg args[3];
2294   args[0].type = G_TYPE_INT;
2295   args[0].name = NULL;
2296   GTK_VALUE_INT (args[0]) = source;
2297   args[1].type = GDK_TYPE_INPUT_CONDITION;
2298   args[1].name = NULL;
2299   GTK_VALUE_FLAGS (args[1]) = condition;
2300   args[2].type = G_TYPE_NONE;
2301   args[2].name = NULL;
2302 
2303   closure->marshal (NULL, closure->data, 2, args);
2304 }
2305 
2306 /**
2307  * gtk_get_current_event:
2308  *
2309  * Obtains a copy of the event currently being processed by GTK+.  For
2310  * example, if you get a "clicked" signal from #GtkButton, the current
2311  * event will be the #GdkEventButton that triggered the "clicked"
2312  * signal. The returned event must be freed with gdk_event_free().
2313  * If there is no current event, the function returns %NULL.
2314  *
2315  * Return value: (transfer full): a copy of the current event, or %NULL if no
2316  *     current event.
2317  **/
2318 GdkEvent*
gtk_get_current_event(void)2319 gtk_get_current_event (void)
2320 {
2321   if (current_events)
2322     return gdk_event_copy (current_events->data);
2323   else
2324     return NULL;
2325 }
2326 
2327 /**
2328  * gtk_get_current_event_time:
2329  *
2330  * If there is a current event and it has a timestamp, return that
2331  * timestamp, otherwise return %GDK_CURRENT_TIME.
2332  *
2333  * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
2334  **/
2335 guint32
gtk_get_current_event_time(void)2336 gtk_get_current_event_time (void)
2337 {
2338   if (current_events)
2339     return gdk_event_get_time (current_events->data);
2340   else
2341     return GDK_CURRENT_TIME;
2342 }
2343 
2344 /**
2345  * gtk_get_current_event_state:
2346  * @state: (out): a location to store the state of the current event
2347  *
2348  * If there is a current event and it has a state field, place
2349  * that state field in @state and return %TRUE, otherwise return
2350  * %FALSE.
2351  *
2352  * Return value: %TRUE if there was a current event and it had a state field
2353  **/
2354 gboolean
gtk_get_current_event_state(GdkModifierType * state)2355 gtk_get_current_event_state (GdkModifierType *state)
2356 {
2357   g_return_val_if_fail (state != NULL, FALSE);
2358 
2359   if (current_events)
2360     return gdk_event_get_state (current_events->data, state);
2361   else
2362     {
2363       *state = 0;
2364       return FALSE;
2365     }
2366 }
2367 
2368 /**
2369  * gtk_get_event_widget:
2370  * @event: a #GdkEvent
2371  *
2372  * If @event is %NULL or the event was not associated with any widget,
2373  * returns %NULL, otherwise returns the widget that received the event
2374  * originally.
2375  *
2376  * Return value: (transfer none): the widget that originally
2377  *     received @event, or %NULL
2378  **/
2379 GtkWidget*
gtk_get_event_widget(GdkEvent * event)2380 gtk_get_event_widget (GdkEvent *event)
2381 {
2382   GtkWidget *widget;
2383   gpointer widget_ptr;
2384 
2385   widget = NULL;
2386   if (event && event->any.window &&
2387       (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
2388     {
2389       gdk_window_get_user_data (event->any.window, &widget_ptr);
2390       widget = widget_ptr;
2391     }
2392 
2393   return widget;
2394 }
2395 
2396 static gint
gtk_quit_invoke_function(GtkQuitFunction * quitf)2397 gtk_quit_invoke_function (GtkQuitFunction *quitf)
2398 {
2399   if (!quitf->marshal)
2400     return quitf->function (quitf->data);
2401   else
2402     {
2403       GtkArg args[1];
2404       gint ret_val = FALSE;
2405 
2406       args[0].name = NULL;
2407       args[0].type = G_TYPE_BOOLEAN;
2408       args[0].d.pointer_data = &ret_val;
2409       ((GtkCallbackMarshal) quitf->marshal) (NULL,
2410 					     quitf->data,
2411 					     0, args);
2412       return ret_val;
2413     }
2414 }
2415 
2416 /**
2417  * gtk_propagate_event:
2418  * @widget: a #GtkWidget
2419  * @event: an event
2420  *
2421  * Sends an event to a widget, propagating the event to parent widgets
2422  * if the event remains unhandled. Events received by GTK+ from GDK
2423  * normally begin in gtk_main_do_event(). Depending on the type of
2424  * event, existence of modal dialogs, grabs, etc., the event may be
2425  * propagated; if so, this function is used. gtk_propagate_event()
2426  * calls gtk_widget_event() on each widget it decides to send the
2427  * event to.  So gtk_widget_event() is the lowest-level function; it
2428  * simply emits the "event" and possibly an event-specific signal on a
2429  * widget.  gtk_propagate_event() is a bit higher-level, and
2430  * gtk_main_do_event() is the highest level.
2431  *
2432  * All that said, you most likely don't want to use any of these
2433  * functions; synthesizing events is rarely needed. Consider asking on
2434  * the mailing list for better ways to achieve your goals. For
2435  * example, use gdk_window_invalidate_rect() or
2436  * gtk_widget_queue_draw() instead of making up expose events.
2437  *
2438  **/
2439 void
gtk_propagate_event(GtkWidget * widget,GdkEvent * event)2440 gtk_propagate_event (GtkWidget *widget,
2441 		     GdkEvent  *event)
2442 {
2443   gint handled_event;
2444 
2445   g_return_if_fail (GTK_IS_WIDGET (widget));
2446   g_return_if_fail (event != NULL);
2447 
2448   handled_event = FALSE;
2449 
2450   g_object_ref (widget);
2451 
2452   if ((event->type == GDK_KEY_PRESS) ||
2453       (event->type == GDK_KEY_RELEASE))
2454     {
2455       /* Only send key events within Window widgets to the Window
2456        *  The Window widget will in turn pass the
2457        *  key event on to the currently focused widget
2458        *  for that window.
2459        */
2460       GtkWidget *window;
2461 
2462       window = gtk_widget_get_toplevel (widget);
2463       if (GTK_IS_WINDOW (window))
2464 	{
2465 	  /* If there is a grab within the window, give the grab widget
2466 	   * a first crack at the key event
2467 	   */
2468 	  if (widget != window && gtk_widget_has_grab (widget))
2469 	    handled_event = gtk_widget_event (widget, event);
2470 
2471 	  if (!handled_event)
2472 	    {
2473 	      window = gtk_widget_get_toplevel (widget);
2474 	      if (GTK_IS_WINDOW (window))
2475 		{
2476 		  if (gtk_widget_is_sensitive (window))
2477 		    gtk_widget_event (window, event);
2478 		}
2479 	    }
2480 
2481 	  handled_event = TRUE; /* don't send to widget */
2482 	}
2483     }
2484 
2485   /* Other events get propagated up the widget tree
2486    *  so that parents can see the button and motion
2487    *  events of the children.
2488    */
2489   if (!handled_event)
2490     {
2491       while (TRUE)
2492 	{
2493 	  GtkWidget *tmp;
2494 
2495 	  /* Scroll events are special cased here because it
2496 	   * feels wrong when scrolling a GtkViewport, say,
2497 	   * to have children of the viewport eat the scroll
2498 	   * event
2499 	   */
2500 	  if (!gtk_widget_is_sensitive (widget))
2501 	    handled_event = event->type != GDK_SCROLL;
2502 	  else
2503 	    handled_event = gtk_widget_event (widget, event);
2504 
2505 	  tmp = widget->parent;
2506 	  g_object_unref (widget);
2507 
2508 	  widget = tmp;
2509 
2510 	  if (!handled_event && widget)
2511 	    g_object_ref (widget);
2512 	  else
2513 	    break;
2514 	}
2515     }
2516   else
2517     g_object_unref (widget);
2518 }
2519 
2520 #if 0
2521 static void
2522 gtk_error (gchar *str)
2523 {
2524   gtk_print (str);
2525 }
2526 
2527 static void
2528 gtk_warning (gchar *str)
2529 {
2530   gtk_print (str);
2531 }
2532 
2533 static void
2534 gtk_message (gchar *str)
2535 {
2536   gtk_print (str);
2537 }
2538 
2539 static void
2540 gtk_print (gchar *str)
2541 {
2542   static GtkWidget *window = NULL;
2543   static GtkWidget *text;
2544   static int level = 0;
2545   GtkWidget *box1;
2546   GtkWidget *box2;
2547   GtkWidget *table;
2548   GtkWidget *hscrollbar;
2549   GtkWidget *vscrollbar;
2550   GtkWidget *separator;
2551   GtkWidget *button;
2552 
2553   if (level > 0)
2554     {
2555       fputs (str, stdout);
2556       fflush (stdout);
2557       return;
2558     }
2559 
2560   if (!window)
2561     {
2562       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
2563 
2564       gtk_signal_connect (GTK_OBJECT (window), "destroy",
2565 			  G_CALLBACK (gtk_widget_destroyed),
2566 			  &window);
2567 
2568       gtk_window_set_title (GTK_WINDOW (window), "Messages");
2569 
2570       box1 = gtk_vbox_new (FALSE, 0);
2571       gtk_container_add (GTK_CONTAINER (window), box1);
2572       gtk_widget_show (box1);
2573 
2574 
2575       box2 = gtk_vbox_new (FALSE, 10);
2576       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2577       gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
2578       gtk_widget_show (box2);
2579 
2580 
2581       table = gtk_table_new (2, 2, FALSE);
2582       gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
2583       gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
2584       gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
2585       gtk_widget_show (table);
2586 
2587       text = gtk_text_new (NULL, NULL);
2588       gtk_text_set_editable (GTK_TEXT (text), FALSE);
2589       gtk_table_attach_defaults (GTK_TABLE (table), text, 0, 1, 0, 1);
2590       gtk_widget_show (text);
2591       gtk_widget_realize (text);
2592 
2593       hscrollbar = gtk_hscrollbar_new (GTK_TEXT (text)->hadj);
2594       gtk_table_attach (GTK_TABLE (table), hscrollbar, 0, 1, 1, 2,
2595 			GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0);
2596       gtk_widget_show (hscrollbar);
2597 
2598       vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
2599       gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
2600 			GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
2601       gtk_widget_show (vscrollbar);
2602 
2603       separator = gtk_hseparator_new ();
2604       gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
2605       gtk_widget_show (separator);
2606 
2607 
2608       box2 = gtk_vbox_new (FALSE, 10);
2609       gtk_container_set_border_width (GTK_CONTAINER (box2), 10);
2610       gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
2611       gtk_widget_show (box2);
2612 
2613 
2614       button = gtk_button_new_with_label ("close");
2615       gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
2616 				 G_CALLBACK (gtk_widget_hide),
2617 				 GTK_OBJECT (window));
2618       gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
2619       gtk_widget_set_can_default (button, TRUE);
2620       gtk_widget_grab_default (button);
2621       gtk_widget_show (button);
2622     }
2623 
2624   level += 1;
2625   gtk_text_insert (GTK_TEXT (text), NULL, NULL, NULL, str, -1);
2626   level -= 1;
2627 
2628   if (!gtk_widget_get_visible (window))
2629     gtk_widget_show (window);
2630 }
2631 #endif
2632 
2633 gboolean
_gtk_boolean_handled_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)2634 _gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
2635 				  GValue                *return_accu,
2636 				  const GValue          *handler_return,
2637 				  gpointer               dummy)
2638 {
2639   gboolean continue_emission;
2640   gboolean signal_handled;
2641 
2642   signal_handled = g_value_get_boolean (handler_return);
2643   g_value_set_boolean (return_accu, signal_handled);
2644   continue_emission = !signal_handled;
2645 
2646   return continue_emission;
2647 }
2648 
2649 gboolean
_gtk_button_event_triggers_context_menu(GdkEventButton * event)2650 _gtk_button_event_triggers_context_menu (GdkEventButton *event)
2651 {
2652   if (event->type == GDK_BUTTON_PRESS)
2653     {
2654       if (event->button == 3 &&
2655           ! (event->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK)))
2656         return TRUE;
2657 
2658 #ifdef GDK_WINDOWING_QUARTZ
2659       if (event->button == 1 &&
2660           ! (event->state & (GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) &&
2661           (event->state & GDK_CONTROL_MASK))
2662         return TRUE;
2663 #endif
2664     }
2665 
2666   return FALSE;
2667 }
2668 
2669 gboolean
_gtk_translate_keyboard_accel_state(GdkKeymap * keymap,guint hardware_keycode,GdkModifierType state,GdkModifierType accel_mask,gint group,guint * keyval,gint * effective_group,gint * level,GdkModifierType * consumed_modifiers)2670 _gtk_translate_keyboard_accel_state (GdkKeymap       *keymap,
2671                                      guint            hardware_keycode,
2672                                      GdkModifierType  state,
2673                                      GdkModifierType  accel_mask,
2674                                      gint             group,
2675                                      guint           *keyval,
2676                                      gint            *effective_group,
2677                                      gint            *level,
2678                                      GdkModifierType *consumed_modifiers)
2679 {
2680   gboolean group_mask_disabled = FALSE;
2681   gboolean retval;
2682 
2683   /* if the group-toggling modifier is part of the accel mod mask, and
2684    * it is active, disable it for matching
2685    */
2686   if (accel_mask & state & GTK_TOGGLE_GROUP_MOD_MASK)
2687     {
2688       state &= ~GTK_TOGGLE_GROUP_MOD_MASK;
2689       group = 0;
2690       group_mask_disabled = TRUE;
2691     }
2692 
2693   retval = gdk_keymap_translate_keyboard_state (keymap,
2694                                                 hardware_keycode, state, group,
2695                                                 keyval,
2696                                                 effective_group, level,
2697                                                 consumed_modifiers);
2698 
2699   /* add back the group mask, we want to match against the modifier,
2700    * but not against the keyval from its group
2701    */
2702   if (group_mask_disabled)
2703     {
2704       if (effective_group)
2705         *effective_group = 1;
2706 
2707       if (consumed_modifiers)
2708         *consumed_modifiers &= ~GTK_TOGGLE_GROUP_MOD_MASK;
2709     }
2710 
2711   return retval;
2712 }
2713 
2714 #define __GTK_MAIN_C__
2715 #include "gtkaliasdef.c"
2716