* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
-#include <config.h>
+#include "config.h"
#include <glib.h>
#include "gdkconfig.h"
#include <locale.h>
-#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
-#include <libintl.h>
-#endif
-
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#undef STRICT
#endif
-#include <pango/pango-types.h> /* For pango_language_from_string */
-
#include "gtkintl.h"
#include "gtkaccelmap.h"
#include "gtkmain.h"
#include "gtkmodules.h"
#include "gtkrc.h"
+#include "gtkrecentmanager.h"
#include "gtkselection.h"
#include "gtksettings.h"
#include "gtkwidget.h"
#include "gtkwindow.h"
-#include "gtkprivate.h"
+#include "gtktooltip.h"
#include "gtkdebug.h"
#include "gtkalias.h"
+#include "gdk/gdkprivate.h" /* for GDK_WINDOW_DESTROYED */
+
+#ifdef G_OS_WIN32
+
+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;
+}
+
+/* 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.
+ */
+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;
+}
+
+const gchar *
+_gtk_get_localedir (void)
+{
+ static char *gtk_localedir = NULL;
+ if (gtk_localedir == NULL)
+ {
+ const gchar *p;
+ gchar *root, *temp;
+
+ /* GTK_LOCALEDIR ends in either /lib/locale or
+ * /share/locale. Scan for that slash.
+ */
+ p = GTK_LOCALEDIR + strlen (GTK_LOCALEDIR);
+ while (*--p != '/')
+ ;
+ while (*--p != '/')
+ ;
+
+ root = g_win32_get_package_installation_directory_of_module (gtk_dll);
+ temp = g_build_filename (root, p, NULL);
+ g_free (root);
+
+ /* 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"
+
/* Private type definitions
*/
typedef struct _GtkInitFunction GtkInitFunction;
GtkCallbackMarshal marshal;
GtkFunction function;
gpointer data;
- GtkDestroyNotify destroy;
+ GDestroyNotify destroy;
};
struct _GtkClosure
{
GtkCallbackMarshal marshal;
gpointer data;
- GtkDestroyNotify destroy;
+ GDestroyNotify destroy;
};
struct _GtkKeySnooperData
const guint gtk_interface_age = GTK_INTERFACE_AGE;
static guint gtk_main_loop_level = 0;
+static gint pre_initialized = FALSE;
static gint gtk_initialized = FALSE;
static GList *current_events = NULL;
*/
static GList *quit_functions = NULL; /* A list of quit functions.
*/
-static GMemChunk *quit_mem_chunk = NULL;
-
static GSList *key_snoopers = NULL;
guint gtk_debug_flags = 0; /* Global GTK debug flag */
{"multihead", GTK_DEBUG_MULTIHEAD},
{"modules", GTK_DEBUG_MODULES},
{"geometry", GTK_DEBUG_GEOMETRY},
- {"icontheme", GTK_DEBUG_ICONTHEME}
+ {"icontheme", GTK_DEBUG_ICONTHEME},
+ {"printing", GTK_DEBUG_PRINTING},
+ {"builder", GTK_DEBUG_BUILDER}
};
-
-static const guint gtk_ndebug_keys = sizeof (gtk_debug_keys) / sizeof (GDebugKey);
-
#endif /* G_ENABLE_DEBUG */
/**
* gtk_check_version:
* @required_major: the required major version.
- * @required_minor: the required major version.
- * @required_micro: the required major version.
+ * @required_minor: the required minor version.
+ * @required_micro: the required micro version.
*
* Checks that the GTK+ library in use is compatible with the
* given version. Generally you would pass in the constants
* The returned string is owned by GTK+ and should not be modified
* or freed.
**/
-gchar*
+const gchar*
gtk_check_version (guint required_major,
guint required_minor,
guint required_micro)
#ifdef G_OS_WIN32
-G_WIN32_DLLMAIN_FOR_DLL_NAME(static, dll_name)
-
const gchar *
_gtk_get_datadir (void)
{
static char *gtk_datadir = NULL;
if (gtk_datadir == NULL)
- gtk_datadir = g_win32_get_package_installation_subdirectory
- (GETTEXT_PACKAGE, dll_name, "share");
+ {
+ gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
+ gtk_datadir = g_build_filename (root, "share", NULL);
+ g_free (root);
+ }
return gtk_datadir;
}
-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");
+ {
+ gchar *root = g_win32_get_package_installation_directory_of_module (gtk_dll);
+ gtk_sysconfdir = g_build_filename (root, "etc", NULL);
+ g_free (root);
+ }
return gtk_sysconfdir;
}
{
static char *gtk_data_prefix = NULL;
if (gtk_data_prefix == NULL)
- gtk_data_prefix = g_win32_get_package_installation_directory
- (GETTEXT_PACKAGE, dll_name);
+ gtk_data_prefix = g_win32_get_package_installation_directory_of_module (gtk_dll);
return gtk_data_prefix;
}
void
gtk_disable_setlocale (void)
{
- if (gtk_initialized)
+ if (pre_initialized)
g_warning ("gtk_disable_setlocale() must be called before gtk_init()");
do_setlocale = FALSE;
{
gtk_debug_flags |= g_parse_debug_string (value,
gtk_debug_keys,
- gtk_ndebug_keys);
+ G_N_ELEMENTS (gtk_debug_keys));
return TRUE;
}
{
gtk_debug_flags &= ~g_parse_debug_string (value,
gtk_debug_keys,
- gtk_ndebug_keys);
+ G_N_ELEMENTS (gtk_debug_keys));
return TRUE;
}
return TRUE;
}
-static GOptionEntry gtk_args[] = {
+static const GOptionEntry gtk_args[] = {
{ "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") },
{ NULL }
};
+#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
+
+static void
+setlocale_initialization (void)
+{
+ static gboolean initialized = FALSE;
+
+ if (initialized)
+ return;
+ initialized = TRUE;
+
+ if (do_setlocale)
+ {
+#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
+ if (!setlocale (LC_ALL, ""))
+ g_warning ("Locale not supported by C library.\n\tUsing the fallback 'C' locale.");
+#endif
+ }
+}
+
static void
do_pre_parse_initialization (int *argc,
char ***argv)
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.");
- }
+ if (pre_initialized)
+ return;
+
+ pre_initialized = TRUE;
gdk_pre_parse_libgtk_only ();
gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
{
gtk_debug_flags = g_parse_debug_string (env_string,
gtk_debug_keys,
- gtk_ndebug_keys);
+ G_N_ELEMENTS (gtk_debug_keys));
env_string = NULL;
}
#endif /* G_ENABLE_DEBUG */
static void
gettext_initialization (void)
{
+ setlocale_initialization ();
+
#ifdef ENABLE_NLS
bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR);
bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR);
gettext_initialization ();
+#ifdef SIGPIPE
+ signal (SIGPIPE, SIG_IGN);
+#endif
+
if (g_fatal_warnings)
{
GLogLevelFlags fatal_mask;
* it isn't default:LTR or default:RTL it will not work
*/
char *e = _("default:LTR");
- if (strcmp (e, "default:RTL")==0) {
+ if (strcmp (e, "default:RTL")==0)
gtk_widget_set_default_direction (GTK_TEXT_DIR_RTL);
- } else if (strcmp (e, "default:LTR")) {
+ else if (strcmp (e, "default:LTR"))
g_warning ("Whoever translated default:LTR did so wrongly.\n");
- }
}
- gtk_type_init (0);
- _gtk_accel_map_init ();
+ /* do what the call to gtk_type_init() used to do */
+ g_type_init ();
+ gtk_object_get_type ();
+
+ _gtk_accel_map_init ();
_gtk_rc_init ();
/* Set the 'initialized' flag.
_gtk_modules_init (argc, argv, gtk_modules_string->str);
g_string_free (gtk_modules_string, TRUE);
}
+ else
+ {
+ _gtk_modules_init (argc, argv, NULL);
+ }
}
do_post_parse_initialization (NULL, NULL);
if (info->open_default_display)
- return gdk_display_open_default_libgtk_only () != NULL;
- else
- return TRUE;
+ {
+ if (gdk_display_open_default_libgtk_only () == NULL)
+ {
+ const char *display_name = gdk_get_display_arg_name ();
+ g_set_error (error,
+ G_OPTION_ERROR,
+ G_OPTION_ERROR_FAILED,
+ _("Cannot open display: %s"),
+ display_name ? display_name : "" );
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
}
* with g_option_context_add_group(), if you are using
* g_option_context_parse() to parse your commandline arguments.
*
- * Returns a #GOptionGroup for the commandline arguments recognized
+ * Returns: a #GOptionGroup for the commandline arguments recognized
* by GTK+
*
* Since: 2.6
GOptionGroup *group;
OptionGroupInfo *info;
+ gettext_initialization ();
+
info = g_new0 (OptionGroupInfo, 1);
info->open_default_display = open_default_display;
gboolean retval;
if (gtk_initialized)
- return TRUE;
+ return gdk_display_open_default_libgtk_only () != NULL;
gettext_initialization ();
{
GOptionContext *option_context;
GOptionGroup *gtk_group;
+ GError *error = NULL;
if (gtk_initialized)
return TRUE;
g_option_context_set_help_enabled (option_context, FALSE);
gtk_group = gtk_get_option_group (FALSE);
g_option_context_set_main_group (option_context, gtk_group);
- g_option_context_parse (option_context, argc, argv, NULL);
+ if (!g_option_context_parse (option_context, argc, argv, &error))
+ {
+ g_warning ("%s", error->message);
+ g_error_free (error);
+ }
+
g_option_context_free (option_context);
return TRUE;
* 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>
+ *
+ * <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>
**/
void
gtk_init (int *argc, char ***argv)
if (!gtk_init_check (argc, argv))
{
const char *display_name_arg = gdk_get_display_arg_name ();
- g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : " ");
+ if (display_name_arg == NULL)
+ display_name_arg = getenv("DISPLAY");
+ g_warning ("cannot open display: %s", display_name_arg ? display_name_arg : "");
exit (1);
}
}
* 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. See
- * _gtk_get_lc_ctype() for notes on behaviour on Windows.
+ * right-to-left or left-to-right text direction.
+ *
+ * This function is equivalent to pango_language_get_default(). See
+ * that function for details.
*
* Return value: the default language as a #PangoLanguage, must not be
* freed
PangoLanguage *
gtk_get_default_language (void)
{
- gchar *lang;
- PangoLanguage *result;
- gchar *p;
-
- lang = _gtk_get_lc_ctype ();
- p = strchr (lang, '.');
- if (p)
- *p = '\0';
- p = strchr (lang, '@');
- if (p)
- *p = '\0';
-
- result = pango_language_from_string (lang);
- g_free (lang);
-
- return result;
+ return pango_language_get_default ();
}
void
gtk_main_loop_level--;
- /* Try storing all clipboard data we have */
if (gtk_main_loop_level == 0)
- _gtk_clipboard_store_all ();
+ {
+ /* Try storing all clipboard data we have */
+ _gtk_clipboard_store_all ();
+
+ /* Synchronize the recent manager singleton */
+ _gtk_recent_manager_sync ();
+ }
}
guint
{
GdkWindow *grab_window;
GtkWidget *event_widget, *grab_widget;
+ gpointer grab_widget_ptr;
gboolean owner_events;
GdkDisplay *display;
}
event_widget = gtk_get_event_widget (event);
- gdk_window_get_user_data (grab_window, (void**) &grab_widget);
+ gdk_window_get_user_data (grab_window, &grab_widget_ptr);
+ grab_widget = grab_widget_ptr;
if (grab_widget &&
gtk_main_get_window_group (grab_widget) != gtk_main_get_window_group (event_widget))
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.
- */
- next_event = gdk_event_peek ();
-
- /* Try to compress enter/leave notify events. These event
- * pairs occur when the mouse is dragged quickly across
- * a window with many buttons (or through a menu). Instead
- * of highlighting and de-highlighting each widget that
- * is crossed it is better to simply de-highlight the widget
- * which contained the mouse initially and highlight the
- * widget which ends up containing the mouse.
- */
- if (next_event)
- if (((event->type == GDK_ENTER_NOTIFY) ||
- (event->type == GDK_LEAVE_NOTIFY)) &&
- ((next_event->type == GDK_ENTER_NOTIFY) ||
- (next_event->type == GDK_LEAVE_NOTIFY)) &&
- (next_event->type != event->type) &&
- (next_event->any.window == event->any.window))
- {
- /* Throw both the peeked copy and the queued copy away
- */
- gdk_event_free (next_event);
- next_event = gdk_event_get ();
- gdk_event_free (next_event);
-
- return;
- }
-
- if (next_event)
- gdk_event_free (next_event);
-
if (event->type == GDK_SETTING)
{
_gtk_settings_handle_event (&event->setting);
gdk_window_end_paint (event->any.window);
}
else
- gtk_widget_send_expose (event_widget, event);
+ {
+ /* The app may paint with a previously allocated cairo_t,
+ which will draw directly to the window. We can't catch cairo
+ drap operatoins to automatically flush the window, thus we
+ need to explicitly flush any outstanding moves or double
+ buffering */
+ gdk_window_flush (event->any.window);
+ gtk_widget_send_expose (event_widget, event);
+ }
break;
case GDK_PROPERTY_NOTIFY:
case GDK_VISIBILITY_NOTIFY:
case GDK_WINDOW_STATE:
case GDK_GRAB_BROKEN:
+ case GDK_DAMAGE:
gtk_widget_event (event_widget, event);
break;
break;
case GDK_ENTER_NOTIFY:
+ GTK_PRIVATE_SET_FLAG (event_widget, GTK_HAS_POINTER);
+ _gtk_widget_set_pointer_window (event_widget, event->any.window);
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);
- }
+ gtk_widget_event (grab_widget, event);
break;
case GDK_LEAVE_NOTIFY:
- if (GTK_WIDGET_LEAVE_PENDING (event_widget))
- {
- GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_LEAVE_PENDING);
- gtk_widget_event (event_widget, event);
- }
- else if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
+ GTK_PRIVATE_UNSET_FLAG (event_widget, GTK_HAS_POINTER);
+ if (GTK_WIDGET_IS_SENSITIVE (grab_widget))
gtk_widget_event (grab_widget, event);
break;
g_assert_not_reached ();
break;
}
+
+ if (event->type == GDK_ENTER_NOTIFY
+ || event->type == GDK_LEAVE_NOTIFY
+ || event->type == GDK_BUTTON_PRESS
+ || event->type == GDK_2BUTTON_PRESS
+ || event->type == GDK_3BUTTON_PRESS
+ || event->type == GDK_KEY_PRESS
+ || event->type == GDK_DRAG_ENTER
+ || event->type == GDK_GRAB_BROKEN
+ || event->type == GDK_MOTION_NOTIFY
+ || event->type == GDK_SCROLL)
+ {
+ _gtk_tooltip_handle_event (event);
+ }
tmp_list = current_events;
current_events = g_list_remove_link (current_events, tmp_list);
if (widget)
toplevel = gtk_widget_get_toplevel (widget);
- if (toplevel && GTK_IS_WINDOW (toplevel))
- return _gtk_window_get_group (GTK_WINDOW (toplevel));
+ if (GTK_IS_WINDOW (toplevel))
+ return gtk_window_get_group (GTK_WINDOW (toplevel));
else
- return _gtk_window_get_group (NULL);
+ return gtk_window_get_group (NULL);
}
typedef struct
{
GtkWidget *old_grab_widget;
GtkWidget *new_grab_widget;
+ gboolean was_grabbed;
+ gboolean is_grabbed;
+ gboolean from_grab;
} 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);
+
+ gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
- if (was_grabbed != is_grabbed)
- {
- g_object_ref (child);
+ was_grabbed = info->was_grabbed;
+ is_grabbed = info->is_grabbed;
- _gtk_widget_grab_notify (child, was_grabbed);
-
- if (GTK_IS_CONTAINER (child))
- gtk_container_foreach (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
-
- g_object_unref (child);
+ info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
+ info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
+
+ was_shadowed = info->old_grab_widget && !info->was_grabbed;
+ is_shadowed = info->new_grab_widget && !info->is_grabbed;
+
+ g_object_ref (child);
+
+ if ((was_shadowed || is_shadowed) && GTK_IS_CONTAINER (child))
+ gtk_container_forall (GTK_CONTAINER (child), gtk_grab_notify_foreach, info);
+
+ if (is_shadowed)
+ {
+ GTK_PRIVATE_SET_FLAG (child, GTK_SHADOWED);
+ if (!was_shadowed && GTK_WIDGET_HAS_POINTER (child)
+ && GTK_WIDGET_IS_SENSITIVE (child))
+ _gtk_widget_synthesize_crossing (child, info->new_grab_widget,
+ GDK_CROSSING_GTK_GRAB);
+ }
+ else
+ {
+ GTK_PRIVATE_UNSET_FLAG (child, GTK_SHADOWED);
+ if (was_shadowed && GTK_WIDGET_HAS_POINTER (child)
+ && GTK_WIDGET_IS_SENSITIVE (child))
+ _gtk_widget_synthesize_crossing (info->old_grab_widget, child,
+ info->from_grab ? GDK_CROSSING_GTK_GRAB
+ : GDK_CROSSING_GTK_UNGRAB);
}
+
+ if (was_shadowed != is_shadowed)
+ _gtk_widget_grab_notify (child, was_shadowed);
+
+ g_object_unref (child);
+
+ info->was_grabbed = was_grabbed;
+ info->is_grabbed = is_grabbed;
}
static void
gtk_grab_notify (GtkWindowGroup *group,
- GtkWidget *grab_widget,
- gboolean was_grabbed)
+ GtkWidget *old_grab_widget,
+ GtkWidget *new_grab_widget,
+ gboolean from_grab)
{
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;
- }
+ if (old_grab_widget == new_grab_widget)
+ return;
+
+ info.old_grab_widget = old_grab_widget;
+ info.new_grab_widget = new_grab_widget;
+ info.from_grab = from_grab;
g_object_ref (group);
- g_object_ref (grab_widget);
toplevels = gtk_window_list_toplevels ();
g_list_foreach (toplevels, (GFunc)g_object_ref, NULL);
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);
+ info.was_grabbed = FALSE;
+ info.is_grabbed = FALSE;
+
+ if (group == gtk_window_get_group (toplevel))
+ gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &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;
+ GtkWidget *old_grab_widget;
g_return_if_fail (widget != NULL);
group = gtk_main_get_window_group (widget);
- was_grabbed = (group->grabs != NULL);
-
+ if (group->grabs)
+ old_grab_widget = (GtkWidget *)group->grabs->data;
+ else
+ old_grab_widget = NULL;
+
g_object_ref (widget);
group->grabs = g_slist_prepend (group->grabs, widget);
- gtk_grab_notify (group, widget, FALSE);
+ gtk_grab_notify (group, old_grab_widget, widget, TRUE);
}
}
gtk_grab_remove (GtkWidget *widget)
{
GtkWindowGroup *group;
+ GtkWidget *new_grab_widget;
g_return_if_fail (widget != NULL);
group = gtk_main_get_window_group (widget);
group->grabs = g_slist_remove (group->grabs, widget);
- g_object_unref (widget);
+ if (group->grabs)
+ new_grab_widget = (GtkWidget *)group->grabs->data;
+ else
+ new_grab_widget = NULL;
- gtk_grab_notify (group, widget, TRUE);
+ gtk_grab_notify (group, widget, new_grab_widget, FALSE);
+
+ g_object_unref (widget);
}
}
GtkFunction function,
GtkCallbackMarshal marshal,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
static guint quit_id = 1;
GtkQuitFunction *quitf;
g_return_val_if_fail ((function != NULL) || (marshal != NULL), 0);
- if (!quit_mem_chunk)
- quit_mem_chunk = g_mem_chunk_new ("quit mem chunk", sizeof (GtkQuitFunction),
- 512, G_ALLOC_AND_FREE);
-
- quitf = g_chunk_new (GtkQuitFunction, quit_mem_chunk);
+ quitf = g_slice_new (GtkQuitFunction);
quitf->id = quit_id++;
quitf->main_level = main_level;
{
if (quitf->destroy)
quitf->destroy (quitf->data);
- g_mem_chunk_free (quit_mem_chunk, quitf);
+ g_slice_free (GtkQuitFunction, quitf);
}
static gint
GtkFunction function,
GtkCallbackMarshal marshal,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
if (marshal)
{
GtkFunction function,
GtkCallbackMarshal marshal,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
if (marshal)
{
GdkInputFunction function,
GtkCallbackMarshal marshal,
gpointer data,
- GtkDestroyNotify destroy)
+ GDestroyNotify destroy)
{
if (marshal)
{
condition,
(GdkInputFunction) gtk_invoke_input,
closure,
- (GdkDestroyNotify) gtk_destroy_closure);
+ (GDestroyNotify) gtk_destroy_closure);
}
else
return gdk_input_add_full (source, condition, function, data, destroy);
gtk_get_event_widget (GdkEvent *event)
{
GtkWidget *widget;
+ gpointer widget_ptr;
widget = NULL;
- if (event && event->any.window)
- gdk_window_get_user_data (event->any.window, (void**) &widget);
+ if (event && event->any.window &&
+ (event->type == GDK_DESTROY || !GDK_WINDOW_DESTROYED (event->any.window)))
+ {
+ gdk_window_get_user_data (event->any.window, &widget_ptr);
+ widget = widget_ptr;
+ }
return widget;
}
GtkWidget *window;
window = gtk_widget_get_toplevel (widget);
- if (window && GTK_IS_WINDOW (window))
+ if (GTK_IS_WINDOW (window))
{
/* If there is a grab within the window, give the grab widget
* a first crack at the key event
if (!handled_event)
{
window = gtk_widget_get_toplevel (widget);
- if (window && GTK_IS_WINDOW (window))
+ if (GTK_IS_WINDOW (window))
{
if (GTK_WIDGET_IS_SENSITIVE (window))
gtk_widget_event (window, event);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_signal_connect (GTK_OBJECT (window), "destroy",
- (GtkSignalFunc) gtk_widget_destroyed,
+ G_CALLBACK (gtk_widget_destroyed),
&window);
gtk_window_set_title (GTK_WINDOW (window), "Messages");
button = gtk_button_new_with_label ("close");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
- (GtkSignalFunc) gtk_widget_hide,
+ G_CALLBACK (gtk_widget_hide),
GTK_OBJECT (window));
gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);