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, see <http://www.gnu.org/licenses/>.
16 */
17
18/*
19 * Modified by the GTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the GTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23 */
24
25#include "config.h"
26
27#include "gdk/gdk.h"
28#include "gdk/gdk-private.h"
29#include "gdk/gdkprofilerprivate.h"
30#include "gsk/gskprivate.h"
31#include "gsk/gskrendernodeprivate.h"
32#include "gtknative.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 "gtkbox.h"
53#include "gtkdebug.h"
54#include "gtkdropprivate.h"
55#include "gtkmain.h"
56#include "gtkmediafileprivate.h"
57#include "gtkmodulesprivate.h"
58#include "gtkprivate.h"
59#include "gtkrecentmanager.h"
60#include "gtksettingsprivate.h"
61#include "gtktooltipprivate.h"
62#include "gtkwidgetprivate.h"
63#include "gtkwindowprivate.h"
64#include "gtkwindowgroup.h"
65#include "gtkprintbackendprivate.h"
66#include "gtkimmoduleprivate.h"
67#include "gtkroot.h"
68#include "gtknative.h"
69#include "gtkpopcountprivate.h"
70
71#include "inspector/init.h"
72#include "inspector/window.h"
73
74#include "gdk/gdkeventsprivate.h"
75#include "gdk/gdksurfaceprivate.h"
76
77#define GDK_ARRAY_ELEMENT_TYPE GtkWidget *
78#define GDK_ARRAY_TYPE_NAME GtkWidgetStack
79#define GDK_ARRAY_NAME gtk_widget_stack
80#define GDK_ARRAY_FREE_FUNC g_object_unref
81#define GDK_ARRAY_PREALLOC 16
82#include "gdk/gdkarrayimpl.c"
83
84static GtkWindowGroup *gtk_main_get_window_group (GtkWidget *widget);
85
86static int pre_initialized = FALSE;
87static int gtk_initialized = FALSE;
88static GList *current_events = NULL;
89
90typedef struct {
91 GdkDisplay *display;
92 guint flags;
93} DisplayDebugFlags;
94
95#define N_DEBUG_DISPLAYS 4
96
97DisplayDebugFlags debug_flags[N_DEBUG_DISPLAYS];
98/* This is a flag to speed up development builds. We set it to TRUE when
99 * any of the debug displays has debug flags >0, but we never set it back
100 * to FALSE. This way we don't need to call gtk_widget_get_display() in
101 * hot paths. */
102gboolean any_display_debug_flags_set = FALSE;
103
104GtkDebugFlags
105gtk_get_display_debug_flags (GdkDisplay *display)
106{
107 int i;
108
109 if (display == NULL)
110 display = gdk_display_get_default ();
111
112 for (i = 0; i < N_DEBUG_DISPLAYS; i++)
113 {
114 if (debug_flags[i].display == display)
115 return (GtkDebugFlags)debug_flags[i].flags;
116 }
117
118 return 0;
119}
120
121gboolean
122gtk_get_any_display_debug_flag_set (void)
123{
124 return any_display_debug_flags_set;
125}
126
127void
128gtk_set_display_debug_flags (GdkDisplay *display,
129 GtkDebugFlags flags)
130{
131 int i;
132
133 for (i = 0; i < N_DEBUG_DISPLAYS; i++)
134 {
135 if (debug_flags[i].display == NULL)
136 debug_flags[i].display = display;
137
138 if (debug_flags[i].display == display)
139 {
140 debug_flags[i].flags = flags;
141 if (flags > 0)
142 any_display_debug_flags_set = TRUE;
143
144 return;
145 }
146 }
147}
148
149/**
150 * gtk_get_debug_flags:
151 *
152 * Returns the GTK debug flags that are currently active.
153 *
154 * This function is intended for GTK modules that want
155 * to adjust their debug output based on GTK debug flags.
156 *
157 * Returns: the GTK debug flags.
158 */
159GtkDebugFlags
160gtk_get_debug_flags (void)
161{
162 if (gtk_get_any_display_debug_flag_set ())
163 return gtk_get_display_debug_flags (display: gdk_display_get_default ());
164
165 return 0;
166}
167
168/**
169 * gtk_set_debug_flags:
170 * @flags: the debug flags to set
171 *
172 * Sets the GTK debug flags.
173 */
174void
175gtk_set_debug_flags (GtkDebugFlags flags)
176{
177 gtk_set_display_debug_flags (display: gdk_display_get_default (), flags);
178}
179
180gboolean
181gtk_simulate_touchscreen (void)
182{
183 return (gtk_get_debug_flags () & GTK_DEBUG_TOUCHSCREEN) != 0;
184}
185
186static const GdkDebugKey gtk_debug_keys[] = {
187 { "keybindings", GTK_DEBUG_KEYBINDINGS, "Information about keyboard shortcuts" },
188 { "modules", GTK_DEBUG_MODULES, "Information about modules and extensions" },
189 { "icontheme", GTK_DEBUG_ICONTHEME, "Information about icon themes" },
190 { "printing", GTK_DEBUG_PRINTING, "Information about printing" },
191 { "geometry", GTK_DEBUG_GEOMETRY, "Information about size allocation" },
192 { "size-request", GTK_DEBUG_SIZE_REQUEST, "Information about size requests" },
193 { "actions", GTK_DEBUG_ACTIONS, "Information about actions and menu models" },
194 { "constraints", GTK_DEBUG_CONSTRAINTS, "Information from the constraints solver" },
195 { "text", GTK_DEBUG_TEXT, "Information about GtkTextView" },
196 { "tree", GTK_DEBUG_TREE, "Information about GtkTreeView" },
197 { "layout", GTK_DEBUG_LAYOUT, "Information from layout managers" },
198 { "builder", GTK_DEBUG_BUILDER, "Trace GtkBuilder operation" },
199 { "builder-objects", GTK_DEBUG_BUILDER_OBJECTS, "Log unused GtkBuilder objects" },
200 { "no-css-cache", GTK_DEBUG_NO_CSS_CACHE, "Disable style property cache" },
201 { "interactive", GTK_DEBUG_INTERACTIVE, "Enable the GTK inspector", TRUE },
202 { "touchscreen", GTK_DEBUG_TOUCHSCREEN, "Pretend the pointer is a touchscreen" },
203 { "snapshot", GTK_DEBUG_SNAPSHOT, "Generate debug render nodes" },
204 { "accessibility", GTK_DEBUG_A11Y, "Information about accessibility state changes" },
205 { "iconfallback", GTK_DEBUG_ICONFALLBACK, "Information about icon fallback" },
206};
207
208/* This checks to see if the process is running suid or sgid
209 * at the current time. If so, we don’t allow GTK to be initialized.
210 * This is meant to be a mild check - we only error out if we
211 * can prove the programmer is doing something wrong, not if
212 * they could be doing something wrong. For this reason, we
213 * don’t use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
214 */
215static gboolean
216check_setugid (void)
217{
218/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
219#ifndef G_OS_WIN32
220 uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
221 gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
222
223#ifdef HAVE_GETRESUID
224 if (getresuid (ruid: &ruid, euid: &euid, suid: &suid) != 0 ||
225 getresgid (rgid: &rgid, egid: &egid, sgid: &sgid) != 0)
226#endif /* HAVE_GETRESUID */
227 {
228 suid = ruid = getuid ();
229 sgid = rgid = getgid ();
230 euid = geteuid ();
231 egid = getegid ();
232 }
233
234 if (ruid != euid || ruid != suid ||
235 rgid != egid || rgid != sgid)
236 {
237 g_warning ("This process is currently running setuid or setgid.\n"
238 "This is not a supported use of GTK. You must create a helper\n"
239 "program instead. For further details, see:\n\n"
240 " http://www.gtk.org/setuid.html\n\n"
241 "Refusing to initialize GTK.");
242 exit (status: 1);
243 }
244#endif
245 return TRUE;
246}
247
248static gboolean do_setlocale = TRUE;
249
250/**
251 * gtk_disable_setlocale:
252 *
253 * Prevents [id@gtk_init] and [id@gtk_init_check] from automatically calling
254 * `setlocale (LC_ALL, "")`.
255 *
256 * You would want to use this function if you wanted to set the locale for
257 * your program to something other than the user’s locale, or if
258 * you wanted to set different values for different locale categories.
259 *
260 * Most programs should not need to call this function.
261 **/
262void
263gtk_disable_setlocale (void)
264{
265 if (pre_initialized)
266 g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
267
268 do_setlocale = FALSE;
269}
270
271#ifdef G_PLATFORM_WIN32
272#undef gtk_init_check
273#endif
274
275#ifdef G_OS_WIN32
276
277static char *iso639_to_check = NULL;
278static char *iso3166_to_check = NULL;
279static char *script_to_check = NULL;
280static gboolean setlocale_called = FALSE;
281
282static BOOL CALLBACK
283enum_locale_proc (LPTSTR locale)
284{
285 LCID lcid;
286 char iso639[10];
287 char iso3166[10];
288 char *endptr;
289
290
291 lcid = strtoul (locale, &endptr, 16);
292 if (*endptr == '\0' &&
293 GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
294 GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
295 {
296 if (strcmp (iso639, iso639_to_check) == 0 &&
297 ((iso3166_to_check != NULL &&
298 strcmp (iso3166, iso3166_to_check) == 0) ||
299 (iso3166_to_check == NULL &&
300 SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
301 {
302 char language[100], country[100];
303
304 if (script_to_check != NULL)
305 {
306 /* If lcid is the "other" script for this language,
307 * return TRUE, i.e. continue looking.
308 */
309 if (strcmp (script_to_check, "Latn") == 0)
310 {
311 switch (LANGIDFROMLCID (lcid))
312 {
313 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
314 return TRUE;
315 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
316 return TRUE;
317 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
318 return TRUE;
319 case MAKELANGID (LANG_SERBIAN, 0x07):
320 /* Serbian in Bosnia and Herzegovina, Cyrillic */
321 return TRUE;
322 default:
323 break;
324 }
325 }
326 else if (strcmp (script_to_check, "Cyrl") == 0)
327 {
328 switch (LANGIDFROMLCID (lcid))
329 {
330 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
331 return TRUE;
332 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
333 return TRUE;
334 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
335 return TRUE;
336 case MAKELANGID (LANG_SERBIAN, 0x06):
337 /* Serbian in Bosnia and Herzegovina, Latin */
338 return TRUE;
339 default:
340 break;
341 }
342 }
343 }
344
345 SetThreadLocale (lcid);
346
347 if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
348 GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
349 {
350 char str[300];
351
352 strcpy (str, language);
353 strcat (str, "_");
354 strcat (str, country);
355
356 if (setlocale (LC_ALL, str) != NULL)
357 setlocale_called = TRUE;
358 }
359
360 return FALSE;
361 }
362 }
363
364 return TRUE;
365}
366
367#endif
368
369void
370setlocale_initialization (void)
371{
372 static gboolean initialized = FALSE;
373
374 if (initialized)
375 return;
376 initialized = TRUE;
377
378 if (do_setlocale)
379 {
380#ifdef G_OS_WIN32
381 /* If some of the POSIXish environment variables are set, set
382 * the Win32 thread locale correspondingly.
383 */
384 char *p = getenv ("LC_ALL");
385 if (p == NULL)
386 p = getenv ("LANG");
387
388 if (p != NULL)
389 {
390 p = g_strdup (p);
391 if (strcmp (p, "C") == 0)
392 SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
393 else
394 {
395 /* Check if one of the supported locales match the
396 * environment variable. If so, use that locale.
397 */
398 iso639_to_check = p;
399 iso3166_to_check = strchr (iso639_to_check, '_');
400 if (iso3166_to_check != NULL)
401 {
402 *iso3166_to_check++ = '\0';
403
404 script_to_check = strchr (iso3166_to_check, '@');
405 if (script_to_check != NULL)
406 *script_to_check++ = '\0';
407
408 /* Handle special cases. */
409
410 /* The standard code for Serbia and Montenegro was
411 * "CS", but MSFT uses for some reason "SP". By now
412 * (October 2006), SP has split into two, "RS" and
413 * "ME", but don't bother trying to handle those
414 * yet. Do handle the even older "YU", though.
415 */
416 if (strcmp (iso3166_to_check, "CS") == 0 ||
417 strcmp (iso3166_to_check, "YU") == 0)
418 iso3166_to_check = (char *) "SP";
419 }
420 else
421 {
422 script_to_check = strchr (iso639_to_check, '@');
423 if (script_to_check != NULL)
424 *script_to_check++ = '\0';
425 /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
426 if (strcmp (iso639_to_check, "sr") == 0)
427 iso3166_to_check = (char *) "SP";
428 }
429
430 EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
431 }
432 g_free (p);
433 }
434 if (!setlocale_called)
435 setlocale (LC_ALL, "");
436#else
437 if (!setlocale (LC_ALL, locale: ""))
438 g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
439#endif
440 }
441}
442
443/* Return TRUE if module_to_check causes version conflicts.
444 * If module_to_check is NULL, check the main module.
445 */
446static gboolean
447_gtk_module_has_mixed_deps (GModule *module_to_check)
448{
449 GModule *module;
450 gpointer func;
451 gboolean result;
452
453 if (!module_to_check)
454 module = g_module_open (NULL, flags: 0);
455 else
456 module = module_to_check;
457
458 if (g_module_symbol (module, symbol_name: "gtk_progress_get_type", symbol: &func))
459 result = TRUE;
460 else if (g_module_symbol (module, symbol_name: "gtk_misc_get_type", symbol: &func))
461 result = TRUE;
462 else
463 result = FALSE;
464
465 if (!module_to_check)
466 g_module_close (module);
467
468 return result;
469}
470
471static void
472do_pre_parse_initialization (void)
473{
474 const char *env_string;
475 double slowdown;
476
477 if (pre_initialized)
478 return;
479
480 pre_initialized = TRUE;
481
482 if (_gtk_module_has_mixed_deps (NULL))
483 g_error ("GTK 2/3 symbols detected. Using GTK 2/3 and GTK 4 in the same process is not supported");
484
485 gdk_pre_parse ();
486
487 debug_flags[0].flags = gdk_parse_debug_var (variable: "GTK_DEBUG",
488 keys: gtk_debug_keys,
489 G_N_ELEMENTS (gtk_debug_keys));
490 any_display_debug_flags_set = debug_flags[0].flags > 0;
491
492 env_string = g_getenv (variable: "GTK_SLOWDOWN");
493 if (env_string)
494 {
495 slowdown = g_ascii_strtod (nptr: env_string, NULL);
496 _gtk_set_slowdown (slowdown_factor: slowdown);
497 }
498
499 /* Trigger fontconfig initialization early */
500 pango_cairo_font_map_get_default ();
501}
502
503static void
504gettext_initialization (void)
505{
506 setlocale_initialization ();
507
508 bindtextdomain (GETTEXT_PACKAGE, dirname: _gtk_get_localedir ());
509 bindtextdomain (GETTEXT_PACKAGE "-properties", dirname: _gtk_get_localedir ());
510#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
511 bind_textdomain_codeset (GETTEXT_PACKAGE, codeset: "UTF-8");
512 bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", codeset: "UTF-8");
513#endif
514}
515
516static void
517default_display_notify_cb (GdkDisplayManager *dm)
518{
519 debug_flags[0].display = gdk_display_get_default ();
520}
521
522static void
523do_post_parse_initialization (void)
524{
525 GdkDisplayManager *display_manager;
526 gint64 before G_GNUC_UNUSED;
527
528 if (gtk_initialized)
529 return;
530
531 before = GDK_PROFILER_CURRENT_TIME;
532
533 gettext_initialization ();
534
535#ifdef SIGPIPE
536 signal (SIGPIPE, SIG_IGN);
537#endif
538
539 gtk_widget_set_default_direction (dir: gtk_get_locale_direction ());
540
541 gdk_event_init_types ();
542
543 gsk_ensure_resources ();
544 gsk_render_node_init_types ();
545 _gtk_ensure_resources ();
546
547 gdk_profiler_end_mark (before, "basic initialization", NULL);
548
549 gtk_initialized = TRUE;
550
551 before = GDK_PROFILER_CURRENT_TIME;
552#ifdef G_OS_UNIX
553 gtk_print_backends_init ();
554#endif
555 gtk_im_modules_init ();
556 gtk_media_file_extension_init ();
557 gdk_profiler_end_mark (before, "init modules", NULL);
558
559 before = GDK_PROFILER_CURRENT_TIME;
560 display_manager = gdk_display_manager_get ();
561 if (gdk_display_manager_get_default_display (manager: display_manager) != NULL)
562 default_display_notify_cb (dm: display_manager);
563 gdk_profiler_end_mark (before, "create display", NULL);
564
565 g_signal_connect (display_manager, "notify::default-display",
566 G_CALLBACK (default_display_notify_cb),
567 NULL);
568
569 gtk_inspector_register_extension ();
570}
571
572#ifdef G_PLATFORM_WIN32
573#undef gtk_init_check
574#endif
575
576/**
577 * gtk_init_check:
578 *
579 * This function does the same work as gtk_init() with only a single
580 * change: It does not terminate the program if the windowing system
581 * can’t be initialized. Instead it returns %FALSE on failure.
582 *
583 * This way the application can fall back to some other means of
584 * communication with the user - for example a curses or command line
585 * interface.
586 *
587 * Returns: %TRUE if the windowing system has been successfully
588 * initialized, %FALSE otherwise
589 */
590gboolean
591gtk_init_check (void)
592{
593 gboolean ret;
594
595 if (gtk_initialized)
596 return TRUE;
597
598 if (gdk_profiler_is_running ())
599 g_info ("Profiling is active");
600
601 gettext_initialization ();
602
603 if (!check_setugid ())
604 return FALSE;
605
606 do_pre_parse_initialization ();
607 do_post_parse_initialization ();
608
609 ret = gdk_display_open_default () != NULL;
610
611 if (ret && (gtk_get_debug_flags () & GTK_DEBUG_INTERACTIVE))
612 gtk_window_set_interactive_debugging (TRUE);
613
614 return ret;
615}
616
617#ifdef G_PLATFORM_WIN32
618#undef gtk_init
619#endif
620
621/**
622 * gtk_init:
623 *
624 * Call this function before using any other GTK functions in your GUI
625 * applications. It will initialize everything needed to operate the
626 * toolkit.
627 *
628 * If you are using `GtkApplication`, you don't have to call gtk_init()
629 * or gtk_init_check(); the `GApplication::startup` handler
630 * does it for you.
631 *
632 * This function will terminate your program if it was unable to
633 * initialize the windowing system for some reason. If you want
634 * your program to fall back to a textual interface you want to
635 * call gtk_init_check() instead.
636 *
637 * GTK calls `signal (SIGPIPE, SIG_IGN)`
638 * during initialization, to ignore SIGPIPE signals, since these are
639 * almost never wanted in graphical applications. If you do need to
640 * handle SIGPIPE for some reason, reset the handler after gtk_init(),
641 * but notice that other libraries (e.g. libdbus or gvfs) might do
642 * similar things.
643 */
644void
645gtk_init (void)
646{
647 if (!gtk_init_check ())
648 {
649 const char *display_name_arg = NULL;
650 if (display_name_arg == NULL)
651 display_name_arg = getenv (name: "DISPLAY");
652 g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
653 exit (status: 1);
654 }
655}
656
657#ifdef G_OS_WIN32
658
659/* This is relevant when building with gcc for Windows (MinGW),
660 * where we want to be struct packing compatible with MSVC,
661 * i.e. use the -mms-bitfields switch.
662 * For Cygwin there should be no need to be compatible with MSVC,
663 * so no need to use G_PLATFORM_WIN32.
664 */
665
666static void
667check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
668{
669 if (sizeof_GtkWindow != sizeof (GtkWindow))
670 g_error ("Incompatible build!\n"
671 "The code using GTK thinks GtkWindow is of different\n"
672 "size than it actually is in this build of GTK.\n"
673 "On Windows, this probably means that you have compiled\n"
674 "your code with gcc without the -mms-bitfields switch,\n"
675 "or that you are using an unsupported compiler.");
676}
677
678/* In GTK 2.0 the GtkWindow struct actually is the same size in
679 * gcc-compiled code on Win32 whether compiled with -fnative-struct or
680 * not. Unfortunately this wan’t noticed until after GTK 2.0.1. So,
681 * from GTK 2.0.2 on, check some other struct, too, where the use of
682 * -fnative-struct still matters. GtkBox is one such.
683 */
684static void
685check_sizeof_GtkBox (size_t sizeof_GtkBox)
686{
687 if (sizeof_GtkBox != sizeof (GtkBox))
688 g_error ("Incompatible build!\n"
689 "The code using GTK thinks GtkBox is of different\n"
690 "size than it actually is in this build of GTK.\n"
691 "On Windows, this probably means that you have compiled\n"
692 "your code with gcc without the -mms-bitfields switch,\n"
693 "or that you are using an unsupported compiler.");
694}
695
696/* These two functions might get more checks added later, thus pass
697 * in the number of extra args.
698 */
699void
700gtk_init_abi_check (int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
701{
702 check_sizeof_GtkWindow (sizeof_GtkWindow);
703 if (num_checks >= 2)
704 check_sizeof_GtkBox (sizeof_GtkBox);
705 gtk_init ();
706}
707
708gboolean
709gtk_init_check_abi_check (int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
710{
711 check_sizeof_GtkWindow (sizeof_GtkWindow);
712 if (num_checks >= 2)
713 check_sizeof_GtkBox (sizeof_GtkBox);
714 return gtk_init_check ();
715}
716
717#endif
718
719/**
720 * gtk_is_initialized:
721 *
722 * Use this function to check if GTK has been initialized with gtk_init()
723 * or gtk_init_check().
724 *
725 * Returns: the initialization status
726 */
727gboolean
728gtk_is_initialized (void)
729{
730 return gtk_initialized;
731}
732
733
734/**
735 * gtk_get_locale_direction:
736 *
737 * Get the direction of the current locale. This is the expected
738 * reading direction for text and UI.
739 *
740 * This function depends on the current locale being set with
741 * setlocale() and will default to setting the %GTK_TEXT_DIR_LTR
742 * direction otherwise. %GTK_TEXT_DIR_NONE will never be returned.
743 *
744 * GTK sets the default text direction according to the locale
745 * during gtk_init(), and you should normally use
746 * gtk_widget_get_direction() or gtk_widget_get_default_direction()
747 * to obtain the current direction.
748 *
749 * This function is only needed rare cases when the locale is
750 * changed after GTK has already been initialized. In this case,
751 * you can use it to update the default text direction as follows:
752 *
753 * |[<!-- language="C" -->
754 * #include <locale.h>
755 *
756 * static void
757 * update_locale (const char *new_locale)
758 * {
759 * setlocale (LC_ALL, new_locale);
760 * GtkTextDirection direction = gtk_get_locale_direction ();
761 * gtk_widget_set_default_direction (direction);
762 * }
763 * ]|
764 *
765 * Returns: the `GtkTextDirection` of the current locale
766 */
767GtkTextDirection
768gtk_get_locale_direction (void)
769{
770 /* Translate to default:RTL if you want your widgets
771 * to be RTL, otherwise translate to default:LTR.
772 * Do *not* translate it to "predefinito:LTR", if it
773 * it isn't default:LTR or default:RTL it will not work
774 */
775 char *e = _("default:LTR");
776 GtkTextDirection dir = GTK_TEXT_DIR_LTR;
777
778 if (g_strcmp0 (str1: e, str2: "default:RTL") == 0)
779 dir = GTK_TEXT_DIR_RTL;
780 else if (g_strcmp0 (str1: e, str2: "default:LTR") != 0)
781 g_warning ("Whoever translated default:LTR did so wrongly. Defaulting to LTR.");
782
783 return dir;
784}
785
786/**
787 * gtk_get_default_language:
788 *
789 * Returns the `PangoLanguage` for the default language
790 * currently in effect.
791 *
792 * Note that this can change over the life of an
793 * application.
794 *
795 * The default language is derived from the current
796 * locale. It determines, for example, whether GTK uses
797 * the right-to-left or left-to-right text direction.
798 *
799 * This function is equivalent to
800 * [func@Pango.Language.get_default].
801 * See that function for details.
802 *
803 * Returns: (transfer none): the default language as a
804 * `PangoLanguage`
805 */
806PangoLanguage *
807gtk_get_default_language (void)
808{
809 return pango_language_get_default ();
810}
811
812typedef struct {
813 GMainLoop *store_loop;
814 guint n_clipboards;
815 guint timeout_id;
816} ClipboardStore;
817
818static void
819clipboard_store_finished (GObject *source,
820 GAsyncResult *result,
821 gpointer data)
822{
823 ClipboardStore *store;
824 GError *error = NULL;
825
826 if (!gdk_clipboard_store_finish (GDK_CLIPBOARD (source), result, error: &error))
827 {
828 if (g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CANCELLED))
829 {
830 g_error_free (error);
831 return;
832 }
833
834 g_error_free (error);
835 }
836
837 store = data;
838 store->n_clipboards--;
839 if (store->n_clipboards == 0)
840 g_main_loop_quit (loop: store->store_loop);
841}
842
843static gboolean
844sync_timed_out_cb (ClipboardStore *store)
845{
846 store->timeout_id = 0;
847 g_main_loop_quit (loop: store->store_loop);
848 return G_SOURCE_REMOVE;
849}
850
851void
852gtk_main_sync (void)
853{
854 ClipboardStore store = { NULL, };
855 GSList *displays, *l;
856 GCancellable *cancel;
857
858 /* Try storing all clipboard data we have */
859 displays = gdk_display_manager_list_displays (manager: gdk_display_manager_get ());
860 if (displays == NULL)
861 return;
862
863 cancel = g_cancellable_new ();
864
865 for (l = displays; l; l = l->next)
866 {
867 GdkDisplay *display = l->data;
868 GdkClipboard *clipboard = gdk_display_get_clipboard (display);
869
870 gdk_clipboard_store_async (clipboard,
871 G_PRIORITY_HIGH,
872 cancellable: cancel,
873 callback: clipboard_store_finished,
874 user_data: &store);
875 store.n_clipboards++;
876 }
877 g_slist_free (list: displays);
878
879 store.store_loop = g_main_loop_new (NULL, TRUE);
880 store.timeout_id = g_timeout_add_seconds (interval: 10, function: (GSourceFunc) sync_timed_out_cb, data: &store);
881 gdk_source_set_static_name_by_id (tag: store.timeout_id, name: "[gtk] gtk_main_sync clipboard store timeout");
882
883 if (g_main_loop_is_running (loop: store.store_loop))
884 g_main_loop_run (loop: store.store_loop);
885
886 g_cancellable_cancel (cancellable: cancel);
887 g_object_unref (object: cancel);
888 g_clear_handle_id (&store.timeout_id, g_source_remove);
889 g_clear_pointer (&store.store_loop, g_main_loop_unref);
890
891 /* Synchronize the recent manager singleton */
892 _gtk_recent_manager_sync ();
893}
894
895static GdkEvent *
896rewrite_event_for_surface (GdkEvent *event,
897 GdkSurface *new_surface)
898{
899 GdkEventType type;
900 double x, y;
901 double dx, dy;
902
903 type = gdk_event_get_event_type (event);
904
905 switch ((guint) type)
906 {
907 case GDK_BUTTON_PRESS:
908 case GDK_BUTTON_RELEASE:
909 case GDK_MOTION_NOTIFY:
910 case GDK_TOUCH_BEGIN:
911 case GDK_TOUCH_UPDATE:
912 case GDK_TOUCH_END:
913 case GDK_TOUCH_CANCEL:
914 case GDK_TOUCHPAD_SWIPE:
915 case GDK_TOUCHPAD_PINCH:
916 case GDK_TOUCHPAD_HOLD:
917 gdk_event_get_position (event, x: &x, y: &y);
918 gdk_surface_translate_coordinates (from: gdk_event_get_surface (event), to: new_surface, x: &x, y: &y);
919 break;
920 default:
921 x = y = 0;
922 break;
923 }
924
925 switch ((guint) type)
926 {
927 case GDK_BUTTON_PRESS:
928 case GDK_BUTTON_RELEASE:
929 return gdk_button_event_new (type,
930 surface: new_surface,
931 device: gdk_event_get_device (event),
932 tool: gdk_event_get_device_tool (event),
933 time: gdk_event_get_time (event),
934 state: gdk_event_get_modifier_state (event),
935 button: gdk_button_event_get_button (event),
936 x, y,
937 axes: gdk_event_dup_axes (event));
938 case GDK_MOTION_NOTIFY:
939 return gdk_motion_event_new (surface: new_surface,
940 device: gdk_event_get_device (event),
941 tool: gdk_event_get_device_tool (event),
942 time: gdk_event_get_time (event),
943 state: gdk_event_get_modifier_state (event),
944 x, y,
945 axes: gdk_event_dup_axes (event));
946 case GDK_TOUCH_BEGIN:
947 case GDK_TOUCH_UPDATE:
948 case GDK_TOUCH_END:
949 case GDK_TOUCH_CANCEL:
950 return gdk_touch_event_new (type,
951 sequence: gdk_event_get_event_sequence (event),
952 surface: new_surface,
953 device: gdk_event_get_device (event),
954 time: gdk_event_get_time (event),
955 state: gdk_event_get_modifier_state (event),
956 x, y,
957 axes: gdk_event_dup_axes (event),
958 emulating: gdk_touch_event_get_emulating_pointer (event));
959 case GDK_TOUCHPAD_SWIPE:
960 gdk_touchpad_event_get_deltas (event, dx: &dx, dy: &dy);
961 return gdk_touchpad_event_new_swipe (surface: new_surface,
962 sequence: gdk_event_get_event_sequence (event),
963 device: gdk_event_get_device (event),
964 time: gdk_event_get_time (event),
965 state: gdk_event_get_modifier_state (event),
966 phase: gdk_touchpad_event_get_gesture_phase (event),
967 x, y,
968 n_fingers: gdk_touchpad_event_get_n_fingers (event),
969 dx, dy);
970 case GDK_TOUCHPAD_PINCH:
971 gdk_touchpad_event_get_deltas (event, dx: &dx, dy: &dy);
972 return gdk_touchpad_event_new_pinch (surface: new_surface,
973 sequence: gdk_event_get_event_sequence (event),
974 device: gdk_event_get_device (event),
975 time: gdk_event_get_time (event),
976 state: gdk_event_get_modifier_state (event),
977 phase: gdk_touchpad_event_get_gesture_phase (event),
978 x, y,
979 n_fingers: gdk_touchpad_event_get_n_fingers (event),
980 dx, dy,
981 scale: gdk_touchpad_event_get_pinch_scale (event),
982 angle_delta: gdk_touchpad_event_get_pinch_angle_delta (event));
983 case GDK_TOUCHPAD_HOLD:
984 return gdk_touchpad_event_new_hold (surface: new_surface,
985 device: gdk_event_get_device (event),
986 time: gdk_event_get_time (event),
987 state: gdk_event_get_modifier_state (event),
988 phase: gdk_touchpad_event_get_gesture_phase (event),
989 x, y,
990 n_fingers: gdk_touchpad_event_get_n_fingers (event));
991 default:
992 break;
993 }
994
995 return NULL;
996}
997
998/* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
999 * then what X11 does is deliver the event normally if it was going to this
1000 * client, otherwise, delivers it in terms of the grab surface. This function
1001 * rewrites events to the effect that events going to the same window group
1002 * are delivered normally, otherwise, the event is delivered in terms of the
1003 * grab window.
1004 */
1005static GdkEvent *
1006rewrite_event_for_grabs (GdkEvent *event)
1007{
1008 GdkSurface *grab_surface;
1009 GtkWidget *event_widget, *grab_widget;
1010 gboolean owner_events;
1011 GdkDisplay *display;
1012 GdkDevice *device;
1013
1014 switch ((guint) gdk_event_get_event_type (event))
1015 {
1016 case GDK_SCROLL:
1017 case GDK_BUTTON_PRESS:
1018 case GDK_BUTTON_RELEASE:
1019 case GDK_MOTION_NOTIFY:
1020 case GDK_PROXIMITY_IN:
1021 case GDK_PROXIMITY_OUT:
1022 case GDK_KEY_PRESS:
1023 case GDK_KEY_RELEASE:
1024 case GDK_TOUCH_BEGIN:
1025 case GDK_TOUCH_UPDATE:
1026 case GDK_TOUCH_END:
1027 case GDK_TOUCH_CANCEL:
1028 case GDK_TOUCHPAD_SWIPE:
1029 case GDK_TOUCHPAD_PINCH:
1030 case GDK_TOUCHPAD_HOLD:
1031 display = gdk_event_get_display (event);
1032 device = gdk_event_get_device (event);
1033
1034 if (!gdk_device_grab_info (display, device, grab_surface: &grab_surface, owner_events: &owner_events) ||
1035 !owner_events)
1036 return NULL;
1037 break;
1038 default:
1039 return NULL;
1040 }
1041
1042 event_widget = gtk_get_event_widget (event);
1043 grab_widget = GTK_WIDGET (gtk_native_get_for_surface (grab_surface));
1044
1045 if (grab_widget &&
1046 gtk_main_get_window_group (widget: grab_widget) != gtk_main_get_window_group (widget: event_widget))
1047 return rewrite_event_for_surface (event, new_surface: grab_surface);
1048 else
1049 return NULL;
1050}
1051
1052static GdkEvent *
1053rewrite_event_for_toplevel (GdkEvent *event)
1054{
1055 GdkSurface *surface;
1056 GdkEventType event_type;
1057 GdkTranslatedKey *key, *key_no_lock;
1058
1059 surface = gdk_event_get_surface (event);
1060 if (!surface->parent)
1061 return NULL;
1062
1063 event_type = gdk_event_get_event_type (event);
1064 if (event_type != GDK_KEY_PRESS &&
1065 event_type != GDK_KEY_RELEASE)
1066 return NULL;
1067
1068 while (surface->parent)
1069 surface = surface->parent;
1070
1071 key = gdk_key_event_get_translated_key (event, FALSE);
1072 key_no_lock = gdk_key_event_get_translated_key (event, TRUE);
1073
1074 return gdk_key_event_new (type: gdk_event_get_event_type (event),
1075 surface,
1076 device: gdk_event_get_device (event),
1077 time: gdk_event_get_time (event),
1078 keycode: gdk_key_event_get_keycode (event),
1079 modifiers: gdk_event_get_modifier_state (event),
1080 is_modifier: gdk_key_event_is_modifier (event),
1081 translated: key, no_lock: key_no_lock);
1082}
1083
1084static gboolean
1085translate_coordinates (double event_x,
1086 double event_y,
1087 double *x,
1088 double *y,
1089 GtkWidget *widget)
1090{
1091 GtkNative *native;
1092 graphene_point_t p;
1093
1094 *x = *y = 0;
1095 native = gtk_widget_get_native (widget);
1096
1097 if (!gtk_widget_compute_point (GTK_WIDGET (native),
1098 target: widget,
1099 point: &GRAPHENE_POINT_INIT (event_x, event_y),
1100 out_point: &p))
1101 return FALSE;
1102
1103 *x = p.x;
1104 *y = p.y;
1105
1106 return TRUE;
1107}
1108
1109void
1110gtk_synthesize_crossing_events (GtkRoot *toplevel,
1111 GtkCrossingType crossing_type,
1112 GtkWidget *old_target,
1113 GtkWidget *new_target,
1114 double surface_x,
1115 double surface_y,
1116 GdkCrossingMode mode,
1117 GdkDrop *drop)
1118{
1119 GtkCrossingData crossing;
1120 GtkWidget *ancestor;
1121 GtkWidget *widget;
1122 double x, y;
1123 GtkWidget *prev;
1124 gboolean seen_ancestor;
1125 GtkWidgetStack target_array;
1126 int i;
1127
1128 if (old_target == new_target)
1129 return;
1130
1131 if (old_target && new_target)
1132 ancestor = gtk_widget_common_ancestor (widget_a: old_target, widget_b: new_target);
1133 else
1134 ancestor = NULL;
1135
1136 crossing.type = crossing_type;
1137 crossing.mode = mode;
1138 crossing.old_target = old_target ? g_object_ref (old_target) : NULL;
1139 crossing.old_descendent = NULL;
1140 crossing.new_target = new_target ? g_object_ref (new_target) : NULL;
1141 crossing.new_descendent = NULL;
1142 crossing.drop = drop;
1143
1144 crossing.direction = GTK_CROSSING_OUT;
1145
1146 prev = NULL;
1147 seen_ancestor = FALSE;
1148 widget = old_target;
1149 while (widget)
1150 {
1151 crossing.old_descendent = prev;
1152 if (seen_ancestor)
1153 {
1154 crossing.new_descendent = new_target ? prev : NULL;
1155 }
1156 else if (widget == ancestor)
1157 {
1158 GtkWidget *w;
1159
1160 crossing.new_descendent = NULL;
1161 for (w = new_target; w != ancestor; w = _gtk_widget_get_parent (widget: w))
1162 crossing.new_descendent = w;
1163
1164 seen_ancestor = TRUE;
1165 }
1166 else
1167 {
1168 crossing.new_descendent = NULL;
1169 }
1170 check_crossing_invariants (widget, crossing: &crossing);
1171 translate_coordinates (event_x: surface_x, event_y: surface_y, x: &x, y: &y, widget);
1172 gtk_widget_handle_crossing (widget, crossing: &crossing, x, y);
1173 if (crossing_type == GTK_CROSSING_POINTER)
1174 gtk_widget_unset_state_flags (widget, flags: GTK_STATE_FLAG_PRELIGHT);
1175 prev = widget;
1176 widget = _gtk_widget_get_parent (widget);
1177 }
1178
1179 gtk_widget_stack_init (self: &target_array);
1180 for (widget = new_target; widget; widget = _gtk_widget_get_parent (widget))
1181 gtk_widget_stack_append (self: &target_array, g_object_ref (widget));
1182
1183 crossing.direction = GTK_CROSSING_IN;
1184
1185 seen_ancestor = FALSE;
1186 for (i = gtk_widget_stack_get_size (self: &target_array) - 1; i >= 0; i--)
1187 {
1188 widget = gtk_widget_stack_get (self: &target_array, pos: i);
1189
1190 if (i < gtk_widget_stack_get_size (self: &target_array) - 1)
1191 crossing.new_descendent = gtk_widget_stack_get (self: &target_array, pos: i + 1);
1192 else
1193 crossing.new_descendent = NULL;
1194
1195 if (seen_ancestor)
1196 {
1197 crossing.old_descendent = NULL;
1198 }
1199 else if (widget == ancestor)
1200 {
1201 GtkWidget *w;
1202
1203 crossing.old_descendent = NULL;
1204 for (w = old_target; w != ancestor; w = _gtk_widget_get_parent (widget: w))
1205 crossing.old_descendent = w;
1206
1207 seen_ancestor = TRUE;
1208 }
1209 else
1210 {
1211 crossing.old_descendent = old_target ? crossing.new_descendent : NULL;
1212 }
1213
1214 translate_coordinates (event_x: surface_x, event_y: surface_y, x: &x, y: &y, widget);
1215 gtk_widget_handle_crossing (widget, crossing: &crossing, x, y);
1216 if (crossing_type == GTK_CROSSING_POINTER)
1217 gtk_widget_set_state_flags (widget, flags: GTK_STATE_FLAG_PRELIGHT, FALSE);
1218 }
1219
1220 g_clear_object (&crossing.old_target);
1221 g_clear_object (&crossing.new_target);
1222
1223 gtk_widget_stack_clear (self: &target_array);
1224}
1225
1226static GtkWidget *
1227update_pointer_focus_state (GtkWindow *toplevel,
1228 GdkEvent *event,
1229 GtkWidget *new_target)
1230{
1231 GtkWidget *old_target = NULL;
1232 GdkEventSequence *sequence;
1233 GdkDevice *device;
1234 double x, y;
1235 double nx, ny;
1236
1237 device = gdk_event_get_device (event);
1238 sequence = gdk_event_get_event_sequence (event);
1239 old_target = gtk_window_lookup_pointer_focus_widget (window: toplevel, device, sequence);
1240 if (old_target == new_target)
1241 return old_target;
1242
1243 gdk_event_get_position (event, x: &x, y: &y);
1244 gtk_native_get_surface_transform (self: GTK_NATIVE (ptr: toplevel), x: &nx, y: &ny);
1245 x -= nx;
1246 y -= ny;
1247
1248 gtk_window_update_pointer_focus (window: toplevel, device, sequence,
1249 target: new_target, x, y);
1250
1251 return old_target;
1252}
1253
1254static gboolean
1255is_pointing_event (GdkEvent *event)
1256{
1257 switch ((guint) gdk_event_get_event_type (event))
1258 {
1259 case GDK_MOTION_NOTIFY:
1260 case GDK_ENTER_NOTIFY:
1261 case GDK_LEAVE_NOTIFY:
1262 case GDK_BUTTON_PRESS:
1263 case GDK_BUTTON_RELEASE:
1264 case GDK_SCROLL:
1265 case GDK_TOUCH_BEGIN:
1266 case GDK_TOUCH_UPDATE:
1267 case GDK_TOUCH_END:
1268 case GDK_TOUCH_CANCEL:
1269 case GDK_TOUCHPAD_PINCH:
1270 case GDK_TOUCHPAD_SWIPE:
1271 case GDK_TOUCHPAD_HOLD:
1272 case GDK_DRAG_ENTER:
1273 case GDK_DRAG_LEAVE:
1274 case GDK_DRAG_MOTION:
1275 case GDK_DROP_START:
1276 return TRUE;
1277
1278 case GDK_GRAB_BROKEN:
1279 return gdk_device_get_source (device: gdk_event_get_device (event)) != GDK_SOURCE_KEYBOARD;
1280
1281 default:
1282 return FALSE;
1283 }
1284}
1285
1286static gboolean
1287is_key_event (GdkEvent *event)
1288{
1289 switch ((guint) gdk_event_get_event_type (event))
1290 {
1291 case GDK_KEY_PRESS:
1292 case GDK_KEY_RELEASE:
1293 return TRUE;
1294 break;
1295 case GDK_GRAB_BROKEN:
1296 return gdk_device_get_source (device: gdk_event_get_device (event)) == GDK_SOURCE_KEYBOARD;
1297 default:
1298 return FALSE;
1299 }
1300}
1301
1302static inline void
1303set_widget_active_state (GtkWidget *target,
1304 const gboolean is_active)
1305{
1306 GtkWidget *w;
1307
1308 w = target;
1309 while (w)
1310 {
1311 gtk_widget_set_active_state (widget: w, active: is_active);
1312 w = _gtk_widget_get_parent (widget: w);
1313 }
1314}
1315
1316static GtkWidget *
1317handle_pointing_event (GdkEvent *event)
1318{
1319 GtkWidget *target = NULL, *old_target = NULL, *event_widget;
1320 GtkWindow *toplevel;
1321 GdkEventSequence *sequence;
1322 GdkDevice *device;
1323 double x, y;
1324 double native_x, native_y;
1325 GtkWidget *native;
1326 GdkEventType type;
1327 gboolean has_implicit;
1328 GdkModifierType modifiers;
1329
1330 event_widget = gtk_get_event_widget (event);
1331 device = gdk_event_get_device (event);
1332 gdk_event_get_position (event, x: &x, y: &y);
1333
1334 toplevel = GTK_WINDOW (gtk_widget_get_root (event_widget));
1335 native = GTK_WIDGET (gtk_widget_get_native (event_widget));
1336
1337 gtk_native_get_surface_transform (self: GTK_NATIVE (ptr: native), x: &native_x, y: &native_y);
1338 x -= native_x;
1339 y -= native_y;
1340
1341 type = gdk_event_get_event_type (event);
1342 sequence = gdk_event_get_event_sequence (event);
1343
1344 if (type == GDK_SCROLL &&
1345 (gdk_device_get_source (device) == GDK_SOURCE_TOUCHPAD ||
1346 gdk_device_get_source (device) == GDK_SOURCE_TRACKPOINT ||
1347 gdk_device_get_source (device) == GDK_SOURCE_MOUSE))
1348 {
1349 /* A bit of a kludge, resolve target lookups for scrolling devices
1350 * on the seat pointer.
1351 */
1352 device = gdk_seat_get_pointer (seat: gdk_event_get_seat (event));
1353 }
1354 else if (type == GDK_TOUCHPAD_PINCH ||
1355 type == GDK_TOUCHPAD_SWIPE ||
1356 type == GDK_TOUCHPAD_HOLD)
1357 {
1358 /* Another bit of a kludge, touchpad gesture sequences do not
1359 * reflect on the pointer focus lookup.
1360 */
1361 sequence = NULL;
1362 }
1363
1364 switch ((guint) type)
1365 {
1366 case GDK_LEAVE_NOTIFY:
1367 if (gdk_crossing_event_get_mode (event) == GDK_CROSSING_GRAB)
1368 {
1369 GtkWidget *grab_widget;
1370
1371 grab_widget =
1372 gtk_window_lookup_pointer_focus_implicit_grab (window: toplevel,
1373 device,
1374 sequence);
1375 if (grab_widget)
1376 set_widget_active_state (target: grab_widget, FALSE);
1377 }
1378
1379 old_target = update_pointer_focus_state (toplevel, event, NULL);
1380 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: toplevel), crossing_type: GTK_CROSSING_POINTER, old_target, NULL,
1381 surface_x: x, surface_y: y, mode: gdk_crossing_event_get_mode (event), NULL);
1382 break;
1383 case GDK_TOUCH_END:
1384 case GDK_TOUCH_CANCEL:
1385 old_target = update_pointer_focus_state (toplevel, event, NULL);
1386 set_widget_active_state (target: old_target, FALSE);
1387 break;
1388 case GDK_DRAG_LEAVE:
1389 {
1390 GdkDrop *drop = gdk_dnd_event_get_drop (event);
1391 old_target = update_pointer_focus_state (toplevel, event, NULL);
1392 gtk_drop_begin_event (drop, event_type: GDK_DRAG_LEAVE);
1393 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: toplevel), crossing_type: GTK_CROSSING_DROP, old_target, NULL,
1394 surface_x: x, surface_y: y, mode: GDK_CROSSING_NORMAL, drop);
1395 gtk_drop_end_event (drop);
1396 }
1397 break;
1398 case GDK_ENTER_NOTIFY:
1399 case GDK_DRAG_ENTER:
1400 case GDK_DRAG_MOTION:
1401 case GDK_DROP_START:
1402 case GDK_TOUCH_BEGIN:
1403 case GDK_TOUCH_UPDATE:
1404 case GDK_MOTION_NOTIFY:
1405 target = gtk_window_lookup_pointer_focus_implicit_grab (window: toplevel, device, sequence);
1406
1407 if (!target)
1408 target = gtk_widget_pick (widget: native, x, y, flags: GTK_PICK_DEFAULT);
1409
1410 if (!target)
1411 target = GTK_WIDGET (native);
1412
1413 old_target = update_pointer_focus_state (toplevel, event, new_target: target);
1414
1415 if (type == GDK_MOTION_NOTIFY || type == GDK_ENTER_NOTIFY)
1416 {
1417 if (!gtk_window_lookup_pointer_focus_implicit_grab (window: toplevel, device,
1418 sequence))
1419 {
1420 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: toplevel), crossing_type: GTK_CROSSING_POINTER, old_target, new_target: target,
1421 surface_x: x, surface_y: y, mode: GDK_CROSSING_NORMAL, NULL);
1422 }
1423
1424 gtk_window_maybe_update_cursor (window: toplevel, NULL, device);
1425 }
1426 else if ((old_target != target) &&
1427 (type == GDK_DRAG_ENTER || type == GDK_DRAG_MOTION || type == GDK_DROP_START))
1428 {
1429 GdkDrop *drop = gdk_dnd_event_get_drop (event);
1430 gtk_drop_begin_event (drop, event_type: type);
1431 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: toplevel), crossing_type: GTK_CROSSING_DROP, old_target, new_target: target,
1432 surface_x: x, surface_y: y, mode: GDK_CROSSING_NORMAL, drop: gdk_dnd_event_get_drop (event));
1433 gtk_drop_end_event (drop);
1434 }
1435 else if (type == GDK_TOUCH_BEGIN)
1436 {
1437 gtk_window_set_pointer_focus_grab (window: toplevel, device, sequence, grab_widget: target);
1438 set_widget_active_state (target, TRUE);
1439 }
1440
1441 /* Let it take the effective pointer focus anyway, as it may change due
1442 * to implicit grabs.
1443 */
1444 target = NULL;
1445 break;
1446 case GDK_BUTTON_PRESS:
1447 case GDK_BUTTON_RELEASE:
1448 target = gtk_window_lookup_effective_pointer_focus_widget (window: toplevel,
1449 device,
1450 sequence);
1451 has_implicit =
1452 gtk_window_lookup_pointer_focus_implicit_grab (window: toplevel,
1453 device,
1454 sequence) != NULL;
1455 modifiers = gdk_event_get_modifier_state (event);
1456
1457 if (type == GDK_BUTTON_RELEASE &&
1458 gtk_popcount (modifiers & (GDK_BUTTON1_MASK |
1459 GDK_BUTTON2_MASK |
1460 GDK_BUTTON3_MASK |
1461 GDK_BUTTON4_MASK |
1462 GDK_BUTTON5_MASK)) == 1)
1463 {
1464 GtkWidget *new_target = gtk_widget_pick (widget: native, x, y, flags: GTK_PICK_DEFAULT);
1465
1466 gtk_window_set_pointer_focus_grab (window: toplevel, device, sequence, NULL);
1467
1468 if (new_target == NULL)
1469 new_target = GTK_WIDGET (toplevel);
1470
1471 gtk_synthesize_crossing_events (toplevel: GTK_ROOT (ptr: toplevel), crossing_type: GTK_CROSSING_POINTER, old_target: target, new_target,
1472 surface_x: x, surface_y: y, mode: GDK_CROSSING_UNGRAB, NULL);
1473 gtk_window_maybe_update_cursor (window: toplevel, NULL, device);
1474 update_pointer_focus_state (toplevel, event, new_target);
1475 }
1476 else if (type == GDK_BUTTON_PRESS)
1477 {
1478 gtk_window_set_pointer_focus_grab (window: toplevel, device,
1479 sequence, grab_widget: target);
1480 }
1481
1482 if (type == GDK_BUTTON_PRESS)
1483 set_widget_active_state (target, TRUE);
1484 else if (has_implicit)
1485 set_widget_active_state (target, FALSE);
1486
1487 break;
1488 case GDK_SCROLL:
1489 case GDK_TOUCHPAD_PINCH:
1490 case GDK_TOUCHPAD_SWIPE:
1491 case GDK_TOUCHPAD_HOLD:
1492 break;
1493 case GDK_GRAB_BROKEN:
1494 if (gdk_grab_broken_event_get_implicit (event))
1495 {
1496 target = gtk_window_lookup_effective_pointer_focus_widget (window: toplevel,
1497 device,
1498 sequence);
1499 set_widget_active_state (target, FALSE);
1500 }
1501 break;
1502 default:
1503 g_assert_not_reached ();
1504 }
1505
1506 if (!target)
1507 target = gtk_window_lookup_effective_pointer_focus_widget (window: toplevel,
1508 device,
1509 sequence);
1510 return target ? target : old_target;
1511}
1512
1513static GtkWidget *
1514handle_key_event (GdkEvent *event)
1515{
1516 GtkWidget *event_widget;
1517 GtkWidget *focus_widget;
1518
1519 event_widget = gtk_get_event_widget (event);
1520
1521 focus_widget = gtk_root_get_focus (self: gtk_widget_get_root (widget: event_widget));
1522 return focus_widget ? focus_widget : event_widget;
1523}
1524
1525static gboolean
1526is_transient_for (GtkWindow *child,
1527 GtkWindow *parent)
1528{
1529 GtkWindow *transient_for;
1530
1531 transient_for = gtk_window_get_transient_for (window: child);
1532
1533 while (transient_for)
1534 {
1535 if (transient_for == parent)
1536 return TRUE;
1537
1538 transient_for = gtk_window_get_transient_for (window: transient_for);
1539 }
1540
1541 return FALSE;
1542}
1543
1544void
1545gtk_main_do_event (GdkEvent *event)
1546{
1547 GtkWidget *event_widget;
1548 GtkWidget *target_widget;
1549 GtkWidget *grab_widget = NULL;
1550 GtkWindowGroup *window_group;
1551 GdkEvent *rewritten_event = NULL;
1552 GList *tmp_list;
1553
1554 if (gtk_inspector_handle_event (event))
1555 return;
1556
1557 /* Find the widget which got the event. We store the widget
1558 * in the user_data field of GdkSurface's. Ignore the event
1559 * if we don't have a widget for it.
1560 */
1561 event_widget = gtk_get_event_widget (event);
1562 if (!event_widget)
1563 return;
1564
1565 target_widget = event_widget;
1566
1567 /* We propagate key events from the root, even if they are
1568 * delivered to a popup surface.
1569 *
1570 * If pointer or keyboard grabs are in effect, munge the events
1571 * so that each window group looks like a separate app.
1572 */
1573 if (is_key_event (event))
1574 rewritten_event = rewrite_event_for_toplevel (event);
1575 else
1576 rewritten_event = rewrite_event_for_grabs (event);
1577 if (rewritten_event)
1578 {
1579 event = rewritten_event;
1580 target_widget = gtk_get_event_widget (event);
1581 }
1582
1583 /* Push the event onto a stack of current events for
1584 * gtk_current_event_get().
1585 */
1586 current_events = g_list_prepend (list: current_events, data: event);
1587
1588 if (is_pointing_event (event))
1589 {
1590 target_widget = handle_pointing_event (event);
1591 }
1592 else if (is_key_event (event))
1593 {
1594 target_widget = handle_key_event (event);
1595 }
1596
1597 if (!target_widget)
1598 goto cleanup;
1599
1600 window_group = gtk_main_get_window_group (widget: target_widget);
1601
1602 /* check whether there is a grab in effect... */
1603 grab_widget = gtk_window_group_get_current_grab (window_group);
1604
1605 /* If the grab widget is an ancestor of the event widget
1606 * then we send the event to the original event widget.
1607 * This is the key to implementing modality. This also applies
1608 * across windows that are directly or indirectly transient-for
1609 * the modal one.
1610 */
1611 if (!grab_widget ||
1612 ((gtk_widget_is_sensitive (widget: target_widget) || gdk_event_get_event_type (event) == GDK_SCROLL) &&
1613 gtk_widget_is_ancestor (widget: target_widget, ancestor: grab_widget)) ||
1614 (GTK_IS_WINDOW (grab_widget) &&
1615 GTK_IS_WINDOW (event_widget) &&
1616 grab_widget != event_widget &&
1617 is_transient_for (GTK_WINDOW (event_widget), GTK_WINDOW (grab_widget))))
1618 grab_widget = target_widget;
1619
1620 g_object_ref (target_widget);
1621
1622 /* Not all events get sent to the grabbing widget.
1623 * The delete, destroy, expose, focus change and resize
1624 * events still get sent to the event widget because
1625 * 1) these events have no meaning for the grabbing widget
1626 * and 2) redirecting these events to the grabbing widget
1627 * could cause the display to be messed up.
1628 *
1629 * Drag events are also not redirected, since it isn't
1630 * clear what the semantics of that would be.
1631 */
1632 switch ((guint)gdk_event_get_event_type (event))
1633 {
1634 case GDK_DELETE:
1635 if (!gtk_window_group_get_current_grab (window_group) ||
1636 GTK_WIDGET (gtk_widget_get_root (gtk_window_group_get_current_grab (window_group))) == target_widget)
1637 {
1638 if (GTK_IS_WINDOW (target_widget) &&
1639 !gtk_window_emit_close_request (GTK_WINDOW (target_widget)))
1640 gtk_window_destroy (GTK_WINDOW (target_widget));
1641 }
1642 break;
1643
1644 case GDK_FOCUS_CHANGE:
1645 {
1646 GtkWidget *root = GTK_WIDGET (gtk_widget_get_root (target_widget));
1647 if (!_gtk_widget_captured_event (widget: root, event, target: root))
1648 gtk_widget_event (widget: root, event, target: root);
1649 }
1650 break;
1651
1652 case GDK_KEY_PRESS:
1653 case GDK_KEY_RELEASE:
1654 case GDK_SCROLL:
1655 case GDK_BUTTON_PRESS:
1656 case GDK_TOUCH_BEGIN:
1657 case GDK_MOTION_NOTIFY:
1658 case GDK_BUTTON_RELEASE:
1659 case GDK_PROXIMITY_IN:
1660 case GDK_PROXIMITY_OUT:
1661 case GDK_TOUCH_UPDATE:
1662 case GDK_TOUCH_END:
1663 case GDK_TOUCH_CANCEL:
1664 case GDK_TOUCHPAD_SWIPE:
1665 case GDK_TOUCHPAD_PINCH:
1666 case GDK_TOUCHPAD_HOLD:
1667 case GDK_PAD_BUTTON_PRESS:
1668 case GDK_PAD_BUTTON_RELEASE:
1669 case GDK_PAD_RING:
1670 case GDK_PAD_STRIP:
1671 case GDK_PAD_GROUP_MODE:
1672 case GDK_GRAB_BROKEN:
1673 gtk_propagate_event (widget: grab_widget, event);
1674 break;
1675
1676 case GDK_ENTER_NOTIFY:
1677 case GDK_LEAVE_NOTIFY:
1678 case GDK_DRAG_ENTER:
1679 case GDK_DRAG_LEAVE:
1680 /* Crossing event propagation happens during picking */
1681 break;
1682
1683 case GDK_DRAG_MOTION:
1684 case GDK_DROP_START:
1685 {
1686 GdkDrop *drop = gdk_dnd_event_get_drop (event);
1687 gtk_drop_begin_event (drop, event_type: gdk_event_get_event_type (event));
1688 gtk_propagate_event (widget: target_widget, event);
1689 gtk_drop_end_event (drop);
1690 }
1691 break;
1692
1693 case GDK_EVENT_LAST:
1694 default:
1695 g_assert_not_reached ();
1696 break;
1697 }
1698
1699 _gtk_tooltip_handle_event (target: target_widget, event);
1700
1701 g_object_unref (object: target_widget);
1702
1703 cleanup:
1704 tmp_list = current_events;
1705 current_events = g_list_remove_link (list: current_events, llink: tmp_list);
1706 g_list_free_1 (list: tmp_list);
1707
1708 if (rewritten_event)
1709 gdk_event_unref (event: rewritten_event);
1710}
1711
1712static GtkWindowGroup *
1713gtk_main_get_window_group (GtkWidget *widget)
1714{
1715 GtkWidget *toplevel = NULL;
1716
1717 if (widget)
1718 toplevel = GTK_WIDGET (gtk_widget_get_root (widget));
1719
1720 if (GTK_IS_WINDOW (toplevel))
1721 return gtk_window_get_group (GTK_WINDOW (toplevel));
1722 else
1723 return gtk_window_get_group (NULL);
1724}
1725
1726static void
1727gtk_grab_notify (GtkWindowGroup *group,
1728 GtkWidget *old_grab_widget,
1729 GtkWidget *new_grab_widget,
1730 gboolean from_grab)
1731{
1732 GList *toplevels;
1733
1734 if (old_grab_widget == new_grab_widget)
1735 return;
1736
1737 g_object_ref (group);
1738
1739 toplevels = gtk_window_list_toplevels ();
1740 g_list_foreach (list: toplevels, func: (GFunc)g_object_ref, NULL);
1741
1742 while (toplevels)
1743 {
1744 GtkWindow *toplevel = toplevels->data;
1745 toplevels = g_list_delete_link (list: toplevels, link_: toplevels);
1746
1747 gtk_window_grab_notify (window: toplevel,
1748 old_grab_widget,
1749 new_grab_widget,
1750 from_grab);
1751 g_object_unref (object: toplevel);
1752 }
1753
1754 g_object_unref (object: group);
1755}
1756
1757/**
1758 * gtk_grab_add: (method)
1759 * @widget: The widget that grabs keyboard and pointer events
1760 *
1761 * Makes @widget the current grabbed widget.
1762 *
1763 * This means that interaction with other widgets in the same
1764 * application is blocked and mouse as well as keyboard events
1765 * are delivered to this widget.
1766 *
1767 * If @widget is not sensitive, it is not set as the current
1768 * grabbed widget and this function does nothing.
1769 */
1770void
1771gtk_grab_add (GtkWidget *widget)
1772{
1773 GtkWindowGroup *group;
1774 GtkWidget *old_grab_widget;
1775
1776 g_return_if_fail (widget != NULL);
1777
1778 if (!gtk_widget_has_grab (widget) && gtk_widget_is_sensitive (widget))
1779 {
1780 _gtk_widget_set_has_grab (widget, TRUE);
1781
1782 group = gtk_main_get_window_group (widget);
1783
1784 old_grab_widget = gtk_window_group_get_current_grab (window_group: group);
1785
1786 g_object_ref (widget);
1787 _gtk_window_group_add_grab (window_group: group, widget);
1788
1789 gtk_grab_notify (group, old_grab_widget, new_grab_widget: widget, TRUE);
1790 }
1791}
1792
1793/**
1794 * gtk_grab_remove: (method)
1795 * @widget: The widget which gives up the grab
1796 *
1797 * Removes the grab from the given widget.
1798 *
1799 * You have to pair calls to gtk_grab_add() and gtk_grab_remove().
1800 *
1801 * If @widget does not have the grab, this function does nothing.
1802 */
1803void
1804gtk_grab_remove (GtkWidget *widget)
1805{
1806 GtkWindowGroup *group;
1807 GtkWidget *new_grab_widget;
1808
1809 g_return_if_fail (widget != NULL);
1810
1811 if (gtk_widget_has_grab (widget))
1812 {
1813 _gtk_widget_set_has_grab (widget, FALSE);
1814
1815 group = gtk_main_get_window_group (widget);
1816 _gtk_window_group_remove_grab (window_group: group, widget);
1817 new_grab_widget = gtk_window_group_get_current_grab (window_group: group);
1818
1819 gtk_grab_notify (group, old_grab_widget: widget, new_grab_widget, FALSE);
1820
1821 g_object_unref (object: widget);
1822 }
1823}
1824
1825guint32
1826gtk_get_current_event_time (void)
1827{
1828 if (current_events)
1829 return gdk_event_get_time (event: current_events->data);
1830 else
1831 return GDK_CURRENT_TIME;
1832}
1833
1834/**
1835 * gtk_get_event_widget:
1836 * @event: a `GdkEvent`
1837 *
1838 * If @event is %NULL or the event was not associated with any widget,
1839 * returns %NULL, otherwise returns the widget that received the event
1840 * originally.
1841 *
1842 * Returns: (transfer none) (nullable): the widget that originally
1843 * received @event
1844 */
1845GtkWidget *
1846gtk_get_event_widget (GdkEvent *event)
1847{
1848 GdkSurface *surface;
1849
1850 surface = gdk_event_get_surface (event);
1851 if (surface && !gdk_surface_is_destroyed (surface))
1852 return GTK_WIDGET (gtk_native_get_for_surface (surface));
1853
1854 return NULL;
1855}
1856
1857gboolean
1858gtk_propagate_event_internal (GtkWidget *widget,
1859 GdkEvent *event,
1860 GtkWidget *topmost)
1861{
1862 int handled_event = FALSE;
1863 GtkWidget *target = widget;
1864 GtkWidgetStack widget_array;
1865 int i;
1866
1867 /* First, propagate event down */
1868 gtk_widget_stack_init (self: &widget_array);
1869 gtk_widget_stack_append (self: &widget_array, g_object_ref (widget));
1870
1871 for (;;)
1872 {
1873 widget = _gtk_widget_get_parent (widget);
1874 if (!widget)
1875 break;
1876
1877 gtk_widget_stack_append (self: &widget_array, g_object_ref (widget));
1878
1879 if (widget == topmost)
1880 break;
1881 }
1882
1883 i = gtk_widget_stack_get_size (self: &widget_array) - 1;
1884 for (;;)
1885 {
1886 widget = gtk_widget_stack_get (self: &widget_array, pos: i);
1887
1888 if (!_gtk_widget_is_sensitive (widget))
1889 {
1890 /* stop propagating on SCROLL, but don't handle the event, so it
1891 * can propagate up again and reach its handling widget
1892 */
1893 if (gdk_event_get_event_type (event) == GDK_SCROLL)
1894 break;
1895 else
1896 handled_event = TRUE;
1897 }
1898 else if (_gtk_widget_get_realized (widget))
1899 handled_event = _gtk_widget_captured_event (widget, event, target);
1900
1901 handled_event |= !_gtk_widget_get_realized (widget);
1902
1903 if (handled_event)
1904 break;
1905
1906 if (i == 0)
1907 break;
1908
1909 i--;
1910 }
1911
1912 /* If not yet handled, also propagate down */
1913 if (!handled_event)
1914 {
1915 /* Propagate event up the widget tree so that
1916 * parents can see the button and motion
1917 * events of the children.
1918 */
1919 for (i = 0; i < gtk_widget_stack_get_size (self: &widget_array); i++)
1920 {
1921 widget = gtk_widget_stack_get (self: &widget_array, pos: i);
1922
1923 /* Scroll events are special cased here because it
1924 * feels wrong when scrolling a GtkViewport, say,
1925 * to have children of the viewport eat the scroll
1926 * event
1927 */
1928 if (!_gtk_widget_is_sensitive (widget))
1929 handled_event = gdk_event_get_event_type (event) != GDK_SCROLL;
1930 else if (_gtk_widget_get_realized (widget))
1931 handled_event = gtk_widget_event (widget, event, target);
1932
1933 handled_event |= !_gtk_widget_get_realized (widget);
1934
1935 if (handled_event)
1936 break;
1937 }
1938 }
1939
1940 gtk_widget_stack_clear (self: &widget_array);
1941 return handled_event;
1942}
1943
1944/**
1945 * gtk_propagate_event:
1946 * @widget: a `GtkWidget`
1947 * @event: an event
1948 *
1949 * Sends an event to a widget, propagating the event to parent widgets
1950 * if the event remains unhandled. This function will emit the event
1951 * through all the hierarchy of @widget through all propagation phases.
1952 *
1953 * Events received by GTK from GDK normally begin at a `GtkRoot` widget.
1954 * Depending on the type of event, existence of modal dialogs, grabs, etc.,
1955 * the event may be propagated; if so, this function is used.
1956 *
1957 * All that said, you most likely don’t want to use any of these
1958 * functions; synthesizing events is rarely needed. There are almost
1959 * certainly better ways to achieve your goals. For example, use
1960 * gtk_widget_queue_draw() instead
1961 * of making up expose events.
1962 *
1963 * Returns: %TRUE if the event was handled
1964 */
1965gboolean
1966gtk_propagate_event (GtkWidget *widget,
1967 GdkEvent *event)
1968{
1969 GtkWindowGroup *window_group;
1970 GtkWidget *event_widget, *topmost = NULL;
1971
1972 g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
1973 g_return_val_if_fail (event != NULL, FALSE);
1974
1975 event_widget = gtk_get_event_widget (event);
1976 window_group = gtk_main_get_window_group (widget: event_widget);
1977
1978 /* check whether there is a grab in effect... */
1979 topmost = gtk_window_group_get_current_grab (window_group);
1980
1981 return gtk_propagate_event_internal (widget, event, topmost);
1982}
1983

source code of gtk/gtk/gtkmain.c