[gtk+/touchscreens: 2/39] Add GtkWidget::captured-event signal
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/touchscreens: 2/39] Add GtkWidget::captured-event signal
- Date: Wed, 23 Nov 2011 23:09:53 +0000 (UTC)
commit 0c229a0e936298ec3af76a624f5a3e4a029990ab
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Tue Feb 8 14:49:31 2011 +0100
Add GtkWidget::captured-event signal
https://bugzilla.gnome.org/show_bug.cgi?id=641836
gtk/gtkmain.c | 205 +++++++++++++++++++++++++++++++-----------------
gtk/gtkwidget.c | 62 +++++++++++++++
gtk/gtkwidget.h | 3 +-
gtk/gtkwidgetprivate.h | 3 +
4 files changed, 200 insertions(+), 73 deletions(-)
---
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 25e61eb..286085d 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -129,6 +129,8 @@
#include "gtkwidgetprivate.h"
#include "gtkwindowprivate.h"
+static gboolean gtk_propagate_captured_event (GtkWidget *widget,
+ GdkEvent *event);
/* Private type definitions
*/
@@ -1624,14 +1626,16 @@ 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);
+ if (!gtk_propagate_captured_event (grab_widget, event))
+ gtk_propagate_event (grab_widget, event);
break;
case GDK_KEY_PRESS:
@@ -1683,7 +1687,8 @@ gtk_main_do_event (GdkEvent *event)
case GDK_BUTTON_RELEASE:
case GDK_PROXIMITY_IN:
case GDK_PROXIMITY_OUT:
- gtk_propagate_event (grab_widget, event);
+ if (!gtk_propagate_captured_event (grab_widget, event))
+ gtk_propagate_event (grab_widget, event);
break;
case GDK_ENTER_NOTIFY:
@@ -1691,7 +1696,8 @@ gtk_main_do_event (GdkEvent *event)
gdk_event_get_device (event),
event->any.window);
if (gtk_widget_is_sensitive (grab_widget))
- gtk_widget_event (grab_widget, event);
+ if (!_gtk_widget_captured_event (grab_widget, event))
+ gtk_widget_event (grab_widget, event);
break;
case GDK_LEAVE_NOTIFY:
@@ -1699,7 +1705,8 @@ gtk_main_do_event (GdkEvent *event)
gdk_event_get_device (event),
NULL);
if (gtk_widget_is_sensitive (grab_widget))
- gtk_widget_event (grab_widget, event);
+ if (!_gtk_widget_captured_event (grab_widget, event))
+ gtk_widget_event (grab_widget, event);
break;
case GDK_DRAG_STATUS:
@@ -2320,45 +2327,87 @@ 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)
{
- 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);
+
+ widget = tmp;
+
+ if (handled_event || !widget)
+ break;
+ }
+
+ return handled_event;
+}
+
+static gboolean
+propagate_event_down (GtkWidget *widget,
+ GdkEvent *event)
+{
+ gint handled_event = FALSE;
+ GList *widgets = NULL;
+ GList *l;
- handled_event = FALSE;
+ widgets = g_list_prepend (widgets, g_object_ref (widget));
+ while (TRUE)
+ {
+ widget = gtk_widget_get_parent (widget);
+ if (!widget)
+ break;
- g_object_ref (widget);
+ widgets = g_list_prepend (widgets, g_object_ref (widget));
+ }
- if ((event->type == GDK_KEY_PRESS) ||
- (event->type == GDK_KEY_RELEASE))
+ for (l = widgets; l && !handled_event; l = g_list_next (l))
+ {
+ widget = (GtkWidget *)l->data;
+
+ if (!gtk_widget_is_sensitive (widget))
+ 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)
+{
+ 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
@@ -2370,11 +2419,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)
{
@@ -2382,45 +2432,56 @@ 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);
+ /* Other events get propagated up/down the widget tree */
+ return captured ? propagate_event_down (widget, event) : propagate_event_up (widget, event);
+}
- tmp = gtk_widget_get_parent (widget);
- g_object_unref (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)
+{
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+ g_return_if_fail (event != NULL);
- widget = tmp;
+ propagate_event (widget, event, FALSE);
+}
- if (!handled_event && widget)
- g_object_ref (widget);
- else
- break;
- }
- }
- else
- g_object_unref (widget);
+static gboolean
+gtk_propagate_captured_event (GtkWidget *widget,
+ GdkEvent *event)
+{
+ return propagate_event (widget, event, TRUE);
}
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 0babbbb..c2ce0b6 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -479,6 +479,7 @@ enum {
QUERY_TOOLTIP,
DRAG_FAILED,
STYLE_UPDATED,
+ CAPTURED_EVENT,
LAST_SIGNAL
};
@@ -699,6 +700,7 @@ static void gtk_widget_set_device_enabled_internal (GtkWidget *widget,
GdkDevice *device,
gboolean recurse,
gboolean enabled);
+static gboolean event_window_is_still_viewable (GdkEvent *event);
/* --- variables --- */
static gpointer gtk_widget_parent_class = NULL;
@@ -1791,6 +1793,9 @@ gtk_widget_class_init (GtkWidgetClass *klass)
* #GtkWidget::key-press-event) and finally a generic
* #GtkWidget::event-after signal.
*
+ * An event can be captured before ::event signal is emitted by connecting to
+ * ::captured-event event signal.
+ *
* Returns: %TRUE to stop other handlers from being invoked for the event
* and to cancel the emission of the second specific ::event signal.
* %FALSE to propagate the event further and to allow the emission of
@@ -1828,6 +1833,33 @@ gtk_widget_class_init (GtkWidgetClass *klass)
GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
/**
+ * GtkWidget::captured-event:
+ * @widget: the object which received the signal.
+ * @event: the #GdkEvent which triggered this signal
+ *
+ * The ::captured-event signal is emitted before the ::event signal to
+ * allow capturing an event before the specialized events are emitted.
+ * The event is propagated starting from the top-level container to
+ * the widget that received the event going down the hierarchy.
+ *
+ * Returns: %TRUE to stop other handlers from being invoked for the event
+ * and to cancel the emission of the ::event signal.
+ * %FALSE to propagate the event further and to allow the emission of
+ * the ::event signal.
+ *
+ * Since: 3.2
+ */
+ widget_signals[CAPTURED_EVENT] =
+ g_signal_new (I_("captured-event"),
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkWidgetClass, captured_event),
+ _gtk_boolean_handled_accumulator, NULL,
+ _gtk_marshal_BOOLEAN__BOXED,
+ G_TYPE_BOOLEAN, 1,
+ GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
+
+ /**
* GtkWidget::button-press-event:
* @widget: the object which received the signal.
* @event: (type Gdk.EventButton): the #GdkEventButton which triggered
@@ -5845,6 +5877,36 @@ gtk_widget_event (GtkWidget *widget,
return gtk_widget_event_internal (widget, event);
}
+gboolean
+_gtk_widget_captured_event (GtkWidget *widget,
+ GdkEvent *event)
+{
+ gboolean return_val = FALSE;
+
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
+ g_return_val_if_fail (WIDGET_REALIZED_FOR_EVENT (widget, event), TRUE);
+
+ if (event->type == GDK_EXPOSE)
+ {
+ g_warning ("Events of type GDK_EXPOSE cannot be synthesized. To get "
+ "the same effect, call gdk_window_invalidate_rect/region(), "
+ "followed by gdk_window_process_updates().");
+ return TRUE;
+ }
+
+ if (!event_window_is_still_viewable (event))
+ return TRUE;
+
+ g_object_ref (widget);
+
+ g_signal_emit (widget, widget_signals[CAPTURED_EVENT], 0, event, &return_val);
+ return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
+
+ g_object_unref (widget);
+
+ return return_val;
+}
+
/* Returns TRUE if a translation should be done */
gboolean
_gtk_widget_get_translation_to_window (GtkWidget *widget,
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 76d192c..1f7b15a 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -425,6 +425,8 @@ struct _GtkWidgetClass
void (* style_updated) (GtkWidget *widget);
+ void (* captured_event) (GtkWidget *widget,
+ GdkEvent *event);
/*< private >*/
GtkWidgetClassPrivate *priv;
@@ -436,7 +438,6 @@ struct _GtkWidgetClass
void (*_gtk_reserved5) (void);
void (*_gtk_reserved6) (void);
void (*_gtk_reserved7) (void);
- void (*_gtk_reserved8) (void);
};
struct _GtkWidgetAuxInfo
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 35f99b9..8716c67 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -163,6 +163,9 @@ void _gtk_widget_set_style (GtkWidget *widget,
GtkStyle *style);
+gboolean _gtk_widget_captured_event (GtkWidget *widget,
+ GdkEvent *event);
+
G_END_DECLS
#endif /* __GTK_WIDGET_PRIVATE_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]