gtkmain.c 57.5 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
Elliot Lee's avatar
Elliot Lee committed
2
3
4
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
Elliot Lee's avatar
Elliot Lee committed
6
7
8
9
10
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Matthias Clasen's avatar
Matthias Clasen committed
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
Elliot Lee's avatar
Elliot Lee committed
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Elliot Lee's avatar
Elliot Lee committed
16
 */
17
18

/*
19
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20
21
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
22
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23
24
 */

25
#include "config.h"
26

Matthias Clasen's avatar
Matthias Clasen committed
27
#include "gdk/gdk.h"
28
#include "gdk/gdk-private.h"
Matthias Clasen's avatar
Matthias Clasen committed
29
#include "gdk/gdkprofilerprivate.h"
30
#include "gsk/gskprivate.h"
31
#include "gsk/gskrendernodeprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
32
#include "gtknative.h"
33

34
#include <locale.h>
Robert Brady's avatar
Robert Brady committed
35

Elliot Lee's avatar
Elliot Lee committed
36
37
#include <stdio.h>
#include <stdlib.h>
38
#include <string.h>
39
#ifdef HAVE_UNISTD_H
40
41
#include <unistd.h>
#endif
Matthias Clasen's avatar
Matthias Clasen committed
42
#include <sys/types.h>          /* For uid_t, gid_t */
43

Tor Lillqvist's avatar
Tor Lillqvist committed
44
45
46
47
48
#ifdef G_OS_WIN32
#define STRICT
#include <windows.h>
#undef STRICT
#endif
49

Tor Lillqvist's avatar
Tor Lillqvist committed
50
51
#include "gtkintl.h"

52
#include "gtkbox.h"
53
#include "gtkdebug.h"
Benjamin Otte's avatar
Benjamin Otte committed
54
#include "gtkdropprivate.h"
55
#include "gtkmain.h"
56
#include "gtkmediafileprivate.h"
57
#include "gtkmodulesprivate.h"
58
#include "gtkprivate.h"
59
#include "gtkrecentmanager.h"
Matthias Clasen's avatar
Matthias Clasen committed
60
#include "gtksettingsprivate.h"
61
#include "gtktooltipprivate.h"
Emmanuele Bassi's avatar
Emmanuele Bassi committed
62
#include "gtkwidgetprivate.h"
Matthias Clasen's avatar
Matthias Clasen committed
63
#include "gtkwindowprivate.h"
64
#include "gtkwindowgroup.h"
65
#include "gtkprintbackendprivate.h"
66
#include "gtkimmoduleprivate.h"
67
#include "gtkroot.h"
68
#include "gtknative.h"
69
#include "gtkpopcountprivate.h"
70

71
#include "inspector/window.h"
72

73
74
75
#include "gdk/gdkeventsprivate.h"
#include "gdk/gdksurfaceprivate.h"

Benjamin Otte's avatar
Benjamin Otte committed
76
77
78
79
80
81
82
#define GDK_ARRAY_ELEMENT_TYPE GtkWidget *
#define GDK_ARRAY_TYPE_NAME GtkWidgetStack
#define GDK_ARRAY_NAME gtk_widget_stack
#define GDK_ARRAY_FREE_FUNC g_object_unref
#define GDK_ARRAY_PREALLOC 16
#include "gdk/gdkarrayimpl.c"

83
84
static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);

Benjamin Otte's avatar
Benjamin Otte committed
85
86
static int pre_initialized = FALSE;
static int gtk_initialized = FALSE;
87
static GList *current_events = NULL;
88

89
90
91
92
93
94
95
96
typedef struct {
  GdkDisplay *display;
  guint flags;
} DisplayDebugFlags;

#define N_DEBUG_DISPLAYS 4

DisplayDebugFlags debug_flags[N_DEBUG_DISPLAYS];
97
98
99
100
101
/* This is a flag to speed up development builds. We set it to TRUE when
 * any of the debug displays has debug flags >0, but we never set it back
 * to FALSE. This way we don't need to call gtk_widget_get_display() in
 * hot paths. */
gboolean any_display_debug_flags_set = FALSE;
102

Matthias Clasen's avatar
Matthias Clasen committed
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
GtkDebugFlags
gtk_get_display_debug_flags (GdkDisplay *display)
{
  int i;

  if (display == NULL)
    display = gdk_display_get_default ();

  for (i = 0; i < N_DEBUG_DISPLAYS; i++)
    {
      if (debug_flags[i].display == display)
        return (GtkDebugFlags)debug_flags[i].flags;
    }

  return 0;
}

gboolean
gtk_get_any_display_debug_flag_set (void)
{
  return any_display_debug_flags_set;
}

void
gtk_set_display_debug_flags (GdkDisplay    *display,
                             GtkDebugFlags  flags)
{
  int i;

  for (i = 0; i < N_DEBUG_DISPLAYS; i++)
    {
      if (debug_flags[i].display == NULL)
        debug_flags[i].display = display;

      if (debug_flags[i].display == display)
        {
          debug_flags[i].flags = flags;
          if (flags > 0)
            any_display_debug_flags_set = TRUE;

          return;
        }
    }
}

/**
 * gtk_get_debug_flags:
 *
 * Returns the GTK debug flags that are currently active.
 *
 * This function is intended for GTK modules that want
 * to adjust their debug output based on GTK debug flags.
 *
 * Returns: the GTK debug flags.
 */
GtkDebugFlags
gtk_get_debug_flags (void)
{
  if (gtk_get_any_display_debug_flag_set ())
    return gtk_get_display_debug_flags (gdk_display_get_default ());

  return 0;
}

/**
 * gtk_set_debug_flags:
 * @flags: the debug flags to set
 *
 * Sets the GTK debug flags.
 */
void
gtk_set_debug_flags (GtkDebugFlags flags)
{
  gtk_set_display_debug_flags (gdk_display_get_default (), flags);
}

gboolean
gtk_simulate_touchscreen (void)
{
  return (gtk_get_debug_flags () & GTK_DEBUG_TOUCHSCREEN) != 0;
}

185
186
187
188
189
190
191
192
static const GdkDebugKey gtk_debug_keys[] = {
  { "keybindings", GTK_DEBUG_KEYBINDINGS, "Information about keyboard shortcuts" },
  { "modules", GTK_DEBUG_MODULES, "Information about modules and extensions" },
  { "icontheme", GTK_DEBUG_ICONTHEME, "Information about icon themes" },
  { "printing", GTK_DEBUG_PRINTING, "Information about printing" },
  { "geometry", GTK_DEBUG_GEOMETRY, "Information about size allocation" },
  { "size-request", GTK_DEBUG_SIZE_REQUEST, "Information about size requests" },
  { "actions", GTK_DEBUG_ACTIONS, "Information about actions and menu models" },
193
  { "constraints", GTK_DEBUG_CONSTRAINTS, "Information from the constraints solver" },
194
195
  { "text", GTK_DEBUG_TEXT, "Information about GtkTextView" },
  { "tree", GTK_DEBUG_TREE, "Information about GtkTreeView" },
196
  { "layout", GTK_DEBUG_LAYOUT, "Information from layout managers" },
197
198
199
  { "builder", GTK_DEBUG_BUILDER, "Trace GtkBuilder operation" },
  { "builder-objects", GTK_DEBUG_BUILDER_OBJECTS, "Log unused GtkBuilder objects" },
  { "no-css-cache", GTK_DEBUG_NO_CSS_CACHE, "Disable style property cache" },
200
  { "interactive", GTK_DEBUG_INTERACTIVE, "Enable the GTK inspector", TRUE },
201
202
  { "touchscreen", GTK_DEBUG_TOUCHSCREEN, "Pretend the pointer is a touchscreen" },
  { "snapshot", GTK_DEBUG_SNAPSHOT, "Generate debug render nodes" },
Matthias Clasen's avatar
Matthias Clasen committed
203
  { "accessibility", GTK_DEBUG_A11Y, "Information about accessibility state changes" },
204
  { "iconfallback", GTK_DEBUG_ICONFALLBACK, "Information about icon fallback" },
205
};
Elliot Lee's avatar
Elliot Lee committed
206

Owen Taylor's avatar
Owen Taylor committed
207
/* This checks to see if the process is running suid or sgid
Matthias Clasen's avatar
Matthias Clasen committed
208
 * at the current time. If so, we don’t allow GTK to be initialized.
Owen Taylor's avatar
Owen Taylor committed
209
210
211
 * This is meant to be a mild check - we only error out if we
 * can prove the programmer is doing something wrong, not if
 * they could be doing something wrong. For this reason, we
212
 * don’t use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
Owen Taylor's avatar
Owen Taylor committed
213
214
215
216
 */
static gboolean
check_setugid (void)
{
217
/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
Hans Breuer's avatar
Hans Breuer committed
218
#ifndef G_OS_WIN32
Owen Taylor's avatar
Owen Taylor committed
219
220
  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
221

Owen Taylor's avatar
Owen Taylor committed
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
#ifdef HAVE_GETRESUID
  if (getresuid (&ruid, &euid, &suid) != 0 ||
      getresgid (&rgid, &egid, &sgid) != 0)
#endif /* HAVE_GETRESUID */
    {
      suid = ruid = getuid ();
      sgid = rgid = getgid ();
      euid = geteuid ();
      egid = getegid ();
    }

  if (ruid != euid || ruid != suid ||
      rgid != egid || rgid != sgid)
    {
      g_warning ("This process is currently running setuid or setgid.\n"
Matthias Clasen's avatar
Matthias Clasen committed
237
                 "This is not a supported use of GTK. You must create a helper\n"
Matthias Clasen's avatar
Matthias Clasen committed
238
239
                 "program instead. For further details, see:\n\n"
                 "    http://www.gtk.org/setuid.html\n\n"
Matthias Clasen's avatar
Matthias Clasen committed
240
                 "Refusing to initialize GTK.");
Owen Taylor's avatar
Owen Taylor committed
241
242
      exit (1);
    }
Hans Breuer's avatar
Hans Breuer committed
243
#endif
Owen Taylor's avatar
Owen Taylor committed
244
245
246
  return TRUE;
}

247
248
249
250
static gboolean do_setlocale = TRUE;

/**
 * gtk_disable_setlocale:
251
 *
Emmanuele Bassi's avatar
Emmanuele Bassi committed
252
253
254
255
 * Prevents [id@gtk_init] and [id@gtk_init_check] from automatically calling
 * `setlocale (LC_ALL, "")`.
 *
 * You would want to use this function if you wanted to set the locale for
256
 * your program to something other than the user’s locale, or if
257
 * you wanted to set different values for different locale categories.
258
259
260
 *
 * Most programs should not need to call this function.
 **/
261
void
262
263
gtk_disable_setlocale (void)
{
Matthias Clasen's avatar
Matthias Clasen committed
264
  if (pre_initialized)
265
    g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
266

267
268
269
  do_setlocale = FALSE;
}

270
#ifdef G_PLATFORM_WIN32
271
#undef gtk_init_check
272
#endif
273

Tor Lillqvist's avatar
Tor Lillqvist committed
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
#ifdef G_OS_WIN32

static char *iso639_to_check = NULL;
static char *iso3166_to_check = NULL;
static char *script_to_check = NULL;
static gboolean setlocale_called = FALSE;

static BOOL CALLBACK
enum_locale_proc (LPTSTR locale)
{
  LCID lcid;
  char iso639[10];
  char iso3166[10];
  char *endptr;


  lcid = strtoul (locale, &endptr, 16);
  if (*endptr == '\0' &&
      GetLocaleInfo (lcid, LOCALE_SISO639LANGNAME, iso639, sizeof (iso639)) &&
      GetLocaleInfo (lcid, LOCALE_SISO3166CTRYNAME, iso3166, sizeof (iso3166)))
    {
      if (strcmp (iso639, iso639_to_check) == 0 &&
Matthias Clasen's avatar
Matthias Clasen committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
          ((iso3166_to_check != NULL &&
            strcmp (iso3166, iso3166_to_check) == 0) ||
           (iso3166_to_check == NULL &&
            SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
        {
          char language[100], country[100];

          if (script_to_check != NULL)
            {
              /* If lcid is the "other" script for this language,
               * return TRUE, i.e. continue looking.
               */
              if (strcmp (script_to_check, "Latn") == 0)
                {
                  switch (LANGIDFROMLCID (lcid))
                    {
                    case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_CYRILLIC):
                      return TRUE;
                    case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_CYRILLIC):
                      return TRUE;
                    case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_CYRILLIC):
                      return TRUE;
                    case MAKELANGID (LANG_SERBIAN, 0x07):
                      /* Serbian in Bosnia and Herzegovina, Cyrillic */
                      return TRUE;
LRN's avatar
LRN committed
321
322
                    default:
                      break;
Matthias Clasen's avatar
Matthias Clasen committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
                    }
                }
              else if (strcmp (script_to_check, "Cyrl") == 0)
                {
                  switch (LANGIDFROMLCID (lcid))
                    {
                    case MAKELANGID (LANG_AZERI, SUBLANG_AZERI_LATIN):
                      return TRUE;
                    case MAKELANGID (LANG_UZBEK, SUBLANG_UZBEK_LATIN):
                      return TRUE;
                    case MAKELANGID (LANG_SERBIAN, SUBLANG_SERBIAN_LATIN):
                      return TRUE;
                    case MAKELANGID (LANG_SERBIAN, 0x06):
                      /* Serbian in Bosnia and Herzegovina, Latin */
                      return TRUE;
LRN's avatar
LRN committed
338
339
                    default:
                      break;
Matthias Clasen's avatar
Matthias Clasen committed
340
341
342
343
344
345
346
347
348
                    }
                }
            }

          SetThreadLocale (lcid);

          if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
              GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
            {
349
              char str[300];
Matthias Clasen's avatar
Matthias Clasen committed
350

351
352
353
354
355
              strcpy (str, language);
              strcat (str, "_");
              strcat (str, country);

              if (setlocale (LC_ALL, str) != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
356
357
358
359
360
                setlocale_called = TRUE;
            }

          return FALSE;
        }
Tor Lillqvist's avatar
Tor Lillqvist committed
361
362
363
364
    }

  return TRUE;
}
365

Tor Lillqvist's avatar
Tor Lillqvist committed
366
367
#endif

368
void
369
setlocale_initialization (void)
370
{
371
  static gboolean initialized = FALSE;
372

373
  if (initialized)
Matthias Clasen's avatar
Matthias Clasen committed
374
    return;
375
  initialized = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
376

377
  if (do_setlocale)
378
    {
Tor Lillqvist's avatar
Tor Lillqvist committed
379
380
381
#ifdef G_OS_WIN32
      /* If some of the POSIXish environment variables are set, set
       * the Win32 thread locale correspondingly.
382
       */
Tor Lillqvist's avatar
Tor Lillqvist committed
383
384
      char *p = getenv ("LC_ALL");
      if (p == NULL)
Matthias Clasen's avatar
Matthias Clasen committed
385
        p = getenv ("LANG");
Tor Lillqvist's avatar
Tor Lillqvist committed
386
387

      if (p != NULL)
Matthias Clasen's avatar
Matthias Clasen committed
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
        {
          p = g_strdup (p);
          if (strcmp (p, "C") == 0)
            SetThreadLocale (LOCALE_SYSTEM_DEFAULT);
          else
            {
              /* Check if one of the supported locales match the
               * environment variable. If so, use that locale.
               */
              iso639_to_check = p;
              iso3166_to_check = strchr (iso639_to_check, '_');
              if (iso3166_to_check != NULL)
                {
                  *iso3166_to_check++ = '\0';

                  script_to_check = strchr (iso3166_to_check, '@');
                  if (script_to_check != NULL)
                    *script_to_check++ = '\0';

                  /* Handle special cases. */

                  /* The standard code for Serbia and Montenegro was
                   * "CS", but MSFT uses for some reason "SP". By now
                   * (October 2006), SP has split into two, "RS" and
                   * "ME", but don't bother trying to handle those
                   * yet. Do handle the even older "YU", though.
                   */
                  if (strcmp (iso3166_to_check, "CS") == 0 ||
                      strcmp (iso3166_to_check, "YU") == 0)
LRN's avatar
LRN committed
417
                    iso3166_to_check = (char *) "SP";
Matthias Clasen's avatar
Matthias Clasen committed
418
419
420
421
422
423
424
425
                }
              else
                {
                  script_to_check = strchr (iso639_to_check, '@');
                  if (script_to_check != NULL)
                    *script_to_check++ = '\0';
                  /* LANG_SERBIAN == LANG_CROATIAN, recognize just "sr" */
                  if (strcmp (iso639_to_check, "sr") == 0)
LRN's avatar
LRN committed
426
                    iso3166_to_check = (char *) "SP";
Matthias Clasen's avatar
Matthias Clasen committed
427
428
429
430
431
432
                }

              EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
            }
          g_free (p);
        }
Tor Lillqvist's avatar
Tor Lillqvist committed
433
      if (!setlocale_called)
Matthias Clasen's avatar
Matthias Clasen committed
434
        setlocale (LC_ALL, "");
Tor Lillqvist's avatar
Tor Lillqvist committed
435
#else
436
      if (!setlocale (LC_ALL, ""))
Matthias Clasen's avatar
Matthias Clasen committed
437
        g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
Tor Lillqvist's avatar
Tor Lillqvist committed
438
#endif
439
    }
440
441
}

442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
/* Return TRUE if module_to_check causes version conflicts.
 * If module_to_check is NULL, check the main module.
 */
static gboolean
_gtk_module_has_mixed_deps (GModule *module_to_check)
{
  GModule *module;
  gpointer func;
  gboolean result;

  if (!module_to_check)
    module = g_module_open (NULL, 0);
  else
    module = module_to_check;

  if (g_module_symbol (module, "gtk_progress_get_type", &func))
    result = TRUE;
  else if (g_module_symbol (module, "gtk_misc_get_type", &func))
    result = TRUE;
  else
    result = FALSE;

  if (!module_to_check)
    g_module_close (module);

  return result;
}

470
static void
Matthias Clasen's avatar
Matthias Clasen committed
471
do_pre_parse_initialization (void)
472
{
Benjamin Otte's avatar
Benjamin Otte committed
473
  const char *env_string;
474
  double slowdown;
Matthias Clasen's avatar
Matthias Clasen committed
475

476
477
478
479
  if (pre_initialized)
    return;

  pre_initialized = TRUE;
480

481
  if (_gtk_module_has_mixed_deps (NULL))
Matthias Clasen's avatar
Matthias Clasen committed
482
    g_error ("GTK 2/3 symbols detected. Using GTK 2/3 and GTK 4 in the same process is not supported");
483

484
  gdk_pre_parse ();
485

486
487
488
489
  debug_flags[0].flags = gdk_parse_debug_var ("GTK_DEBUG",
                                              gtk_debug_keys,
                                              G_N_ELEMENTS (gtk_debug_keys));
  any_display_debug_flags_set = debug_flags[0].flags > 0;
490

491
492
493
494
495
496
  env_string = g_getenv ("GTK_SLOWDOWN");
  if (env_string)
    {
      slowdown = g_ascii_strtod (env_string, NULL);
      _gtk_set_slowdown (slowdown);
    }
497
498
499

  /* Trigger fontconfig initialization early */
  pango_cairo_font_map_get_default ();
500
}
501

502
503
504
static void
gettext_initialization (void)
{
505
506
  setlocale_initialization ();

507
#ifdef ENABLE_NLS
508
509
  bindtextdomain (GETTEXT_PACKAGE, _gtk_get_localedir ());
  bindtextdomain (GETTEXT_PACKAGE "-properties", _gtk_get_localedir ());
510
511
512
513
#    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
#    endif
Matthias Clasen's avatar
Matthias Clasen committed
514
#endif
515
516
}

517
518
519
static void
default_display_notify_cb (GdkDisplayManager *dm)
{
520
  debug_flags[0].display = gdk_display_get_default ();
521
522
}

523
static void
Matthias Clasen's avatar
Matthias Clasen committed
524
do_post_parse_initialization (void)
525
{
526
  GdkDisplayManager *display_manager;
Matthias Clasen's avatar
Matthias Clasen committed
527
  gint64 before G_GNUC_UNUSED;
528

529
530
531
  if (gtk_initialized)
    return;

Matthias Clasen's avatar
Matthias Clasen committed
532
533
  before = GDK_PROFILER_CURRENT_TIME;

534
535
  gettext_initialization ();

536
#ifdef SIGPIPE
537
  signal (SIGPIPE, SIG_IGN);
538
#endif
539

540
  gtk_widget_set_default_direction (gtk_get_locale_direction ());
541

542
  gdk_event_init_types ();
Matthias Clasen's avatar
Matthias Clasen committed
543

544
  gsk_ensure_resources ();
545
  gsk_render_node_init_types ();
546
  _gtk_ensure_resources ();
547

Matthias Clasen's avatar
Matthias Clasen committed
548
549
  gdk_profiler_end_mark (before, "basic initialization", NULL);

550
  gtk_initialized = TRUE;
551

Matthias Clasen's avatar
Matthias Clasen committed
552
  before = GDK_PROFILER_CURRENT_TIME;
553
554
555
556
557
#ifdef G_OS_UNIX
  gtk_print_backends_init ();
#endif
  gtk_im_modules_init ();
  gtk_media_file_extension_init ();
Matthias Clasen's avatar
Matthias Clasen committed
558
  gdk_profiler_end_mark (before, "init modules", NULL);
559

Matthias Clasen's avatar
Matthias Clasen committed
560
  before = GDK_PROFILER_CURRENT_TIME;
561
562
  display_manager = gdk_display_manager_get ();
  if (gdk_display_manager_get_default_display (display_manager) != NULL)
563
    default_display_notify_cb (display_manager);
Matthias Clasen's avatar
Matthias Clasen committed
564
  gdk_profiler_end_mark (before, "create display", NULL);
565
566

  g_signal_connect (display_manager, "notify::default-display",
567
568
                    G_CALLBACK (default_display_notify_cb),
                    NULL);
569
570
}

571
#ifdef G_PLATFORM_WIN32
572
#undef gtk_init_check
573
#endif
574
575
576

/**
 * gtk_init_check:
577
 *
Matthias Clasen's avatar
Matthias Clasen committed
578
579
 * This function does the same work as gtk_init() with only a single
 * change: It does not terminate the program if the windowing system
580
 * can’t be initialized. Instead it returns %FALSE on failure.
581
 *
Matthias Clasen's avatar
Matthias Clasen committed
582
583
584
585
 * This way the application can fall back to some other means of
 * communication with the user - for example a curses or command line
 * interface.
 *
586
 * Returns: %TRUE if the windowing system has been successfully
Matthias Clasen's avatar
Matthias Clasen committed
587
 *   initialized, %FALSE otherwise
Matthias Clasen's avatar
Matthias Clasen committed
588
 */
589
gboolean
Matthias Clasen's avatar
Matthias Clasen committed
590
gtk_init_check (void)
591
{
592
593
  gboolean ret;

Matthias Clasen's avatar
Matthias Clasen committed
594
595
596
  if (gtk_initialized)
    return TRUE;

Matthias Clasen's avatar
Matthias Clasen committed
597
598
599
  if (gdk_profiler_is_running ())
    g_info ("Profiling is active");

Matthias Clasen's avatar
Matthias Clasen committed
600
601
602
  gettext_initialization ();

  if (!check_setugid ())
603
604
    return FALSE;

Matthias Clasen's avatar
Matthias Clasen committed
605
606
  do_pre_parse_initialization ();
  do_post_parse_initialization ();
Matthias Clasen's avatar
Matthias Clasen committed
607

608
  ret = gdk_display_open_default () != NULL;
609

610
  if (ret && (gtk_get_debug_flags () & GTK_DEBUG_INTERACTIVE))
611
612
613
    gtk_window_set_interactive_debugging (TRUE);

  return ret;
614
615
}

616
#ifdef G_PLATFORM_WIN32
617
#undef gtk_init
618
#endif
619

620
/**
Matthias Clasen's avatar
Matthias Clasen committed
621
 * gtk_init:
622
 *
Matthias Clasen's avatar
Matthias Clasen committed
623
 * Call this function before using any other GTK functions in your GUI
624
 * applications.  It will initialize everything needed to operate the
625
 * toolkit.
Matthias Clasen's avatar
Matthias Clasen committed
626
 *
Matthias Clasen's avatar
Matthias Clasen committed
627
628
 * If you are using `GtkApplication`, you don't have to call gtk_init()
 * or gtk_init_check(); the `GApplication::startup` handler
Matthias Clasen's avatar
Matthias Clasen committed
629
630
 * does it for you.
 *
631
632
633
634
 * This function will terminate your program if it was unable to
 * initialize the windowing system for some reason. If you want
 * your program to fall back to a textual interface you want to
 * call gtk_init_check() instead.
635
 *
Matthias Clasen's avatar
Matthias Clasen committed
636
 * GTK calls `signal (SIGPIPE, SIG_IGN)`
637
638
639
640
641
 * during initialization, to ignore SIGPIPE signals, since these are
 * almost never wanted in graphical applications. If you do need to
 * handle SIGPIPE for some reason, reset the handler after gtk_init(),
 * but notice that other libraries (e.g. libdbus or gvfs) might do
 * similar things.
642
 */
643
void
Matthias Clasen's avatar
Matthias Clasen committed
644
gtk_init (void)
645
{
Matthias Clasen's avatar
Matthias Clasen committed
646
  if (!gtk_init_check ())
647
    {
648
      const char *display_name_arg = NULL;
649
      if (display_name_arg == NULL)
Matthias Clasen's avatar
Matthias Clasen committed
650
        display_name_arg = getenv ("DISPLAY");
651
      g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
652
      exit (1);
653
    }
Elliot Lee's avatar
Elliot Lee committed
654
655
}

Fridrich Štrba's avatar
Fridrich Štrba committed
656
657
658
659
660
661
662
663
#ifdef G_OS_WIN32

/* This is relevant when building with gcc for Windows (MinGW),
 * where we want to be struct packing compatible with MSVC,
 * i.e. use the -mms-bitfields switch.
 * For Cygwin there should be no need to be compatible with MSVC,
 * so no need to use G_PLATFORM_WIN32.
 */
664
665
666
667
668
669

static void
check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
{
  if (sizeof_GtkWindow != sizeof (GtkWindow))
    g_error ("Incompatible build!\n"
Matthias Clasen's avatar
Matthias Clasen committed
670
671
             "The code using GTK thinks GtkWindow is of different\n"
             "size than it actually is in this build of GTK.\n"
Matthias Clasen's avatar
Matthias Clasen committed
672
673
674
             "On Windows, this probably means that you have compiled\n"
             "your code with gcc without the -mms-bitfields switch,\n"
             "or that you are using an unsupported compiler.");
675
676
}

Matthias Clasen's avatar
Matthias Clasen committed
677
/* In GTK 2.0 the GtkWindow struct actually is the same size in
678
 * gcc-compiled code on Win32 whether compiled with -fnative-struct or
Matthias Clasen's avatar
Matthias Clasen committed
679
680
 * not. Unfortunately this wan’t noticed until after GTK 2.0.1. So,
 * from GTK 2.0.2 on, check some other struct, too, where the use of
681
682
683
684
685
686
687
 * -fnative-struct still matters. GtkBox is one such.
 */
static void
check_sizeof_GtkBox (size_t sizeof_GtkBox)
{
  if (sizeof_GtkBox != sizeof (GtkBox))
    g_error ("Incompatible build!\n"
Matthias Clasen's avatar
Matthias Clasen committed
688
689
             "The code using GTK thinks GtkBox is of different\n"
             "size than it actually is in this build of GTK.\n"
Matthias Clasen's avatar
Matthias Clasen committed
690
691
692
             "On Windows, this probably means that you have compiled\n"
             "your code with gcc without the -mms-bitfields switch,\n"
             "or that you are using an unsupported compiler.");
693
694
695
696
697
698
}

/* These two functions might get more checks added later, thus pass
 * in the number of extra args.
 */
void
Chun-wei Fan's avatar
Chun-wei Fan committed
699
gtk_init_abi_check (int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
700
701
{
  check_sizeof_GtkWindow (sizeof_GtkWindow);
702
703
  if (num_checks >= 2)
    check_sizeof_GtkBox (sizeof_GtkBox);
Chun-wei Fan's avatar
Chun-wei Fan committed
704
  gtk_init ();
705
706
707
}

gboolean
Chun-wei Fan's avatar
Chun-wei Fan committed
708
gtk_init_check_abi_check (int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
709
710
{
  check_sizeof_GtkWindow (sizeof_GtkWindow);
711
712
  if (num_checks >= 2)
    check_sizeof_GtkBox (sizeof_GtkBox);
Chun-wei Fan's avatar
Chun-wei Fan committed
713
  return gtk_init_check ();
714
715
716
717
}

#endif

718
719
720
/**
 * gtk_is_initialized:
 *
Matthias Clasen's avatar
Matthias Clasen committed
721
 * Use this function to check if GTK has been initialized with gtk_init()
722
723
724
725
726
727
728
729
730
731
 * or gtk_init_check().
 *
 * Returns: the initialization status
 */
gboolean
gtk_is_initialized (void)
{
  return gtk_initialized;
}

732

733
734
735
736
737
738
739
740
741
742
/**
 * gtk_get_locale_direction:
 *
 * Get the direction of the current locale. This is the expected
 * reading direction for text and UI.
 *
 * This function depends on the current locale being set with
 * setlocale() and will default to setting the %GTK_TEXT_DIR_LTR
 * direction otherwise. %GTK_TEXT_DIR_NONE will never be returned.
 *
Matthias Clasen's avatar
Matthias Clasen committed
743
 * GTK sets the default text direction according to the locale
744
745
 * during gtk_init(), and you should normally use
 * gtk_widget_get_direction() or gtk_widget_get_default_direction()
Yuri Chornoivan's avatar
Yuri Chornoivan committed
746
 * to obtain the current direction.
747
748
 *
 * This function is only needed rare cases when the locale is
Matthias Clasen's avatar
Matthias Clasen committed
749
 * changed after GTK has already been initialized. In this case,
750
751
 * you can use it to update the default text direction as follows:
 *
752
 * |[<!-- language="C" -->
753
754
755
756
757
 * setlocale (LC_ALL, new_locale);
 * direction = gtk_get_locale_direction ();
 * gtk_widget_set_default_direction (direction);
 * ]|
 *
Matthias Clasen's avatar
Matthias Clasen committed
758
 * Returns: the `GtkTextDirection` of the current locale
759
760
761
762
763
764
765
766
767
 */
GtkTextDirection
gtk_get_locale_direction (void)
{
  /* Translate to default:RTL if you want your widgets
   * to be RTL, otherwise translate to default:LTR.
   * Do *not* translate it to "predefinito:LTR", if it
   * it isn't default:LTR or default:RTL it will not work
   */
Benjamin Otte's avatar
Benjamin Otte committed
768
  char             *e   = _("default:LTR");
769
770
  GtkTextDirection  dir = GTK_TEXT_DIR_LTR;

771
772
773
  if (g_strcmp0 (e, "default:RTL") == 0)
    dir = GTK_TEXT_DIR_RTL;
  else if (g_strcmp0 (e, "default:LTR") != 0)
774
    g_warning ("Whoever translated default:LTR did so wrongly. Defaulting to LTR.");
775
776
777
778

  return dir;
}

779
780
781
/**
 * gtk_get_default_language:
 *
Matthias Clasen's avatar
Matthias Clasen committed
782
783
 * Returns the `PangoLanguage` for the default language
 * currently in effect.
784
 *
Matthias Clasen's avatar
Matthias Clasen committed
785
786
787
788
789
790
791
792
793
 * Note that this can change over the life of an
 * application.
 *
 * The default language is derived from the current
 * locale. It determines, for example, whether GTK uses
 * the right-to-left or left-to-right text direction.
 *
 * This function is equivalent to
 * [func@Pango.Language.get_default].
Matthias Clasen's avatar
Matthias Clasen committed
794
795
 * See that function for details.
 *
Matthias Clasen's avatar
Matthias Clasen committed
796
797
 * Returns: (transfer none): the default language as a
 *   `PangoLanguage`
Matthias Clasen's avatar
Matthias Clasen committed
798
 */
799
800
801
PangoLanguage *
gtk_get_default_language (void)
{
802
  return pango_language_get_default ();
803
804
}

805
806
807
typedef struct {
  GMainLoop *store_loop;
  guint n_clipboards;
808
  guint timeout_id;
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
} ClipboardStore;

static void
clipboard_store_finished (GObject      *source,
                          GAsyncResult *result,
                          gpointer      data)
{
  ClipboardStore *store;
  GError *error = NULL;

  if (!gdk_clipboard_store_finish (GDK_CLIPBOARD (source), result, &error))
    {
      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
        {
          g_error_free (error);
          return;
        }

      g_error_free (error);
    }

  store = data;
  store->n_clipboards--;
  if (store->n_clipboards == 0)
    g_main_loop_quit (store->store_loop);
}

836
837
838
839
840
841
842
843
static gboolean
sync_timed_out_cb (ClipboardStore *store)
{
  store->timeout_id = 0;
  g_main_loop_quit (store->store_loop);
  return G_SOURCE_REMOVE;
}

844
845
846
void
gtk_main_sync (void)
{
847
848
849
  ClipboardStore store = { NULL, };
  GSList *displays, *l;
  GCancellable *cancel;
850

851
852
  /* Try storing all clipboard data we have */
  displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
853
854
855
  if (displays == NULL)
    return;

856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
  cancel = g_cancellable_new ();

  for (l = displays; l; l = l->next)
    {
      GdkDisplay *display = l->data;
      GdkClipboard *clipboard = gdk_display_get_clipboard (display);

      gdk_clipboard_store_async (clipboard,
                                 G_PRIORITY_HIGH,
                                 cancel,
                                 clipboard_store_finished,
                                 &store);
      store.n_clipboards++;
    }
  g_slist_free (displays);

  store.store_loop = g_main_loop_new (NULL, TRUE);
873
  store.timeout_id = g_timeout_add_seconds (10, (GSourceFunc) sync_timed_out_cb, &store);
874
  gdk_source_set_static_name_by_id (store.timeout_id, "[gtk] gtk_main_sync clipboard store timeout");
875
876

  if (g_main_loop_is_running (store.store_loop))
Emmanuele Bassi's avatar
Emmanuele Bassi committed
877
    g_main_loop_run (store.store_loop);
878

879
880
  g_cancellable_cancel (cancel);
  g_object_unref (cancel);
881
882
  g_clear_handle_id (&store.timeout_id, g_source_remove);
  g_clear_pointer (&store.store_loop, g_main_loop_unref);
883

884
885
  /* Synchronize the recent manager singleton */
  _gtk_recent_manager_sync ();
886
887
}

888
static GdkEvent *
889
rewrite_event_for_surface (GdkEvent  *event,
890
			   GdkSurface *new_surface)
891
{
Matthias Clasen's avatar
Matthias Clasen committed
892
  GdkEventType type;
893
  double x, y;
Matthias Clasen's avatar
Matthias Clasen committed
894
  double dx, dy;
895

Matthias Clasen's avatar
Matthias Clasen committed
896
897
898
  type = gdk_event_get_event_type (event);

  switch ((guint) type)
899
    {
Matthias Clasen's avatar
Matthias Clasen committed
900
901
902
903
904
905
906
907
908
909
910
911
912
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
    case GDK_MOTION_NOTIFY:
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
    case GDK_TOUCHPAD_SWIPE:
    case GDK_TOUCHPAD_PINCH:
      gdk_event_get_position (event, &x, &y);
      gdk_surface_translate_coordinates (gdk_event_get_surface (event), new_surface, &x, &y);
      break;
    default:
913
      x = y = 0;
Matthias Clasen's avatar
Matthias Clasen committed
914
      break;
915
    }
916

Matthias Clasen's avatar
Matthias Clasen committed
917
  switch ((guint) type)
918
919
920
    {
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
921
      return gdk_button_event_new (type,
922
                                   new_surface,
Matthias Clasen's avatar
Matthias Clasen committed
923
924
925
926
927
                                   gdk_event_get_device (event),
                                   gdk_event_get_device_tool (event),
                                   gdk_event_get_time (event),
                                   gdk_event_get_modifier_state (event),
                                   gdk_button_event_get_button (event),
928
                                   x, y,
929
                                   gdk_event_dup_axes (event));
930
    case GDK_MOTION_NOTIFY:
931
      return gdk_motion_event_new (new_surface,
Matthias Clasen's avatar
Matthias Clasen committed
932
933
934
935
                                   gdk_event_get_device (event),
                                   gdk_event_get_device_tool (event),
                                   gdk_event_get_time (event),
                                   gdk_event_get_modifier_state (event),
936
                                   x, y,
937
                                   gdk_event_dup_axes (event));
938
939
940
941
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
942
      return gdk_touch_event_new (type,
Matthias Clasen's avatar
Matthias Clasen committed
943
                                  gdk_event_get_event_sequence (event),
944
                                  new_surface,
Matthias Clasen's avatar
Matthias Clasen committed
945
946
947
                                  gdk_event_get_device (event),
                                  gdk_event_get_time (event),
                                  gdk_event_get_modifier_state (event),
948
                                  x, y,
949
                                  gdk_event_dup_axes (event),
Matthias Clasen's avatar
Matthias Clasen committed
950
                                  gdk_touch_event_get_emulating_pointer (event));
951
    case GDK_TOUCHPAD_SWIPE:
Matthias Clasen's avatar
Matthias Clasen committed
952
      gdk_touchpad_event_get_deltas (event, &dx, &dy);
953
      return gdk_touchpad_event_new_swipe (new_surface,
Matthias Clasen's avatar
Matthias Clasen committed
954
955
956
957
                                           gdk_event_get_device (event),
                                           gdk_event_get_time (event),
                                           gdk_event_get_modifier_state (event),
                                           gdk_touchpad_event_get_gesture_phase (event),
958
                                           x, y,
Matthias Clasen's avatar
Matthias Clasen committed
959
960
                                           gdk_touchpad_event_get_n_fingers (event),
                                           dx, dy);
961
    case GDK_TOUCHPAD_PINCH:
Matthias Clasen's avatar
Matthias Clasen committed
962
      gdk_touchpad_event_get_deltas (event, &dx, &dy);
963
      return gdk_touchpad_event_new_pinch (new_surface,
Matthias Clasen's avatar
Matthias Clasen committed
964
965
966
967
                                           gdk_event_get_device (event),
                                           gdk_event_get_time (event),
                                           gdk_event_get_modifier_state (event),
                                           gdk_touchpad_event_get_gesture_phase (event),
968
                                           x, y,
Matthias Clasen's avatar
Matthias Clasen committed
969
970
                                           gdk_touchpad_event_get_n_fingers (event),
                                           dx, dy,
971
972
                                           gdk_touchpad_event_get_pinch_scale (event),
                                           gdk_touchpad_event_get_pinch_angle_delta (event));
973
    default:
974
      break;
975
976
    }

977
  return NULL;
978
979
980
981
}

/* If there is a pointer or keyboard grab in effect with owner_events = TRUE,
 * then what X11 does is deliver the event normally if it was going to this
982
 * client, otherwise, delivers it in terms of the grab surface. This function
983
984
985
986
987
988
989
 * rewrites events to the effect that events going to the same window group
 * are delivered normally, otherwise, the event is delivered in terms of the
 * grab window.
 */
static GdkEvent *
rewrite_event_for_grabs (GdkEvent *event)
{
990
  GdkSurface *grab_surface;
991
  GtkWidget *event_widget, *grab_widget;
992
  gboolean owner_events;
993
  GdkDisplay *display;
994
  GdkDevice *device;
995

Matthias Clasen's avatar
Matthias Clasen committed
996
  switch ((guint) gdk_event_get_event_type (event))
997
998
999
1000
1001
1002
1003
1004
1005
    {
    case GDK_SCROLL:
    case GDK_BUTTON_PRESS:
    case GDK_BUTTON_RELEASE:
    case GDK_MOTION_NOTIFY:
    case GDK_PROXIMITY_IN:
    case GDK_PROXIMITY_OUT:
    case GDK_KEY_PRESS:
    case GDK_KEY_RELEASE:
1006
1007
1008
1009
    case GDK_TOUCH_BEGIN:
    case GDK_TOUCH_UPDATE:
    case GDK_TOUCH_END:
    case GDK_TOUCH_CANCEL:
1010
1011
    case GDK_TOUCHPAD_SWIPE:
    case GDK_TOUCHPAD_PINCH:
Matthias Clasen's avatar
Matthias Clasen committed
1012
      display = gdk_event_get_display (event);
1013
1014
      device = gdk_event_get_device (event);

1015
      if (!gdk_device_grab_info (display, device, &grab_surface, &owner_events) ||
Matthias Clasen's avatar
Matthias Clasen committed
1016
          !owner_events)
1017
        return NULL;
1018
1019
1020
1021
1022
1023
      break;
    default:
      return NULL;
    }

  event_widget = gtk_get_event_widget (event);
1024
  grab_widget = GTK_WIDGET (gtk_native_get_for_surface (grab_surface));
1025
1026
1027

  if (grab_widget &&
      gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
1028
    return rewrite_event_for_surface (event, grab_surface);
1029
1030
1031
1032
  else
    return NULL;
}

Matthias Clasen's avatar
Matthias Clasen committed
1033
1034
1035
1036
static GdkEvent *
rewrite_event_for_toplevel (GdkEvent *event)
{
  GdkSurface *surface;
1037
  GdkEventType event_type;
1038
  GdkTranslatedKey *key, *key_no_lock;
Matthias Clasen's avatar
Matthias Clasen committed
1039
1040
1041
1042
1043

  surface = gdk_event_get_surface (event);
  if (!surface->parent)
    return NULL;

1044
1045
1046
1047
1048
  event_type = gdk_event_get_event_type (event);
  if (event_type != GDK_KEY_PRESS &&
      event_type != GDK_KEY_RELEASE)
    return NULL;

Matthias Clasen's avatar
Matthias Clasen committed
1049
1050
1051
  while (surface->parent)
    surface = surface->parent;

1052
1053
  key = gdk_key_event_get_translated_key (event, FALSE);
  key_no_lock = gdk_key_event_get_translated_key (event, TRUE);
1054
1055

  return gdk_key_event_new (gdk_event_get_event_type (event),
Matthias Clasen's avatar
Matthias Clasen committed
1056
1057
1058
1059
1060
1061
                            surface,
                            gdk_event_get_device (event),
                            gdk_event_get_time (event),
                            gdk_key_event_get_keycode (event),
                            gdk_event_get_modifier_state (event),
                            gdk_key_event_is_modifier (event),
1062
                            key, key_no_lock);
Matthias Clasen's avatar
Matthias Clasen committed
1063
1064
}

Matthias Clasen's avatar
Matthias Clasen committed
1065
static gboolean
1066
1067
1068
1069
translate_event_coordinates (GdkEvent  *event,
                             double    *x,
                             double    *y,
                             GtkWidget *widget)
1070
{
1071
  GtkWidget *event_widget;
1072
  GtkNative *native;
1073
1074
  graphene_point_t p;
  double event_x, event_y;
1075
  double native_x, native_y;
1076

1077
  *x = *y = 0;
1078

Matthias Clasen's avatar
Matthias Clasen committed
1079
  if (!gdk_event_get_position (event, &event_x, &event_y))
1080
    return FALSE;
1081

1082
  event_widget = gtk_get_event_widget (event);
1083
1084
1085
1086
1087
  native = gtk_widget_get_native (event_widget);

  gtk_native_get_surface_transform (GTK_NATIVE (native), &native_x, &native_y);
  event_x -= native_x;
  event_y -= native_y;
1088

1089
1090
1091
1092
1093
  if (!gtk_widget_compute_point (event_widget,
                                 widget,
                                 &GRAPHENE_POINT_INIT (event_x, event_y),
                                 &p))
    return FALSE;
1094