X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkmain.c;h=f5b4c5a520fcab8e9317930f1a416597990c8b45;hb=56bcb1933f6de613e5d8689e23420d47b65425c3;hp=47af37774a531464fc59e5cff6307577d390a8f3;hpb=d2bdd50a0b1f754540fe4038862c7c983513875c;p=~andy%2Fgtk diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c index 47af37774..f5b4c5a52 100644 --- a/gtk/gtkmain.c +++ b/gtk/gtkmain.c @@ -12,9 +12,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . */ /* @@ -91,9 +89,6 @@ #include "config.h" -#include "gtkmainprivate.h" - -#include #include "gdk/gdk.h" #include @@ -114,97 +109,26 @@ #include "gtkintl.h" -#include "gtkaccelmap.h" +#include "gtkaccelmapprivate.h" #include "gtkbox.h" #include "gtkclipboard.h" +#include "gtkdebug.h" #include "gtkdnd.h" -#include "gtkversion.h" +#include "gtkmain.h" +#include "gtkmenu.h" #include "gtkmodules.h" -#include "gtkrc.h" +#include "gtkmodulesprivate.h" +#include "gtkprivate.h" #include "gtkrecentmanager.h" +#include "gtkresources.h" #include "gtkselectionprivate.h" #include "gtksettingsprivate.h" +#include "gtktooltip.h" +#include "gtkversion.h" #include "gtkwidgetprivate.h" #include "gtkwindowprivate.h" -#include "gtktooltip.h" -#include "gtkdebug.h" -#include "gtkmenu.h" - -#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" +#include "a11y/gtkaccessibility.h" /* Private type definitions */ @@ -248,6 +172,7 @@ static const GDebugKey gtk_debug_keys[] = { {"printing", GTK_DEBUG_PRINTING}, {"builder", GTK_DEBUG_BUILDER}, {"size-request", GTK_DEBUG_SIZE_REQUEST}, + {"no-css-cache", GTK_DEBUG_NO_CSS_CACHE} }; #endif /* G_ENABLE_DEBUG */ @@ -448,48 +373,6 @@ check_setugid (void) return TRUE; } -#ifdef G_OS_WIN32 - -const gchar * -_gtk_get_datadir (void) -{ - static char *gtk_datadir = NULL; - if (gtk_datadir == NULL) - { - 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_sysconfdir (void) -{ - static char *gtk_sysconfdir = NULL; - if (gtk_sysconfdir == NULL) - { - 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; -} - -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_of_module (gtk_dll); - - return gtk_data_prefix; -} - -#endif /* G_OS_WIN32 */ - static gboolean do_setlocale = TRUE; /** @@ -738,32 +621,6 @@ setlocale_initialization (void) } } -/* Return TRUE if module_to_check causes version conflicts. - * If module_to_check is NULL, check the main module. - */ -gboolean -_gtk_module_has_mixed_deps (GModule *module_to_check) -{ - GModule *module; - gpointer func; - gboolean result; - - if (!module_to_check) - module = g_module_open (NULL, 0); - else - module = module_to_check; - - if (g_module_symbol (module, "gtk_progress_get_type", &func)) - result = TRUE; - else - result = FALSE; - - if (!module_to_check) - g_module_close (module); - - return result; -} - static void do_pre_parse_initialization (int *argc, char ***argv) @@ -803,8 +660,8 @@ gettext_initialization (void) setlocale_initialization (); #ifdef ENABLE_NLS - bindtextdomain (GETTEXT_PACKAGE, GTK_LOCALEDIR); - bindtextdomain (GETTEXT_PACKAGE "-properties", GTK_LOCALEDIR); + bindtextdomain (GETTEXT_PACKAGE, _gtk_get_localedir ()); + bindtextdomain (GETTEXT_PACKAGE "-properties", _gtk_get_localedir ()); # ifdef HAVE_BIND_TEXTDOMAIN_CODESET bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); bind_textdomain_codeset (GETTEXT_PACKAGE "-properties", "UTF-8"); @@ -850,8 +707,7 @@ do_post_parse_initialization (int *argc, g_warning ("Whoever translated default:LTR did so wrongly.\n"); } - /* do what the call to gtk_type_init() used to do */ - g_type_init (); + _gtk_register_resource (); _gtk_accel_map_init (); @@ -869,6 +725,8 @@ do_post_parse_initialization (int *argc, { _gtk_modules_init (argc, argv, NULL); } + + _gtk_accessibility_init (); } @@ -985,9 +843,12 @@ gtk_get_option_group (gboolean open_default_display) /** * gtk_init_with_args: - * @argc: a pointer to the number of command line arguments - * @argv: (inout) (array length=argc): a pointer to the array of - * command line arguments + * @argc: (inout): Address of the argc parameter of + * your main() function (or 0 if @argv is %NULL). This will be changed if + * any arguments were handled. + * @argv: (array length=argc) (inout) (allow-none): Address of the + * argv parameter of main(), or %NULL. Any options + * understood by GTK+ are stripped before return. * @parameter_string: a string which is displayed in * the first line of output, after * programname [OPTION...] @@ -1102,10 +963,11 @@ gtk_parse_args (int *argc, /** * gtk_init_check: * @argc: (inout): Address of the argc parameter of - * your main() function. Changed if any arguments were handled + * your main() function (or 0 if @argv is %NULL). This will be changed if + * any arguments were handled. * @argv: (array length=argc) (inout) (allow-none): Address of the - * argv parameter of main() - * Any parameters understood by gtk_init() are stripped before return + * argv parameter of main(), or %NULL. Any options + * understood by GTK+ 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 windowing system @@ -1135,15 +997,20 @@ gtk_init_check (int *argc, /** * gtk_init: * @argc: (inout): Address of the argc parameter of - * your main() function. Changed if any arguments were handled + * your main() function (or 0 if @argv is %NULL). This will be changed if + * any arguments were handled. * @argv: (array length=argc) (inout) (allow-none): Address of the - * argv parameter of main(). Any options + * argv parameter of main(), or %NULL. Any options * understood by GTK+ 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 parses some standard command line options. * + * Although you are expected to pass the @argc, @argv parameters from main() to + * this function, it is possible to pass %NULL if @argv is not available or + * commandline handling is not required. + * * @argc and @argv are adjusted accordingly so your own code will * never see those standard arguments. * @@ -1244,66 +1111,6 @@ gtk_init_check_abi_check (int *argc, char ***argv, int num_checks, size_t sizeof #endif -/* - * _gtk_get_lc_ctype: - * - * Return the Unix-style locale string for the language currently in - * effect. On Unix systems, this is the return value from - * setlocale(LC_CTYPE, NULL), and the user can - * affect this through the environment variables LC_ALL, LC_CTYPE or - * LANG (checked in that order). The locale strings typically is in - * the form lang_COUNTRY, where lang is an ISO-639 language code, and - * COUNTRY is an ISO-3166 country code. For instance, sv_FI for - * Swedish as written in Finland or pt_BR for Portuguese as written in - * Brazil. - * - * On Windows, the C library doesn't use any such environment - * variables, and setting them won't affect the behaviour of functions - * like ctime(). The user sets the locale through the Regional Options - * in the Control Panel. The C library (in the setlocale() function) - * does not use country and language codes, but country and language - * names spelled out in English. - * However, this function does check the above environment - * variables, and does return a Unix-style locale string based on - * either said environment variables or the thread's current locale. - * - * Return value: a dynamically allocated string, free with g_free(). - */ - -gchar * -_gtk_get_lc_ctype (void) -{ -#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, LC_CTYPE and LANG 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.) - */ - gchar *p; - - p = getenv ("LC_ALL"); - if (p != NULL) - return g_strdup (p); - - p = getenv ("LC_CTYPE"); - if (p != NULL) - return g_strdup (p); - - p = getenv ("LANG"); - if (p != NULL) - return g_strdup (p); - - return g_win32_getlocale (); -#else - return g_strdup (setlocale (LC_CTYPE, NULL)); -#endif -} - /** * gtk_get_default_language: * @@ -1345,9 +1152,9 @@ gtk_main (void) if (g_main_loop_is_running (main_loops->data)) { - GDK_THREADS_LEAVE (); + gdk_threads_leave (); g_main_loop_run (loop); - GDK_THREADS_ENTER (); + gdk_threads_enter (); gdk_flush (); } @@ -1359,11 +1166,15 @@ gtk_main (void) if (gtk_main_loop_level == 0) { + /* Keep this section in sync with gtk_application_shutdown() */ + /* Try storing all clipboard data we have */ _gtk_clipboard_store_all (); /* Synchronize the recent manager singleton */ _gtk_recent_manager_sync (); + + _gtk_accessibility_shutdown (); } } @@ -1422,9 +1233,9 @@ gtk_events_pending (void) { gboolean result; - GDK_THREADS_LEAVE (); + gdk_threads_leave (); result = g_main_context_pending (NULL); - GDK_THREADS_ENTER (); + gdk_threads_enter (); return result; } @@ -1445,9 +1256,9 @@ gtk_events_pending (void) gboolean gtk_main_iteration (void) { - GDK_THREADS_LEAVE (); + gdk_threads_leave (); g_main_context_iteration (NULL, TRUE); - GDK_THREADS_ENTER (); + gdk_threads_enter (); if (main_loops) return !g_main_loop_is_running (main_loops->data); @@ -1469,9 +1280,9 @@ gtk_main_iteration (void) gboolean gtk_main_iteration_do (gboolean blocking) { - GDK_THREADS_LEAVE (); + gdk_threads_leave (); g_main_context_iteration (NULL, blocking); - GDK_THREADS_ENTER (); + gdk_threads_enter (); if (main_loops) return !g_main_loop_is_running (main_loops->data); @@ -1527,6 +1338,14 @@ rewrite_event_for_window (GdkEvent *event, new_window, &event->motion.x, &event->motion.y); break; + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + rewrite_events_translate (event->any.window, + new_window, + &event->touch.x, &event->touch.y); + break; case GDK_KEY_PRESS: case GDK_KEY_RELEASE: case GDK_PROXIMITY_IN: @@ -1572,6 +1391,10 @@ rewrite_event_for_grabs (GdkEvent *event) case GDK_PROXIMITY_OUT: case GDK_KEY_PRESS: case GDK_KEY_RELEASE: + case GDK_TOUCH_BEGIN: + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: display = gdk_window_get_display (event->any.window); device = gdk_event_get_device (event); @@ -1616,8 +1439,7 @@ rewrite_event_for_grabs (GdkEvent *event) * * * Find the widget which got the event. If the widget can't be determined - * the event is thrown away unless it belongs to a INCR transaction. In that - * case it is passed to gtk_selection_incr_event(). + * the event is thrown away unless it belongs to a INCR transaction. * * * Then the event is pushed onto a stack so you can query the currently @@ -1659,6 +1481,7 @@ gtk_main_do_event (GdkEvent *event) { GtkWidget *event_widget; GtkWidget *grab_widget = NULL; + GtkWidget *topmost_widget = NULL; GtkWindowGroup *window_group; GdkEvent *rewritten_event = NULL; GdkDevice *device; @@ -1718,12 +1541,20 @@ gtk_main_do_event (GdkEvent *event) if (!grab_widget) grab_widget = gtk_window_group_get_current_grab (window_group); + /* Find out the topmost widget where captured event propagation + * should start, which is the widget holding the GTK+ grab + * if any, otherwise it's left NULL and events are emitted + * from the toplevel (or topmost parentless parent). + */ + if (grab_widget) + topmost_widget = grab_widget; + /* If the grab widget is an ancestor of the event widget * then we send the event to the original event widget. * This is the key to implementing modality. */ if (!grab_widget || - (gtk_widget_is_sensitive (event_widget) && + ((gtk_widget_is_sensitive (event_widget) || event->type == GDK_SCROLL) && gtk_widget_is_ancestor (event_widget, grab_widget))) grab_widget = event_widget; @@ -1814,27 +1645,41 @@ gtk_main_do_event (GdkEvent *event) case GDK_WINDOW_STATE: case GDK_GRAB_BROKEN: case GDK_DAMAGE: - gtk_widget_event (event_widget, event); + if (!_gtk_widget_captured_event (event_widget, event)) + gtk_widget_event (event_widget, event); break; case GDK_SCROLL: case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: - gtk_propagate_event (grab_widget, event); + case GDK_TOUCH_BEGIN: + if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget)) + gtk_propagate_event (grab_widget, event); break; case GDK_KEY_PRESS: case GDK_KEY_RELEASE: - if (key_snoopers) - { - if (gtk_invoke_key_snoopers (grab_widget, event)) - break; - } + if (gtk_invoke_key_snoopers (grab_widget, event)) + break; + + /* make focus visible in a window that receives a key event */ + { + GtkWidget *window; + GtkPolicyType visible_focus; + + window = gtk_widget_get_toplevel (grab_widget); + g_object_get (gtk_widget_get_settings (grab_widget), "gtk-visible-focus", &visible_focus, NULL); + if (GTK_IS_WINDOW (window) && visible_focus != GTK_POLICY_NEVER) + gtk_window_set_focus_visible (GTK_WINDOW (window), TRUE); + } + /* Catch alt press to enable auto-mnemonics; * menus are handled elsewhere + * FIXME: this does not work with mnemonic modifiers other than Alt */ if ((event->key.keyval == GDK_KEY_Alt_L || event->key.keyval == GDK_KEY_Alt_R) && + ((event->key.state & (gtk_accelerator_get_default_mod_mask ()) & ~(GDK_RELEASE_MASK|GDK_MOD1_MASK)) == 0) && !GTK_IS_MENU_SHELL (grab_widget)) { gboolean auto_mnemonics; @@ -1850,9 +1695,13 @@ gtk_main_do_event (GdkEvent *event) mnemonics_visible = (event->type == GDK_KEY_PRESS); window = gtk_widget_get_toplevel (grab_widget); - if (GTK_IS_WINDOW (window)) - gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible); + { + if (mnemonics_visible) + _gtk_window_set_auto_mnemonics_visible (GTK_WINDOW (window)); + else + gtk_window_set_mnemonics_visible (GTK_WINDOW (window), FALSE); + } } } /* else fall through */ @@ -1860,22 +1709,32 @@ gtk_main_do_event (GdkEvent *event) case GDK_BUTTON_RELEASE: case GDK_PROXIMITY_IN: case GDK_PROXIMITY_OUT: - gtk_propagate_event (grab_widget, event); + case GDK_TOUCH_UPDATE: + case GDK_TOUCH_END: + case GDK_TOUCH_CANCEL: + if (!_gtk_propagate_captured_event (grab_widget, event, topmost_widget)) + gtk_propagate_event (grab_widget, event); break; case GDK_ENTER_NOTIFY: - _gtk_widget_set_device_window (event_widget, - gdk_event_get_device (event), - event->any.window); - if (gtk_widget_is_sensitive (grab_widget)) + if (event->crossing.detail != GDK_NOTIFY_VIRTUAL && + event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL) + _gtk_widget_set_device_window (event_widget, + gdk_event_get_device (event), + event->any.window); + if (gtk_widget_is_sensitive (grab_widget) && + !_gtk_propagate_captured_event (grab_widget, event, topmost_widget)) gtk_widget_event (grab_widget, event); break; case GDK_LEAVE_NOTIFY: - _gtk_widget_set_device_window (event_widget, - gdk_event_get_device (event), - NULL); - if (gtk_widget_is_sensitive (grab_widget)) + if (event->crossing.detail != GDK_NOTIFY_VIRTUAL && + event->crossing.detail != GDK_NOTIFY_NONLINEAR_VIRTUAL) + _gtk_widget_set_device_window (event_widget, + gdk_event_get_device (event), + NULL); + if (gtk_widget_is_sensitive (grab_widget) && + !_gtk_propagate_captured_event (grab_widget, event, topmost_widget)) gtk_widget_event (grab_widget, event); break; @@ -1903,6 +1762,7 @@ gtk_main_do_event (GdkEvent *event) || event->type == GDK_DRAG_ENTER || event->type == GDK_GRAB_BROKEN || event->type == GDK_MOTION_NOTIFY + || event->type == GDK_TOUCH_UPDATE || event->type == GDK_SCROLL) { _gtk_tooltip_handle_event (event); @@ -2250,7 +2110,7 @@ gtk_grab_remove (GtkWidget *widget) /** * gtk_device_grab_add: * @widget: a #GtkWidget - * @device: a #GtkDevice to grab on. + * @device: a #GdkDevice to grab on. * @block_others: %TRUE to prevent other devices to interact with @widget. * * Adds a GTK+ grab on @device, so all the events on @device and its @@ -2319,6 +2179,9 @@ gtk_device_grab_remove (GtkWidget *widget, * * Returns: a unique id for this key snooper for use with * gtk_key_snooper_remove(). + * + * Deprecated: 3.4: Key snooping should not be done. Events should + * be handled by widgets. */ guint gtk_key_snooper_install (GtkKeySnoopFunc snooper, @@ -2343,6 +2206,9 @@ gtk_key_snooper_install (GtkKeySnoopFunc snooper, * @snooper_handler_id: Identifies the key snooper to remove * * Removes the key snooper function with the given id. + * + * Deprecated: 3.4: Key snooping should not be done. Events should + * be handled by widgets. */ void gtk_key_snooper_remove (guint snooper_id) @@ -2374,6 +2240,8 @@ gtk_invoke_key_snoopers (GtkWidget *grab_widget, GSList *slist; gint return_val = FALSE; + return_val = _gtk_accessibility_key_snooper (grab_widget, (GdkEventKey *) event); + slist = key_snoopers; while (slist && !return_val) { @@ -2497,45 +2365,104 @@ gtk_get_event_widget (GdkEvent *event) return widget; } -/** - * 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 #GtkWidget::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. There are almost - * certainly 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) +static gboolean +propagate_event_up (GtkWidget *widget, + GdkEvent *event, + GtkWidget *topmost) { - gint handled_event; + gboolean handled_event = FALSE; - g_return_if_fail (GTK_IS_WIDGET (widget)); - g_return_if_fail (event != NULL); + /* Propagate event up the widget tree so that + * parents can see the button and motion + * events of the children. + */ + while (TRUE) + { + GtkWidget *tmp; + + g_object_ref (widget); + + /* Scroll events are special cased here because it + * feels wrong when scrolling a GtkViewport, say, + * to have children of the viewport eat the scroll + * event + */ + if (!gtk_widget_is_sensitive (widget)) + handled_event = event->type != GDK_SCROLL; + else + handled_event = gtk_widget_event (widget, event); + + tmp = gtk_widget_get_parent (widget); + g_object_unref (widget); + + if (widget == topmost) + break; + + widget = tmp; + + if (handled_event || !widget) + break; + } + + return handled_event; +} + +static gboolean +propagate_event_down (GtkWidget *widget, + GdkEvent *event, + GtkWidget *topmost) +{ + gint handled_event = FALSE; + GList *widgets = NULL; + GList *l; + + widgets = g_list_prepend (widgets, g_object_ref (widget)); + while (widget && widget != topmost) + { + widget = gtk_widget_get_parent (widget); + if (!widget) + break; + + widgets = g_list_prepend (widgets, g_object_ref (widget)); + + if (widget == topmost) + break; + } + + for (l = widgets; l && !handled_event; l = g_list_next (l)) + { + widget = (GtkWidget *)l->data; + + if (!gtk_widget_is_sensitive (widget)) + { + /* stop propagating on SCROLL, but don't handle the event, so it + * can propagate up again and reach its handling widget + */ + if (event->type == GDK_SCROLL) + break; + else + handled_event = TRUE; + } + else + handled_event = _gtk_widget_captured_event (widget, event); + } + g_list_free_full (widgets, (GDestroyNotify)g_object_unref); - handled_event = FALSE; + return handled_event; +} - g_object_ref (widget); +static gboolean +propagate_event (GtkWidget *widget, + GdkEvent *event, + gboolean captured, + GtkWidget *topmost) +{ + gboolean handled_event = FALSE; + gboolean (* propagate_func) (GtkWidget *widget, GdkEvent *event); + + propagate_func = captured ? _gtk_widget_captured_event : gtk_widget_event; - if ((event->type == GDK_KEY_PRESS) || - (event->type == GDK_KEY_RELEASE)) + if (event->type == GDK_KEY_PRESS || event->type == GDK_KEY_RELEASE) { /* Only send key events within Window widgets to the Window * The Window widget will in turn pass the @@ -2547,11 +2474,12 @@ gtk_propagate_event (GtkWidget *widget, window = gtk_widget_get_toplevel (widget); if (GTK_IS_WINDOW (window)) { + g_object_ref (widget); /* 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); + handled_event = propagate_func (widget, event); if (!handled_event) { @@ -2559,61 +2487,59 @@ gtk_propagate_event (GtkWidget *widget, if (GTK_IS_WINDOW (window)) { if (gtk_widget_is_sensitive (window)) - gtk_widget_event (window, event); + handled_event = propagate_func (window, event); } } - handled_event = TRUE; /* don't send to widget */ + g_object_unref (widget); + return handled_event; } } - /* Other events get propagated up the widget tree - * so that parents can see the button and motion - * events of the children. - */ - if (!handled_event) - { - while (TRUE) - { - GtkWidget *tmp; - - /* Scroll events are special cased here because it - * feels wrong when scrolling a GtkViewport, say, - * to have children of the viewport eat the scroll - * event - */ - if (!gtk_widget_is_sensitive (widget)) - handled_event = event->type != GDK_SCROLL; - else - handled_event = gtk_widget_event (widget, event); - - tmp = gtk_widget_get_parent (widget); - g_object_unref (widget); + /* Other events get propagated up/down the widget tree */ + return captured ? + propagate_event_down (widget, event, topmost) : + propagate_event_up (widget, event, topmost); +} - widget = tmp; +/** + * 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 #GtkWidget::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. There are almost + * certainly 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) +{ + g_return_if_fail (GTK_IS_WIDGET (widget)); + g_return_if_fail (event != NULL); - if (!handled_event && widget) - g_object_ref (widget); - else - break; - } - } - else - g_object_unref (widget); + propagate_event (widget, event, FALSE, NULL); } gboolean -_gtk_boolean_handled_accumulator (GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer dummy) +_gtk_propagate_captured_event (GtkWidget *widget, + GdkEvent *event, + GtkWidget *topmost) { - 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; + return propagate_event (widget, event, TRUE, topmost); }