gtkmain.c 59 KB
Newer Older
Elliot Lee's avatar
Elliot Lee committed
1 2 3 4
/* GTK - The GIMP Toolkit
 * 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 28
#include "gdkconfig.h"

29
#include <locale.h>
Robert Brady's avatar
Robert Brady committed
30 31 32 33 34

#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
#include <libintl.h>
#endif

Elliot Lee's avatar
Elliot Lee committed
35 36
#include <stdio.h>
#include <stdlib.h>
37
#include <string.h>
38
#include <gmodule.h>
39 40
#ifdef G_OS_UNIX
#include <unistd.h>
41
#include <sys/types.h>		/* For uid_t, gid_t */
42
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
43 44 45 46 47
#ifdef G_OS_WIN32
#define STRICT
#include <windows.h>
#undef STRICT
#endif
48 49 50

#include <pango/pango-utils.h>	/* For pango_split_file_list */

51
#include "gtkaccelmap.h"
52
#include "gtkbox.h"
53
#include "gtkdnd.h"
54
#include "gtkversion.h"
Elliot Lee's avatar
Elliot Lee committed
55 56 57
#include "gtkmain.h"
#include "gtkrc.h"
#include "gtkselection.h"
58
#include "gtksettings.h"
Elliot Lee's avatar
Elliot Lee committed
59 60
#include "gtkwidget.h"
#include "gtkwindow.h"
61
#include "gtkprivate.h"
62
#include "config.h"
63
#include "gtkdebug.h"
Owen Taylor's avatar
Owen Taylor committed
64
#include "gtkintl.h"
Elliot Lee's avatar
Elliot Lee committed
65 66 67

/* Private type definitions
 */
68 69
typedef struct _GtkInitFunction		 GtkInitFunction;
typedef struct _GtkQuitFunction		 GtkQuitFunction;
70
typedef struct _GtkClosure	         GtkClosure;
71
typedef struct _GtkKeySnooperData	 GtkKeySnooperData;
72
typedef struct _GtkModuleInfo            GtkModuleInfo;
Elliot Lee's avatar
Elliot Lee committed
73 74 75 76 77 78 79

struct _GtkInitFunction
{
  GtkFunction function;
  gpointer data;
};

80 81
struct _GtkQuitFunction
{
82
  guint id;
83 84 85 86 87 88 89
  guint main_level;
  GtkCallbackMarshal marshal;
  GtkFunction function;
  gpointer data;
  GtkDestroyNotify destroy;
};

90
struct _GtkClosure
Elliot Lee's avatar
Elliot Lee committed
91
{
92
  GtkCallbackMarshal marshal;
Elliot Lee's avatar
Elliot Lee committed
93 94 95 96
  gpointer data;
  GtkDestroyNotify destroy;
};

97 98 99 100
struct _GtkKeySnooperData
{
  GtkKeySnoopFunc func;
  gpointer func_data;
101
  guint id;
102 103
};

104 105 106 107 108 109
struct _GtkModuleInfo
{
  GtkModuleInitFunc init_func;
  GtkModuleDisplayInitFunc display_init_func;
};

110 111 112 113
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);
114 115 116 117 118 119 120

static void     gtk_destroy_closure      (gpointer            data);
static gboolean gtk_invoke_idle_timeout  (gpointer            data);
static void     gtk_invoke_input         (gpointer            data,
					  gint                source,
					  GdkInputCondition   condition);

Manish Singh's avatar
Manish Singh committed
121
#if 0
122 123 124 125
static void  gtk_error			 (gchar		     *str);
static void  gtk_warning		 (gchar		     *str);
static void  gtk_message		 (gchar		     *str);
static void  gtk_print			 (gchar		     *str);
Manish Singh's avatar
Manish Singh committed
126
#endif
127

128 129
static GtkWindowGroup *gtk_main_get_window_group (GtkWidget   *widget);

130 131 132
const guint gtk_major_version = GTK_MAJOR_VERSION;
const guint gtk_minor_version = GTK_MINOR_VERSION;
const guint gtk_micro_version = GTK_MICRO_VERSION;
133 134
const guint gtk_binary_age = GTK_BINARY_AGE;
const guint gtk_interface_age = GTK_INTERFACE_AGE;
135

136 137 138 139 140 141 142
static GSList *gtk_modules;

/* Saved argc,argv for delayed module initialization
 */
static gint    gtk_argc = 0;
static gchar **gtk_argv = NULL;

Tim Janik's avatar
Tim Janik committed
143
static guint gtk_main_loop_level = 0;
144
static gint gtk_initialized = FALSE;
145
static GList *current_events = NULL;
Elliot Lee's avatar
Elliot Lee committed
146

147 148
static GSList *main_loops = NULL;      /* stack of currently executing main loops */

149
static GList *init_functions = NULL;	   /* A list of init functions.
Elliot Lee's avatar
Elliot Lee committed
150
					    */
151 152 153
static GList *quit_functions = NULL;	   /* A list of quit functions.
					    */
static GMemChunk *quit_mem_chunk = NULL;
Elliot Lee's avatar
Elliot Lee committed
154

155 156
static GSList *key_snoopers = NULL;

157
guint gtk_debug_flags = 0;		   /* Global GTK debug flag */
158 159

#ifdef G_ENABLE_DEBUG
160
static const GDebugKey gtk_debug_keys[] = {
161
  {"misc", GTK_DEBUG_MISC},
162
  {"plugsocket", GTK_DEBUG_PLUGSOCKET},
163
  {"text", GTK_DEBUG_TEXT},
Havoc Pennington's avatar
Havoc Pennington committed
164
  {"tree", GTK_DEBUG_TREE},
165
  {"updates", GTK_DEBUG_UPDATES},
166 167
  {"keybindings", GTK_DEBUG_KEYBINDINGS},
  {"multihead", GTK_DEBUG_MULTIHEAD}
168
};
169

170
static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
171

172
#endif /* G_ENABLE_DEBUG */
Elliot Lee's avatar
Elliot Lee committed
173

174 175 176 177 178
gchar*
gtk_check_version (guint required_major,
		   guint required_minor,
		   guint required_micro)
{
179 180 181
  gint gtk_effective_micro = 100 * GTK_MINOR_VERSION + GTK_MICRO_VERSION;
  gint required_effective_micro = 100 * required_minor + required_micro;

182
  if (required_major > GTK_MAJOR_VERSION)
183
    return "Gtk+ version too old (major mismatch)";
184
  if (required_major < GTK_MAJOR_VERSION)
185
    return "Gtk+ version too new (major mismatch)";
186
  if (required_effective_micro < gtk_effective_micro - GTK_BINARY_AGE)
187
    return "Gtk+ version too new (micro mismatch)";
188
  if (required_effective_micro > gtk_effective_micro)
189
    return "Gtk+ version too old (micro mismatch)";
190 191 192
  return NULL;
}

Owen Taylor's avatar
Owen Taylor committed
193 194 195 196 197 198 199 200 201 202
/* 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)
{
203
/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
Hans Breuer's avatar
Hans Breuer committed
204
#ifndef G_OS_WIN32
Owen Taylor's avatar
Owen Taylor committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
  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
234
#endif
Owen Taylor's avatar
Owen Taylor committed
235 236 237
  return TRUE;
}

Tor Lillqvist's avatar
Tor Lillqvist committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
#ifdef G_OS_WIN32

G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)

const gchar *
_gtk_get_libdir (void)
{
  static char *gtk_libdir = NULL;
  if (gtk_libdir == NULL)
    gtk_libdir = g_win32_get_package_installation_subdirectory
      (GETTEXT_PACKAGE, dll_name, "lib");

  return gtk_libdir;
}

const gchar *
_gtk_get_localedir (void)
{
  static char *gtk_localedir = NULL;
  if (gtk_localedir == NULL)
    gtk_localedir = g_win32_get_package_installation_subdirectory
      (GETTEXT_PACKAGE, dll_name, "lib\\locale");

  return gtk_localedir;
}

const gchar *
_gtk_get_sysconfdir (void)
{
  static char *gtk_sysconfdir = NULL;
  if (gtk_sysconfdir == NULL)
    gtk_sysconfdir = g_win32_get_package_installation_subdirectory
      (GETTEXT_PACKAGE, dll_name, "etc");

  return gtk_sysconfdir;
}

const gchar *
_gtk_get_data_prefix (void)
{
  static char *gtk_data_prefix = NULL;
  if (gtk_data_prefix == NULL)
    gtk_data_prefix = g_win32_get_package_installation_directory
      (GETTEXT_PACKAGE, dll_name);

  return gtk_data_prefix;
}

#endif /* G_OS_WIN32 */

288 289 290
static gchar **
get_module_path (void)
{
291 292 293 294
  const gchar *module_path_env;
  const gchar *exe_prefix;
  const gchar *home_dir;
  gchar *home_gtk_dir = NULL;
Owen Taylor's avatar
Owen Taylor committed
295
  gchar *module_path;
296
  gchar *default_dir;
297 298 299 300 301 302 303 304 305 306 307
  static gchar **result = NULL;

  if (result)
    return result;

  home_dir = g_get_home_dir();
  if (home_dir)
    home_gtk_dir = g_build_filename (home_dir, ".gtk-2.0", NULL);

  module_path_env = g_getenv ("GTK_PATH");
  exe_prefix = g_getenv ("GTK_EXE_PREFIX");
308 309

  if (exe_prefix)
310 311 312 313 314 315 316 317 318 319 320 321 322
    default_dir = g_build_filename (exe_prefix, "lib", "gtk-2.0", NULL);
  else
    default_dir = g_build_filename (GTK_LIBDIR, "gtk-2.0", NULL);

  if (module_path_env && home_gtk_dir)
    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
				module_path_env, home_gtk_dir, default_dir, NULL);
  else if (module_path_env)
    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
				module_path_env, default_dir, NULL);
  else if (home_gtk_dir)
    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
				home_gtk_dir, default_dir, NULL);
323
  else
324 325
    module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
				default_dir, NULL);
Tor Lillqvist's avatar
Tor Lillqvist committed
326

327 328
  g_free (home_gtk_dir);
  g_free (default_dir);
329 330 331 332 333 334 335

  result = pango_split_file_list (module_path);
  g_free (module_path);

  return result;
}

336 337 338 339 340 341 342 343 344 345
/**
 * _gtk_get_module_path:
 * @type: the type of the module, for instance 'modules', 'engines', immodules'
 * 
 * Determines the search path for a particular type of module.
 * 
 * Return value: the search path for the module type. Free with g_strfreev().
 **/
gchar **
_gtk_get_module_path (const gchar *type)
346
{
347 348 349 350
  gchar **paths = get_module_path();
  gchar **path;
  gchar **result;
  gint count = 0;
351

352 353
  for (path = paths; *path; path++)
    count++;
354

355
  result = g_new (gchar *, count * 4 + 1);
356

357 358 359 360
  count = 0;
  for (path = get_module_path (); *path; path++)
    {
      gint use_version, use_host;
361
      
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
      for (use_version = TRUE; use_version >= FALSE; use_version--)
	for (use_host = TRUE; use_host >= FALSE; use_host--)
	  {
	    gchar *tmp_dir;
	    
	    if (use_version && use_host)
	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, GTK_HOST, type, NULL);
	    else if (use_version)
	      tmp_dir = g_build_filename (*path, GTK_BINARY_VERSION, type, NULL);
	    else if (use_host)
	      tmp_dir = g_build_filename (*path, GTK_HOST, type, NULL);
	    else
	      tmp_dir = g_build_filename (*path, type, NULL);

	    result[count++] = tmp_dir;
	  }
    }
379

380 381 382 383 384
  result[count++] = NULL;

  return result;
}

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
/* Like g_module_path, but use .la as the suffix
 */
static gchar*
module_build_la_path (const gchar *directory,
		      const gchar *module_name)
{
	gchar *filename;
	gchar *result;
	
	if (strncmp (module_name, "lib", 3) == 0)
		filename = (gchar *)module_name;
	else
		filename =  g_strconcat ("lib", module_name, ".la", NULL);

	if (directory && *directory)
		result = g_build_filename (directory, filename, NULL);
	else
		result = g_strdup (filename);

	if (filename != module_name)
		g_free (filename);

	return result;
}

410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
/**
 * _gtk_find_module:
 * @name: the name of the module
 * @type: the type of the module, for instance 'modules', 'engines', immodules'
 * 
 * Looks for a dynamically module named @name of type @type in the standard GTK+
 *  module search path.
 * 
 * Return value: the pathname to the found module, or %NULL if it wasn't found.
 *  Free with g_free().
 **/
gchar *
_gtk_find_module (const gchar *name,
		  const gchar *type)
{
  gchar **paths;
  gchar **path;
  gchar *module_name = NULL;

  if (g_path_is_absolute (name))
    return g_strdup (name);

  paths = _gtk_get_module_path (type);
  for (path = paths; *path; path++)
    {
435 436 437 438 439 440 441 442 443 444 445
      gchar *tmp_name;

      tmp_name = g_module_build_path (*path, name);
      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
	{
	  module_name = tmp_name;
	  goto found;
	}
      g_free(tmp_name);

      tmp_name = module_build_la_path (*path, name);
446
      if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
447
	{
448 449
	  module_name = tmp_name;
	  goto found;
450
	}
451
      g_free(tmp_name);
452 453
    }

454
 found:
Michael Meeks's avatar
Michael Meeks committed
455
  g_strfreev (paths);
456 457 458 459
  return module_name;
}

static GModule *
460
find_module (const gchar *name)
461 462 463 464 465 466 467 468 469 470 471 472 473
{
  GModule *module;
  gchar *module_name;

  module_name = _gtk_find_module (name, "modules");
  if (!module_name)
    {
      /* As last resort, try loading without an absolute path (using system
       * library path)
       */
      module_name = g_module_build_path (NULL, name);
    }
  
474 475 476 477 478 479 480
  module = g_module_open (module_name, G_MODULE_BIND_LAZY);
  g_free(module_name);

  return module;
}

static GSList *
481
load_module (GSList      *module_list,
482 483 484
	     const gchar *name)
{
  GtkModuleInitFunc modinit_func = NULL;
485
  GtkModuleInfo *info;
486 487 488 489
  GModule *module = NULL;
  
  if (g_module_supported ())
    {
490
      module = find_module (name);
491
      if (module &&
492
	  g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
493 494
	  modinit_func)
	{
495
	  if (!g_slist_find (module_list, (gconstpointer) modinit_func))
496 497
	    {
	      g_module_make_resident (module);
498 499 500 501 502 503 504
	      info = g_new (GtkModuleInfo, 1);

	      info->init_func = modinit_func;
	      g_module_symbol (module, "gtk_module_display_init",
			       (gpointer *) &info->display_init_func);
	      
	      module_list = g_slist_prepend (module_list, info);
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
	    }
	  else
	    {
	      g_module_close (module);
	      module = NULL;
	    }
	}
    }
  if (!modinit_func)
    {
      g_message ("Failed to load module \"%s\": %s",
		 module ? g_module_name (module) : name,
		 g_module_error ());
      if (module)
	g_module_close (module);
    }
  
522
  return module_list;
523 524 525 526 527 528
}

static GSList *
load_modules (const char *module_str)
{
  gchar **module_names = pango_split_file_list (module_str);
529
  GSList *module_list = NULL;
530 531 532
  gint i;
  
  for (i = 0; module_names[i]; i++)
533
    module_list = load_module (module_list, module_names[i]);
534
  
535
  module_list = g_slist_reverse (module_list);
536 537 538
  
  g_strfreev (module_names);

539
  return module_list;
540 541
}

542 543 544 545 546 547
static gboolean do_setlocale = TRUE;

/**
 * gtk_disable_setlocale:
 * 
 * Prevents gtk_init() and gtk_init_check() from automatically
548 549 550 551
 * 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.
552 553 554
 *
 * Most programs should not need to call this function.
 **/
555
void
556 557 558 559 560 561 562 563
gtk_disable_setlocale (void)
{
  if (gtk_initialized)
    g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
    
  do_setlocale = FALSE;
}

564 565
#undef gtk_init_check

566 567 568 569 570 571 572 573 574 575
static void
default_display_notify_cb (GdkDisplayManager *display_manager)
{
  GSList *slist;

  /* Initialize non-multihead-aware modules when the
   * default display is first set to a non-NULL value.
   */
  static gboolean initialized = FALSE;

Owen Taylor's avatar
Owen Taylor committed
576
  if (!gdk_display_get_default () || initialized)
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
    return;

  initialized = TRUE;

  for (slist = gtk_modules; slist; slist = slist->next)
    {
      if (slist->data)
	{
	  GtkModuleInfo *info = slist->data;

	  if (!info->display_init_func)
	    info->init_func (&gtk_argc, &gtk_argv);
	}
    }
}

static void
display_opened_cb (GdkDisplayManager *display_manager,
		   GdkDisplay        *display)
{
  GSList *slist;
  
  for (slist = gtk_modules; slist; slist = slist->next)
    {
      if (slist->data)
	{
	  GtkModuleInfo *info = slist->data;

	  if (info->display_init_func)
	    info->display_init_func (display);
	}
    }
}

/**
 * gdk_parse_args:
 * @argc: the number of command line arguments.
 * @argv: the array of command line arguments.
 * 
 * Parses command line arguments, and initializes global
 * attributes of GTK+, but does not actually open a connection
Owen Taylor's avatar
Owen Taylor committed
618
 * to a display. (See gdk_display_open(), gdk_get_display_arg_name())
619 620 621 622 623 624 625 626 627
 *
 * 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.
 **/
628
gboolean
629 630
gtk_parse_args (int    *argc,
		char ***argv)
Elliot Lee's avatar
Elliot Lee committed
631
{
632
  GString *gtk_modules_string = NULL;
633
  GSList *slist;
634
  GdkDisplayManager *display_manager;
635
  const gchar *env_string;
636

Tim Janik's avatar
Tim Janik committed
637
  if (gtk_initialized)
638
    return TRUE;
Tim Janik's avatar
Tim Janik committed
639

Owen Taylor's avatar
Owen Taylor committed
640 641 642
  if (!check_setugid ())
    return FALSE;
  
643 644 645 646 647 648
#if	0
  g_set_error_handler (gtk_error);
  g_set_warning_handler (gtk_warning);
  g_set_message_handler (gtk_message);
  g_set_print_handler (gtk_print);
#endif
649 650

  if (do_setlocale)
651 652 653 654
    {
      if (!setlocale (LC_ALL, ""))
	g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
    }
655

656
  gdk_parse_args (argc, argv);
Owen Taylor's avatar
Owen Taylor committed
657
  gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
658
  
659
#ifdef G_ENABLE_DEBUG
Matthias Clasen's avatar
Matthias Clasen committed
660
  env_string = g_getenv ("GTK_DEBUG");
661 662 663
  if (env_string != NULL)
    {
      gtk_debug_flags = g_parse_debug_string (env_string,
664 665
					      gtk_debug_keys,
					      gtk_ndebug_keys);
666 667
      env_string = NULL;
    }
668
#endif	/* G_ENABLE_DEBUG */
669

Matthias Clasen's avatar
Matthias Clasen committed
670
  env_string = g_getenv ("GTK_MODULES");
671
  if (env_string)
672
    gtk_modules_string = g_string_new (env_string);
673

674 675
  if (argc && argv)
    {
Owen Taylor's avatar
Owen Taylor committed
676
      gint i, j, k;
677 678 679
      
      for (i = 1; i < *argc;)
	{
680 681
	  if (strcmp ("--gtk-module", (*argv)[i]) == 0 ||
	      strncmp ("--gtk-module=", (*argv)[i], 13) == 0)
682
	    {
683
	      gchar *module_name = (*argv)[i] + 12;
684
	      
685 686
	      if (*module_name == '=')
		module_name++;
687
	      else if (i + 1 < *argc)
688 689 690 691 692 693
		{
		  (*argv)[i] = NULL;
		  i += 1;
		  module_name = (*argv)[i];
		}
	      (*argv)[i] = NULL;
694

695
	      if (module_name && *module_name)
696 697 698 699 700 701 702 703
		{
		  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, module_name);
		}
704
	    }
705 706
	  else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
	    {
707
	      GLogLevelFlags fatal_mask;
708
	      
709 710 711
	      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);
712 713
	      (*argv)[i] = NULL;
	    }
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
#ifdef G_ENABLE_DEBUG
	  else if ((strcmp ("--gtk-debug", (*argv)[i]) == 0) ||
		   (strncmp ("--gtk-debug=", (*argv)[i], 12) == 0))
	    {
	      gchar *equal_pos = strchr ((*argv)[i], '=');
	      
	      if (equal_pos != NULL)
		{
		  gtk_debug_flags |= g_parse_debug_string (equal_pos+1,
							   gtk_debug_keys,
							   gtk_ndebug_keys);
		}
	      else if ((i + 1) < *argc && (*argv)[i + 1])
		{
		  gtk_debug_flags |= g_parse_debug_string ((*argv)[i+1],
							   gtk_debug_keys,
							   gtk_ndebug_keys);
		  (*argv)[i] = NULL;
		  i += 1;
		}
	      (*argv)[i] = NULL;
	    }
	  else if ((strcmp ("--gtk-no-debug", (*argv)[i]) == 0) ||
		   (strncmp ("--gtk-no-debug=", (*argv)[i], 15) == 0))
	    {
	      gchar *equal_pos = strchr ((*argv)[i], '=');
	      
	      if (equal_pos != NULL)
		{
		  gtk_debug_flags &= ~g_parse_debug_string (equal_pos+1,
							    gtk_debug_keys,
							    gtk_ndebug_keys);
		}
	      else if ((i + 1) < *argc && (*argv)[i + 1])
		{
		  gtk_debug_flags &= ~g_parse_debug_string ((*argv)[i+1],
							    gtk_debug_keys,
							    gtk_ndebug_keys);
		  (*argv)[i] = NULL;
		  i += 1;
		}
	      (*argv)[i] = NULL;
	    }
#endif /* G_ENABLE_DEBUG */
758 759
	  i += 1;
	}
760
      
Owen Taylor's avatar
Owen Taylor committed
761 762 763 764 765 766 767 768 769 770 771 772 773 774
      for (i = 1; i < *argc; i++)
	{
	  for (k = i; k < *argc; k++)
	    if ((*argv)[k] != NULL)
	      break;
	  
	  if (k > i)
	    {
	      k -= i;
	      for (j = i + k; j < *argc; j++)
		(*argv)[j-k] = (*argv)[j];
	      *argc -= k;
	    }
	}
775 776 777 778 779

      gtk_argv = g_malloc ((gtk_argc + 1) * sizeof (char*));
      for (i = 0; i < gtk_argc; i++)
	gtk_argv[i] = g_strdup ((*argv)[i]);
      gtk_argv[gtk_argc] = NULL;
780
    }
Havoc Pennington's avatar
Havoc Pennington committed
781 782 783

  if (gtk_debug_flags & GTK_DEBUG_UPDATES)
    gdk_window_set_debug_updates (TRUE);
784

785
  /* load gtk modules */
786
  if (gtk_modules_string)
787
    {
788 789
      gtk_modules = load_modules (gtk_modules_string->str);
      g_string_free (gtk_modules_string, TRUE);
790 791
    }

Owen Taylor's avatar
Owen Taylor committed
792
#ifdef ENABLE_NLS
793
  bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
Robert Brady's avatar
Robert Brady committed
794
#    ifdef HAVE_BIND_TEXTDOMAIN_CODESET
795
  bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
796
#    endif
Owen Taylor's avatar
Owen Taylor committed
797 798
#endif  

799 800
  {
  /* Translate to default:RTL if you want your widgets
Robert Brady's avatar
Robert Brady committed
801 802 803
   * 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 
804 805 806 807 808 809 810 811 812
   */
    char *e = _("default:LTR");
    if (strcmp (e, "default:RTL")==0) {
      gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
    } else if (strcmp (e, "default:LTR")) {
      g_warning ("Whoever translated default:LTR did so wrongly.\n");
    }
  }

813
  gtk_type_init (0);
814
  _gtk_accel_map_init ();  
815
  _gtk_rc_init ();
816
  
Elliot Lee's avatar
Elliot Lee committed
817 818
  /* Set the 'initialized' flag.
   */
819
  gtk_initialized = TRUE;
820

821 822 823 824 825 826 827 828
  display_manager = gdk_display_manager_get ();
  g_signal_connect (display_manager, "notify::default-display",
		    G_CALLBACK (default_display_notify_cb), NULL);
  g_signal_connect (display_manager, "display-opened",
		    G_CALLBACK (display_opened_cb), NULL);

  /* initialize multhead aware gtk modules; for other modules,
   * we wait until we have a display open;
829
   */
830
  for (slist = gtk_modules; slist; slist = slist->next)
831
    {
832
      if (slist->data)
833
	{
834 835 836 837
	  GtkModuleInfo *info = slist->data;

	  if (info->display_init_func)
	    info->init_func (argc, argv);
838 839
	}
    }
840
  
841 842
  return TRUE;
}
843

844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871
#undef gtk_init_check

/**
 * gtk_init_check:
 * @argc: Address of the <parameter>argc</parameter> parameter of your 
 *   <function>main()</function> function. Changed if any arguments were 
 *   handled.
 * @argv: Address of the <parameter>argv</parameter> parameter of 
 *   <function>main()</function>. Any parameters understood by gtk_init() 
 *   are stripped before return.
 * 
 * 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 
 * 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;

872
  return gdk_display_open_default_libgtk_only () != NULL;
873 874
}

875 876
#undef gtk_init

877
/**
Matthias Clasen's avatar
Matthias Clasen committed
878
 * gtk_init:
879 880 881 882 883 884 885 886 887
 * @argc: Address of the <parameter>argc</parameter> parameter of your 
 *   <function>main()</function> function. Changed if any arguments were 
 *   handled.
 * @argv: Address of the <parameter>argv</parameter> parameter of 
 *   <function>main()</function>. Any parameters understood by gtk_init() 
 *   are stripped before return.
 * 
 * Call this function before using any other GTK+ functions in your GUI
 * applications.  It will initialize everything needed to operate the toolkit and
Matthias Clasen's avatar
Matthias Clasen committed
888 889
 * parses some standard command line options. @argc and 
 * @argv are adjusted accordingly so your own code will 
890 891 892 893 894 895 896 897
 * never see those standard arguments.
 *
 * <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>
 **/
898 899 900 901 902
void
gtk_init (int *argc, char ***argv)
{
  if (!gtk_init_check (argc, argv))
    {
903
      const char *display_name_arg = gdk_get_display_arg_name ();
904
      g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : " ");
905
      exit (1);
906
    }
Elliot Lee's avatar
Elliot Lee committed
907 908
}

909
#ifdef G_PLATFORM_WIN32
910 911 912 913 914 915 916 917 918

static void
check_sizeof_GtkWindow (size_t sizeof_GtkWindow)
{
  if (sizeof_GtkWindow != sizeof (GtkWindow))
    g_error ("Incompatible build!\n"
	     "The code using GTK+ thinks GtkWindow is of different\n"
             "size than it actually is in this build of GTK+.\n"
	     "On Windows, this probably means that you have compiled\n"
919 920 921
	     "your code with gcc without the -fnative-struct\n"
	     "(or -mms-bitfields) switch, or that you are using\n"
	     "an unsupported compiler.");
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
}

/* In GTK+ 2.0 the GtkWindow struct actually is the same size in
 * gcc-compiled code on Win32 whether compiled with -fnative-struct or
 * 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
 * -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"
	     "The code using GTK+ thinks GtkBox is of different\n"
             "size than it actually is in this build of GTK+.\n"
	     "On Windows, this probably means that you have compiled\n"
938 939 940
	     "your code with gcc without the -fnative-struct\n"
	     "(or -mms-bitfields) switch, or that you are using\n"
	     "an unsupported compiler.");
941 942 943 944 945 946
}

/* These two functions might get more checks added later, thus pass
 * in the number of extra args.
 */
void
947
gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
948 949
{
  check_sizeof_GtkWindow (sizeof_GtkWindow);
950 951
  if (num_checks >= 2)
    check_sizeof_GtkBox (sizeof_GtkBox);
952 953 954 955
  gtk_init (argc, argv);
}

gboolean
956
gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow, size_t sizeof_GtkBox)
957 958
{
  check_sizeof_GtkWindow (sizeof_GtkWindow);
959 960
  if (num_checks >= 2)
    check_sizeof_GtkBox (sizeof_GtkBox);
961 962 963 964 965
  return gtk_init_check (argc, argv);
}

#endif

Elliot Lee's avatar
Elliot Lee committed
966
void
Tor Lillqvist's avatar
Tor Lillqvist committed
967
gtk_exit (gint errorcode)
Elliot Lee's avatar
Elliot Lee committed
968
{
Manish Singh's avatar
Manish Singh committed
969
  exit (errorcode);
Elliot Lee's avatar
Elliot Lee committed
970 971
}

972 973 974 975

/**
 * gtk_set_locale:
 *
976 977 978
 * Initializes internationalization support for GTK+. gtk_init()
 * automatically does this, so there is typically no point
 * in calling this function.
979
 *
980 981 982 983 984
 * If you are calling this function because you changed the locale
 * after GTK+ is was initialized, then calling this function
 * may help a bit. (Note, however, that changing the locale
 * after GTK+ is initialized may produce inconsistent results and
 * is not really supported.)
985
 * 
986
 * In detail - sets the current locale according to the
987 988 989
 * program environment. This is the same as calling the C library function
 * <literal>setlocale (LC_ALL, "")</literal> but also takes care of the 
 * locale specific setup of the windowing system used by GDK.
990
 * 
991
 * Return value: a string corresponding to the locale set, as with the
992
 * C library function <function>setlocale()</function>.
993
 **/
Elliot Lee's avatar
Elliot Lee committed
994
gchar*
995
gtk_set_locale (void)
Elliot Lee's avatar
Elliot Lee committed
996 997 998 999
{
  return gdk_set_locale ();
}

1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
/**
 * gtk_get_default_language:
 *
 * Returns the ISO language code for the default language currently in
 * effect. (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.
 * 
 * Return value: the default language as an allocated string, must be freed
 **/
1011
PangoLanguage *
1012 1013 1014
gtk_get_default_language (void)
{
  gchar *lang;
1015
  PangoLanguage *result;
1016 1017
  gchar *p;
  
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
#ifdef G_OS_WIN32
  /* Somebody might try to set the locale for this process using the
   * LANG or LC_ environment variables. The Microsoft C library
   * doesn't know anything about them. You set the locale in the
   * Control Panel. Setting these env vars won't have any affect on
   * locale-dependent C library functions like ctime. But just for
   * kicks, do obey LC_ALL, LANG and LC_CTYPE in GTK. (This also makes
   * it easier to test GTK and Pango in various default languages, you
   * don't have to clickety-click in the Control Panel, you can simply
   * start the program with LC_ALL=something on the command line.)
   */
  p = getenv ("LC_ALL");
  if (p != NULL)
    lang = g_strdup (p);
  else
    {
      p = getenv ("LANG");
      if (p != NULL)
	lang = g_strdup (p);
      else
	{
	  p = getenv ("LC_CTYPE");
	  if (p != NULL)
	    lang = g_strdup (p);
	  else
	    lang = g_win32_getlocale ();
	}
    }
#else
1047
  lang = g_strdup (setlocale (LC_CTYPE, NULL));
1048
#endif
1049 1050 1051 1052 1053 1054 1055
  p = strchr (lang, '.');
  if (p)
    *p = '\0';
  p = strchr (lang, '@');
  if (p)
    *p = '\0';

1056 1057 1058
  result = pango_language_from_string (lang);
  g_free (lang);
  
Hans Breuer's avatar
Hans Breuer committed
1059
  return result;
1060 1061
}

Elliot Lee's avatar
Elliot Lee committed
1062
void
1063
gtk_main (void)
Elliot Lee's avatar
Elliot Lee committed
1064 1065 1066 1067
{
  GList *tmp_list;
  GList *functions;
  GtkInitFunction *init;
1068 1069
  GMainLoop *loop;

Tim Janik's avatar
Tim Janik committed
1070
  gtk_main_loop_level++;
1071
  
Manish Singh's avatar
Manish Singh committed
1072
  loop = g_main_loop_new (NULL, TRUE);
1073 1074
  main_loops = g_slist_prepend (main_loops, loop);

Elliot Lee's avatar
Elliot Lee committed
1075 1076
  tmp_list = functions = init_functions;
  init_functions = NULL;
1077
  
Elliot Lee's avatar
Elliot Lee committed
1078 1079 1080 1081
  while (tmp_list)
    {
      init = tmp_list->data;
      tmp_list = tmp_list->next;
1082
      
Elliot Lee's avatar
Elliot Lee committed
1083 1084 1085 1086
      (* init->function) (init->data);
      g_free (init);
    }
  g_list_free (functions);
1087

Manish Singh's avatar
Manish Singh committed
1088
  if (g_main_loop_is_running (main_loops->data))
1089 1090
    {
      GDK_THREADS_LEAVE ();
Manish Singh's avatar
Manish Singh committed
1091
      g_main_loop_run (loop);
1092 1093 1094
      GDK_THREADS_ENTER ();
      gdk_flush ();
    }