gtkmain.c 67.7 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
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
15 16 17
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
Elliot Lee's avatar
Elliot Lee committed
18
 */
19 20

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

27
#include "config.h"
28

Matthias Clasen's avatar
2.5.3  
Matthias Clasen committed
29
#include <glib.h>
30 31
#include "gdkconfig.h"

32
#include <locale.h>
Robert Brady's avatar
Robert Brady committed
33

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

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

Tor Lillqvist's avatar
Tor Lillqvist committed
48 49
#include "gtkintl.h"

50
#include "gtkaccelmap.h"
51
#include "gtkbox.h"
52
#include "gtkclipboard.h"
53
#include "gtkdnd.h"
54
#include "gtkversion.h"
Elliot Lee's avatar
Elliot Lee committed
55
#include "gtkmain.h"
56
#include "gtkmodules.h"
Elliot Lee's avatar
Elliot Lee committed
57
#include "gtkrc.h"
58
#include "gtkrecentmanager.h"
Elliot Lee's avatar
Elliot Lee committed
59
#include "gtkselection.h"
60
#include "gtksettings.h"
Elliot Lee's avatar
Elliot Lee committed
61 62
#include "gtkwidget.h"
#include "gtkwindow.h"
Kristian Rietveld's avatar
Kristian Rietveld committed
63
#include "gtktooltip.h"
64
#include "gtkdebug.h"
65 66
#include "gtkmenu.h"
#include "gdk/gdkkeysyms.h"
Elliot Lee's avatar
Elliot Lee committed
67

68 69
#include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */

70 71
#ifdef G_OS_WIN32

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
static HMODULE gtk_dll;

BOOL WINAPI
DllMain (HINSTANCE hinstDLL,
	 DWORD     fdwReason,
	 LPVOID    lpvReserved)
{
  switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
      gtk_dll = (HMODULE) hinstDLL;
      break;
    }

  return TRUE;
}
88

89 90 91
/* These here before inclusion of gtkprivate.h so that the original
 * GTK_LIBDIR and GTK_LOCALEDIR definitions are seen. Yeah, this is a
 * bit sucky.
92
 */
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
const gchar *
_gtk_get_libdir (void)
{
  static char *gtk_libdir = NULL;
  if (gtk_libdir == NULL)
    {
      gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
      gchar *slash = strrchr (root, '\\');
      if (g_ascii_strcasecmp (slash + 1, ".libs") == 0)
	gtk_libdir = GTK_LIBDIR;
      else
	gtk_libdir = g_build_filename (root, "lib", NULL);
      g_free (root);
    }

  return gtk_libdir;
}

111 112 113 114 115 116 117
const gchar *
_gtk_get_localedir (void)
{
  static char *gtk_localedir = NULL;
  if (gtk_localedir == NULL)
    {
      const gchar *p;
118
      gchar *root, *temp;
119 120 121 122 123 124 125 126 127 128
      
      /* GTK_LOCALEDIR ends in either /lib/locale or
       * /share/locale. Scan for that slash.
       */
      p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
      while (*--p != '/')
	;
      while (*--p != '/')
	;

129 130 131
      root = g_win32_get_package_installation_directory_of_module (gtk_dll);
      temp = g_build_filename (root, p, NULL);
      g_free (root);
132 133 134 135 136 137 138 139 140 141 142 143 144 145

      /* gtk_localedir is passed to bindtextdomain() which isn't
       * UTF-8-aware.
       */
      gtk_localedir = g_win32_locale_filename_from_utf8 (temp);
      g_free (temp);
    }
  return gtk_localedir;
}

#endif

#include "gtkprivate.h"

Elliot Lee's avatar
Elliot Lee committed
146 147
/* Private type definitions
 */
148 149 150
typedef struct _GtkInitFunction		 GtkInitFunction;
typedef struct _GtkQuitFunction		 GtkQuitFunction;
typedef struct _GtkKeySnooperData	 GtkKeySnooperData;
Elliot Lee's avatar
Elliot Lee committed
151 152 153 154 155 156 157

struct _GtkInitFunction
{
  GtkFunction function;
  gpointer data;
};

158 159
struct _GtkQuitFunction
{
160
  guint id;
161 162 163 164
  guint main_level;
  GtkCallbackMarshal marshal;
  GtkFunction function;
  gpointer data;
Michael Natterer's avatar
Michael Natterer committed
165
  GDestroyNotify destroy;
166 167
};

168 169 170 171
struct _GtkKeySnooperData
{
  GtkKeySnoopFunc func;
  gpointer func_data;
172
  guint id;
173 174
};

175 176 177 178
static gint  gtk_quit_invoke_function	 (GtkQuitFunction    *quitf);
static void  gtk_quit_destroy		 (GtkQuitFunction    *quitf);
static gint  gtk_invoke_key_snoopers	 (GtkWidget	     *grab_widget,
					  GdkEvent	     *event);
179

180 181
static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);

Tim Janik's avatar
Tim Janik committed
182
static guint gtk_main_loop_level = 0;
Matthias Clasen's avatar
Matthias Clasen committed
183
static gint pre_initialized = FALSE;
184
static gint gtk_initialized = FALSE;
185
static GList *current_events = NULL;
Elliot Lee's avatar
Elliot Lee committed
186

187 188
static GSList *main_loops = NULL;      /* stack of currently executing main loops */

189
static GList *init_functions = NULL;	   /* A list of init functions.
Elliot Lee's avatar
Elliot Lee committed
190
					    */
191 192
static GList *quit_functions = NULL;	   /* A list of quit functions.
					    */
193 194
static GSList *key_snoopers = NULL;

195
static guint debug_flags = 0;		   /* Global GTK debug flag */
196 197

#ifdef G_ENABLE_DEBUG
198
static const GDebugKey gtk_debug_keys[] = {
199
  {"misc", GTK_DEBUG_MISC},
200
  {"plugsocket", GTK_DEBUG_PLUGSOCKET},
201
  {"text", GTK_DEBUG_TEXT},
Havoc Pennington's avatar
Havoc Pennington committed
202
  {"tree", GTK_DEBUG_TREE},
203
  {"updates", GTK_DEBUG_UPDATES},
204
  {"keybindings", GTK_DEBUG_KEYBINDINGS},
205
  {"multihead", GTK_DEBUG_MULTIHEAD},
206
  {"modules", GTK_DEBUG_MODULES},
207
  {"geometry", GTK_DEBUG_GEOMETRY},
208
  {"icontheme", GTK_DEBUG_ICONTHEME},
Johan Dahlin's avatar
Johan Dahlin committed
209
  {"printing", GTK_DEBUG_PRINTING},
210
  {"builder", GTK_DEBUG_BUILDER},
211
  {"size-request", GTK_DEBUG_SIZE_REQUEST},
212 213
};
#endif /* G_ENABLE_DEBUG */
Elliot Lee's avatar
Elliot Lee committed
214

215
/**
216
 * gtk_get_major_version:
217 218 219 220 221 222 223 224 225
 *
 * Returns the major version number of the GTK+ library.  (e.g. in GTK+ version
 * 3.1.5 this is 3.) 
 *
 * This function is in the library, so it represents the GTK+ library
 * your code is running against. Contrast with the #GTK_MAJOR_VERSION
 * macro, which represents the major version of the GTK+ headers you
 * have included when compiling your code.
 *
226 227 228
 * Returns: the major version number of the GTK+ library.
 *
 * Since: 3.0
229 230
 */
guint
231
gtk_get_major_version (void)
232 233 234 235 236
{
  return GTK_MAJOR_VERSION;
}

/**
237
 * gtk_get_minor_version:
238 239 240 241 242 243 244 245 246
 *
 * Returns the minor version number of the GTK+ library.  (e.g. in GTK+ version
 * 3.1.5 this is 1.) 
 *
 * This function is in the library, so it represents the GTK+ library
 * your code is are running against. Contrast with the
 * #GTK_MINOR_VERSION macro, which represents the minor version of the
 * GTK+ headers you have included when compiling your code.
 *
247 248 249
 * Returns: the minor version number of the GTK+ library.
 *
 * Since: 3.0
250 251
 */
guint
252
gtk_get_minor_version (void)
253 254 255 256 257
{
  return GTK_MINOR_VERSION;
}

/**
258
 * gtk_get_micro_version:
259 260 261 262 263 264 265 266 267
 *
 * Returns the micro version number of the GTK+ library.  (e.g. in GTK+ version
 * 3.1.5 this is 5.) 
 *
 * This function is in the library, so it represents the GTK+ library
 * your code is are running against. Contrast with the
 * #GTK_MICRO_VERSION macro, which represents the micro version of the
 * GTK+ headers you have included when compiling your code.
 *
268 269 270
 * Returns: the micro version number of the GTK+ library.
 *
 * Since: 3.0
271 272
 */
guint
273
gtk_get_micro_version (void)
274 275 276 277 278
{
  return GTK_MICRO_VERSION;
}

/**
279
 * gtk_get_binary_age:
280 281 282 283 284 285 286
 *
 * Returns the binary age as passed to
 * <application>libtool</application> when building the GTK+ library
 * the process is running against. If
 * <application>libtool</application> means nothing to you, don't
 * worry about it.
 *
287 288 289
 * Returns: the binary age of the GTK+ library.
 *
 * Since: 3.0
290 291
 */
guint
292
gtk_get_binary_age (void)
293 294 295 296 297
{
  return GTK_BINARY_AGE;
}

/**
298
 * gtk_get_interface_age:
299 300 301 302 303 304 305
 *
 * Returns the interface age as passed to
 * <application>libtool</application> when building the GTK+ library
 * the process is running against. If
 * <application>libtool</application> means nothing to you, don't
 * worry about it.
 *
306 307 308
 * Returns: the interface age of the GTK+ library.
 *
 * Since: 3.0
309 310
 */
guint
311
gtk_get_interface_age (void)
312 313 314 315
{
  return GTK_INTERFACE_AGE;
}

316 317 318
/**
 * gtk_check_version:
 * @required_major: the required major version.
319 320
 * @required_minor: the required minor version.
 * @required_micro: the required micro version.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
 * 
 * Checks that the GTK+ library in use is compatible with the
 * given version. Generally you would pass in the constants
 * #GTK_MAJOR_VERSION, #GTK_MINOR_VERSION, #GTK_MICRO_VERSION
 * as the three arguments to this function; that produces
 * a check that the library in use is compatible with
 * the version of GTK+ the application or module was compiled
 * against.
 *
 * Compatibility is defined by two things: first the version
 * of the running library is newer than the version
 * @required_major.required_minor.@required_micro. Second
 * the running library must be binary compatible with the
 * version @required_major.required_minor.@required_micro
 * (same major version.)
 *
 * This function is primarily for GTK+ modules; the module
 * can call this function to check that it wasn't loaded
 * into an incompatible version of GTK+. However, such a
 * a check isn't completely reliable, since the module may be
 * linked against an old version of GTK+ and calling the
 * old version of gtk_check_version(), but still get loaded
 * into an application using a newer version of GTK+.
 *
 * Return value: %NULL if the GTK+ library is compatible with the
 *   given version, or a string describing the version mismatch.
 *   The returned string is owned by GTK+ and should not be modified
 *   or freed.
 **/
350
const gchar*
351 352 353 354
gtk_check_version (guint required_major,
		   guint required_minor,
		   guint required_micro)
{
355 356 357
  gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
  gint required_effective_micro = 100 * required_minor + required_micro;

358
  if (required_major > GTK_MAJOR_VERSION)
359
    return "Gtk+ version too old (major mismatch)";
360
  if (required_major < GTK_MAJOR_VERSION)
361
    return "Gtk+ version too new (major mismatch)";
362
  if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
363
    return "Gtk+ version too new (micro mismatch)";
364
  if (required_effective_micro > gtk_effective_micro)
365
    return "Gtk+ version too old (micro mismatch)";
366 367 368
  return NULL;
}

Owen Taylor's avatar
Owen Taylor committed
369 370 371 372 373 374 375 376 377 378
/* This checks to see if the process is running suid or sgid
 * at the current time. If so, we don't allow GTK+ to be initialized.
 * 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
 * don't use issetugid() on BSD or prctl (PR_GET_DUMPABLE).
 */
static gboolean
check_setugid (void)
{
379
/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
Hans Breuer's avatar
Hans Breuer committed
380
#ifndef G_OS_WIN32
Owen Taylor's avatar
Owen Taylor committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
  uid_t ruid, euid, suid; /* Real, effective and saved user ID's */
  gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */
  
#ifdef HAVE_GETRESUID
  /* These aren't in the header files, so we prototype them here.
   */
  int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
  int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);

  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"
		 "This is not a supported use of GTK+. You must create a helper\n"
		 "program instead. For further details, see:\n\n"
		 "    http://www.gtk.org/setuid.html\n\n"
		 "Refusing to initialize GTK+.");
      exit (1);
    }
Hans Breuer's avatar
Hans Breuer committed
410
#endif
Owen Taylor's avatar
Owen Taylor committed
411 412 413
  return TRUE;
}

Tor Lillqvist's avatar
Tor Lillqvist committed
414 415
#ifdef G_OS_WIN32

416 417 418 419 420
const gchar *
_gtk_get_datadir (void)
{
  static char *gtk_datadir = NULL;
  if (gtk_datadir == NULL)
421 422 423 424 425
    {
      gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
      gtk_datadir = g_build_filename (root, "share", NULL);
      g_free (root);
    }
426 427 428 429

  return gtk_datadir;
}

Tor Lillqvist's avatar
Tor Lillqvist committed
430 431 432 433 434
const gchar *
_gtk_get_sysconfdir (void)
{
  static char *gtk_sysconfdir = NULL;
  if (gtk_sysconfdir == NULL)
435 436 437 438 439
    {
      gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
      gtk_sysconfdir = g_build_filename (root, "etc", NULL);
      g_free (root);
    }
Tor Lillqvist's avatar
Tor Lillqvist committed
440 441 442 443 444 445 446 447 448

  return gtk_sysconfdir;
}

const gchar *
_gtk_get_data_prefix (void)
{
  static char *gtk_data_prefix = NULL;
  if (gtk_data_prefix == NULL)
449
    gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
Tor Lillqvist's avatar
Tor Lillqvist committed
450 451 452 453 454 455

  return gtk_data_prefix;
}

#endif /* G_OS_WIN32 */

456 457 458 459 460
static gboolean do_setlocale = TRUE;

/**
 * gtk_disable_setlocale:
 * 
Matthias Clasen's avatar
Matthias Clasen committed
461 462
 * Prevents gtk_init(), gtk_init_check(), gtk_init_with_args() and
 * gtk_parse_args() from automatically
463 464 465 466
 * calling <literal>setlocale (LC_ALL, "")</literal>. You would 
 * want to use this function if you wanted to set the locale for 
 * your program to something other than the user's locale, or if 
 * you wanted to set different values for different locale categories.
467 468 469
 *
 * Most programs should not need to call this function.
 **/
470
void
471 472
gtk_disable_setlocale (void)
{
Matthias Clasen's avatar
Matthias Clasen committed
473
  if (pre_initialized)
474 475 476 477 478
    g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
    
  do_setlocale = FALSE;
}

479
#ifdef G_PLATFORM_WIN32
480
#undef gtk_init_check
481
#endif
482

483
static GString *gtk_modules_string = NULL;
484
static gboolean g_fatal_warnings = FALSE;
485 486 487 488

#ifdef G_ENABLE_DEBUG
static gboolean
gtk_arg_debug_cb (const char *key, const char *value, gpointer user_data)
Elliot Lee's avatar
Elliot Lee committed
489
{
490 491 492
  debug_flags |= g_parse_debug_string (value,
				       gtk_debug_keys,
				       G_N_ELEMENTS (gtk_debug_keys));
493

494 495
  return TRUE;
}
Tim Janik's avatar
Tim Janik committed
496

497 498 499
static gboolean
gtk_arg_no_debug_cb (const char *key, const char *value, gpointer user_data)
{
500 501 502
  debug_flags &= ~g_parse_debug_string (value,
					gtk_debug_keys,
					G_N_ELEMENTS (gtk_debug_keys));
503 504

  return TRUE;
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
}
#endif /* G_ENABLE_DEBUG */

static gboolean
gtk_arg_module_cb (const char *key, const char *value, gpointer user_data)
{
  if (value && *value)
    {
      if (gtk_modules_string)
	g_string_append_c (gtk_modules_string, G_SEARCHPATH_SEPARATOR);
      else
	gtk_modules_string = g_string_new (NULL);
      
      g_string_append (gtk_modules_string, value);
    }

  return TRUE;
}

Matthias Clasen's avatar
Matthias Clasen committed
524
static const GOptionEntry gtk_args[] = {
525 526 527
  { "gtk-module",       0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_module_cb,   
    /* Description of --gtk-module=MODULES in --help output */ N_("Load additional GTK+ modules"), 
    /* Placeholder in --gtk-module=MODULES in --help output */ N_("MODULES") },
528
  { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, 
529
    /* Description of --g-fatal-warnings in --help output */   N_("Make all warnings fatal"), NULL },
530
#ifdef G_ENABLE_DEBUG
531 532 533 534 535 536 537
  { "gtk-debug",        0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_debug_cb,    
    /* Description of --gtk-debug=FLAGS in --help output */    N_("GTK+ debugging flags to set"), 
    /* Placeholder in --gtk-debug=FLAGS in --help output */    N_("FLAGS") },
  { "gtk-no-debug",     0, 0, G_OPTION_ARG_CALLBACK, gtk_arg_no_debug_cb, 
    /* Description of --gtk-no-debug=FLAGS in --help output */ N_("GTK+ debugging flags to unset"), 
    /* Placeholder in --gtk-no-debug=FLAGS in --help output */ N_("FLAGS") },
#endif 
538 539 540
  { NULL }
};

Tor Lillqvist's avatar
Tor Lillqvist committed
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629
#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 &&
	  ((iso3166_to_check != NULL &&
	    strcmp (iso3166, iso3166_to_check) == 0) ||
	   (iso3166_to_check == NULL &&
	    SUBLANGID (LANGIDFROMLCID (lcid)) == SUBLANG_DEFAULT)))
	{
	  char language[100], country[100];
	  char locale[300];

	  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;
		    }
		}
	      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;
		    }
		}
	    }

	  SetThreadLocale (lcid);

	  if (GetLocaleInfo (lcid, LOCALE_SENGLANGUAGE, language, sizeof (language)) &&
	      GetLocaleInfo (lcid, LOCALE_SENGCOUNTRY, country, sizeof (country)))
	    {
	      strcpy (locale, language);
	      strcat (locale, "_");
	      strcat (locale, country);

	      if (setlocale (LC_ALL, locale) != NULL)
		setlocale_called = TRUE;
	    }

	  return FALSE;
	}
    }

  return TRUE;
}
  
#endif

630
static void
631
setlocale_initialization (void)
632
{
633
  static gboolean initialized = FALSE;
634

635
  if (initialized)
Matthias Clasen's avatar
Matthias Clasen committed
636
    return;
637
  initialized = TRUE;
Matthias Clasen's avatar
Matthias Clasen committed
638

639
  if (do_setlocale)
640
    {
Tor Lillqvist's avatar
Tor Lillqvist committed
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697
#ifdef G_OS_WIN32
      /* If some of the POSIXish environment variables are set, set
       * the Win32 thread locale correspondingly.
       */ 
      char *p = getenv ("LC_ALL");
      if (p == NULL)
	p = getenv ("LANG");

      if (p != NULL)
	{
	  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)
		    iso3166_to_check = "SP";
		}
	      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)
		    iso3166_to_check = "SP";
		}

	      EnumSystemLocales (enum_locale_proc, LCID_SUPPORTED);
	    }
	  g_free (p);
	}
      if (!setlocale_called)
	setlocale (LC_ALL, "");
#else
698 699
      if (!setlocale (LC_ALL, ""))
	g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
Tor Lillqvist's avatar
Tor Lillqvist committed
700
#endif
701
    }
702 703
}

704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
static void
check_mixed_deps (void)
{
  GModule *module;
  gpointer func;

  module = g_module_open (NULL, 0);

  if (g_module_symbol (module, "gtk_progress_get_type", &func))
    {
      g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
    }

  g_module_close (module);
}

720 721 722 723 724 725 726 727 728 729
static void
do_pre_parse_initialization (int    *argc,
			     char ***argv)
{
  const gchar *env_string;
  
  if (pre_initialized)
    return;

  pre_initialized = TRUE;
730

731 732
  check_mixed_deps ();

Matthias Clasen's avatar
Matthias Clasen committed
733
  gdk_pre_parse_libgtk_only ();
Owen Taylor's avatar
Owen Taylor committed
734
  gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
735
  
736
#ifdef G_ENABLE_DEBUG
Matthias Clasen's avatar
Matthias Clasen committed
737
  env_string = g_getenv ("GTK_DEBUG");
738 739
  if (env_string != NULL)
    {
740 741 742
      debug_flags = g_parse_debug_string (env_string,
					  gtk_debug_keys,
					  G_N_ELEMENTS (gtk_debug_keys));
743 744
      env_string = NULL;
    }
745
#endif	/* G_ENABLE_DEBUG */
746

Matthias Clasen's avatar
Matthias Clasen committed
747
  env_string = g_getenv ("GTK_MODULES");
748
  if (env_string)
749
    gtk_modules_string = g_string_new (env_string);
750
}
751

752 753 754
static void
gettext_initialization (void)
{
755 756
  setlocale_initialization ();

757 758 759 760 761 762 763 764 765 766
#ifdef ENABLE_NLS
  bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
  bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
#    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
  bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8");
#    endif
#endif  
}

767 768 769 770
static void
do_post_parse_initialization (int    *argc,
			      char ***argv)
{
771 772 773
  if (gtk_initialized)
    return;

774 775
  gettext_initialization ();

776
#ifdef SIGPIPE
777
  signal (SIGPIPE, SIG_IGN);
778
#endif
779

780 781 782 783 784 785 786 787 788
  if (g_fatal_warnings)
    {
      GLogLevelFlags fatal_mask;

      fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
      fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
      g_log_set_always_fatal (fatal_mask);
    }

789
  if (debug_flags & GTK_DEBUG_UPDATES)
Havoc Pennington's avatar
Havoc Pennington committed
790
    gdk_window_set_debug_updates (TRUE);
791

792 793
  {
  /* Translate to default:RTL if you want your widgets
Robert Brady's avatar
Robert Brady committed
794 795 796
   * 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 
797 798
   */
    char *e = _("default:LTR");
Matthias Clasen's avatar
Matthias Clasen committed
799
    if (strcmp (e, "default:RTL")==0) 
800
      gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
Matthias Clasen's avatar
Matthias Clasen committed
801
    else if (strcmp (e, "default:LTR"))
802 803 804
      g_warning ("Whoever translated default:LTR did so wrongly.\n");
  }

805 806 807 808
  /* do what the call to gtk_type_init() used to do */
  g_type_init ();

  _gtk_accel_map_init ();
809
  _gtk_rc_init ();
810

Elliot Lee's avatar
Elliot Lee committed
811 812
  /* Set the 'initialized' flag.
   */
813
  gtk_initialized = TRUE;
814

815 816
  /* load gtk modules */
  if (gtk_modules_string)
817
    {
818 819
      _gtk_modules_init (argc, argv, gtk_modules_string->str);
      g_string_free (gtk_modules_string, TRUE);
820
    }
821 822 823 824
  else
    {
      _gtk_modules_init (argc, argv, NULL);
    }
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
}


typedef struct
{
  gboolean open_default_display;
} OptionGroupInfo;

static gboolean
pre_parse_hook (GOptionContext *context,
		GOptionGroup   *group,
		gpointer	data,
		GError        **error)
{
  do_pre_parse_initialization (NULL, NULL);
  
  return TRUE;
}

static gboolean
post_parse_hook (GOptionContext *context,
		 GOptionGroup   *group,
		 gpointer	data,
		 GError        **error)
{
  OptionGroupInfo *info = data;

  
  do_post_parse_initialization (NULL, NULL);
  
  if (info->open_default_display)
856 857 858
    {
      if (gdk_display_open_default_libgtk_only () == NULL)
	{
859
	  const char *display_name = gdk_get_display_arg_name ();
860 861 862
	  g_set_error (error, 
		       G_OPTION_ERROR, 
		       G_OPTION_ERROR_FAILED,
863
		       _("Cannot open display: %s"),
864
		       display_name ? display_name : "" );
865 866 867 868 869 870
	  
	  return FALSE;
	}
    }

  return TRUE;
871 872 873
}


874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895
/**
 * gtk_get_debug_flags:
 *
 * Returns the GTK+ debug flags setting.
 */
guint
gtk_get_debug_flags (void)
{
  return debug_flags;
}

/**
 * gtk_set_debug_flags:
 *
 * Sets the GTK+ debug flags.
 */
void
gtk_set_debug_flags (guint flags)
{
  debug_flags = flags;
}

Matthias Clasen's avatar
Matthias Clasen committed
896 897 898 899 900 901 902 903 904 905
/**
 * gtk_get_option_group:
 * @open_default_display: whether to open the default display 
 *    when parsing the commandline arguments
 * 
 * Returns a #GOptionGroup for the commandline arguments recognized
 * by GTK+ and GDK. You should add this group to your #GOptionContext 
 * with g_option_context_add_group(), if you are using 
 * g_option_context_parse() to parse your commandline arguments.
 *
906
 * Returns: a #GOptionGroup for the commandline arguments recognized
Matthias Clasen's avatar
Matthias Clasen committed
907 908 909 910
 *   by GTK+
 *
 * Since: 2.6
 */
911 912 913 914 915 916
GOptionGroup *
gtk_get_option_group (gboolean open_default_display)
{
  GOptionGroup *group;
  OptionGroupInfo *info;

917 918
  gettext_initialization ();

919 920 921 922 923 924 925 926
  info = g_new0 (OptionGroupInfo, 1);
  info->open_default_display = open_default_display;
  
  group = g_option_group_new ("gtk", _("GTK+ Options"), _("Show GTK+ Options"), info, g_free);
  g_option_group_set_parse_hooks (group, pre_parse_hook, post_parse_hook);

  gdk_add_option_entries_libgtk_only (group);
  g_option_group_add_entries (group, gtk_args);
927
  g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
928 929 930 931
  
  return group;
}

Matthias Clasen's avatar
Matthias Clasen committed
932 933 934 935 936
/**
 * gtk_init_with_args:
 * @argc: a pointer to the number of command line arguments.
 * @argv: a pointer to the array of command line arguments.
 * @parameter_string: a string which is displayed in
937
 *    the first line of <option>--help</option> output, after
Matthias Clasen's avatar
Matthias Clasen committed
938 939 940 941 942
 *    <literal><replaceable>programname</replaceable> [OPTION...]</literal>
 * @entries: a %NULL-terminated array of #GOptionEntry<!-- -->s
 *    describing the options of your program
 * @translation_domain: a translation domain to use for translating
 *    the <option>--help</option> output for the options in @entries
943 944
 *    and the @parameter_string with gettext(), or %NULL
 * @error: a return location for errors
Matthias Clasen's avatar
Matthias Clasen committed
945
 *
946 947 948
 * This function does the same work as gtk_init_check().
 * Additionally, it allows you to add your own commandline options,
 * and it automatically generates nicely formatted
Matthias Clasen's avatar
Matthias Clasen committed
949 950 951
 * <option>--help</option> output. Note that your program will
 * be terminated after writing out the help output.
 *
952
 * Returns: %TRUE if the GUI has been successfully initialized,
Matthias Clasen's avatar
Matthias Clasen committed
953
 *               %FALSE otherwise.
954
 *
Matthias Clasen's avatar
Matthias Clasen committed
955 956
 * Since: 2.6
 */
957
gboolean
958 959 960 961 962 963
gtk_init_with_args (gint                 *argc,
                    gchar              ***argv,
                    const gchar          *parameter_string,
                    const GOptionEntry   *entries,
                    const gchar          *translation_domain,
                    GError              **error)
964 965 966 967
{
  GOptionContext *context;
  GOptionGroup *gtk_group;
  gboolean retval;
Matthias Clasen's avatar
Matthias Clasen committed
968

969
  if (gtk_initialized)
970
    return gdk_display_open_default_libgtk_only () != NULL;
971

972 973
  gettext_initialization ();

Matthias Clasen's avatar
Matthias Clasen committed
974 975 976
  if (!check_setugid ())
    return FALSE;

977
  gtk_group = gtk_get_option_group (TRUE);
978

979 980
  context = g_option_context_new (parameter_string);
  g_option_context_add_group (context, gtk_group);
981 982
  g_option_context_set_translation_domain (context, translation_domain);

983 984 985
  if (entries)
    g_option_context_add_main_entries (context, entries, translation_domain);
  retval = g_option_context_parse (context, argc, argv, error);
986

987 988 989 990 991 992 993 994
  g_option_context_free (context);

  return retval;
}


/**
 * gtk_parse_args:
995 996 997
 * @argc: (inout): a pointer to the number of command line arguments.
 * @argv: (array) (inout): a pointer to the array of command line arguments.
 *
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
 * Parses command line arguments, and initializes global
 * attributes of GTK+, but does not actually open a connection
 * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
 *
 * Any arguments used by GTK+ or GDK are removed from the array and
 * @argc and @argv are updated accordingly.
 *
 * You shouldn't call this function explicitely if you are using
 * gtk_init(), or gtk_init_check().
 *
 * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
 **/
gboolean
gtk_parse_args (int    *argc,
		char ***argv)
{
  GOptionContext *option_context;
1015
  GOptionGroup *gtk_group;
1016
  GError *error = NULL;
1017 1018 1019 1020
  
  if (gtk_initialized)
    return TRUE;

1021 1022
  gettext_initialization ();

1023 1024 1025 1026 1027 1028
  if (!check_setugid ())
    return FALSE;

  option_context = g_option_context_new (NULL);
  g_option_context_set_ignore_unknown_options (option_context, TRUE);
  g_option_context_set_help_enabled (option_context, FALSE);
1029 1030
  gtk_group = gtk_get_option_group (FALSE);
  g_option_context_set_main_group (option_context, gtk_group);
1031 1032 1033 1034 1035 1036
  if (!g_option_context_parse (option_context, argc, argv, &error))
    {
      g_warning ("%s", error->message);
      g_error_free (error);
    }

1037 1038
  g_option_context_free (option_context);

1039 1040
  return TRUE;
}
1041

1042
#ifdef G_PLATFORM_WIN32
1043
#undef gtk_init_check
1044
#endif
1045 1046 1047

/**
 * gtk_init_check:
1048
 * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
Matthias Clasen's avatar
Matthias Clasen committed
1049
 *   main() function. Changed if any arguments were handled.
1050
 * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
Matthias Clasen's avatar
Matthias Clasen committed
1051
 *   Any parameters understood by gtk_init() are stripped before return.
1052 1053 1054
 *
 * This function does the same work as gtk_init() with only
 * a single change: It does not terminate the program if the GUI can't be
1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069
 * initialized. Instead it returns %FALSE on failure.
 *
 * This way the application can fall back to some other means of communication 
 * with the user - for example a curses or command line interface.
 * 
 * Return value: %TRUE if the GUI has been successfully initialized, 
 *               %FALSE otherwise.
 **/
gboolean
gtk_init_check (int	 *argc,
		char   ***argv)
{
  if (!gtk_parse_args (argc, argv))
    return FALSE;

1070
  return gdk_display_open_default_libgtk_only () != NULL;
1071 1072
}

1073
#ifdef G_PLATFORM_WIN32
1074
#undef gtk_init
1075
#endif
1076

1077
/**
Matthias Clasen's avatar
Matthias Clasen committed
1078
 * gtk_init:
1079
 * @argc: (inout): Address of the <parameter>argc</parameter> parameter of your
Matthias Clasen's avatar
Matthias Clasen committed
1080
 *   main() function. Changed if any arguments were handled.
1081
 * @argv: (array length=argc) (inout) (allow-none): Address of the <parameter>argv</parameter> parameter of main().
Matthias Clasen's avatar
Matthias Clasen committed
1082
 *   Any parameters understood by gtk_init() are stripped before return.
1083
 *
1084
 * Call this function before using any other GTK+ functions in your GUI
1085
 * applications.  It will initialize everything needed to operate the
Matthias Clasen's avatar
Matthias Clasen committed
1086
 * toolkit and parses some standard command line options. @argc and 
Matthias Clasen's avatar
Matthias Clasen committed
1087
 * @argv are adjusted accordingly so your own code will 
Matthias Clasen's avatar
Matthias Clasen committed
1088 1089 1090 1091 1092 1093 1094
 * never see those standard arguments. 
 *
 * Note that there are some alternative ways to initialize GTK+: 
 * if you are calling gtk_parse_args(), gtk_init_check(), 
 * gtk_init_with_args() or g_option_context_parse() with 
 * the option group returned by gtk_get_option_group(), you 
 * <emphasis>don't</emphasis> have to call gtk_init().
1095 1096 1097 1098 1099 1100
 *
 * <note><para>
 * This function will terminate your program if it was unable to initialize 
 * the GUI for some reason. If you want your program to fall back to a 
 * textual interface you want to call gtk_init_check() instead.
 * </para></note>
1101 1102 1103 1104 1105 1106 1107 1108 1109
 *
 * <note><para>
 * Since 2.18, GTK+ calls <literal>signal (SIGPIPE, SIG_IGN)</literal>
 * 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.
 * </para></note>
1110
 **/