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