Bug Summary

File:ctk/ctkmain.c
Warning:line 984, column 12
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ctkmain.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/ctk -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -D G_LOG_DOMAIN="Ctk" -D G_LOG_USE_STRUCTURED=1 -D CTK_VERSION="3.25.5" -D CTK_BINARY_VERSION="3.0.0" -D CTK_COMPILATION -D CTK_PRINT_BACKEND_ENABLE_UNSUPPORTED -D CTK_LIBDIR="/usr/lib" -D CTK_LOCALEDIR="/usr/share/locale" -D CTK_DATADIR="/usr/share" -D CTK_DATA_PREFIX="/usr" -D CTK_SYSCONFDIR="/usr/etc" -D CTK_HOST="x86_64-pc-linux-gnu" -D CTK_PRINT_BACKENDS="file,cups" -D X11_DATA_PREFIX="/usr" -D ISO_CODES_PREFIX="" -I .. -I ../ctk -I .. -I ../cdk -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -D G_ENABLE_DEBUG -D G_ENABLE_CONSISTENCY_CHECKS -D GLIB_MIN_REQUIRED_VERSION=GLIB_VERSION_2_66 -D GLIB_MAX_ALLOWED_VERSION=GLIB_VERSION_2_66 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/atk-1.0 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/gio-unix-2.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/pango-1.0 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/ctk -ferror-limit 19 -fvisibility=hidden -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-09-19-172934-43638-1 -x c ctkmain.c
1/* CTK - 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 CTK+ Team and others 1997-2000. See the AUTHORS
20 * file for a list of people on the CTK+ Team. See the ChangeLog
21 * files for a list of changes. These files are distributed with
22 * CTK+ at ftp://ftp.ctk.org/pub/ctk/.
23 */
24
25/**
26 * SECTION:ctkmain
27 * @Short_description: Library initialization, main event loop, and events
28 * @Title: Main loop and Events
29 * @See_also:See the GLib manual, especially #GMainLoop and signal-related
30 * functions such as g_signal_connect()
31 *
32 * Before using CTK+, you need to initialize it; initialization connects to the
33 * window system display, and parses some standard command line arguments. The
34 * ctk_init() macro initializes CTK+. ctk_init() exits the application if errors
35 * occur; to avoid this, use ctk_init_check(). ctk_init_check() allows you to
36 * recover from a failed CTK+ initialization - you might start up your
37 * application in text mode instead.
38 *
39 * Like all GUI toolkits, CTK+ uses an event-driven programming model. When the
40 * user is doing nothing, CTK+ sits in the “main loop” and
41 * waits for input. If the user performs some action - say, a mouse click - then
42 * the main loop “wakes up” and delivers an event to CTK+. CTK+ forwards the
43 * event to one or more widgets.
44 *
45 * When widgets receive an event, they frequently emit one or more
46 * “signals”. Signals notify your program that "something
47 * interesting happened" by invoking functions you’ve connected to the signal
48 * with g_signal_connect(). Functions connected to a signal are often termed
49 * “callbacks”.
50 *
51 * When your callbacks are invoked, you would typically take some action - for
52 * example, when an Open button is clicked you might display a
53 * #CtkFileChooserDialog. After a callback finishes, CTK+ will return to the
54 * main loop and await more user input.
55 *
56 * ## Typical main() function for a CTK+ application
57 *
58 * |[<!-- language="C" -->
59 * int
60 * main (int argc, char **argv)
61 * {
62 * CtkWidget *mainwin;
63 * // Initialize i18n support with bindtextdomain(), etc.
64 *
65 * // ...
66 *
67 * // Initialize the widget set
68 * ctk_init (&argc, &argv);
69 *
70 * // Create the main window
71 * mainwin = ctk_window_new (CTK_WINDOW_TOPLEVEL);
72 *
73 * // Set up our GUI elements
74 *
75 * // ...
76 *
77 * // Show the application window
78 * ctk_widget_show_all (mainwin);
79 *
80 * // Enter the main event loop, and wait for user interaction
81 * ctk_main ();
82 *
83 * // The user lost interest
84 * return 0;
85 * }
86 * ]|
87 *
88 * It’s OK to use the GLib main loop directly instead of ctk_main(), though it
89 * involves slightly more typing. See #GMainLoop in the GLib documentation.
90 */
91
92#include "config.h"
93
94#include "cdk/cdk.h"
95#include "cdk/cdk-private.h"
96
97#include <locale.h>
98
99#include <stdio.h>
100#include <stdlib.h>
101#include <string.h>
102#ifdef HAVE_UNISTD_H1
103#include <unistd.h>
104#endif
105#include <sys/types.h> /* For uid_t, gid_t */
106
107#ifdef G_OS_WIN32
108#define STRICT
109#include <windows.h>
110#undef STRICT
111#endif
112
113#include "ctkintl.h"
114
115#include "ctkaccelmapprivate.h"
116#include "ctkbox.h"
117#include "ctkclipboardprivate.h"
118#include "ctkdebug.h"
119#include "ctkdndprivate.h"
120#include "ctkmain.h"
121#include "ctkmenu.h"
122#include "ctkmodules.h"
123#include "ctkmodulesprivate.h"
124#include "ctkprivate.h"
125#include "ctkrecentmanager.h"
126#include "ctkselectionprivate.h"
127#include "ctksettingsprivate.h"
128#include "ctktooltipprivate.h"
129#include "ctkversion.h"
130#include "ctkwidgetprivate.h"
131#include "ctkwindowprivate.h"
132#include "ctkwindowgroup.h"
133
134#include "a11y/ctkaccessibility.h"
135
136/* Private type definitions
137 */
138typedef struct _CtkKeySnooperData CtkKeySnooperData;
139
140struct _CtkKeySnooperData
141{
142 CtkKeySnoopFunc func;
143 gpointer func_data;
144 guint id;
145};
146
147static gint ctk_invoke_key_snoopers (CtkWidget *grab_widget,
148 CdkEvent *event);
149
150static CtkWindowGroup *ctk_main_get_window_group (CtkWidget *widget);
151
152static guint ctk_main_loop_level = 0;
153static gint pre_initialized = FALSE(0);
154static gint ctk_initialized = FALSE(0);
155static GList *current_events = NULL((void*)0);
156
157static GSList *main_loops = NULL((void*)0); /* stack of currently executing main loops */
158
159static GSList *key_snoopers = NULL((void*)0);
160
161typedef struct {
162 CdkDisplay *display;
163 guint flags;
164} DisplayDebugFlags;
165
166#define N_DEBUG_DISPLAYS4 4
167
168DisplayDebugFlags debug_flags[N_DEBUG_DISPLAYS4];
169
170#ifdef G_ENABLE_DEBUG1
171static const GDebugKey ctk_debug_keys[] = {
172 { "misc", CTK_DEBUG_MISC },
173 { "plugsocket", CTK_DEBUG_PLUGSOCKET },
174 { "text", CTK_DEBUG_TEXT },
175 { "tree", CTK_DEBUG_TREE },
176 { "updates", CTK_DEBUG_UPDATES },
177 { "keybindings", CTK_DEBUG_KEYBINDINGS },
178 { "multihead", CTK_DEBUG_MULTIHEAD },
179 { "modules", CTK_DEBUG_MODULES },
180 { "geometry", CTK_DEBUG_GEOMETRY },
181 { "icontheme", CTK_DEBUG_ICONTHEME },
182 { "printing", CTK_DEBUG_PRINTING} ,
183 { "builder", CTK_DEBUG_BUILDER },
184 { "size-request", CTK_DEBUG_SIZE_REQUEST },
185 { "no-css-cache", CTK_DEBUG_NO_CSS_CACHE },
186 { "baselines", CTK_DEBUG_BASELINES },
187 { "pixel-cache", CTK_DEBUG_PIXEL_CACHE },
188 { "no-pixel-cache", CTK_DEBUG_NO_PIXEL_CACHE },
189 { "interactive", CTK_DEBUG_INTERACTIVE },
190 { "touchscreen", CTK_DEBUG_TOUCHSCREEN },
191 { "actions", CTK_DEBUG_ACTIONS },
192 { "resize", CTK_DEBUG_RESIZE },
193 { "layout", CTK_DEBUG_LAYOUT }
194};
195#endif /* G_ENABLE_DEBUG */
196
197/**
198 * ctk_get_major_version:
199 *
200 * Returns the major version number of the CTK+ library.
201 * (e.g. in CTK+ version 3.1.5 this is 3.)
202 *
203 * This function is in the library, so it represents the CTK+ library
204 * your code is running against. Contrast with the #CTK_MAJOR_VERSION
205 * macro, which represents the major version of the CTK+ headers you
206 * have included when compiling your code.
207 *
208 * Returns: the major version number of the CTK+ library
209 *
210 * Since: 3.0
211 */
212guint
213ctk_get_major_version (void)
214{
215 return CTK_MAJOR_VERSION(3);
216}
217
218/**
219 * ctk_get_minor_version:
220 *
221 * Returns the minor version number of the CTK+ library.
222 * (e.g. in CTK+ version 3.1.5 this is 1.)
223 *
224 * This function is in the library, so it represents the CTK+ library
225 * your code is are running against. Contrast with the
226 * #CTK_MINOR_VERSION macro, which represents the minor version of the
227 * CTK+ headers you have included when compiling your code.
228 *
229 * Returns: the minor version number of the CTK+ library
230 *
231 * Since: 3.0
232 */
233guint
234ctk_get_minor_version (void)
235{
236 return CTK_MINOR_VERSION(25);
237}
238
239/**
240 * ctk_get_micro_version:
241 *
242 * Returns the micro version number of the CTK+ library.
243 * (e.g. in CTK+ version 3.1.5 this is 5.)
244 *
245 * This function is in the library, so it represents the CTK+ library
246 * your code is are running against. Contrast with the
247 * #CTK_MICRO_VERSION macro, which represents the micro version of the
248 * CTK+ headers you have included when compiling your code.
249 *
250 * Returns: the micro version number of the CTK+ library
251 *
252 * Since: 3.0
253 */
254guint
255ctk_get_micro_version (void)
256{
257 return CTK_MICRO_VERSION(5);
258}
259
260/**
261 * ctk_get_binary_age:
262 *
263 * Returns the binary age as passed to `libtool`
264 * when building the CTK+ library the process is running against.
265 * If `libtool` means nothing to you, don't
266 * worry about it.
267 *
268 * Returns: the binary age of the CTK+ library
269 *
270 * Since: 3.0
271 */
272guint
273ctk_get_binary_age (void)
274{
275 return CTK_BINARY_AGE(2505);
276}
277
278/**
279 * ctk_get_interface_age:
280 *
281 * Returns the interface age as passed to `libtool`
282 * when building the CTK+ library the process is running against.
283 * If `libtool` means nothing to you, don't
284 * worry about it.
285 *
286 * Returns: the interface age of the CTK+ library
287 *
288 * Since: 3.0
289 */
290guint
291ctk_get_interface_age (void)
292{
293 return CTK_INTERFACE_AGE(3);
294}
295
296/**
297 * ctk_check_version:
298 * @required_major: the required major version
299 * @required_minor: the required minor version
300 * @required_micro: the required micro version
301 *
302 * Checks that the CTK+ library in use is compatible with the
303 * given version. Generally you would pass in the constants
304 * #CTK_MAJOR_VERSION, #CTK_MINOR_VERSION, #CTK_MICRO_VERSION
305 * as the three arguments to this function; that produces
306 * a check that the library in use is compatible with
307 * the version of CTK+ the application or module was compiled
308 * against.
309 *
310 * Compatibility is defined by two things: first the version
311 * of the running library is newer than the version
312 * @required_major.required_minor.@required_micro. Second
313 * the running library must be binary compatible with the
314 * version @required_major.required_minor.@required_micro
315 * (same major version.)
316 *
317 * This function is primarily for CTK+ modules; the module
318 * can call this function to check that it wasn’t loaded
319 * into an incompatible version of CTK+. However, such a
320 * check isn’t completely reliable, since the module may be
321 * linked against an old version of CTK+ and calling the
322 * old version of ctk_check_version(), but still get loaded
323 * into an application using a newer version of CTK+.
324 *
325 * Returns: (nullable): %NULL if the CTK+ library is compatible with the
326 * given version, or a string describing the version mismatch.
327 * The returned string is owned by CTK+ and should not be modified
328 * or freed.
329 */
330const gchar*
331ctk_check_version (guint required_major,
332 guint required_minor,
333 guint required_micro)
334{
335 gint ctk_effective_micro = 100 * CTK_MINOR_VERSION(25) + CTK_MICRO_VERSION(5);
336 gint required_effective_micro = 100 * required_minor + required_micro;
337
338 if (required_major > CTK_MAJOR_VERSION(3))
339 return "CTK+ version too old (major mismatch)";
340 if (required_major < CTK_MAJOR_VERSION(3))
341 return "CTK+ version too new (major mismatch)";
342 if (required_effective_micro < ctk_effective_micro - CTK_BINARY_AGE(2505))
343 return "CTK+ version too new (micro mismatch)";
344 if (required_effective_micro > ctk_effective_micro)
345 return "CTK+ version too old (micro mismatch)";
346 return NULL((void*)0);
347}
348
349/* This checks to see if the process is running suid or sgid
350 * at the current time. If so, we don’t allow CTK+ to be initialized.
351 * This is meant to be a mild check - we only error out if we
352 * can prove the programmer is doing something wrong, not if
353 * they could be doing something wrong. For this reason, we
354 * don’t use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
355 */
356static gboolean
357check_setugid (void)
358{
359/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
360#ifndef G_OS_WIN32
361 uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
362 gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
363
364#ifdef HAVE_GETRESUID1
365 /* These aren't in the header files, so we prototype them here.
366 */
367 int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
368 int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);
369
370 if (getresuid (&ruid, &euid, &suid) != 0 ||
371 getresgid (&rgid, &egid, &sgid) != 0)
372#endif /* HAVE_GETRESUID */
373 {
374 suid = ruid = getuid ();
375 sgid = rgid = getgid ();
376 euid = geteuid ();
377 egid = getegid ();
378 }
379
380 if (ruid != euid || ruid != suid ||
381 rgid != egid || rgid != sgid)
382 {
383 g_warning ("This process is currently running setuid or setgid.\n"
384 "This is not a supported use of CTK+. You must create a helper\n"
385 "program instead. For further details, see:\n\n"
386 " http://github.com/cafe-desktop/ctk/setuid.html\n\n"
387 "Refusing to initialize CTK+.");
388 exit (1);
389 }
390#endif
391 return TRUE(!(0));
392}
393
394static gboolean do_setlocale = TRUE(!(0));
395
396/**
397 * ctk_disable_setlocale:
398 *
399 * Prevents ctk_init(), ctk_init_check(), ctk_init_with_args() and
400 * ctk_parse_args() from automatically
401 * calling `setlocale (LC_ALL, "")`. You would
402 * want to use this function if you wanted to set the locale for
403 * your program to something other than the user’s locale, or if
404 * you wanted to set different values for different locale categories.
405 *
406 * Most programs should not need to call this function.
407 **/
408void
409ctk_disable_setlocale (void)
410{
411 if (pre_initialized)
412 g_warning ("ctk_disable_setlocale() must be called before ctk_init()");
413
414 do_setlocale = FALSE(0);
415}
416
417#ifdef G_PLATFORM_WIN32
418#undef ctk_init_check
419#endif
420
421static GString *ctk_modules_string = NULL((void*)0);
422static gboolean g_fatal_warnings = FALSE(0);
423
424#ifdef G_ENABLE_DEBUG1
425static gboolean
426ctk_arg_debug_cb (const char *key G_GNUC_UNUSED__attribute__ ((__unused__)),
427 const char *value,
428 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
429{
430 debug_flags[0].flags |= g_parse_debug_string (value,
431 ctk_debug_keys,
432 G_N_ELEMENTS (ctk_debug_keys)(sizeof (ctk_debug_keys) / sizeof ((ctk_debug_keys)[0])));
433
434 return TRUE(!(0));
435}
436
437static gboolean
438ctk_arg_no_debug_cb (const char *key G_GNUC_UNUSED__attribute__ ((__unused__)),
439 const char *value,
440 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
441{
442 debug_flags[0].flags &= ~g_parse_debug_string (value,
443 ctk_debug_keys,
444 G_N_ELEMENTS (ctk_debug_keys)(sizeof (ctk_debug_keys) / sizeof ((ctk_debug_keys)[0])));
445
446 return TRUE(!(0));
447}
448#endif /* G_ENABLE_DEBUG */
449
450static gboolean
451ctk_arg_module_cb (const char *key G_GNUC_UNUSED__attribute__ ((__unused__)),
452 const char *value,
453 gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__)))
454{
455 if (value && *value)
456 {
457 if (ctk_modules_string)
458 g_string_append_c (ctk_modules_string, G_SEARCHPATH_SEPARATOR)g_string_append_c_inline (ctk_modules_string, ':');
459 else
460 ctk_modules_string = g_string_new (NULL((void*)0));
461
462 g_string_append (ctk_modules_string, value)(__builtin_constant_p (value) ? __extension__ ({ const char *
const __val = (value); g_string_append_len_inline (ctk_modules_string
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (ctk_modules_string
, value, (gssize) -1))
;
463 }
464
465 return TRUE(!(0));
466}
467
468static const GOptionEntry ctk_args[] = {
469 { "ctk-module", 0, 0, G_OPTION_ARG_CALLBACK, ctk_arg_module_cb,
470 /* Description of --ctk-module=MODULES in --help output */ N_("Load additional CTK+ modules")("Load additional CTK+ modules"),
471 /* Placeholder in --ctk-module=MODULES in --help output */ N_("MODULES")("MODULES") },
472 { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings,
473 /* Description of --g-fatal-warnings in --help output */ N_("Make all warnings fatal")("Make all warnings fatal"), NULL((void*)0) },
474#ifdef G_ENABLE_DEBUG1
475 { "ctk-debug", 0, 0, G_OPTION_ARG_CALLBACK, ctk_arg_debug_cb,
476 /* Description of --ctk-debug=FLAGS in --help output */ N_("CTK+ debugging flags to set")("CTK+ debugging flags to set"),
477 /* Placeholder in --ctk-debug=FLAGS in --help output */ N_("FLAGS")("FLAGS") },
478 { "ctk-no-debug", 0, 0, G_OPTION_ARG_CALLBACK, ctk_arg_no_debug_cb,
479 /* Description of --ctk-no-debug=FLAGS in --help output */ N_("CTK+ debugging flags to unset")("CTK+ debugging flags to unset"),
480 /* Placeholder in --ctk-no-debug=FLAGS in --help output */ N_("FLAGS")("FLAGS") },
481#endif
482 { NULL((void*)0) }
483};
484
485#ifdef G_OS_WIN32
486
487static char *iso639_to_check = NULL((void*)0);
488static char *iso3166_to_check = NULL((void*)0);
489static char *script_to_check = NULL((void*)0);
490static gboolean setlocale_called = FALSE(0);
491
492static BOOL CALLBACK
493enum_locale_proc (LPTSTR locale)
494{
495 LCID lcid;
496 char iso639[10];
497 char iso3166[10];
498 char *endptr;
499
500
501 lcid = strtoul (locale, &endptr, 16);
502 if (*endptr == '\0' &&
503 GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
504 GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
505 {
506 if (strcmp (iso639, iso639_to_check) == 0 &&
507 ((iso3166_to_check != NULL((void*)0) &&
508 strcmp (iso3166, iso3166_to_check) == 0) ||
509 (iso3166_to_check == NULL((void*)0) &&
510 SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
511 {
512 char language[100], country[100];
513 char locale[300];
514
515 if (script_to_check != NULL((void*)0))
516 {
517 /* If lcid is the "other" script for this language,
518 * return TRUE, i.e. continue looking.
519 */
520 if (strcmp (script_to_check, "Latn") == 0)
521 {
522 switch (LANGIDFROMLCID (lcid))
523 {
524 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
525 return TRUE(!(0));
526 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
527 return TRUE(!(0));
528 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
529 return TRUE(!(0));
530 case MAKELANGID (LANG_SERBIAN, 0x07):
531 /* Serbian in Bosnia and Herzegovina, Cyrillic */
532 return TRUE(!(0));
533 }
534 }
535 else if (strcmp (script_to_check, "Cyrl") == 0)
536 {
537 switch (LANGIDFROMLCID (lcid))
538 {
539 case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
540 return TRUE(!(0));
541 case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
542 return TRUE(!(0));
543 case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
544 return TRUE(!(0));
545 case MAKELANGID (LANG_SERBIAN, 0x06):
546 /* Serbian in Bosnia and Herzegovina, Latin */
547 return TRUE(!(0));
548 }
549 }
550 }
551
552 SetThreadLocale (lcid);
553
554 if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
555 GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
556 {
557 strcpy (locale, language);
558 strcat (locale, "_");
559 strcat (locale, country);
560
561 if (setlocale (LC_ALL6, locale) != NULL((void*)0))
562 setlocale_called = TRUE(!(0));
563 }
564
565 return FALSE(0);
566 }
567 }
568
569 return TRUE(!(0));
570}
571
572#endif
573
574static void
575setlocale_initialization (void)
576{
577 static gboolean initialized = FALSE(0);
578
579 if (initialized)
580 return;
581 initialized = TRUE(!(0));
582
583 if (do_setlocale)
584 {
585#ifdef G_OS_WIN32
586 /* If some of the POSIXish environment variables are set, set
587 * the Win32 thread locale correspondingly.
588 */
589 char *p = getenv ("LC_ALL");
590 if (p == NULL((void*)0))
591 p = getenv ("LANG");
592
593 if (p != NULL((void*)0))
594 {
595 p = g_strdup (p)g_strdup_inline (p);
596 if (strcmp (p, "C") == 0)
597 SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
598 else
599 {
600 /* Check if one of the supported locales match the
601 * environment variable. If so, use that locale.
602 */
603 iso639_to_check = p;
604 iso3166_to_check = strchr (iso639_to_check, '_');
605 if (iso3166_to_check != NULL((void*)0))
606 {
607 *iso3166_to_check++ = '\0';
608
609 script_to_check = strchr (iso3166_to_check, '@');
610 if (script_to_check != NULL((void*)0))
611 *script_to_check++ = '\0';
612
613 /* Handle special cases. */
614
615 /* The standard code for Serbia and Montenegro was
616 * "CS", but MSFT uses for some reason "SP". By now
617 * (October 2006), SP has split into two, "RS" and
618 * "ME", but don't bother trying to handle those
619 * yet. Do handle the even older "YU", though.
620 */
621 if (strcmp (iso3166_to_check, "CS") == 0 ||
622 strcmp (iso3166_to_check, "YU") == 0)
623 iso3166_to_check = "SP";
624 }
625 else
626 {
627 script_to_check = strchr (iso639_to_check, '@');
628 if (script_to_check != NULL((void*)0))
629 *script_to_check++ = '\0';
630 /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
631 if (strcmp (iso639_to_check, "sr") == 0)
632 iso3166_to_check = "SP";
633 }
634
635 EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
636 }
637 g_free (p);
638 }
639 if (!setlocale_called)
640 setlocale (LC_ALL6, "");
641#else
642 if (!setlocale (LC_ALL6, ""))
643 g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
644#endif
645 }
646}
647
648static void
649do_pre_parse_initialization (int *argc G_GNUC_UNUSED__attribute__ ((__unused__)),
650 char ***argv G_GNUC_UNUSED__attribute__ ((__unused__)))
651{
652 const gchar *env_string;
653 double slowdown;
654
655 if (pre_initialized)
656 return;
657
658 pre_initialized = TRUE(!(0));
659
660 if (_ctk_module_has_mixed_deps (NULL((void*)0)))
661 g_error ("CTK+ 2.x symbols detected. Using CTK+ 2.x and CTK+ 3 in the same process is not supported");
662
663 CDK_PRIVATE_CALL (cdk_pre_parse)(cdk__private__ ()->cdk_pre_parse) ();
664 cdk_event_handler_set ((CdkEventFunc)ctk_main_do_event, NULL((void*)0), NULL((void*)0));
665
666 env_string = g_getenv ("CTK_DEBUG");
667 if (env_string != NULL((void*)0))
668 {
669#ifdef G_ENABLE_DEBUG1
670 debug_flags[0].flags = g_parse_debug_string (env_string,
671 ctk_debug_keys,
672 G_N_ELEMENTS (ctk_debug_keys)(sizeof (ctk_debug_keys) / sizeof ((ctk_debug_keys)[0])));
673#else
674 g_warning ("CTK_DEBUG set but ignored because ctk isn't built with G_ENABLE_DEBUG");
675#endif /* G_ENABLE_DEBUG */
676 env_string = NULL((void*)0);
677 }
678
679 env_string = g_getenv ("CTK3_MODULES");
680 if (env_string)
681 ctk_modules_string = g_string_new (env_string);
682
683 env_string = g_getenv ("CTK_MODULES");
684 if (env_string)
685 {
686 if (ctk_modules_string)
687 g_string_append_c (ctk_modules_string, G_SEARCHPATH_SEPARATOR)g_string_append_c_inline (ctk_modules_string, ':');
688 else
689 ctk_modules_string = g_string_new (NULL((void*)0));
690
691 g_string_append (ctk_modules_string, env_string)(__builtin_constant_p (env_string) ? __extension__ ({ const char
* const __val = (env_string); g_string_append_len_inline (ctk_modules_string
, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !
(__val))) : (gssize) -1); }) : g_string_append_len_inline (ctk_modules_string
, env_string, (gssize) -1))
;
692 }
693
694 env_string = g_getenv ("CTK_SLOWDOWN");
695 if (env_string)
696 {
697 slowdown = g_ascii_strtod (env_string, NULL((void*)0));
698 _ctk_set_slowdown (slowdown);
699 }
700}
701
702static void
703gettext_initialization (void)
704{
705 setlocale_initialization ();
706
707#ifdef ENABLE_NLS1
708 bindtextdomain (GETTEXT_PACKAGE"ctk30", _ctk_get_localedir ());
709 bindtextdomain (GETTEXT_PACKAGE"ctk30" "-properties", _ctk_get_localedir ());
710# ifdef HAVE_BIND_TEXTDOMAIN_CODESET1
711 bind_textdomain_codeset (GETTEXT_PACKAGE"ctk30", "UTF-8");
712 bind_textdomain_codeset (GETTEXT_PACKAGE"ctk30" "-properties", "UTF-8");
713# endif
714#endif
715}
716
717static void
718default_display_notify_cb (CdkDisplayManager *dm G_GNUC_UNUSED__attribute__ ((__unused__)))
719{
720 _ctk_accessibility_init ();
721 debug_flags[0].display = cdk_display_get_default ();
722}
723
724static void
725do_post_parse_initialization (int *argc,
726 char ***argv)
727{
728 CdkDisplayManager *display_manager;
729
730 if (ctk_initialized)
731 return;
732
733 gettext_initialization ();
734
735#ifdef SIGPIPE13
736 signal (SIGPIPE13, SIG_IGN((__sighandler_t) 1));
737#endif
738
739 if (g_fatal_warnings)
740 {
741 GLogLevelFlags fatal_mask;
742
743 fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK(G_LOG_FLAG_RECURSION | G_LOG_LEVEL_ERROR));
744 fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
745 g_log_set_always_fatal (fatal_mask);
746 }
747
748 if (debug_flags[0].flags & CTK_DEBUG_UPDATES)
749 cdk_window_set_debug_updates (TRUE(!(0)));
750
751 ctk_widget_set_default_direction (ctk_get_locale_direction ());
752
753 _ctk_ensure_resources ();
754
755 _ctk_accel_map_init ();
756
757 ctk_initialized = TRUE(!(0));
758
759 if (ctk_modules_string)
760 {
761 _ctk_modules_init (argc, argv, ctk_modules_string->str);
762 g_string_free (ctk_modules_string, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) (
(ctk_modules_string), ((!(0)))) : g_string_free_and_steal (ctk_modules_string
)) : (g_string_free) ((ctk_modules_string), ((!(0)))))
;
763 }
764 else
765 {
766 _ctk_modules_init (argc, argv, NULL((void*)0));
767 }
768
769 display_manager = cdk_display_manager_get ();
770 if (cdk_display_manager_get_default_display (display_manager) != NULL((void*)0))
771 default_display_notify_cb (display_manager);
772
773 g_signal_connect (display_manager, "notify::default-display",g_signal_connect_data ((display_manager), ("notify::default-display"
), (((GCallback) (default_display_notify_cb))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
774 G_CALLBACK (default_display_notify_cb),g_signal_connect_data ((display_manager), ("notify::default-display"
), (((GCallback) (default_display_notify_cb))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
775 NULL)g_signal_connect_data ((display_manager), ("notify::default-display"
), (((GCallback) (default_display_notify_cb))), (((void*)0)),
((void*)0), (GConnectFlags) 0)
;
776}
777
778
779typedef struct
780{
781 gboolean open_default_display;
782} OptionGroupInfo;
783
784static gboolean
785pre_parse_hook (GOptionContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
786 GOptionGroup *group G_GNUC_UNUSED__attribute__ ((__unused__)),
787 gpointer data G_GNUC_UNUSED__attribute__ ((__unused__)),
788 GError **error G_GNUC_UNUSED__attribute__ ((__unused__)))
789{
790 do_pre_parse_initialization (NULL((void*)0), NULL((void*)0));
791
792 return TRUE(!(0));
793}
794
795static gboolean
796post_parse_hook (GOptionContext *context G_GNUC_UNUSED__attribute__ ((__unused__)),
797 GOptionGroup *group G_GNUC_UNUSED__attribute__ ((__unused__)),
798 gpointer data,
799 GError **error)
800{
801 OptionGroupInfo *info = data;
802
803
804 do_post_parse_initialization (NULL((void*)0), NULL((void*)0));
805
806 if (info->open_default_display)
807 {
808 if (CDK_PRIVATE_CALL (cdk_display_open_default)(cdk__private__ ()->cdk_display_open_default) () == NULL((void*)0))
809 {
810 const char *display_name = cdk_get_display_arg_name ();
811 g_set_error (error,
812 G_OPTION_ERROR(g_option_error_quark ()),
813 G_OPTION_ERROR_FAILED,
814 _("Cannot open display: %s")((char *) g_dgettext ("ctk30", "Cannot open display: %s")),
815 display_name ? display_name : "" );
816
817 return FALSE(0);
818 }
819
820 if (ctk_get_debug_flags () & CTK_DEBUG_INTERACTIVE)
821 ctk_window_set_interactive_debugging (TRUE(!(0)));
822 }
823
824 return TRUE(!(0));
825}
826
827guint
828ctk_get_display_debug_flags (CdkDisplay *display)
829{
830 gint i;
831
832 for (i = 0; i < N_DEBUG_DISPLAYS4; i++)
833 {
834 if (debug_flags[i].display == display)
835 return debug_flags[i].flags;
836 }
837
838 return 0;
839}
840
841void
842ctk_set_display_debug_flags (CdkDisplay *display,
843 guint flags)
844{
845 gint i;
846
847 for (i = 0; i < N_DEBUG_DISPLAYS4; i++)
848 {
849 if (debug_flags[i].display == NULL((void*)0))
850 debug_flags[i].display = display;
851
852 if (debug_flags[i].display == display)
853 {
854 debug_flags[i].flags = flags;
855 return;
856 }
857 }
858}
859
860/**
861 * ctk_get_debug_flags:
862 *
863 * Returns the CTK+ debug flags.
864 *
865 * This function is intended for CTK+ modules that want
866 * to adjust their debug output based on CTK+ debug flags.
867 *
868 * Returns: the CTK+ debug flags.
869 */
870guint
871ctk_get_debug_flags (void)
872{
873 return ctk_get_display_debug_flags (cdk_display_get_default ());
874}
875
876/**
877 * ctk_set_debug_flags:
878 *
879 * Sets the CTK+ debug flags.
880 */
881void
882ctk_set_debug_flags (guint flags)
883{
884 ctk_set_display_debug_flags (cdk_display_get_default (), flags);
885}
886
887gboolean
888ctk_simulate_touchscreen (void)
889{
890 static gint test_touchscreen;
891
892 if (test_touchscreen == 0)
893 test_touchscreen = g_getenv ("CTK_TEST_TOUCHSCREEN") != NULL((void*)0) ? 1 : -1;
894
895 return test_touchscreen > 0 || (ctk_get_debug_flags () & CTK_DEBUG_TOUCHSCREEN) != 0;
896 }
897
898/**
899 * ctk_get_option_group:
900 * @open_default_display: whether to open the default display
901 * when parsing the commandline arguments
902 *
903 * Returns a #GOptionGroup for the commandline arguments recognized
904 * by CTK+ and CDK.
905 *
906 * You should add this group to your #GOptionContext
907 * with g_option_context_add_group(), if you are using
908 * g_option_context_parse() to parse your commandline arguments.
909 *
910 * Returns: (transfer full): a #GOptionGroup for the commandline
911 * arguments recognized by CTK+
912 *
913 * Since: 2.6
914 */
915GOptionGroup *
916ctk_get_option_group (gboolean open_default_display)
917{
918 GOptionGroup *group;
919 OptionGroupInfo *info;
920
921 gettext_initialization ();
922
923 info = g_new0 (OptionGroupInfo, 1)((OptionGroupInfo *) g_malloc0_n ((1), sizeof (OptionGroupInfo
)))
;
924 info->open_default_display = open_default_display;
925
926 group = g_option_group_new ("ctk", _("CTK+ Options")((char *) g_dgettext ("ctk30", "CTK+ Options")), _("Show CTK+ Options")((char *) g_dgettext ("ctk30", "Show CTK+ Options")), info, g_free);
927 g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);
928
929 CDK_PRIVATE_CALL (cdk_add_option_entries)(cdk__private__ ()->cdk_add_option_entries) (group);
930 g_option_group_add_entries (group, ctk_args);
931 g_option_group_set_translation_domain (group, GETTEXT_PACKAGE"ctk30");
932
933 return group;
934}
935
936/**
937 * ctk_init_with_args:
938 * @argc: (inout): Address of the `argc` parameter of
939 * your main() function (or 0 if @argv is %NULL). This will be changed if
940 * any arguments were handled.
941 * @argv: (array length=argc) (inout) (allow-none): Address of the
942 * `argv` parameter of main(), or %NULL. Any options
943 * understood by CTK+ are stripped before return.
944 * @parameter_string: (allow-none): a string which is displayed in
945 * the first line of `--help` output, after
946 * `programname [OPTION...]`
947 * @entries: (array zero-terminated=1): a %NULL-terminated array
948 * of #GOptionEntrys describing the options of your program
949 * @translation_domain: (nullable): a translation domain to use for translating
950 * the `--help` output for the options in @entries
951 * and the @parameter_string with gettext(), or %NULL
952 * @error: a return location for errors
953 *
954 * This function does the same work as ctk_init_check().
955 * Additionally, it allows you to add your own commandline options,
956 * and it automatically generates nicely formatted
957 * `--help` output. Note that your program will
958 * be terminated after writing out the help output.
959 *
960 * Returns: %TRUE if the commandline arguments (if any) were valid and
961 * if the windowing system has been successfully initialized,
962 * %FALSE otherwise
963 *
964 * Since: 2.6
965 */
966gboolean
967ctk_init_with_args (gint *argc,
968 gchar ***argv,
969 const gchar *parameter_string,
970 const GOptionEntry *entries,
971 const gchar *translation_domain,
972 GError **error)
973{
974 GOptionContext *context;
975 GOptionGroup *ctk_group;
976 gboolean retval;
977
978 if (ctk_initialized)
979 goto done;
980
981 gettext_initialization ();
982
983 if (!check_setugid ())
984 return FALSE(0);
This statement is never executed
985
986 ctk_group = ctk_get_option_group (FALSE(0));
987
988 context = g_option_context_new (parameter_string);
989 g_option_context_add_group (context, ctk_group);
990 g_option_context_set_translation_domain (context, translation_domain);
991
992 if (entries)
993 g_option_context_add_main_entries (context, entries, translation_domain);
994 retval = g_option_context_parse (context, argc, argv, error);
995
996 g_option_context_free (context);
997
998 if (!retval)
999 return FALSE(0);
1000
1001done:
1002 if (CDK_PRIVATE_CALL (cdk_display_open_default)(cdk__private__ ()->cdk_display_open_default) () == NULL((void*)0))
1003 {
1004 const char *display_name = cdk_get_display_arg_name ();
1005 g_set_error (error,
1006 G_OPTION_ERROR(g_option_error_quark ()),
1007 G_OPTION_ERROR_FAILED,
1008 _("Cannot open display: %s")((char *) g_dgettext ("ctk30", "Cannot open display: %s")),
1009 display_name ? display_name : "" );
1010
1011 return FALSE(0);
1012 }
1013
1014 if (ctk_get_debug_flags () & CTK_DEBUG_INTERACTIVE)
1015 ctk_window_set_interactive_debugging (TRUE(!(0)));
1016
1017 return TRUE(!(0));
1018}
1019
1020
1021/**
1022 * ctk_parse_args:
1023 * @argc: (inout): a pointer to the number of command line arguments
1024 * @argv: (array length=argc) (inout): a pointer to the array of
1025 * command line arguments
1026 *
1027 * Parses command line arguments, and initializes global
1028 * attributes of CTK+, but does not actually open a connection
1029 * to a display. (See cdk_display_open(), cdk_get_display_arg_name())
1030 *
1031 * Any arguments used by CTK+ or CDK are removed from the array and
1032 * @argc and @argv are updated accordingly.
1033 *
1034 * There is no need to call this function explicitly if you are using
1035 * ctk_init(), or ctk_init_check().
1036 *
1037 * Note that many aspects of CTK+ require a display connection to
1038 * function, so this way of initializing CTK+ is really only useful
1039 * for specialized use cases.
1040 *
1041 * Returns: %TRUE if initialization succeeded, otherwise %FALSE
1042 */
1043gboolean
1044ctk_parse_args (int *argc,
1045 char ***argv)
1046{
1047 GOptionContext *option_context;
1048 GOptionGroup *ctk_group;
1049 GError *error = NULL((void*)0);
1050
1051 if (ctk_initialized)
1052 return TRUE(!(0));
1053
1054 gettext_initialization ();
1055
1056 if (!check_setugid ())
1057 return FALSE(0);
1058
1059 option_context = g_option_context_new (NULL((void*)0));
1060 g_option_context_set_ignore_unknown_options (option_context, TRUE(!(0)));
1061 g_option_context_set_help_enabled (option_context, FALSE(0));
1062 ctk_group = ctk_get_option_group (FALSE(0));
1063 g_option_context_set_main_group (option_context, ctk_group);
1064 if (!g_option_context_parse (option_context, argc, argv, &error))
1065 {
1066 g_warning ("%s", error->message);
1067 g_error_free (error);
1068 }
1069
1070 g_option_context_free (option_context);
1071
1072 return TRUE(!(0));
1073}
1074
1075#ifdef G_PLATFORM_WIN32
1076#undef ctk_init_check
1077#endif
1078
1079/**
1080 * ctk_init_check:
1081 * @argc: (inout): Address of the `argc` parameter of
1082 * your main() function (or 0 if @argv is %NULL). This will be changed if
1083 * any arguments were handled.
1084 * @argv: (array length=argc) (inout) (allow-none): Address of the
1085 * `argv` parameter of main(), or %NULL. Any options
1086 * understood by CTK+ are stripped before return.
1087 *
1088 * This function does the same work as ctk_init() with only a single
1089 * change: It does not terminate the program if the commandline
1090 * arguments couldn’t be parsed or the windowing system can’t be
1091 * initialized. Instead it returns %FALSE on failure.
1092 *
1093 * This way the application can fall back to some other means of
1094 * communication with the user - for example a curses or command line
1095 * interface.
1096 *
1097 * Note that calling any CTK function or instantiating any CTK type after
1098 * this function returns %FALSE results in undefined behavior.
1099 *
1100 * Returns: %TRUE if the commandline arguments (if any) were valid and
1101 * the windowing system has been successfully initialized, %FALSE
1102 * otherwise
1103 */
1104gboolean
1105ctk_init_check (int *argc,
1106 char ***argv)
1107{
1108 gboolean ret;
1109
1110 if (!ctk_parse_args (argc, argv))
1111 return FALSE(0);
1112
1113 ret = CDK_PRIVATE_CALL (cdk_display_open_default)(cdk__private__ ()->cdk_display_open_default) () != NULL((void*)0);
1114
1115 if (ctk_get_debug_flags () & CTK_DEBUG_INTERACTIVE)
1116 ctk_window_set_interactive_debugging (TRUE(!(0)));
1117
1118 return ret;
1119}
1120
1121#ifdef G_PLATFORM_WIN32
1122#undef ctk_init
1123#endif
1124
1125/**
1126 * ctk_init:
1127 * @argc: (inout): Address of the `argc` parameter of
1128 * your main() function (or 0 if @argv is %NULL). This will be changed if
1129 * any arguments were handled.
1130 * @argv: (array length=argc) (inout) (allow-none): Address of the
1131 * `argv` parameter of main(), or %NULL. Any options
1132 * understood by CTK+ are stripped before return.
1133 *
1134 * Call this function before using any other CTK+ functions in your GUI
1135 * applications. It will initialize everything needed to operate the
1136 * toolkit and parses some standard command line options.
1137 *
1138 * Although you are expected to pass the @argc, @argv parameters from main() to
1139 * this function, it is possible to pass %NULL if @argv is not available or
1140 * commandline handling is not required.
1141 *
1142 * @argc and @argv are adjusted accordingly so your own code will
1143 * never see those standard arguments.
1144 *
1145 * Note that there are some alternative ways to initialize CTK+:
1146 * if you are calling ctk_parse_args(), ctk_init_check(),
1147 * ctk_init_with_args() or g_option_context_parse() with
1148 * the option group returned by ctk_get_option_group(),
1149 * you don’t have to call ctk_init().
1150 *
1151 * And if you are using #CtkApplication, you don't have to call any of the
1152 * initialization functions either; the #CtkApplication::startup handler
1153 * does it for you.
1154 *
1155 * This function will terminate your program if it was unable to
1156 * initialize the windowing system for some reason. If you want
1157 * your program to fall back to a textual interface you want to
1158 * call ctk_init_check() instead.
1159 *
1160 * Since 2.18, CTK+ calls `signal (SIGPIPE, SIG_IGN)`
1161 * during initialization, to ignore SIGPIPE signals, since these are
1162 * almost never wanted in graphical applications. If you do need to
1163 * handle SIGPIPE for some reason, reset the handler after ctk_init(),
1164 * but notice that other libraries (e.g. libdbus or gvfs) might do
1165 * similar things.
1166 */
1167void
1168ctk_init (int *argc, char ***argv)
1169{
1170 if (!ctk_init_check (argc, argv))
1171 {
1172 const char *display_name_arg = cdk_get_display_arg_name ();
1173 if (display_name_arg == NULL((void*)0))
1174 display_name_arg = getenv("DISPLAY");
1175 g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
1176 exit (1);
1177 }
1178}
1179
1180#ifdef G_OS_WIN32
1181
1182/* This is relevant when building with gcc for Windows (MinGW),
1183 * where we want to be struct packing compatible with MSVC,
1184 * i.e. use the -mms-bitfields switch.
1185 * For Cygwin there should be no need to be compatible with MSVC,
1186 * so no need to use G_PLATFORM_WIN32.
1187 */
1188
1189static void
1190check_sizeof_CtkWindow (size_t sizeof_CtkWindow)
1191{
1192 if (sizeof_CtkWindow != sizeof (CtkWindow))
1193 g_error ("Incompatible build!\n"
1194 "The code using CTK+ thinks CtkWindow is of different\n"
1195 "size than it actually is in this build of CTK+.\n"
1196 "On Windows, this probably means that you have compiled\n"
1197 "your code with gcc without the -mms-bitfields switch,\n"
1198 "or that you are using an unsupported compiler.");
1199}
1200
1201/* In CTK+ 2.0 the CtkWindow struct actually is the same size in
1202 * gcc-compiled code on Win32 whether compiled with -fnative-struct or
1203 * not. Unfortunately this wan’t noticed until after CTK+ 2.0.1. So,
1204 * from CTK+ 2.0.2 on, check some other struct, too, where the use of
1205 * -fnative-struct still matters. CtkBox is one such.
1206 */
1207static void
1208check_sizeof_CtkBox (size_t sizeof_CtkBox)
1209{
1210 if (sizeof_CtkBox != sizeof (CtkBox))
1211 g_error ("Incompatible build!\n"
1212 "The code using CTK+ thinks CtkBox is of different\n"
1213 "size than it actually is in this build of CTK+.\n"
1214 "On Windows, this probably means that you have compiled\n"
1215 "your code with gcc without the -mms-bitfields switch,\n"
1216 "or that you are using an unsupported compiler.");
1217}
1218
1219/* These two functions might get more checks added later, thus pass
1220 * in the number of extra args.
1221 */
1222void
1223ctk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_CtkWindow, size_t sizeof_CtkBox)
1224{
1225 check_sizeof_CtkWindow (sizeof_CtkWindow);
1226 if (num_checks >= 2)
1227 check_sizeof_CtkBox (sizeof_CtkBox);
1228 ctk_init (argc, argv);
1229}
1230
1231gboolean
1232ctk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_CtkWindow, size_t sizeof_CtkBox)
1233{
1234 check_sizeof_CtkWindow (sizeof_CtkWindow);
1235 if (num_checks >= 2)
1236 check_sizeof_CtkBox (sizeof_CtkBox);
1237 return ctk_init_check (argc, argv);
1238}
1239
1240#endif
1241
1242/**
1243 * ctk_get_locale_direction:
1244 *
1245 * Get the direction of the current locale. This is the expected
1246 * reading direction for text and UI.
1247 *
1248 * This function depends on the current locale being set with
1249 * setlocale() and will default to setting the %CTK_TEXT_DIR_LTR
1250 * direction otherwise. %CTK_TEXT_DIR_NONE will never be returned.
1251 *
1252 * CTK+ sets the default text direction according to the locale
1253 * during ctk_init(), and you should normally use
1254 * ctk_widget_get_direction() or ctk_widget_get_default_direction()
1255 * to obtain the current direcion.
1256 *
1257 * This function is only needed rare cases when the locale is
1258 * changed after CTK+ has already been initialized. In this case,
1259 * you can use it to update the default text direction as follows:
1260 *
1261 * |[<!-- language="C" -->
1262 * setlocale (LC_ALL, new_locale);
1263 * direction = ctk_get_locale_direction ();
1264 * ctk_widget_set_default_direction (direction);
1265 * ]|
1266 *
1267 * Returns: the #CtkTextDirection of the current locale
1268 *
1269 * Since: 3.12
1270 */
1271CtkTextDirection
1272ctk_get_locale_direction (void)
1273{
1274 /* Translate to default:RTL if you want your widgets
1275 * to be RTL, otherwise translate to default:LTR.
1276 * Do *not* translate it to "predefinito:LTR", if it
1277 * it isn't default:LTR or default:RTL it will not work
1278 */
1279 gchar *e = _("default:LTR")((char *) g_dgettext ("ctk30", "default:LTR"));
1280 CtkTextDirection dir = CTK_TEXT_DIR_LTR;
1281
1282 if (g_strcmp0 (e, "default:RTL") == 0)
1283 dir = CTK_TEXT_DIR_RTL;
1284 else if (g_strcmp0 (e, "default:LTR") != 0)
1285 g_warning ("Whoever translated default:LTR did so wrongly. Defaulting to LTR.");
1286
1287 return dir;
1288}
1289
1290/**
1291 * ctk_get_default_language:
1292 *
1293 * Returns the #PangoLanguage for the default language currently in
1294 * effect. (Note that this can change over the life of an
1295 * application.) The default language is derived from the current
1296 * locale. It determines, for example, whether CTK+ uses the
1297 * right-to-left or left-to-right text direction.
1298 *
1299 * This function is equivalent to pango_language_get_default().
1300 * See that function for details.
1301 *
1302 * Returns: (transfer none): the default language as a #PangoLanguage,
1303 * must not be freed
1304 */
1305PangoLanguage *
1306ctk_get_default_language (void)
1307{
1308 return pango_language_get_default ();
1309}
1310
1311/**
1312 * ctk_main:
1313 *
1314 * Runs the main loop until ctk_main_quit() is called.
1315 *
1316 * You can nest calls to ctk_main(). In that case ctk_main_quit()
1317 * will make the innermost invocation of the main loop return.
1318 */
1319void
1320ctk_main (void)
1321{
1322 GMainLoop *loop;
1323
1324 ctk_main_loop_level++;
1325
1326 loop = g_main_loop_new (NULL((void*)0), TRUE(!(0)));
1327 main_loops = g_slist_prepend (main_loops, loop);
1328
1329 if (g_main_loop_is_running (main_loops->data))
1330 {
1331 cdk_threads_leave ();
1332 g_main_loop_run (loop);
1333 cdk_threads_enter ();
1334
1335 G_GNUC_BEGIN_IGNORE_DEPRECATIONSclang diagnostic push clang diagnostic ignored "-Wdeprecated-declarations"
;
1336 cdk_flush ();
1337 G_GNUC_END_IGNORE_DEPRECATIONSclang diagnostic pop ;
1338 }
1339
1340 main_loops = g_slist_remove (main_loops, loop);
1341
1342 g_main_loop_unref (loop);
1343
1344 ctk_main_loop_level--;
1345
1346 if (ctk_main_loop_level == 0)
1347 {
1348 /* Keep this section in sync with ctk_application_shutdown() */
1349
1350 /* Try storing all clipboard data we have */
1351 _ctk_clipboard_store_all ();
1352
1353 /* Synchronize the recent manager singleton */
1354 _ctk_recent_manager_sync ();
1355 }
1356}
1357
1358/**
1359 * ctk_main_level:
1360 *
1361 * Asks for the current nesting level of the main loop.
1362 *
1363 * Returns: the nesting level of the current invocation
1364 * of the main loop
1365 */
1366guint
1367ctk_main_level (void)
1368{
1369 return ctk_main_loop_level;
1370}
1371
1372/**
1373 * ctk_main_quit:
1374 *
1375 * Makes the innermost invocation of the main loop return
1376 * when it regains control.
1377 */
1378void
1379ctk_main_quit (void)
1380{
1381 g_return_if_fail (main_loops != NULL)do { if ((main_loops != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "main_loops != NULL"); return
; } } while (0)
;
1382
1383 g_main_loop_quit (main_loops->data);
1384}
1385
1386/**
1387 * ctk_events_pending:
1388 *
1389 * Checks if any events are pending.
1390 *
1391 * This can be used to update the UI and invoke timeouts etc.
1392 * while doing some time intensive computation.
1393 *
1394 * ## Updating the UI during a long computation
1395 *
1396 * |[<!-- language="C" -->
1397 * // computation going on...
1398 *
1399 * while (ctk_events_pending ())
1400 * ctk_main_iteration ();
1401 *
1402 * // ...computation continued
1403 * ]|
1404 *
1405 * Returns: %TRUE if any events are pending, %FALSE otherwise
1406 */
1407gboolean
1408ctk_events_pending (void)
1409{
1410 gboolean result;
1411
1412 cdk_threads_leave ();
1413 result = g_main_context_pending (NULL((void*)0));
1414 cdk_threads_enter ();
1415
1416 return result;
1417}
1418
1419/**
1420 * ctk_main_iteration:
1421 *
1422 * Runs a single iteration of the mainloop.
1423 *
1424 * If no events are waiting to be processed CTK+ will block
1425 * until the next event is noticed. If you don’t want to block
1426 * look at ctk_main_iteration_do() or check if any events are
1427 * pending with ctk_events_pending() first.
1428 *
1429 * Returns: %TRUE if ctk_main_quit() has been called for the
1430 * innermost mainloop
1431 */
1432gboolean
1433ctk_main_iteration (void)
1434{
1435 cdk_threads_leave ();
1436 g_main_context_iteration (NULL((void*)0), TRUE(!(0)));
1437 cdk_threads_enter ();
1438
1439 if (main_loops)
1440 return !g_main_loop_is_running (main_loops->data);
1441 else
1442 return TRUE(!(0));
1443}
1444
1445/**
1446 * ctk_main_iteration_do:
1447 * @blocking: %TRUE if you want CTK+ to block if no events are pending
1448 *
1449 * Runs a single iteration of the mainloop.
1450 * If no events are available either return or block depending on
1451 * the value of @blocking.
1452 *
1453 * Returns: %TRUE if ctk_main_quit() has been called for the
1454 * innermost mainloop
1455 */
1456gboolean
1457ctk_main_iteration_do (gboolean blocking)
1458{
1459 cdk_threads_leave ();
1460 g_main_context_iteration (NULL((void*)0), blocking);
1461 cdk_threads_enter ();
1462
1463 if (main_loops)
1464 return !g_main_loop_is_running (main_loops->data);
1465 else
1466 return TRUE(!(0));
1467}
1468
1469static void
1470rewrite_events_translate (CdkWindow *old_window,
1471 CdkWindow *new_window,
1472 gdouble *x,
1473 gdouble *y)
1474{
1475 gint old_origin_x, old_origin_y;
1476 gint new_origin_x, new_origin_y;
1477
1478 cdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
1479 cdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
1480
1481 *x += old_origin_x - new_origin_x;
1482 *y += old_origin_y - new_origin_y;
1483}
1484
1485static CdkEvent *
1486rewrite_event_for_window (CdkEvent *event,
1487 CdkWindow *new_window)
1488{
1489 event = cdk_event_copy (event);
1490
1491 switch (event->type)
1492 {
1493 case CDK_SCROLL:
1494 rewrite_events_translate (event->any.window,
1495 new_window,
1496 &event->scroll.x, &event->scroll.y);
1497 break;
1498 case CDK_BUTTON_PRESS:
1499 case CDK_2BUTTON_PRESS:
1500 case CDK_3BUTTON_PRESS:
1501 case CDK_BUTTON_RELEASE:
1502 rewrite_events_translate (event->any.window,
1503 new_window,
1504 &event->button.x, &event->button.y);
1505 break;
1506 case CDK_MOTION_NOTIFY:
1507 rewrite_events_translate (event->any.window,
1508 new_window,
1509 &event->motion.x, &event->motion.y);
1510 break;
1511 case CDK_TOUCH_BEGIN:
1512 case CDK_TOUCH_UPDATE:
1513 case CDK_TOUCH_END:
1514 case CDK_TOUCH_CANCEL:
1515 rewrite_events_translate (event->any.window,
1516 new_window,
1517 &event->touch.x, &event->touch.y);
1518 break;
1519 case CDK_TOUCHPAD_SWIPE:
1520 rewrite_events_translate (event->any.window,
1521 new_window,
1522 &event->touchpad_swipe.x,
1523 &event->touchpad_swipe.y);
1524 break;
1525 case CDK_TOUCHPAD_PINCH:
1526 rewrite_events_translate (event->any.window,
1527 new_window,
1528 &event->touchpad_pinch.x,
1529 &event->touchpad_pinch.y);
1530 break;
1531 case CDK_KEY_PRESS:
1532 case CDK_KEY_RELEASE:
1533 case CDK_PROXIMITY_IN:
1534 case CDK_PROXIMITY_OUT:
1535 break;
1536
1537 default:
1538 return event;
1539 }
1540
1541 g_object_unref (event->any.window);
1542 event->any.window = g_object_ref (new_window)((__typeof__ (new_window)) (g_object_ref) (new_window));
1543
1544 return event;
1545}
1546
1547/* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
1548 * then what X11 does is deliver the event normally if it was going to this
1549 * client, otherwise, delivers it in terms of the grab window. This function
1550 * rewrites events to the effect that events going to the same window group
1551 * are delivered normally, otherwise, the event is delivered in terms of the
1552 * grab window.
1553 */
1554static CdkEvent *
1555rewrite_event_for_grabs (CdkEvent *event)
1556{
1557 CdkWindow *grab_window;
1558 CtkWidget *event_widget, *grab_widget;
1559 gpointer grab_widget_ptr;
1560 gboolean owner_events;
1561 CdkDisplay *display;
1562 CdkDevice *device;
1563
1564 switch (event->type)
1565 {
1566 case CDK_SCROLL:
1567 case CDK_BUTTON_PRESS:
1568 case CDK_2BUTTON_PRESS:
1569 case CDK_3BUTTON_PRESS:
1570 case CDK_BUTTON_RELEASE:
1571 case CDK_MOTION_NOTIFY:
1572 case CDK_PROXIMITY_IN:
1573 case CDK_PROXIMITY_OUT:
1574 case CDK_KEY_PRESS:
1575 case CDK_KEY_RELEASE:
1576 case CDK_TOUCH_BEGIN:
1577 case CDK_TOUCH_UPDATE:
1578 case CDK_TOUCH_END:
1579 case CDK_TOUCH_CANCEL:
1580 case CDK_TOUCHPAD_SWIPE:
1581 case CDK_TOUCHPAD_PINCH:
1582 display = cdk_window_get_display (event->any.window);
1583 device = cdk_event_get_device (event);
1584
1585 if (!CDK_PRIVATE_CALL (cdk_device_grab_info)(cdk__private__ ()->cdk_device_grab_info) (display, device, &grab_window, &owner_events) ||
1586 !owner_events)
1587 return NULL((void*)0);
1588 break;
1589 default:
1590 return NULL((void*)0);
1591 }
1592
1593 event_widget = ctk_get_event_widget (event);
1594 cdk_window_get_user_data (grab_window, &grab_widget_ptr);
1595 grab_widget = grab_widget_ptr;
1596
1597 if (grab_widget &&
1598 ctk_main_get_window_group (grab_widget) != ctk_main_get_window_group (event_widget))
1599 return rewrite_event_for_window (event, grab_window);
1600 else
1601 return NULL((void*)0);
1602}
1603
1604static CtkWidget *
1605widget_get_popover_ancestor (CtkWidget *widget,
1606 CtkWindow *window)
1607{
1608 CtkWidget *parent = ctk_widget_get_parent (widget);
1609
1610 while (parent && parent != CTK_WIDGET (window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_widget_get_type ()))))))
)
1611 {
1612 widget = parent;
1613 parent = ctk_widget_get_parent (widget);
1614 }
1615
1616 if (!parent || parent != CTK_WIDGET (window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_widget_get_type ()))))))
)
1617 return NULL((void*)0);
1618
1619 if (_ctk_window_is_popover_widget (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, widget))
1620 return widget;
1621
1622 return NULL((void*)0);
1623}
1624
1625static gboolean
1626check_event_in_child_popover (CtkWidget *event_widget,
1627 CtkWidget *grab_widget)
1628{
1629 CtkWidget *window, *popover = NULL((void*)0), *popover_parent = NULL((void*)0);
1630
1631 if (grab_widget == event_widget)
1632 return FALSE(0);
1633
1634 window = ctk_widget_get_ancestor (event_widget, CTK_TYPE_WINDOW(ctk_window_get_type ()));
1635
1636 if (!window)
1637 return FALSE(0);
1638
1639 popover = widget_get_popover_ancestor (event_widget, CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
);
1640
1641 if (!popover)
1642 return FALSE(0);
1643
1644 popover_parent = _ctk_window_get_popover_parent (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, popover);
1645
1646 if (!popover_parent)
1647 return FALSE(0);
1648
1649 return (popover_parent == grab_widget || ctk_widget_is_ancestor (popover_parent, grab_widget));
1650}
1651
1652/**
1653 * ctk_main_do_event:
1654 * @event: An event to process (normally passed by CDK)
1655 *
1656 * Processes a single CDK event.
1657 *
1658 * This is public only to allow filtering of events between CDK and CTK+.
1659 * You will not usually need to call this function directly.
1660 *
1661 * While you should not call this function directly, you might want to
1662 * know how exactly events are handled. So here is what this function
1663 * does with the event:
1664 *
1665 * 1. Compress enter/leave notify events. If the event passed build an
1666 * enter/leave pair together with the next event (peeked from CDK), both
1667 * events are thrown away. This is to avoid a backlog of (de-)highlighting
1668 * widgets crossed by the pointer.
1669 *
1670 * 2. Find the widget which got the event. If the widget can’t be determined
1671 * the event is thrown away unless it belongs to a INCR transaction.
1672 *
1673 * 3. Then the event is pushed onto a stack so you can query the currently
1674 * handled event with ctk_get_current_event().
1675 *
1676 * 4. The event is sent to a widget. If a grab is active all events for widgets
1677 * that are not in the contained in the grab widget are sent to the latter
1678 * with a few exceptions:
1679 * - Deletion and destruction events are still sent to the event widget for
1680 * obvious reasons.
1681 * - Events which directly relate to the visual representation of the event
1682 * widget.
1683 * - Leave events are delivered to the event widget if there was an enter
1684 * event delivered to it before without the paired leave event.
1685 * - Drag events are not redirected because it is unclear what the semantics
1686 * of that would be.
1687 * Another point of interest might be that all key events are first passed
1688 * through the key snooper functions if there are any. Read the description
1689 * of ctk_key_snooper_install() if you need this feature.
1690 *
1691 * 5. After finishing the delivery the event is popped from the event stack.
1692 */
1693void
1694ctk_main_do_event (CdkEvent *event)
1695{
1696 CtkWidget *event_widget;
1697 CtkWidget *grab_widget = NULL((void*)0);
1698 CtkWidget *topmost_widget = NULL((void*)0);
1699 CtkWindowGroup *window_group;
1700 CdkEvent *rewritten_event = NULL((void*)0);
1701 CdkDevice *device;
1702 GList *tmp_list;
1703
1704 if (event->type == CDK_SETTING)
1705 {
1706 _ctk_settings_handle_event (&event->setting);
1707 return;
1708 }
1709
1710 if (event->type == CDK_OWNER_CHANGE)
1711 {
1712 _ctk_clipboard_handle_event (&event->owner_change);
1713 return;
1714 }
1715
1716 /* Find the widget which got the event. We store the widget
1717 * in the user_data field of CdkWindow's. Ignore the event
1718 * if we don't have a widget for it, except for CDK_PROPERTY_NOTIFY
1719 * events which are handled specially. Though this happens rarely,
1720 * bogus events can occur for e.g. destroyed CdkWindows.
1721 */
1722 event_widget = ctk_get_event_widget (event);
1723 if (!event_widget)
1724 {
1725 /* To handle selection INCR transactions, we select
1726 * PropertyNotify events on the requestor window and create
1727 * a corresponding (fake) CdkWindow so that events get here.
1728 * There won't be a widget though, so we have to handle
1729 * them specially
1730 */
1731 if (event->type == CDK_PROPERTY_NOTIFY)
1732 _ctk_selection_incr_event (event->any.window,
1733 &event->property);
1734
1735 return;
1736 }
1737
1738 /* If pointer or keyboard grabs are in effect, munge the events
1739 * so that each window group looks like a separate app.
1740 */
1741 rewritten_event = rewrite_event_for_grabs (event);
1742 if (rewritten_event)
1743 {
1744 event = rewritten_event;
1745 event_widget = ctk_get_event_widget (event);
1746 }
1747
1748 /* Push the event onto a stack of current events for
1749 * ctk_current_event_get().
1750 */
1751 current_events = g_list_prepend (current_events, event);
1752
1753 window_group = ctk_main_get_window_group (event_widget);
1754 device = cdk_event_get_device (event);
1755
1756 /* check whether there is a (device) grab in effect... */
1757 if (device)
1758 grab_widget = ctk_window_group_get_current_device_grab (window_group, device);
1759
1760 if (!grab_widget)
1761 grab_widget = ctk_window_group_get_current_grab (window_group);
1762
1763 if (CTK_IS_WINDOW (event_widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(event_widget)); GType __t = ((ctk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
||
1764 (grab_widget && grab_widget != event_widget &&
1765 !ctk_widget_is_ancestor (event_widget, grab_widget)))
1766 {
1767 /* Ignore event if we got a grab on another toplevel */
1768 if (!grab_widget ||
1769 ctk_widget_get_toplevel (event_widget) == ctk_widget_get_toplevel (grab_widget))
1770 {
1771 if (_ctk_window_check_handle_wm_event (event))
1772 goto cleanup;
1773 }
1774 }
1775
1776 /* Find out the topmost widget where captured event propagation
1777 * should start, which is the widget holding the CTK+ grab
1778 * if any, otherwise it's left NULL and events are emitted
1779 * from the toplevel (or topmost parentless parent).
1780 */
1781 if (grab_widget)
1782 topmost_widget = grab_widget;
1783
1784 /* If the grab widget is an ancestor of the event widget
1785 * then we send the event to the original event widget.
1786 * This is the key to implementing modality.
1787 */
1788 if (!grab_widget ||
1789 ((ctk_widget_is_sensitive (event_widget) || event->type == CDK_SCROLL) &&
1790 ctk_widget_is_ancestor (event_widget, grab_widget)))
1791 grab_widget = event_widget;
1792
1793 /* popovers are not really a "child" of their "parent" in the widget/window
1794 * hierarchy sense, we however want to interact with popovers spawn by widgets
1795 * within grab_widget. If this is the case, we let the event go through
1796 * unaffected by the grab.
1797 */
1798 if (check_event_in_child_popover (event_widget, grab_widget))
1799 grab_widget = event_widget;
1800
1801 /* If the widget receiving events is actually blocked by another
1802 * device CTK+ grab
1803 */
1804 if (device &&
1805 _ctk_window_group_widget_is_blocked_for_device (window_group, grab_widget, device))
1806 goto cleanup;
1807
1808 /* Not all events get sent to the grabbing widget.
1809 * The delete, destroy, expose, focus change and resize
1810 * events still get sent to the event widget because
1811 * 1) these events have no meaning for the grabbing widget
1812 * and 2) redirecting these events to the grabbing widget
1813 * could cause the display to be messed up.
1814 *
1815 * Drag events are also not redirected, since it isn't
1816 * clear what the semantics of that would be.
1817 */
1818 switch (event->type)
1819 {
1820 case CDK_NOTHING:
1821 break;
1822
1823 case CDK_DELETE:
1824 g_object_ref (event_widget)((__typeof__ (event_widget)) (g_object_ref) (event_widget));
1825 if ((!ctk_window_group_get_current_grab (window_group) || ctk_widget_get_toplevel (ctk_window_group_get_current_grab (window_group)) == event_widget) &&
1826 !ctk_widget_event (event_widget, event))
1827 ctk_widget_destroy (event_widget);
1828 g_object_unref (event_widget);
1829 break;
1830
1831 case CDK_DESTROY:
1832 /* Unexpected CDK_DESTROY from the outside, ignore for
1833 * child windows, handle like a CDK_DELETE for toplevels
1834 */
1835 if (!ctk_widget_get_parent (event_widget))
1836 {
1837 g_object_ref (event_widget)((__typeof__ (event_widget)) (g_object_ref) (event_widget));
1838 if (!ctk_widget_event (event_widget, event) &&
1839 ctk_widget_get_realized (event_widget))
1840 ctk_widget_destroy (event_widget);
1841 g_object_unref (event_widget);
1842 }
1843 break;
1844
1845 case CDK_EXPOSE:
1846 if (event->any.window)
1847 ctk_widget_render (event_widget, event->any.window, event->expose.region);
1848 break;
1849
1850 case CDK_PROPERTY_NOTIFY:
1851 case CDK_FOCUS_CHANGE:
1852 case CDK_CONFIGURE:
1853 case CDK_MAP:
1854 case CDK_UNMAP:
1855 case CDK_SELECTION_CLEAR:
1856 case CDK_SELECTION_REQUEST:
1857 case CDK_SELECTION_NOTIFY:
1858 case CDK_CLIENT_EVENT:
1859 case CDK_VISIBILITY_NOTIFY:
1860 case CDK_WINDOW_STATE:
1861 case CDK_GRAB_BROKEN:
1862 case CDK_DAMAGE:
1863 if (!_ctk_widget_captured_event (event_widget, event))
1864 ctk_widget_event (event_widget, event);
1865 break;
1866
1867 case CDK_KEY_PRESS:
1868 case CDK_KEY_RELEASE:
1869 if (ctk_invoke_key_snoopers (grab_widget, event))
1870 break;
1871
1872 /* make focus visible in a window that receives a key event */
1873 {
1874 CtkWidget *window;
1875
1876 window = ctk_widget_get_toplevel (grab_widget);
1877 if (CTK_IS_WINDOW (window)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(window)); GType __t = ((ctk_window_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1878 ctk_window_set_focus_visible (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, TRUE(!(0)));
1879 }
1880
1881 /* Catch alt press to enable auto-mnemonics;
1882 * menus are handled elsewhere
1883 * FIXME: this does not work with mnemonic modifiers other than Alt
1884 */
1885 if ((event->key.keyval == CDK_KEY_Alt_L0xffe9 || event->key.keyval == CDK_KEY_Alt_R0xffea) &&
1886 ((event->key.state & (ctk_accelerator_get_default_mod_mask ()) & ~(CDK_RELEASE_MASK|CDK_MOD1_MASK)) == 0) &&
1887 !CTK_IS_MENU_SHELL (grab_widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(grab_widget)); GType __t = ((ctk_menu_shell_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1888 {
1889 gboolean mnemonics_visible;
1890 CtkWidget *window;
1891
1892 mnemonics_visible = (event->type == CDK_KEY_PRESS);
1893
1894 window = ctk_widget_get_toplevel (grab_widget);
1895 if (CTK_IS_WINDOW (window)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(window)); GType __t = ((ctk_window_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
1896 {
1897 if (mnemonics_visible)
1898 _ctk_window_schedule_mnemonics_visible (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
);
1899 else
1900 ctk_window_set_mnemonics_visible (CTK_WINDOW (window)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((window)), ((ctk_window_get_type ()))))))
, FALSE(0));
1901 }
1902 }
1903 /* else fall through */
1904 case CDK_SCROLL:
1905 case CDK_BUTTON_PRESS:
1906 case CDK_2BUTTON_PRESS:
1907 case CDK_3BUTTON_PRESS:
1908 case CDK_TOUCH_BEGIN:
1909 case CDK_MOTION_NOTIFY:
1910 case CDK_BUTTON_RELEASE:
1911 case CDK_PROXIMITY_IN:
1912 case CDK_PROXIMITY_OUT:
1913 case CDK_TOUCH_UPDATE:
1914 case CDK_TOUCH_END:
1915 case CDK_TOUCH_CANCEL:
1916 case CDK_TOUCHPAD_SWIPE:
1917 case CDK_TOUCHPAD_PINCH:
1918 case CDK_PAD_BUTTON_PRESS:
1919 case CDK_PAD_BUTTON_RELEASE:
1920 case CDK_PAD_RING:
1921 case CDK_PAD_STRIP:
1922 case CDK_PAD_GROUP_MODE:
1923 if (!_ctk_propagate_captured_event (grab_widget, event, topmost_widget))
1924 ctk_propagate_event (grab_widget, event);
1925 break;
1926
1927 case CDK_ENTER_NOTIFY:
1928 case CDK_LEAVE_NOTIFY:
1929 if (ctk_widget_is_sensitive (grab_widget) &&
1930 !_ctk_propagate_captured_event (grab_widget, event, topmost_widget))
1931 ctk_widget_event (grab_widget, event);
1932 break;
1933
1934 case CDK_DRAG_STATUS:
1935 case CDK_DROP_FINISHED:
1936 _ctk_drag_source_handle_event (event_widget, event);
1937 break;
1938 case CDK_DRAG_ENTER:
1939 case CDK_DRAG_LEAVE:
1940 case CDK_DRAG_MOTION:
1941 case CDK_DROP_START:
1942 _ctk_drag_dest_handle_event (event_widget, event);
1943 break;
1944 default:
1945 g_assert_not_reached ()do { g_assertion_message_expr ("Ctk", "ctkmain.c", 1945, ((const
char*) (__func__)), ((void*)0)); } while (0)
;
1946 break;
1947 }
1948
1949 if (event->type == CDK_ENTER_NOTIFY
1950 || event->type == CDK_LEAVE_NOTIFY
1951 || event->type == CDK_BUTTON_PRESS
1952 || event->type == CDK_2BUTTON_PRESS
1953 || event->type == CDK_3BUTTON_PRESS
1954 || event->type == CDK_KEY_PRESS
1955 || event->type == CDK_DRAG_ENTER
1956 || event->type == CDK_GRAB_BROKEN
1957 || event->type == CDK_MOTION_NOTIFY
1958 || event->type == CDK_TOUCH_UPDATE
1959 || event->type == CDK_SCROLL)
1960 {
1961 _ctk_tooltip_handle_event (event);
1962 }
1963
1964 cleanup:
1965 tmp_list = current_events;
1966 current_events = g_list_remove_link (current_events, tmp_list);
1967 g_list_free_1 (tmp_list);
1968
1969 if (rewritten_event)
1970 cdk_event_free (rewritten_event);
1971}
1972
1973/**
1974 * ctk_true:
1975 *
1976 * All this function does it to return %TRUE.
1977 *
1978 * This can be useful for example if you want to inhibit the deletion
1979 * of a window. Of course you should not do this as the user expects
1980 * a reaction from clicking the close icon of the window...
1981 *
1982 * ## A persistent window
1983 *
1984 * |[<!-- language="C" -->
1985 * #include <ctk/ctk.h>
1986 *
1987 * int
1988 * main (int argc, char **argv)
1989 * {
1990 * CtkWidget *win, *but;
1991 * const char *text = "Close yourself. I mean it!";
1992 *
1993 * ctk_init (&argc, &argv);
1994 *
1995 * win = ctk_window_new (CTK_WINDOW_TOPLEVEL);
1996 * g_signal_connect (win,
1997 * "delete-event",
1998 * G_CALLBACK (ctk_true),
1999 * NULL);
2000 * g_signal_connect (win, "destroy",
2001 * G_CALLBACK (ctk_main_quit),
2002 * NULL);
2003 *
2004 * but = ctk_button_new_with_label (text);
2005 * g_signal_connect_swapped (but, "clicked",
2006 * G_CALLBACK (ctk_object_destroy),
2007 * win);
2008 * ctk_container_add (CTK_CONTAINER (win), but);
2009 *
2010 * ctk_widget_show_all (win);
2011 *
2012 * ctk_main ();
2013 *
2014 * return 0;
2015 * }
2016 * ]|
2017 *
2018 * Returns: %TRUE
2019 */
2020gboolean
2021ctk_true (void)
2022{
2023 return TRUE(!(0));
2024}
2025
2026/**
2027 * ctk_false:
2028 *
2029 * Analogical to ctk_true(), this function does nothing
2030 * but always returns %FALSE.
2031 *
2032 * Returns: %FALSE
2033 */
2034gboolean
2035ctk_false (void)
2036{
2037 return FALSE(0);
2038}
2039
2040static CtkWindowGroup *
2041ctk_main_get_window_group (CtkWidget *widget)
2042{
2043 CtkWidget *toplevel = NULL((void*)0);
2044
2045 if (widget)
2046 toplevel = ctk_widget_get_toplevel (widget);
2047
2048 if (CTK_IS_WINDOW (toplevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(toplevel)); GType __t = ((ctk_window_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2049 return ctk_window_get_group (CTK_WINDOW (toplevel)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_window_get_type ()))))))
);
2050 else
2051 return ctk_window_get_group (NULL((void*)0));
2052}
2053
2054typedef struct
2055{
2056 CtkWidget *old_grab_widget;
2057 CtkWidget *new_grab_widget;
2058 gboolean was_grabbed;
2059 gboolean is_grabbed;
2060 gboolean from_grab;
2061 GList *notified_windows;
2062 CdkDevice *device;
2063} GrabNotifyInfo;
2064
2065static void
2066synth_crossing_for_grab_notify (CtkWidget *from,
2067 CtkWidget *to,
2068 GrabNotifyInfo *info,
2069 GList *devices,
2070 CdkCrossingMode mode)
2071{
2072 while (devices)
2073 {
2074 CdkDevice *device = devices->data;
2075 CdkWindow *from_window, *to_window;
2076
2077 /* Do not propagate events more than once to
2078 * the same windows if non-multidevice aware.
2079 */
2080 if (!from)
2081 from_window = NULL((void*)0);
2082 else
2083 {
2084 from_window = _ctk_widget_get_device_window (from, device);
2085
2086 if (from_window &&
2087 !cdk_window_get_support_multidevice (from_window) &&
2088 g_list_find (info->notified_windows, from_window))
2089 from_window = NULL((void*)0);
2090 }
2091
2092 if (!to)
2093 to_window = NULL((void*)0);
2094 else
2095 {
2096 to_window = _ctk_widget_get_device_window (to, device);
2097
2098 if (to_window &&
2099 !cdk_window_get_support_multidevice (to_window) &&
2100 g_list_find (info->notified_windows, to_window))
2101 to_window = NULL((void*)0);
2102 }
2103
2104 if (from_window || to_window)
2105 {
2106 _ctk_widget_synthesize_crossing ((from_window) ? from : NULL((void*)0),
2107 (to_window) ? to : NULL((void*)0),
2108 device, mode);
2109
2110 if (from_window)
2111 info->notified_windows = g_list_prepend (info->notified_windows, from_window);
2112
2113 if (to_window)
2114 info->notified_windows = g_list_prepend (info->notified_windows, to_window);
2115 }
2116
2117 devices = devices->next;
2118 }
2119}
2120
2121static void
2122ctk_grab_notify_foreach (CtkWidget *child,
2123 gpointer data)
2124{
2125 GrabNotifyInfo *info = data;
2126 gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
2127 GList *devices;
2128
2129 was_grabbed = info->was_grabbed;
2130 is_grabbed = info->is_grabbed;
2131
2132 info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
2133 info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
2134
2135 was_shadowed = info->old_grab_widget && !info->was_grabbed;
2136 is_shadowed = info->new_grab_widget && !info->is_grabbed;
2137
2138 g_object_ref (child)((__typeof__ (child)) (g_object_ref) (child));
2139
2140 if ((was_shadowed || is_shadowed) && CTK_IS_CONTAINER (child)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(child)); GType __t = ((ctk_container_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2141 ctk_container_forall (CTK_CONTAINER (child)((((CtkContainer*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((child)), ((ctk_container_get_type ()))))))
, ctk_grab_notify_foreach, info);
2142
2143 if (info->device &&
2144 _ctk_widget_get_device_window (child, info->device))
2145 {
2146 /* Device specified and is on widget */
2147 devices = g_list_prepend (NULL((void*)0), info->device);
2148 }
2149 else
2150 devices = _ctk_widget_list_devices (child);
2151
2152 if (is_shadowed)
2153 {
2154 _ctk_widget_set_shadowed (child, TRUE(!(0)));
2155 if (!was_shadowed && devices &&
2156 ctk_widget_is_sensitive (child))
2157 synth_crossing_for_grab_notify (child, info->new_grab_widget,
2158 info, devices,
2159 CDK_CROSSING_CTK_GRAB);
2160 }
2161 else
2162 {
2163 _ctk_widget_set_shadowed (child, FALSE(0));
2164 if (was_shadowed && devices &&
2165 ctk_widget_is_sensitive (child))
2166 synth_crossing_for_grab_notify (info->old_grab_widget, child,
2167 info, devices,
2168 info->from_grab ? CDK_CROSSING_CTK_GRAB :
2169 CDK_CROSSING_CTK_UNGRAB);
2170 }
2171
2172 if (was_shadowed != is_shadowed)
2173 _ctk_widget_grab_notify (child, was_shadowed);
2174
2175 g_object_unref (child);
2176 g_list_free (devices);
2177
2178 info->was_grabbed = was_grabbed;
2179 info->is_grabbed = is_grabbed;
2180}
2181
2182static void
2183ctk_grab_notify (CtkWindowGroup *group,
2184 CdkDevice *device,
2185 CtkWidget *old_grab_widget,
2186 CtkWidget *new_grab_widget,
2187 gboolean from_grab)
2188{
2189 GList *toplevels;
2190 GrabNotifyInfo info = { 0 };
2191
2192 if (old_grab_widget == new_grab_widget)
2193 return;
2194
2195 info.old_grab_widget = old_grab_widget;
2196 info.new_grab_widget = new_grab_widget;
2197 info.from_grab = from_grab;
2198 info.device = device;
2199
2200 g_object_ref (group)((__typeof__ (group)) (g_object_ref) (group));
2201
2202 toplevels = ctk_window_list_toplevels ();
2203 g_list_foreach (toplevels, (GFunc)g_object_ref, NULL((void*)0));
2204
2205 while (toplevels)
2206 {
2207 CtkWindow *toplevel = toplevels->data;
2208 toplevels = g_list_delete_link (toplevels, toplevels);
2209
2210 info.was_grabbed = FALSE(0);
2211 info.is_grabbed = FALSE(0);
2212
2213 if (group == ctk_window_get_group (toplevel))
2214 ctk_grab_notify_foreach (CTK_WIDGET (toplevel)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((toplevel)), ((ctk_widget_get_type ()))))))
, &info);
2215 g_object_unref (toplevel);
2216 }
2217
2218 g_list_free (info.notified_windows);
2219 g_object_unref (group);
2220}
2221
2222/**
2223 * ctk_grab_add: (method)
2224 * @widget: The widget that grabs keyboard and pointer events
2225 *
2226 * Makes @widget the current grabbed widget.
2227 *
2228 * This means that interaction with other widgets in the same
2229 * application is blocked and mouse as well as keyboard events
2230 * are delivered to this widget.
2231 *
2232 * If @widget is not sensitive, it is not set as the current
2233 * grabbed widget and this function does nothing.
2234 */
2235void
2236ctk_grab_add (CtkWidget *widget)
2237{
2238 CtkWindowGroup *group;
2239 CtkWidget *old_grab_widget;
2240 CtkWidget *toplevel;
2241
2242 g_return_if_fail (widget != NULL)do { if ((widget != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "widget != NULL"); return
; } } while (0)
;
2243
2244 toplevel = ctk_widget_get_toplevel (widget);
2245 if (toplevel && cdk_window_get_window_type (ctk_widget_get_window (toplevel)) == CDK_WINDOW_OFFSCREEN)
2246 return;
2247
2248 if (!ctk_widget_has_grab (widget) && ctk_widget_is_sensitive (widget))
2249 {
2250 _ctk_widget_set_has_grab (widget, TRUE(!(0)));
2251
2252 group = ctk_main_get_window_group (widget);
2253
2254 old_grab_widget = ctk_window_group_get_current_grab (group);
2255
2256 g_object_ref (widget)((__typeof__ (widget)) (g_object_ref) (widget));
2257 _ctk_window_group_add_grab (group, widget);
2258
2259 ctk_grab_notify (group, NULL((void*)0), old_grab_widget, widget, TRUE(!(0)));
2260 }
2261}
2262
2263/**
2264 * ctk_grab_get_current:
2265 *
2266 * Queries the current grab of the default window group.
2267 *
2268 * Returns: (transfer none) (nullable): The widget which currently
2269 * has the grab or %NULL if no grab is active
2270 */
2271CtkWidget*
2272ctk_grab_get_current (void)
2273{
2274 CtkWindowGroup *group;
2275
2276 group = ctk_main_get_window_group (NULL((void*)0));
2277
2278 return ctk_window_group_get_current_grab (group);
2279}
2280
2281/**
2282 * ctk_grab_remove: (method)
2283 * @widget: The widget which gives up the grab
2284 *
2285 * Removes the grab from the given widget.
2286 *
2287 * You have to pair calls to ctk_grab_add() and ctk_grab_remove().
2288 *
2289 * If @widget does not have the grab, this function does nothing.
2290 */
2291void
2292ctk_grab_remove (CtkWidget *widget)
2293{
2294 CtkWindowGroup *group;
2295 CtkWidget *new_grab_widget;
2296
2297 g_return_if_fail (widget != NULL)do { if ((widget != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "widget != NULL"); return
; } } while (0)
;
2298
2299 if (ctk_widget_has_grab (widget))
2300 {
2301 _ctk_widget_set_has_grab (widget, FALSE(0));
2302
2303 group = ctk_main_get_window_group (widget);
2304 _ctk_window_group_remove_grab (group, widget);
2305 new_grab_widget = ctk_window_group_get_current_grab (group);
2306
2307 ctk_grab_notify (group, NULL((void*)0), widget, new_grab_widget, FALSE(0));
2308
2309 g_object_unref (widget);
2310 }
2311}
2312
2313/**
2314 * ctk_device_grab_add:
2315 * @widget: a #CtkWidget
2316 * @device: a #CdkDevice to grab on.
2317 * @block_others: %TRUE to prevent other devices to interact with @widget.
2318 *
2319 * Adds a CTK+ grab on @device, so all the events on @device and its
2320 * associated pointer or keyboard (if any) are delivered to @widget.
2321 * If the @block_others parameter is %TRUE, any other devices will be
2322 * unable to interact with @widget during the grab.
2323 *
2324 * Since: 3.0
2325 */
2326void
2327ctk_device_grab_add (CtkWidget *widget,
2328 CdkDevice *device,
2329 gboolean block_others)
2330{
2331 CtkWindowGroup *group;
2332 CtkWidget *old_grab_widget;
2333 CdkWindow *toplevel;
2334
2335 g_return_if_fail (CTK_IS_WIDGET (widget))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_widget_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_WIDGET (widget)"); return; } } while (0)
;
2336 g_return_if_fail (CDK_IS_DEVICE (device))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((device)); GType __t = ((cdk_device_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CDK_IS_DEVICE (device)"); return; } } while (0)
;
2337
2338 toplevel = cdk_window_get_toplevel (ctk_widget_get_window (widget));
2339 if (toplevel && cdk_window_get_window_type (toplevel) == CDK_WINDOW_OFFSCREEN)
2340 return;
2341
2342 group = ctk_main_get_window_group (widget);
2343 old_grab_widget = ctk_window_group_get_current_device_grab (group, device);
2344
2345 if (old_grab_widget != widget)
2346 _ctk_window_group_add_device_grab (group, widget, device, block_others);
2347
2348 ctk_grab_notify (group, device, old_grab_widget, widget, TRUE(!(0)));
2349}
2350
2351/**
2352 * ctk_device_grab_remove:
2353 * @widget: a #CtkWidget
2354 * @device: a #CdkDevice
2355 *
2356 * Removes a device grab from the given widget.
2357 *
2358 * You have to pair calls to ctk_device_grab_add() and
2359 * ctk_device_grab_remove().
2360 *
2361 * Since: 3.0
2362 */
2363void
2364ctk_device_grab_remove (CtkWidget *widget,
2365 CdkDevice *device)
2366{
2367 CtkWindowGroup *group;
2368 CtkWidget *new_grab_widget;
2369
2370 g_return_if_fail (CTK_IS_WIDGET (widget))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_widget_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_WIDGET (widget)"); return; } } while (0)
;
2371 g_return_if_fail (CDK_IS_DEVICE (device))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((device)); GType __t = ((cdk_device_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CDK_IS_DEVICE (device)"); return; } } while (0)
;
2372
2373 group = ctk_main_get_window_group (widget);
2374 _ctk_window_group_remove_device_grab (group, widget, device);
2375 new_grab_widget = ctk_window_group_get_current_device_grab (group, device);
2376
2377 ctk_grab_notify (group, device, widget, new_grab_widget, FALSE(0));
2378}
2379
2380/**
2381 * ctk_key_snooper_install: (skip)
2382 * @snooper: a #CtkKeySnoopFunc
2383 * @func_data: (closure): data to pass to @snooper
2384 *
2385 * Installs a key snooper function, which will get called on all
2386 * key events before delivering them normally.
2387 *
2388 * Returns: a unique id for this key snooper for use with
2389 * ctk_key_snooper_remove().
2390 *
2391 * Deprecated: 3.4: Key snooping should not be done. Events should
2392 * be handled by widgets.
2393 */
2394guint
2395ctk_key_snooper_install (CtkKeySnoopFunc snooper,
2396 gpointer func_data)
2397{
2398 CtkKeySnooperData *data;
2399 static guint snooper_id = 1;
2400
2401 g_return_val_if_fail (snooper != NULL, 0)do { if ((snooper != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "snooper != NULL"); return
(0); } } while (0)
;
2402
2403 data = g_new (CtkKeySnooperData, 1)((CtkKeySnooperData *) g_malloc_n ((1), sizeof (CtkKeySnooperData
)))
;
2404 data->func = snooper;
2405 data->func_data = func_data;
2406 data->id = snooper_id++;
2407 key_snoopers = g_slist_prepend (key_snoopers, data);
2408
2409 return data->id;
2410}
2411
2412/**
2413 * ctk_key_snooper_remove:
2414 * @snooper_handler_id: Identifies the key snooper to remove
2415 *
2416 * Removes the key snooper function with the given id.
2417 *
2418 * Deprecated: 3.4: Key snooping should not be done. Events should
2419 * be handled by widgets.
2420 */
2421void
2422ctk_key_snooper_remove (guint snooper_id)
2423{
2424 CtkKeySnooperData *data = NULL((void*)0);
2425 GSList *slist;
2426
2427 slist = key_snoopers;
2428 while (slist)
2429 {
2430 data = slist->data;
2431 if (data->id == snooper_id)
2432 break;
2433
2434 slist = slist->next;
2435 data = NULL((void*)0);
2436 }
2437 if (data)
2438 {
2439 key_snoopers = g_slist_remove (key_snoopers, data);
2440 g_free (data);
2441 }
2442}
2443
2444static gint
2445ctk_invoke_key_snoopers (CtkWidget *grab_widget,
2446 CdkEvent *event)
2447{
2448 GSList *slist;
2449 gint return_val = FALSE(0);
2450
2451 return_val = _ctk_accessibility_key_snooper (grab_widget, (CdkEventKey *) event);
2452
2453 slist = key_snoopers;
2454 while (slist && !return_val)
2455 {
2456 CtkKeySnooperData *data;
2457
2458 data = slist->data;
2459 slist = slist->next;
2460 return_val = (*data->func) (grab_widget, (CdkEventKey*) event, data->func_data);
2461 }
2462
2463 return return_val;
2464}
2465
2466/**
2467 * ctk_get_current_event:
2468 *
2469 * Obtains a copy of the event currently being processed by CTK+.
2470 *
2471 * For example, if you are handling a #CtkButton::clicked signal,
2472 * the current event will be the #CdkEventButton that triggered
2473 * the ::clicked signal.
2474 *
2475 * Returns: (transfer full) (nullable): a copy of the current event, or
2476 * %NULL if there is no current event. The returned event must be
2477 * freed with cdk_event_free().
2478 */
2479CdkEvent*
2480ctk_get_current_event (void)
2481{
2482 if (current_events)
2483 return cdk_event_copy (current_events->data);
2484 else
2485 return NULL((void*)0);
2486}
2487
2488/**
2489 * ctk_get_current_event_time:
2490 *
2491 * If there is a current event and it has a timestamp,
2492 * return that timestamp, otherwise return %CDK_CURRENT_TIME.
2493 *
2494 * Returns: the timestamp from the current event,
2495 * or %CDK_CURRENT_TIME.
2496 */
2497guint32
2498ctk_get_current_event_time (void)
2499{
2500 if (current_events)
2501 return cdk_event_get_time (current_events->data);
2502 else
2503 return CDK_CURRENT_TIME0L;
2504}
2505
2506/**
2507 * ctk_get_current_event_state:
2508 * @state: (out): a location to store the state of the current event
2509 *
2510 * If there is a current event and it has a state field, place
2511 * that state field in @state and return %TRUE, otherwise return
2512 * %FALSE.
2513 *
2514 * Returns: %TRUE if there was a current event and it
2515 * had a state field
2516 */
2517gboolean
2518ctk_get_current_event_state (CdkModifierType *state)
2519{
2520 g_return_val_if_fail (state != NULL, FALSE)do { if ((state != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "state != NULL"); return
((0)); } } while (0)
;
2521
2522 if (current_events)
2523 return cdk_event_get_state (current_events->data, state);
2524 else
2525 {
2526 *state = 0;
2527 return FALSE(0);
2528 }
2529}
2530
2531/**
2532 * ctk_get_current_event_device:
2533 *
2534 * If there is a current event and it has a device, return that
2535 * device, otherwise return %NULL.
2536 *
2537 * Returns: (transfer none) (nullable): a #CdkDevice, or %NULL
2538 */
2539CdkDevice *
2540ctk_get_current_event_device (void)
2541{
2542 if (current_events)
2543 return cdk_event_get_device (current_events->data);
2544 else
2545 return NULL((void*)0);
2546}
2547
2548/**
2549 * ctk_get_event_widget:
2550 * @event: a #CdkEvent
2551 *
2552 * If @event is %NULL or the event was not associated with any widget,
2553 * returns %NULL, otherwise returns the widget that received the event
2554 * originally.
2555 *
2556 * Returns: (transfer none) (nullable): the widget that originally
2557 * received @event, or %NULL
2558 */
2559CtkWidget*
2560ctk_get_event_widget (CdkEvent *event)
2561{
2562 CtkWidget *widget;
2563 gpointer widget_ptr;
2564
2565 widget = NULL((void*)0);
2566 if (event && event->any.window &&
2567 (event->type == CDK_DESTROY || !cdk_window_is_destroyed (event->any.window)))
2568 {
2569 cdk_window_get_user_data (event->any.window, &widget_ptr);
2570 widget = widget_ptr;
2571 }
2572
2573 return widget;
2574}
2575
2576static gboolean
2577propagate_event_up (CtkWidget *widget,
2578 CdkEvent *event,
2579 CtkWidget *topmost)
2580{
2581 gboolean handled_event = FALSE(0);
2582
2583 /* Propagate event up the widget tree so that
2584 * parents can see the button and motion
2585 * events of the children.
2586 */
2587 while (TRUE(!(0)))
2588 {
2589 CtkWidget *tmp;
2590
2591 g_object_ref (widget)((__typeof__ (widget)) (g_object_ref) (widget));
2592
2593 /* Scroll events are special cased here because it
2594 * feels wrong when scrolling a CtkViewport, say,
2595 * to have children of the viewport eat the scroll
2596 * event
2597 */
2598 if (!ctk_widget_is_sensitive (widget))
2599 handled_event = event->type != CDK_SCROLL;
2600 else
2601 handled_event = ctk_widget_event (widget, event);
2602
2603 tmp = ctk_widget_get_parent (widget);
2604 g_object_unref (widget);
2605
2606 if (widget == topmost)
2607 break;
2608
2609 widget = tmp;
2610
2611 if (handled_event || !widget)
2612 break;
2613 }
2614
2615 return handled_event;
2616}
2617
2618static gboolean
2619propagate_event_down (CtkWidget *widget,
2620 CdkEvent *event,
2621 CtkWidget *topmost)
2622{
2623 gint handled_event = FALSE(0);
2624 GList *widgets = NULL((void*)0);
2625 GList *l;
2626
2627 widgets = g_list_prepend (widgets, g_object_ref (widget)((__typeof__ (widget)) (g_object_ref) (widget)));
2628 while (widget && widget != topmost)
2629 {
2630 widget = ctk_widget_get_parent (widget);
2631 if (!widget)
2632 break;
2633
2634 widgets = g_list_prepend (widgets, g_object_ref (widget)((__typeof__ (widget)) (g_object_ref) (widget)));
2635
2636 if (widget == topmost)
2637 break;
2638 }
2639
2640 for (l = widgets; l && !handled_event; l = l->next)
2641 {
2642 widget = (CtkWidget *)l->data;
2643
2644 if (!ctk_widget_is_sensitive (widget))
2645 {
2646 /* stop propagating on SCROLL, but don't handle the event, so it
2647 * can propagate up again and reach its handling widget
2648 */
2649 if (event->type == CDK_SCROLL)
2650 break;
2651 else
2652 handled_event = TRUE(!(0));
2653 }
2654 else
2655 handled_event = _ctk_widget_captured_event (widget, event);
2656 }
2657 g_list_free_full (widgets, (GDestroyNotify)g_object_unref);
2658
2659 return handled_event;
2660}
2661
2662static gboolean
2663propagate_event (CtkWidget *widget,
2664 CdkEvent *event,
2665 gboolean captured,
2666 CtkWidget *topmost)
2667{
2668 gboolean handled_event = FALSE(0);
2669 gboolean (* propagate_func) (CtkWidget *widget, CdkEvent *event);
2670
2671 propagate_func = captured ? _ctk_widget_captured_event : ctk_widget_event;
2672
2673 if (event->type == CDK_KEY_PRESS || event->type == CDK_KEY_RELEASE)
2674 {
2675 /* Only send key events within Window widgets to the Window
2676 * The Window widget will in turn pass the
2677 * key event on to the currently focused widget
2678 * for that window.
2679 */
2680 CtkWidget *window;
2681
2682 window = ctk_widget_get_toplevel (widget);
2683 if (CTK_IS_WINDOW (window)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(window)); GType __t = ((ctk_window_get_type ())); gboolean __r
; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; }))))
)
2684 {
2685 g_object_ref (widget)((__typeof__ (widget)) (g_object_ref) (widget));
2686 /* If there is a grab within the window, give the grab widget
2687 * a first crack at the key event
2688 */
2689 if (widget != window && ctk_widget_has_grab (widget))
2690 handled_event = propagate_func (widget, event);
2691
2692 if (!handled_event &&
2693 ctk_widget_is_sensitive (window))
2694 handled_event = propagate_func (window, event);
2695
2696 g_object_unref (widget);
2697 return handled_event;
2698 }
2699 }
2700
2701 /* Other events get propagated up/down the widget tree */
2702 return captured ?
2703 propagate_event_down (widget, event, topmost) :
2704 propagate_event_up (widget, event, topmost);
2705}
2706
2707/**
2708 * ctk_propagate_event:
2709 * @widget: a #CtkWidget
2710 * @event: an event
2711 *
2712 * Sends an event to a widget, propagating the event to parent widgets
2713 * if the event remains unhandled.
2714 *
2715 * Events received by CTK+ from CDK normally begin in ctk_main_do_event().
2716 * Depending on the type of event, existence of modal dialogs, grabs, etc.,
2717 * the event may be propagated; if so, this function is used.
2718 *
2719 * ctk_propagate_event() calls ctk_widget_event() on each widget it
2720 * decides to send the event to. So ctk_widget_event() is the lowest-level
2721 * function; it simply emits the #CtkWidget::event and possibly an
2722 * event-specific signal on a widget. ctk_propagate_event() is a bit
2723 * higher-level, and ctk_main_do_event() is the highest level.
2724 *
2725 * All that said, you most likely don’t want to use any of these
2726 * functions; synthesizing events is rarely needed. There are almost
2727 * certainly better ways to achieve your goals. For example, use
2728 * cdk_window_invalidate_rect() or ctk_widget_queue_draw() instead
2729 * of making up expose events.
2730 */
2731void
2732ctk_propagate_event (CtkWidget *widget,
2733 CdkEvent *event)
2734{
2735 g_return_if_fail (CTK_IS_WIDGET (widget))do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((widget)); GType __t = ((ctk_widget_get_type ())); gboolean
__r; if (!__inst) __r = (0); else if (__inst->g_class &&
__inst->g_class->g_type == __t) __r = (!(0)); else __r
= g_type_check_instance_is_a (__inst, __t); __r; })))))) { }
else { g_return_if_fail_warning ("Ctk", ((const char*) (__func__
)), "CTK_IS_WIDGET (widget)"); return; } } while (0)
;
2736 g_return_if_fail (event != NULL)do { if ((event != ((void*)0))) { } else { g_return_if_fail_warning
("Ctk", ((const char*) (__func__)), "event != NULL"); return
; } } while (0)
;
2737
2738 propagate_event (widget, event, FALSE(0), NULL((void*)0));
2739}
2740
2741gboolean
2742_ctk_propagate_captured_event (CtkWidget *widget,
2743 CdkEvent *event,
2744 CtkWidget *topmost)
2745{
2746 return propagate_event (widget, event, TRUE(!(0)), topmost);
2747}