From 09bb109f01e4455f8c286da91fb5314ffac037f5 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 18 Feb 2015 11:13:28 +0000 Subject: [PATCH] docs: Expand input handling documentation to cover event masks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also try and clarify a few things about event propagation. Move input-handling.xml into gtk-doc’s expand_content_files variable so it automatically links to widget documentation. Add links from gtk_widget_add_events() and friends to the new documentation. https://bugzilla.gnome.org/show_bug.cgi?id=744054 --- docs/reference/gtk/Makefile.am | 1 + docs/reference/gtk/gtk-docs.sgml | 2 +- docs/reference/gtk/input-handling.xml | 133 +++++++++++++++++++++----- gdk/gdktypes.h | 3 + gdk/gdkwindow.c | 4 + gtk/gtkwidget.c | 8 +- 6 files changed, 123 insertions(+), 28 deletions(-) diff --git a/docs/reference/gtk/Makefile.am b/docs/reference/gtk/Makefile.am index afa3c3d668..d6fa7b204b 100644 --- a/docs/reference/gtk/Makefile.am +++ b/docs/reference/gtk/Makefile.am @@ -174,6 +174,7 @@ expand_content_files = \ drawing-model.xml \ getting_started.xml \ glossary.xml \ + input-handling.xml \ migrating-2to3.xml \ migrating-checklist.sgml \ migrating-unique-GtkApplication.xml \ diff --git a/docs/reference/gtk/gtk-docs.sgml b/docs/reference/gtk/gtk-docs.sgml index 9e69992a63..67c661f201 100644 --- a/docs/reference/gtk/gtk-docs.sgml +++ b/docs/reference/gtk/gtk-docs.sgml @@ -25,7 +25,7 @@ - + diff --git a/docs/reference/gtk/input-handling.xml b/docs/reference/gtk/input-handling.xml index afd36dff7f..9b2d36cd82 100644 --- a/docs/reference/gtk/input-handling.xml +++ b/docs/reference/gtk/input-handling.xml @@ -87,56 +87,143 @@ - + Event propagation - When GTK+ receives an event, it determines the target widget that - it is directed to. Unless grabs are involved, this is done by finding - the widget to which the window of the event belongs. + For widgets which have a #GdkWindow set, events are received from the + windowing system and passed to gtk_main_do_event(). See its documentation + for details of what it does: compression of enter/leave events, + identification of the widget receiving the event, pushing the event onto a + stack for gtk_get_current_event(), and propagating the event to the + widget. - The event is then propagated from the toplevel window down to the - target widget. In this phase, which is known as the “capture” phase, - gestures that are attached with GTK_PHASE_CAPTURE get a chance - to react to the event. + When a GDK backend produces an input event, it is tied to a #GdkDevice and + a #GdkWindow, which in turn represents a windowing system surface in the + backend. If a widget has grabbed the current input device, or all input + devices, the event is propagated to that #GtkWidget. Otherwise, it is + propagated to the the #GtkWidget which called gtk_widget_register_window() + on the #GdkWindow receiving the event. + + + + Grabs are implemented for each input device, and globally. A grab for a + specific input device (gtk_device_grab_add()), is sent events in + preference to a global grab (gtk_grab_add()). Input grabs only have effect + within the #GtkWindowGroup containing the #GtkWidget which registered the + event’s #GdkWindow. If this #GtkWidget is a child of the grab widget, the + event is propagated to the child — this is the basis for propagating + events within modal dialogs. + + + + An event is propagated to a widget using gtk_propagate_event(). + Propagation differs between event types: key events (%GDK_KEY_PRESS, + %GDK_KEY_RELEASE) are delivered to the top-level #GtkWindow; other events + are propagated down and up the widget hierarchy in three phases (see + #GtkPropagationPhase). + + + + For key events, the top-level window’s default #GtkWindow::key-press-event + and #GtkWindow::key-release-event signal handlers handle mnemonics and + accelerators first. Other key presses are then passed to + gtk_window_propagate_key_event() which propagates the event upwards from + the window’s current focus widget (gtk_window_get_focus()) to the + top-level. + + + + For other events, in the first phase (the “capture” phase) the event is + delivered to each widget from the top-most (for example, the top-level + #GtkWindow or grab widget) down to the target #GtkWidget. + Gestures that are + attached with %GTK_PHASE_CAPTURE get a chance to react to the event. After the “capture” phase, the widget that was intended to be the - destination of the event will let run gestures attached to it with - GTK_PHASE_TARGET. This is known as the “target” phase, and does only - happen on that widget. + destination of the event will run gestures attached to it with + %GTK_PHASE_TARGET. This is known as the “target” phase, and only + happens on that widget. - Next, the appropriate event signal is emitted for the event in question, - e.g. “motion-notify-event”. Handling these signals was the primary - way to handle input in GTK+ widgets before gestures were introduced. - The signals are emitted from the target widget up to the toplevel, - until a signal handler indicates that it has handled the event, by - returning GDK_EVENT_STOP. + Next, the #GtkWidget::event signal is emitted, then the appropriate signal + for the event in question, for example #GtkWidget::motion-notify-event. + Handling these signals was the primary way to handle input in GTK+ widgets + before gestures were introduced. If the widget is realized, the + #GtkWidget::event-after signal is emitted. The signals are emitted from + the target widget up to the top-level, as part of the “bubble” phase. The default handlers for the event signals send the event - to gestures that are attached with GTK_PHASE_BUBBLE. Therefore, + to gestures that are attached with %GTK_PHASE_BUBBLE. Therefore, gestures in the “bubble” phase are only used if the widget does not have its own event handlers, or takes care to chain up to the - default GtkWidget handlers. + default #GtkWidget handlers. - Anytime during the propagation phase, a widget may indicate that a + Events are not delivered to a widget which is insensitive or unmapped. + + + + Any time during the propagation phase, a widget may indicate that a received event was consumed and propagation should therefore be stopped. - In traditional event handlers, this is hinted by returning GDK_EVENT_STOP, - if gestures are used, this may happen when the widget tells the gesture + In traditional event handlers, this is hinted by returning %GDK_EVENT_STOP. + If gestures are used, this may happen when the widget tells the gesture to claim the event touch sequence (or the pointer events) for its own. See the "gesture states" section below to know more of the latter. + + Event masks + + + Each widget instance has a basic event mask and another per input device, + which determine the types of input event it receives. Each event mask set + on a widget is added to the corresponding (basic or per-device) event mask + for the widget’s #GdkWindow, and all child #GdkWindows. + + + + If a widget is windowless (gtk_widget_get_has_window() returns %FALSE) and + an application wants to receive custom events on it, it must be placed + inside a #GtkEventBox to receive the events, and an appropriate event mask + must be set on the box. When implementing a widget, use a %GDK_INPUT_ONLY + #GdkWindow to receive the events instead. + + + + Filtering events against event masks happens inside #GdkWindow, which + exposes event masks to the windowing system to reduce the number of events + GDK receives from it. On receiving an event, it is filtered against the + #GdkWindow’s mask for the input device, if set. Otherwise, it is filtered + against the #GdkWindow’s basic event mask. + + + + This means that widgets must add to the event mask for each event type + they expect to receive, using gtk_widget_set_events() or + gtk_widget_add_events() to preserve the existing mask. Widgets which are + aware of floating devices should use gtk_widget_set_device_events() or + gtk_widget_add_device_events(), and must explicitly enable the device + using gtk_widget_set_device_enabled(). See the #GdkDeviceManager + documentation for more information. + + + + All standard widgets set the event mask for all events they expect to + receive, and it is not necessary to modify this. Masks should be set when + implementing a new widget. + + + Touch events @@ -209,7 +296,7 @@ - + Event controllers and gestures diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h index 1587ebf25a..7f45cee17f 100644 --- a/gdk/gdktypes.h +++ b/gdk/gdktypes.h @@ -372,6 +372,9 @@ typedef enum * Most of these masks map onto one or more of the #GdkEventType event types * above. * + * See the [input handling overview][chap-input-handling] for details of + * [event masks][event-masks] and [event propagation][event-propagation]. + * * %GDK_POINTER_MOTION_HINT_MASK is deprecated. It is a special mask * to reduce the number of %GDK_MOTION_NOTIFY events received. When using * %GDK_POINTER_MOTION_HINT_MASK, fewer %GDK_MOTION_NOTIFY events will diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c index 6e6e56ef8a..9ab1f8a80d 100644 --- a/gdk/gdkwindow.c +++ b/gdk/gdkwindow.c @@ -5425,6 +5425,8 @@ gdk_window_withdraw (GdkWindow *window) * including #GDK_BUTTON_PRESS_MASK means the window should report button * press events. The event mask is the bitwise OR of values from the * #GdkEventMask enumeration. + * + * See the [input handling overview][event-masks] for details. **/ void gdk_window_set_events (GdkWindow *window, @@ -5495,6 +5497,8 @@ gdk_window_get_events (GdkWindow *window) * press events. The event mask is the bitwise OR of values from the * #GdkEventMask enumeration. * + * See the [input handling overview][event-masks] for details. + * * Since: 3.0 **/ void diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index e4ebefa081..11307c6032 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -11301,7 +11301,8 @@ gtk_widget_add_events_internal (GtkWidget *widget, * @events: an event mask, see #GdkEventMask * * Adds the events in the bitfield @events to the event mask for - * @widget. See gtk_widget_set_events() for details. + * @widget. See gtk_widget_set_events() and the + * [input handling overview][event-masks] for details. **/ void gtk_widget_add_events (GtkWidget *widget, @@ -11534,9 +11535,8 @@ gtk_widget_get_settings (GtkWidget *widget) * gtk_widget_get_events: * @widget: a #GtkWidget * - * Returns the event mask for the widget (a bitfield containing flags - * from the #GdkEventMask enumeration). These are the events that the widget - * will receive. + * Returns the event mask (see #GdkEventMask) for the widget. These are the + * events that the widget will receive. * * Note: Internally, the widget event mask will be the logical OR of the event * mask set through gtk_widget_set_events() or gtk_widget_add_events(), and the