* 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 <http://www.gnu.org/licenses/>.
*/
/*
#include "config.h"
-#include "gtkmainprivate.h"
-
-#include <glib.h>
#include "gdk/gdk.h"
#include <locale.h>
#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
*/
{"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 */
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;
/**
}
}
-static void
-check_mixed_deps (void)
-{
- GModule *module;
- gpointer func;
-
- module = g_module_open (NULL, 0);
-
- if (g_module_symbol (module, "gtk_progress_get_type", &func))
- {
- g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
- }
-
- g_module_close (module);
-}
-
static void
do_pre_parse_initialization (int *argc,
char ***argv)
pre_initialized = TRUE;
- check_mixed_deps ();
+ if (_gtk_module_has_mixed_deps (NULL))
+ g_error ("GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in the same process is not supported");
gdk_pre_parse_libgtk_only ();
gdk_event_handler_set ((GdkEventFunc)gtk_main_do_event, NULL, NULL);
-
+
#ifdef G_ENABLE_DEBUG
env_string = g_getenv ("GTK_DEBUG");
if (env_string != NULL)
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");
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 ();
{
_gtk_modules_init (argc, argv, NULL);
}
+
+ _gtk_accessibility_init ();
}
}
/**
- * gtk_get_option_group:
+ * gtk_get_option_group: (skip)
* @open_default_display: whether to open the default display
* when parsing the commandline arguments
*
/**
* 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 <parameter>argc</parameter> 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
+ * <parameter>argv</parameter> 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 <option>--help</option> output, after
* <literal><replaceable>programname</replaceable> [OPTION...]</literal>
/**
* gtk_init_check:
* @argc: (inout): Address of the <parameter>argc</parameter> 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
- * <parameter>argv</parameter> parameter of main()
- * Any parameters understood by gtk_init() are stripped before return
+ * <parameter>argv</parameter> 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
/**
* gtk_init:
* @argc: (inout): Address of the <parameter>argc</parameter> 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
- * <parameter>argv</parameter> parameter of main(). Any options
+ * <parameter>argv</parameter> 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.
*
#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
- * <literal>setlocale(LC_CTYPE, NULL)</literal>, 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:
*
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 ();
}
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 ();
}
}
{
gboolean result;
- GDK_THREADS_LEAVE ();
+ gdk_threads_leave ();
result = g_main_context_pending (NULL);
- GDK_THREADS_ENTER ();
+ gdk_threads_enter ();
return result;
}
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);
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);
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:
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);
* </para></listitem>
* <listitem><para>
* 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.
* </para></listitem>
* <listitem><para>
* Then the event is pushed onto a stack so you can query the currently
{
GtkWidget *event_widget;
GtkWidget *grab_widget = NULL;
+ GtkWidget *topmost_widget = NULL;
GtkWindowGroup *window_group;
GdkEvent *rewritten_event = NULL;
GdkDevice *device;
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;
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;
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 */
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;
|| 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);
}
/**
- * gtk_grab_add:
+ * gtk_grab_add: (method)
* @widget: The widget that grabs keyboard and pointer events
*
* Makes @widget the current grabbed widget.
}
/**
- * gtk_grab_remove:
+ * gtk_grab_remove: (method)
* @widget: The widget which gives up the grab
*
* Removes the grab from the given 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
}
/**
- * gtk_key_snooper_install:
+ * gtk_key_snooper_install: (skip)
* @snooper: a #GtkKeySnoopFunc
* @func_data: data to pass to @snooper
*
*
* 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,
* @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)
GSList *slist;
gint return_val = FALSE;
+ return_val = _gtk_accessibility_key_snooper (grab_widget, (GdkEventKey *) event);
+
slist = key_snoopers;
while (slist && !return_val)
{
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;
- handled_event = FALSE;
+ widget = tmp;
- g_object_ref (widget);
+ 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;
- if ((event->type == GDK_KEY_PRESS) ||
- (event->type == GDK_KEY_RELEASE))
+ 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);
+
+ return handled_event;
+}
+
+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)
{
/* Only send key events within Window widgets to the Window
* The Window widget will in turn pass the
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)
{
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);
}