gtk: Run GtkWidgetClass event signals inside a GtkEventController

This will allow further cleanups and optimizations in capture/target/bubble
event delivery. For simplicity, ATM every widget will receive its own
GtkEventControllerLegacy, it could be desirable to add finer control over
this in the future, so widgets that fully use event controllers for input
management can do away without this legacy piece.
This commit is contained in:
Carlos Garnacho 2017-05-26 18:55:30 +02:00
parent b350db58e0
commit 8c350459ae
5 changed files with 185 additions and 27 deletions

View File

@ -0,0 +1,56 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2017, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#include "config.h"
#include "gtkeventcontrollerlegacyprivate.h"
G_DEFINE_TYPE (GtkEventControllerLegacy, _gtk_event_controller_legacy,
GTK_TYPE_EVENT_CONTROLLER)
static gboolean
gtk_event_controller_legacy_handle_event (GtkEventController *controller,
const GdkEvent *event)
{
GtkWidget *widget = gtk_event_controller_get_widget (controller);
return gtk_widget_emit_event_signals (widget, event);
}
static void
_gtk_event_controller_legacy_class_init (GtkEventControllerLegacyClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
controller_class->handle_event = gtk_event_controller_legacy_handle_event;
}
static void
_gtk_event_controller_legacy_init (GtkEventControllerLegacy *controller)
{
}
GtkEventController *
_gtk_event_controller_legacy_new (GtkWidget *widget)
{
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
return g_object_new (GTK_TYPE_EVENT_CONTROLLER_LEGACY,
"widget", widget,
NULL);
}

View File

@ -0,0 +1,51 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2017, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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, see <http://www.gnu.org/licenses/>.
*
* Author(s): Carlos Garnacho <carlosg@gnome.org>
*/
#ifndef __GTK_EVENT_CONTROLLER_LEGACY_H__
#define __GTK_EVENT_CONTROLLER_LEGACY_H__
#include "gtkeventcontrollerprivate.h"
#include "gtkwidgetprivate.h"
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_CONTROLLER_LEGACY (_gtk_event_controller_legacy_get_type ())
#define GTK_EVENT_CONTROLLER_LEGACY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacy))
#define GTK_EVENT_CONTROLLER_LEGACY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacyClass))
#define GTK_IS_EVENT_CONTROLLER_LEGACY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY))
#define GTK_IS_EVENT_CONTROLLER_LEGACY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER_LEGACY))
#define GTK_EVENT_CONTROLLER_LEGACY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER_LEGACY, GtkEventControllerLegacyClass))
typedef struct _GtkEventControllerLegacy GtkEventControllerLegacy;
typedef struct _GtkEventControllerLegacyClass GtkEventControllerLegacyClass;
struct _GtkEventControllerLegacy
{
GtkEventController parent_instance;
};
struct _GtkEventControllerLegacyClass
{
GtkEventControllerClass parent_class;
};
GType _gtk_event_controller_legacy_get_type (void) G_GNUC_CONST;
GtkEventController *_gtk_event_controller_legacy_new (GtkWidget *widget);
#endif /* __GTK_EVENT_CONTROLLER_LEGACY_H__ */

View File

@ -77,6 +77,7 @@
#include "gtkcssshadowsvalueprivate.h" #include "gtkcssshadowsvalueprivate.h"
#include "gtkdebugupdatesprivate.h" #include "gtkdebugupdatesprivate.h"
#include "gsk/gskdebugprivate.h" #include "gsk/gskdebugprivate.h"
#include "gtkeventcontrollerlegacyprivate.h"
#include "inspector/window.h" #include "inspector/window.h"
@ -3847,6 +3848,8 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
gtk_css_node_set_visible (priv->cssnode, priv->visible); gtk_css_node_set_visible (priv->cssnode, priv->visible);
/* need to set correct type here, and only class has the correct type here */ /* need to set correct type here, and only class has the correct type here */
gtk_css_node_set_widget_type (priv->cssnode, G_TYPE_FROM_CLASS (g_class)); gtk_css_node_set_widget_type (priv->cssnode, G_TYPE_FROM_CLASS (g_class));
gtk_widget_init_legacy_controller (widget);
} }
@ -6466,16 +6469,14 @@ static gboolean
gtk_widget_real_button_event (GtkWidget *widget, gtk_widget_real_button_event (GtkWidget *widget,
GdkEventButton *event) GdkEventButton *event)
{ {
return _gtk_widget_run_controllers (widget, (GdkEvent *) event, return GDK_EVENT_PROPAGATE;
GTK_PHASE_BUBBLE);
} }
static gboolean static gboolean
gtk_widget_real_motion_event (GtkWidget *widget, gtk_widget_real_motion_event (GtkWidget *widget,
GdkEventMotion *event) GdkEventMotion *event)
{ {
return _gtk_widget_run_controllers (widget, (GdkEvent *) event, return GDK_EVENT_PROPAGATE;
GTK_PHASE_BUBBLE);
} }
static gboolean static gboolean
@ -6518,10 +6519,6 @@ gtk_widget_real_touch_event (GtkWidget *widget,
gboolean return_val; gboolean return_val;
gint signum; gint signum;
if (!event->emulating_pointer)
return _gtk_widget_run_controllers (widget, (GdkEvent*) event,
GTK_PHASE_BUBBLE);
if (event->type == GDK_TOUCH_BEGIN || if (event->type == GDK_TOUCH_BEGIN ||
event->type == GDK_TOUCH_END) event->type == GDK_TOUCH_END)
{ {
@ -6587,8 +6584,7 @@ static gboolean
gtk_widget_real_grab_broken_event (GtkWidget *widget, gtk_widget_real_grab_broken_event (GtkWidget *widget,
GdkEventGrabBroken *event) GdkEventGrabBroken *event)
{ {
return _gtk_widget_run_controllers (widget, (GdkEvent*) event, return GDK_EVENT_PROPAGATE;
GTK_PHASE_BUBBLE);
} }
#define WIDGET_REALIZED_FOR_EVENT(widget, event) \ #define WIDGET_REALIZED_FOR_EVENT(widget, event) \
@ -6827,7 +6823,7 @@ static gint
gtk_widget_event_internal (GtkWidget *widget, gtk_widget_event_internal (GtkWidget *widget,
const GdkEvent *event) const GdkEvent *event)
{ {
gboolean return_val = FALSE, handled; gboolean return_val = FALSE;
GdkEvent *event_copy; GdkEvent *event_copy;
/* We check only once for is-still-visible; if someone /* We check only once for is-still-visible; if someone
@ -6838,7 +6834,27 @@ gtk_widget_event_internal (GtkWidget *widget,
if (!event_window_is_still_viewable (event)) if (!event_window_is_still_viewable (event))
return TRUE; return TRUE;
g_object_ref (widget); /* Non input events get handled right away */
switch (event->type)
{
case GDK_VISIBILITY_NOTIFY:
case GDK_EXPOSE:
case GDK_NOTHING:
case GDK_DELETE:
case GDK_DESTROY:
case GDK_CONFIGURE:
case GDK_MAP:
case GDK_UNMAP:
case GDK_WINDOW_STATE:
case GDK_PROPERTY_NOTIFY:
case GDK_SELECTION_CLEAR:
case GDK_SELECTION_REQUEST:
case GDK_SELECTION_NOTIFY:
return gtk_widget_emit_event_signals (widget, event);
default:
break;
}
event_copy = gdk_event_copy (event); event_copy = gdk_event_copy (event);
translate_event_coordinates (event_copy, widget); translate_event_coordinates (event_copy, widget);
@ -6846,18 +6862,39 @@ gtk_widget_event_internal (GtkWidget *widget,
if (widget == gtk_get_event_target (event_copy)) if (widget == gtk_get_event_target (event_copy))
return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_TARGET); return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_TARGET);
g_signal_emit (widget, widget_signals[EVENT], 0, event_copy, &handled); /* XXX: Tooltips should be handled through captured events in the toplevel */
return_val |= handled | !WIDGET_REALIZED_FOR_EVENT (widget, event_copy); if (event_copy->type == GDK_FOCUS_CHANGE)
{
if (event_copy->focus_change.in)
_gtk_tooltip_focus_in (widget);
else
_gtk_tooltip_focus_out (widget);
}
return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_BUBBLE);
gdk_event_free (event_copy);
return return_val;
}
gboolean
gtk_widget_emit_event_signals (GtkWidget *widget,
const GdkEvent *event)
{
gboolean return_val = FALSE, handled;
g_object_ref (widget);
g_signal_emit (widget, widget_signals[EVENT], 0, event, &handled);
return_val |= handled | !WIDGET_REALIZED_FOR_EVENT (widget, event);
if (!return_val) if (!return_val)
{ {
gint signal_num; gint signal_num;
switch (event_copy->type) switch (event->type)
{ {
case GDK_TOUCHPAD_SWIPE: case GDK_TOUCHPAD_SWIPE:
case GDK_TOUCHPAD_PINCH: case GDK_TOUCHPAD_PINCH:
return_val |= _gtk_widget_run_controllers (widget, event_copy, GTK_PHASE_BUBBLE);
/* Fall through */
case GDK_PAD_BUTTON_PRESS: case GDK_PAD_BUTTON_PRESS:
case GDK_PAD_BUTTON_RELEASE: case GDK_PAD_BUTTON_RELEASE:
case GDK_PAD_RING: case GDK_PAD_RING:
@ -6908,11 +6945,7 @@ gtk_widget_event_internal (GtkWidget *widget,
signal_num = LEAVE_NOTIFY_EVENT; signal_num = LEAVE_NOTIFY_EVENT;
break; break;
case GDK_FOCUS_CHANGE: case GDK_FOCUS_CHANGE:
signal_num = event_copy->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT; signal_num = event->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
if (event_copy->focus_change.in)
_gtk_tooltip_focus_in (widget);
else
_gtk_tooltip_focus_out (widget);
break; break;
case GDK_CONFIGURE: case GDK_CONFIGURE:
signal_num = CONFIGURE_EVENT; signal_num = CONFIGURE_EVENT;
@ -6948,23 +6981,22 @@ gtk_widget_event_internal (GtkWidget *widget,
signal_num = GRAB_BROKEN_EVENT; signal_num = GRAB_BROKEN_EVENT;
break; break;
default: default:
g_warning ("gtk_widget_event(): unhandled event type: %d", event_copy->type); g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
signal_num = -1; signal_num = -1;
break; break;
} }
if (signal_num != -1) if (signal_num != -1)
{ {
g_signal_emit (widget, widget_signals[signal_num], 0, event_copy, &handled); g_signal_emit (widget, widget_signals[signal_num], 0, event, &handled);
return_val |= handled; return_val |= handled;
} }
} }
if (WIDGET_REALIZED_FOR_EVENT (widget, event_copy)) if (WIDGET_REALIZED_FOR_EVENT (widget, event))
g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event_copy); g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event);
else else
return_val = TRUE; return_val = TRUE;
g_object_unref (widget); g_object_unref (widget);
gdk_event_free (event_copy);
return return_val; return return_val;
} }
@ -15552,3 +15584,14 @@ gtk_widget_get_pass_through (GtkWidget *widget)
{ {
return widget->priv->pass_through; return widget->priv->pass_through;
} }
void
gtk_widget_init_legacy_controller (GtkWidget *widget)
{
GtkEventController *controller;
controller = _gtk_event_controller_legacy_new (widget);
g_object_set_data_full (G_OBJECT (widget),
"gtk-widget-legacy-event-controller",
controller, g_object_unref);
}

View File

@ -334,6 +334,12 @@ void gtk_widget_set_pass_through (GtkWidget *widget,
gboolean pass_through); gboolean pass_through);
gboolean gtk_widget_get_pass_through (GtkWidget *widget); gboolean gtk_widget_get_pass_through (GtkWidget *widget);
gboolean gtk_widget_emit_event_signals (GtkWidget *widget,
const GdkEvent *event);
void gtk_widget_init_legacy_controller (GtkWidget *widget);
/* inline getters */ /* inline getters */
static inline GtkWidget * static inline GtkWidget *

View File

@ -146,6 +146,7 @@ gtk_public_sources = files([
'gtkentrybuffer.c', 'gtkentrybuffer.c',
'gtkentrycompletion.c', 'gtkentrycompletion.c',
'gtkeventcontroller.c', 'gtkeventcontroller.c',
'gtkeventcontrollerlegacy.c',
'gtkexpander.c', 'gtkexpander.c',
'gtkfilechooser.c', 'gtkfilechooser.c',
'gtkfilechooserbutton.c', 'gtkfilechooserbutton.c',
@ -364,6 +365,7 @@ gtk_public_sources = files([
gtk_private_type_headers = files([ gtk_private_type_headers = files([
'gtkcsstypesprivate.h', 'gtkcsstypesprivate.h',
'gtktexthandleprivate.h', 'gtktexthandleprivate.h',
'gtkeventcontrollerlegacyprivate.h',
]) ])
gtk_private_headers = gtk_private_type_headers + files([ gtk_private_headers = gtk_private_type_headers + files([