* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-#ifdef GDK_WINDOWING_X11
-#include <X11/Xlocale.h> /* so we get the right setlocale */
-#else
+#include "gdkconfig.h"
+
#include <locale.h>
+
+#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+#include <libintl.h>
#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmodule.h>
-#include "gtkbutton.h"
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#include <sys/types.h> /* For uid_t, gid_t */
+#endif
+#ifdef G_OS_WIN32
+#define STRICT
+#include <windows.h>
+#undef STRICT
+#endif
+
+#include <pango/pango-utils.h> /* For pango_split_file_list */
+
+#include "gtkaccelmap.h"
#include "gtkdnd.h"
-#include "gtkcompat.h"
-#include "gtkhscrollbar.h"
-#include "gtkhseparator.h"
+#include "gtkversion.h"
#include "gtkmain.h"
-#include "gtkpreview.h"
#include "gtkrc.h"
-#include "gtkscrolledwindow.h"
#include "gtkselection.h"
+#include "gtksettings.h"
#include "gtksignal.h"
-#include "gtktable.h"
-#include "gtktext.h"
-#include "gtkvbox.h"
-#include "gtkvscrollbar.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
-#include "gdk/gdki18n.h"
#include "config.h"
#include "gtkdebug.h"
#include "gtkintl.h"
guint id;
};
-static void gtk_exit_func (void);
static gint gtk_quit_invoke_function (GtkQuitFunction *quitf);
static void gtk_quit_destroy (GtkQuitFunction *quitf);
static gint gtk_invoke_key_snoopers (GtkWidget *grab_widget,
static void gtk_print (gchar *str);
#endif
+static GtkWindowGroup *gtk_main_get_window_group (GtkWidget *widget);
+
const guint gtk_major_version = GTK_MAJOR_VERSION;
const guint gtk_minor_version = GTK_MINOR_VERSION;
const guint gtk_micro_version = GTK_MICRO_VERSION;
static GSList *main_loops = NULL; /* stack of currently executing main loops */
-static GSList *grabs = NULL; /* A stack of unique grabs. The grabbing
- * widget is the first one on the list.
- */
static GList *init_functions = NULL; /* A list of init functions.
*/
static GList *quit_functions = NULL; /* A list of quit functions.
#ifdef G_ENABLE_DEBUG
static const GDebugKey gtk_debug_keys[] = {
- {"objects", GTK_DEBUG_OBJECTS},
{"misc", GTK_DEBUG_MISC},
- {"signals", GTK_DEBUG_SIGNALS},
- {"dnd", GTK_DEBUG_DND},
{"plugsocket", GTK_DEBUG_PLUGSOCKET},
- {"text", GTK_DEBUG_TEXT}
+ {"text", GTK_DEBUG_TEXT},
+ {"tree", GTK_DEBUG_TREE},
+ {"updates", GTK_DEBUG_UPDATES},
+ {"keybindings", GTK_DEBUG_KEYBINDINGS}
};
static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
return NULL;
}
-#ifdef __EMX__
-static gchar *add_dll_suffix(gchar *module_name)
+#undef gtk_init_check
+
+/* 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)
{
- gchar *suffix = strrchr(module_name, '.');
-
- if (!suffix || stricmp(suffix, ".dll"))
+/* this isn't at all relevant on MS Windows and doesn't compile ... --hb */
+#ifndef G_OS_WIN32
+ 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 */
{
- gchar *old = module_name;
-
- module_name = g_strconcat (module_name, ".dll", NULL);
- g_free (old);
+ 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);
}
- return (module_name);
-}
#endif
+ return TRUE;
+}
+
+#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 */
+
+static gchar **
+get_module_path (void)
+{
+ const gchar *module_path_env;
+ const gchar *exe_prefix;
+ const gchar *home_dir;
+ gchar *home_gtk_dir = NULL;
+ gchar *module_path;
+ gchar *default_dir;
+ 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");
+
+ if (exe_prefix)
+ 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);
+ else
+ module_path = g_build_path (G_SEARCHPATH_SEPARATOR_S,
+ default_dir, NULL);
+
+ g_free (home_gtk_dir);
+ g_free (default_dir);
+
+ result = pango_split_file_list (module_path);
+ g_free (module_path);
+
+ return result;
+}
+
+/**
+ * _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)
+{
+ gchar **paths = get_module_path();
+ gchar **path;
+ gchar **result;
+ gint count = 0;
+
+ for (path = paths; *path; path++)
+ count++;
+
+ result = g_new (gchar *, count * 4 + 1);
+
+ count = 0;
+ for (path = get_module_path (); *path; path++)
+ {
+ gint use_version, use_host;
+
+ 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;
+ }
+ }
+
+ result[count++] = NULL;
+
+ return result;
+}
+
+/**
+ * _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++)
+ {
+ gchar *tmp_name = g_module_build_path (*path, name);
+
+ if (g_file_test (tmp_name, G_FILE_TEST_EXISTS))
+ {
+ module_name = tmp_name;
+ goto found;
+ }
+ else
+ g_free(tmp_name);
+ }
+
+ g_strfreev (paths);
+
+ found:
+ return module_name;
+}
+
+static GModule *
+find_module (gchar **module_path,
+ const gchar *name)
+{
+ 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);
+ }
+
+ module = g_module_open (module_name, G_MODULE_BIND_LAZY);
+ g_free(module_name);
+
+ return module;
+}
+
+static GSList *
+load_module (GSList *gtk_modules,
+ gchar **module_path,
+ const gchar *name)
+{
+ GtkModuleInitFunc modinit_func = NULL;
+ GModule *module = NULL;
+
+ if (g_module_supported ())
+ {
+ module = find_module (module_path, name);
+ if (module &&
+ g_module_symbol (module, "gtk_module_init", (gpointer *) &modinit_func) &&
+ modinit_func)
+ {
+ if (!g_slist_find (gtk_modules, modinit_func))
+ {
+ g_module_make_resident (module);
+ gtk_modules = g_slist_prepend (gtk_modules, modinit_func);
+ }
+ 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);
+ }
+
+ return gtk_modules;
+}
+
+static GSList *
+load_modules (const char *module_str)
+{
+ gchar **module_path = get_module_path ();
+ gchar **module_names = pango_split_file_list (module_str);
+ GSList *gtk_modules = NULL;
+ gint i;
+
+ for (i = 0; module_names[i]; i++)
+ gtk_modules = load_module (gtk_modules, module_path, module_names[i]);
+
+ gtk_modules = g_slist_reverse (gtk_modules);
+
+ g_strfreev (module_names);
+ g_strfreev (module_path);
+
+ return gtk_modules;
+}
+
+static gboolean do_setlocale = TRUE;
+
+/**
+ * gtk_disable_setlocale:
+ *
+ * Prevents gtk_init() and gtk_init_check() from automatically
+ * 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.
+ *
+ * Most programs should not need to call this function.
+ **/
+void
+gtk_disable_setlocale (void)
+{
+ if (gtk_initialized)
+ g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
+
+ do_setlocale = FALSE;
+}
gboolean
gtk_init_check (int *argc,
char ***argv)
{
+ GString *gtk_modules_string = NULL;
GSList *gtk_modules = NULL;
GSList *slist;
- gchar *env_string = NULL;
+ const gchar *env_string;
if (gtk_initialized)
return TRUE;
+ if (!check_setugid ())
+ return FALSE;
+
#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
+
+ if (do_setlocale)
+ {
+ if (!setlocale (LC_ALL, ""))
+ g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
+ }
/* Initialize "gdk". We pass along the 'argc' and 'argv'
* parameters as they contain information that GDK uses
gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
#ifdef G_ENABLE_DEBUG
- env_string = getenv ("GTK_DEBUG");
+ env_string = g_getenv ("GTK_DEBUG");
if (env_string != NULL)
{
gtk_debug_flags = g_parse_debug_string (env_string,
}
#endif /* G_ENABLE_DEBUG */
- env_string = getenv ("GTK_MODULES");
+ env_string = g_getenv ("GTK_MODULES");
if (env_string)
- {
- gchar **modules, **as;
-
-#ifndef __EMX__
- modules = g_strsplit (env_string, G_SEARCHPATH_SEPARATOR_S, -1);
-#else
- modules = g_strsplit (env_string, ";", -1);
-#endif
- for (as = modules; *as; as++)
- {
- if (**as)
- gtk_modules = g_slist_prepend (gtk_modules, *as);
- else
- g_free (*as);
- }
- g_free (modules);
- env_string = NULL;
- }
+ gtk_modules_string = g_string_new (env_string);
if (argc && argv)
{
(*argv)[i] = NULL;
if (module_name && *module_name)
- gtk_modules = g_slist_prepend (gtk_modules, g_strdup (module_name));
+ {
+ 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);
+ }
}
else if (strcmp ("--g-fatal-warnings", (*argv)[i]) == 0)
{
}
}
}
-
+
+ if (gtk_debug_flags & GTK_DEBUG_UPDATES)
+ gdk_window_set_debug_updates (TRUE);
+
/* load gtk modules */
- gtk_modules = g_slist_reverse (gtk_modules);
- for (slist = gtk_modules; slist; slist = slist->next)
+ if (gtk_modules_string)
{
- gchar *module_name;
- GModule *module = NULL;
- GtkModuleInitFunc modinit_func = NULL;
-
- module_name = slist->data;
- slist->data = NULL;
-#ifndef __EMX__
- if (!g_path_is_absolute (module_name))
- {
- gchar *old = module_name;
-
- module_name = g_module_build_path (NULL, module_name);
- g_free (old);
- }
-#else
- module_name = add_dll_suffix(module_name);
-#endif
- if (g_module_supported ())
- {
- module = g_module_open (module_name, G_MODULE_BIND_LAZY);
- if (module &&
- g_module_symbol (module, "gtk_module_init", (gpointer*) &modinit_func) &&
- modinit_func)
- {
- if (!g_slist_find (gtk_modules, modinit_func))
- {
- g_module_make_resident (module);
- slist->data = modinit_func;
- }
- else
- {
- g_module_close (module);
- module = NULL;
- }
- }
- }
- if (!modinit_func)
- {
- g_warning ("Failed to load module \"%s\": %s",
- module ? g_module_name (module) : module_name,
- g_module_error ());
- if (module)
- g_module_close (module);
- }
- g_free (module_name);
+ gtk_modules = load_modules (gtk_modules_string->str);
+ g_string_free (gtk_modules_string, TRUE);
}
#ifdef ENABLE_NLS
-#ifndef G_OS_WIN32
- bindtextdomain(GETTEXT_PACKAGE, GTK_LOCALEDIR);
-#else
+ bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
+# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+# endif
+#endif
+
{
- /* GTk+ locale dir is %WinDir%\gtk+\locale */
- bindtextdomain (GETTEXT_PACKAGE,
- g_strconcat (gtk_win32_get_installation_directory (),
- G_DIR_SEPARATOR_S,
- "locale",
- NULL));
+ /* 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
+ */
+ 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");
+ }
}
-#endif
-#endif
/* Initialize the default visual and colormap to be
* used in creating widgets. (We want to use the system
gtk_visual = gdk_visual_get_system ();
gtk_colormap = gdk_colormap_get_system ();
- gtk_type_init ();
- gtk_signal_init ();
- gtk_rc_init ();
-
-
- /* Register an exit function to make sure we are able to cleanup.
- */
- g_atexit (gtk_exit_func);
+ gtk_type_init (0);
+ _gtk_accel_map_init ();
+ _gtk_rc_init ();
/* Set the 'initialized' flag.
*/
}
g_slist_free (gtk_modules);
-#ifndef G_OS_WIN32
- /* No use warning on Win32, there aren't any non-devel versions anyhow... */
- g_warning ("" "YOU ARE USING THE DEVEL BRANCH 1.3.x OF GTK+ WHICH IS CURRENTLY\n"
- " UNDER HEAVY DEVELOPMENT AND FREQUENTLY INTRODUCES INSTABILITIES.\n"
- " if you don't know why you are getting this, you probably want to\n"
- " use the stable branch which can be retrived from\n"
- " ftp://ftp.gtk.org/pub/gtk/v1.2/ or via CVS with\n"
- " cvs checkout -r glib-1-2 glib; cvs checkout -r gtk-1-2 gtk+");
-#endif
-
return TRUE;
}
+
+#undef gtk_init
+
void
gtk_init (int *argc, char ***argv)
{
if (!gtk_init_check (argc, argv))
{
g_warning ("cannot open display: %s", gdk_get_display ());
- exit(1);
+ exit (1);
}
}
+#ifdef G_OS_WIN32
+
+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"
+ "your code with gcc without the -fnative-struct switch.");
+}
+
+/* These two functions might get more checks added later, thus pass
+ * in the number of extra args.
+ */
+void
+gtk_init_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
+{
+ check_sizeof_GtkWindow (sizeof_GtkWindow);
+ gtk_init (argc, argv);
+}
+
+gboolean
+gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof_GtkWindow)
+{
+ check_sizeof_GtkWindow (sizeof_GtkWindow);
+ return gtk_init_check (argc, argv);
+}
+
+#endif
+
void
gtk_exit (gint errorcode)
{
/* Only if "gtk" has been initialized should we de-initialize.
*/
- /* de-initialisation is done by the gtk_exit_funct(),
- * no need to do this here (Alex J.)
- */
- gdk_exit(errorcode);
+ gdk_exit (errorcode);
}
+
+/**
+ * gtk_set_locale:
+ *
+ * Initializes internationalization support for GTK+. gtk_init()
+ * automatically does this, so there is typically no point
+ * in calling this function.
+ *
+ * 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.)
+ *
+ * In detail - sets the current locale according to the
+ * 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.
+ *
+ * Return value: a string corresponding to the locale set, as with the
+ * C library function <function>setlocale()</function>.
+ **/
gchar*
gtk_set_locale (void)
{
return gdk_set_locale ();
}
-gchar*
+/**
+ * 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
+ **/
+PangoLanguage *
gtk_get_default_language (void)
{
gchar *lang;
+ PangoLanguage *result;
gchar *p;
lang = g_strdup (setlocale (LC_CTYPE, NULL));
if (p)
*p = '\0';
- return lang;
+ result = pango_language_from_string (lang);
+ g_free (lang);
+
+ return result;
}
void
gboolean result;
GDK_THREADS_LEAVE ();
- result = g_main_pending();
+ result = g_main_pending ();
GDK_THREADS_ENTER ();
return result;
}
-gint
+gboolean
gtk_main_iteration (void)
{
GDK_THREADS_LEAVE ();
return TRUE;
}
-gint
+gboolean
gtk_main_iteration_do (gboolean blocking)
{
GDK_THREADS_LEAVE ();
return TRUE;
}
+/* private libgtk to libgdk interfaces
+ */
+gboolean gdk_pointer_grab_info_libgtk_only (GdkWindow **grab_window,
+ gboolean *owner_events);
+gboolean gdk_keyboard_grab_info_libgtk_only (GdkWindow **grab_window,
+ gboolean *owner_events);
+
+static void
+rewrite_events_translate (GdkWindow *old_window,
+ GdkWindow *new_window,
+ gdouble *x,
+ gdouble *y)
+{
+ gint old_origin_x, old_origin_y;
+ gint new_origin_x, new_origin_y;
+
+ gdk_window_get_origin (old_window, &old_origin_x, &old_origin_y);
+ gdk_window_get_origin (new_window, &new_origin_x, &new_origin_y);
+
+ *x += new_origin_x - old_origin_x;
+ *y += new_origin_y - old_origin_y;
+}
+
+GdkEvent *
+rewrite_event_for_window (GdkEvent *event,
+ GdkWindow *new_window)
+{
+ event = gdk_event_copy (event);
+
+ switch (event->type)
+ {
+ case GDK_SCROLL:
+ rewrite_events_translate (event->any.window,
+ new_window,
+ &event->scroll.x, &event->scroll.y);
+ break;
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ rewrite_events_translate (event->any.window,
+ new_window,
+ &event->button.x, &event->button.y);
+ break;
+ case GDK_MOTION_NOTIFY:
+ rewrite_events_translate (event->any.window,
+ new_window,
+ &event->motion.x, &event->motion.y);
+ break;
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ break;
+
+ default:
+ return event;
+ }
+
+ g_object_unref (event->any.window);
+ event->any.window = g_object_ref (new_window);
+
+ return event;
+}
+
+/* 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
+ * client, otherwise, delivers it in terms of the grab window. This function
+ * 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)
+{
+ GdkWindow *grab_window;
+ GtkWidget *event_widget, *grab_widget;;
+ gboolean owner_events;
+
+ switch (event->type)
+ {
+ case GDK_SCROLL:
+ case GDK_BUTTON_PRESS:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_MOTION_NOTIFY:
+ case GDK_PROXIMITY_IN:
+ case GDK_PROXIMITY_OUT:
+ if (!gdk_pointer_grab_info_libgtk_only (&grab_window, &owner_events) ||
+ !owner_events)
+ return NULL;
+ break;
+
+ case GDK_KEY_PRESS:
+ case GDK_KEY_RELEASE:
+ if (!gdk_keyboard_grab_info_libgtk_only (&grab_window, &owner_events) ||
+ !owner_events)
+ return NULL;
+ break;
+
+ default:
+ return NULL;
+ }
+
+ event_widget = gtk_get_event_widget (event);
+ gdk_window_get_user_data (grab_window, (void**) &grab_widget);
+
+ if (grab_widget &&
+ gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
+ return rewrite_event_for_window (event, grab_window);
+ else
+ return NULL;
+}
+
void
gtk_main_do_event (GdkEvent *event)
{
GtkWidget *event_widget;
GtkWidget *grab_widget;
+ GtkWindowGroup *window_group;
GdkEvent *next_event;
+ GdkEvent *rewritten_event = NULL;
GList *tmp_list;
/* If there are any events pending then get the next one.
if (event->type == GDK_PROPERTY_NOTIFY)
gtk_selection_incr_event (event->any.window,
&event->property);
-
+ else if (event->type == GDK_SETTING)
+ _gtk_settings_handle_event (&event->setting);
+
return;
}
+
+ /* If pointer or keyboard grabs are in effect, munge the events
+ * so that each window group looks like a separate app.
+ */
+ rewritten_event = rewrite_event_for_grabs (event);
+ if (rewritten_event)
+ {
+ event = rewritten_event;
+ event_widget = gtk_get_event_widget (event);
+ }
+ window_group = gtk_main_get_window_group (event_widget);
+
/* Push the event onto a stack of current events for
* gtk_current_event_get().
*/
current_events = g_list_prepend (current_events, event);
-
+
/* If there is a grab in effect...
*/
- if (grabs)
+ if (window_group->grabs)
{
- grab_widget = grabs->data;
+ grab_widget = window_group->grabs->data;
/* If the grab widget is an ancestor of the event widget
* then we send the event to the original event widget.
case GDK_DELETE:
gtk_widget_ref (event_widget);
- if ((!grabs || gtk_widget_get_toplevel (grabs->data) == event_widget) &&
+ if ((!window_group->grabs || gtk_widget_get_toplevel (window_group->grabs->data) == event_widget) &&
!gtk_widget_event (event_widget, event))
gtk_widget_destroy (event_widget);
gtk_widget_unref (event_widget);
{
gtk_widget_ref (event_widget);
if (!gtk_widget_event (event_widget, event) &&
- !GTK_OBJECT_DESTROYED (event_widget))
+ GTK_WIDGET_REALIZED (event_widget))
gtk_widget_destroy (event_widget);
gtk_widget_unref (event_widget);
}
case GDK_EXPOSE:
if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
- gdk_window_begin_paint_rect (event->any.window, &event->expose.area);
-
- gtk_widget_event (event_widget, event);
-
- if (event->any.window && GTK_WIDGET_DOUBLE_BUFFERED (event_widget))
- gdk_window_end_paint (event->any.window);
+ {
+ gdk_window_begin_paint_region (event->any.window, event->expose.region);
+ gtk_widget_send_expose (event_widget, event);
+ gdk_window_end_paint (event->any.window);
+ }
+ else
+ gtk_widget_send_expose (event_widget, event);
break;
case GDK_PROPERTY_NOTIFY:
case GDK_SELECTION_NOTIFY:
case GDK_CLIENT_EVENT:
case GDK_VISIBILITY_NOTIFY:
+ case GDK_WINDOW_STATE:
gtk_widget_event (event_widget, event);
break;
case GDK_ENTER_NOTIFY:
if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
{
+ g_object_ref (event_widget);
+
gtk_widget_event (grab_widget, event);
if (event_widget == grab_widget)
GTK_PRIVATE_SET_FLAG (event_widget, GTK_LEAVE_PENDING);
+
+ g_object_unref (event_widget);
}
break;
case GDK_DRAG_STATUS:
case GDK_DROP_FINISHED:
- gtk_drag_source_handle_event (event_widget, event);
+ _gtk_drag_source_handle_event (event_widget, event);
break;
case GDK_DRAG_ENTER:
case GDK_DRAG_LEAVE:
case GDK_DRAG_MOTION:
case GDK_DROP_START:
- gtk_drag_dest_handle_event (event_widget, event);
+ _gtk_drag_dest_handle_event (event_widget, event);
+ break;
+ default:
+ g_assert_not_reached ();
break;
}
tmp_list = current_events;
current_events = g_list_remove_link (current_events, tmp_list);
g_list_free_1 (tmp_list);
+
+ if (rewritten_event)
+ gdk_event_free (rewritten_event);
}
-gint
+gboolean
gtk_true (void)
{
return TRUE;
}
-gint
+gboolean
gtk_false (void)
{
return FALSE;
}
+static GtkWindowGroup *
+gtk_main_get_window_group (GtkWidget *widget)
+{
+ GtkWidget *toplevel = NULL;
+
+ if (widget)
+ toplevel = gtk_widget_get_toplevel (widget);
+
+ if (toplevel && GTK_IS_WINDOW (toplevel))
+ return _gtk_window_get_group (GTK_WINDOW (toplevel));
+ else
+ return _gtk_window_get_group (NULL);
+}
+
+typedef struct
+{
+ GtkWidget *old_grab_widget;
+ GtkWidget *new_grab_widget;
+} GrabNotifyInfo;
+
+static gboolean
+check_is_grabbed (GtkWidget *widget,
+ GtkWidget *grab_widget)
+{
+ if (grab_widget)
+ return !(widget == grab_widget || gtk_widget_is_ancestor (widget, grab_widget));
+ else
+ return FALSE;
+}
+
+static void
+gtk_grab_notify_foreach (GtkWidget *child,
+ gpointer data)
+
+{
+ GrabNotifyInfo *info = data;
+ gboolean was_grabbed = check_is_grabbed (child, info->old_grab_widget);
+ gboolean is_grabbed = check_is_grabbed (child, info->new_grab_widget);
+
+ if (was_grabbed != is_grabbed)
+ {
+ g_object_ref (G_OBJECT (child));
+
+ gtk_signal_emit_by_name (GTK_OBJECT (child), "grab_notify", was_grabbed);
+
+ if (GTK_IS_CONTAINER (child))
+ gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
+
+ g_object_unref (G_OBJECT (child));
+ }
+}
+
+static void
+gtk_grab_notify (GtkWindowGroup *group,
+ GtkWidget *grab_widget,
+ gboolean was_grabbed)
+{
+ GList *toplevels;
+ GrabNotifyInfo info;
+
+ if (was_grabbed)
+ {
+ info.old_grab_widget = grab_widget;
+ info.new_grab_widget = group->grabs ? group->grabs->data : NULL;
+ }
+ else
+ {
+ info.old_grab_widget = (group->grabs && group->grabs->next) ? group->grabs->next->data : NULL;
+ info.new_grab_widget = grab_widget;
+ }
+
+ g_object_ref (group);
+ g_object_ref (grab_widget);
+
+ toplevels = gtk_window_list_toplevels ();
+ g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
+
+ while (toplevels)
+ {
+ GtkWindow *toplevel = toplevels->data;
+ toplevels = g_list_delete_link (toplevels, toplevels);
+
+ if (group == _gtk_window_get_group (toplevel))
+ gtk_container_foreach (GTK_CONTAINER (toplevel), gtk_grab_notify_foreach, &info);
+ g_object_unref (toplevel);
+ }
+
+ g_object_unref (group);
+ g_object_unref (grab_widget);
+}
+
void
gtk_grab_add (GtkWidget *widget)
{
+ GtkWindowGroup *group;
+ gboolean was_grabbed;
+
g_return_if_fail (widget != NULL);
- if (!GTK_WIDGET_HAS_GRAB (widget))
+ if (!GTK_WIDGET_HAS_GRAB (widget) && GTK_WIDGET_IS_SENSITIVE (widget))
{
GTK_WIDGET_SET_FLAGS (widget, GTK_HAS_GRAB);
- grabs = g_slist_prepend (grabs, widget);
+ group = gtk_main_get_window_group (widget);
+
+ was_grabbed = (group->grabs != NULL);
+
gtk_widget_ref (widget);
+ group->grabs = g_slist_prepend (group->grabs, widget);
+
+ gtk_grab_notify (group, widget, FALSE);
}
}
GtkWidget*
gtk_grab_get_current (void)
{
- if (grabs)
- return GTK_WIDGET (grabs->data);
+ GtkWindowGroup *group;
+
+ group = gtk_main_get_window_group (NULL);
+
+ if (group->grabs)
+ return GTK_WIDGET (group->grabs->data);
return NULL;
}
void
gtk_grab_remove (GtkWidget *widget)
{
+ GtkWindowGroup *group;
+
g_return_if_fail (widget != NULL);
if (GTK_WIDGET_HAS_GRAB (widget))
{
GTK_WIDGET_UNSET_FLAGS (widget, GTK_HAS_GRAB);
+
+ group = gtk_main_get_window_group (widget);
+ group->grabs = g_slist_remove (group->grabs, widget);
- grabs = g_slist_remove (grabs, widget);
gtk_widget_unref (widget);
+
+ gtk_grab_notify (group, widget, TRUE);
}
}
GtkObject **object_p;
g_return_if_fail (main_level > 0);
- g_return_if_fail (object != NULL);
g_return_if_fail (GTK_IS_OBJECT (object));
object_p = g_new (GtkObject*, 1);
}
guint
-gtk_idle_add_priority (gint priority,
- GtkFunction function,
- gpointer data)
+gtk_idle_add_priority (gint priority,
+ GtkFunction function,
+ gpointer data)
{
return g_idle_add_full (priority, function, data, NULL);
}
GtkArg args[3];
args[0].type = GTK_TYPE_INT;
args[0].name = NULL;
- GTK_VALUE_INT(args[0]) = source;
- args[1].type = GTK_TYPE_GDK_INPUT_CONDITION;
+ GTK_VALUE_INT (args[0]) = source;
+ args[1].type = GDK_TYPE_INPUT_CONDITION;
args[1].name = NULL;
- GTK_VALUE_FLAGS(args[1]) = condition;
+ GTK_VALUE_FLAGS (args[1]) = condition;
args[2].type = GTK_TYPE_NONE;
args[2].name = NULL;
closure->marshal (NULL, closure->data, 2, args);
}
+/**
+ * gtk_get_current_event:
+ *
+ * Obtains a copy of the event currently being processed by GTK+. For
+ * example, if you get a "clicked" signal from #GtkButton, the current
+ * event will be the #GdkEventButton that triggered the "clicked"
+ * signal. The returned event must be freed with gdk_event_free().
+ * If there is no current event, the function returns %NULL.
+ *
+ * Return value: a copy of the current event, or %NULL if no current event.
+ **/
GdkEvent*
gtk_get_current_event (void)
{
if (current_events)
- return gdk_event_copy ((GdkEvent *) current_events->data);
+ return gdk_event_copy (current_events->data);
else
return NULL;
}
+/**
+ * gtk_get_current_event_time:
+ *
+ * If there is a current event and it has a timestamp, return that
+ * timestamp, otherwise return %GDK_CURRENT_TIME.
+ *
+ * Return value: the timestamp from the current event, or %GDK_CURRENT_TIME.
+ **/
+guint32
+gtk_get_current_event_time (void)
+{
+ if (current_events)
+ return gdk_event_get_time (current_events->data);
+ else
+ return GDK_CURRENT_TIME;
+}
+
+/**
+ * gtk_get_current_event_state:
+ * @state: a location to store the state of the current event
+ *
+ * If there is a current event and it has a state field, place
+ * that state field in @state and return %TRUE, otherwise return
+ * %FALSE.
+ *
+ * Return value: %TRUE if there was a current event and it had a state field
+ **/
+gboolean
+gtk_get_current_event_state (GdkModifierType *state)
+{
+ g_return_val_if_fail (state != NULL, FALSE);
+
+ if (current_events)
+ return gdk_event_get_state (current_events->data, state);
+ else
+ {
+ *state = 0;
+ return FALSE;
+ }
+}
+
+/**
+ * gtk_get_event_widget:
+ * @event: a #GdkEvent
+ *
+ * If @event is %NULL or the event was not associated with any widget,
+ * returns %NULL, otherwise returns the widget that received the event
+ * originally.
+ *
+ * Return value: the widget that originally received @event, or %NULL
+ **/
GtkWidget*
gtk_get_event_widget (GdkEvent *event)
{
return widget;
}
-static void
-gtk_exit_func (void)
-{
- if (gtk_initialized)
- {
- gtk_initialized = FALSE;
- gtk_preview_uninit ();
- }
-}
-
-
static gint
gtk_quit_invoke_function (GtkQuitFunction *quitf)
{
}
}
+/**
+ * gtk_propagate_event:
+ * @widget: a #GtkWidget
+ * @event: an event
+ *
+ * Sends an event to a widget, propagating the event to parent widgets
+ * if the event remains unhandled. Events received by GTK+ from GDK
+ * normally begin in gtk_main_do_event(). Depending on the type of
+ * event, existence of modal dialogs, grabs, etc., the event may be
+ * propagated; if so, this function is used. gtk_propagate_event()
+ * calls gtk_widget_event() on each widget it decides to send the
+ * event to. So gtk_widget_event() is the lowest-level function; it
+ * simply emits the "event" and possibly an event-specific signal on a
+ * widget. gtk_propagate_event() is a bit higher-level, and
+ * gtk_main_do_event() is the highest level.
+ *
+ * All that said, you most likely don't want to use any of these
+ * functions; synthesizing events is rarely needed. Consider asking on
+ * the mailing list for better ways to achieve your goals. For
+ * example, use gdk_window_invalidate_rect() or
+ * gtk_widget_queue_draw() instead of making up expose events.
+ *
+ **/
void
gtk_propagate_event (GtkWidget *widget,
GdkEvent *event)
{
gint handled_event;
- g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (event != NULL);
handled_event = FALSE;
+ gtk_widget_ref (widget);
+
if ((event->type == GDK_KEY_PRESS) ||
(event->type == GDK_KEY_RELEASE))
{
*/
GtkWidget *window;
- window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW);
- if (window)
- {
- if (GTK_WIDGET_IS_SENSITIVE (window))
- gtk_widget_event (window, event);
-
- handled_event = TRUE; /* don't send to widget */
- }
+ window = gtk_widget_get_toplevel (widget);
+ if (window && GTK_IS_WINDOW (window))
+ {
+ /* If there is a grab within the window, give the grab widget
+ * a first crack at the key event
+ */
+ if (widget != window && GTK_WIDGET_HAS_GRAB (widget))
+ handled_event = gtk_widget_event (widget, event);
+
+ if (!handled_event)
+ {
+ window = gtk_widget_get_toplevel (widget);
+ if (window && GTK_IS_WINDOW (window))
+ {
+ if (GTK_WIDGET_IS_SENSITIVE (window))
+ gtk_widget_event (window, event);
+ }
+ }
+
+ handled_event = TRUE; /* don't send to widget */
+ }
}
/* Other events get propagated up the widget tree
* so that parents can see the button and motion
* events of the children.
*/
- while (!handled_event && widget)
+ if (!handled_event)
{
- GtkWidget *tmp;
+ while (TRUE)
+ {
+ GtkWidget *tmp;
+
+ handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
+ tmp = widget->parent;
+ gtk_widget_unref (widget);
- gtk_widget_ref (widget);
- handled_event = !GTK_WIDGET_IS_SENSITIVE (widget) || gtk_widget_event (widget, event);
- tmp = widget->parent;
- gtk_widget_unref (widget);
- widget = tmp;
+ widget = tmp;
+
+ if (!handled_event && widget)
+ gtk_widget_ref (widget);
+ else
+ break;
+ }
}
+ else
+ gtk_widget_unref (widget);
}
#if 0
gtk_widget_show (window);
}
#endif
+
+gboolean
+_gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer dummy)
+{
+ gboolean continue_emission;
+ gboolean signal_handled;
+
+ signal_handled = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, signal_handled);
+ continue_emission = !signal_handled;
+
+ return continue_emission;
+}