diff options
-rw-r--r-- | docs/reference/gtk/gtk4-sections.txt | 2 | ||||
-rw-r--r-- | gtk/gtkshortcutcontroller.c | 29 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 88 | ||||
-rw-r--r-- | gtk/gtkwidget.h | 12 | ||||
-rw-r--r-- | gtk/gtkwidgetprivate.h | 1 |
5 files changed, 130 insertions, 2 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 2d062bc36d..dc0608c0bc 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -4034,6 +4034,8 @@ gtk_widget_add_tick_callback gtk_widget_remove_tick_callback gtk_widget_size_allocate gtk_widget_allocate +gtk_widget_class_add_shortcut +gtk_widget_class_add_binding_signal gtk_widget_add_accelerator gtk_widget_remove_accelerator gtk_widget_set_accel_path diff --git a/gtk/gtkshortcutcontroller.c b/gtk/gtkshortcutcontroller.c index 58bd4c0788..a4c757a699 100644 --- a/gtk/gtkshortcutcontroller.c +++ b/gtk/gtkshortcutcontroller.c @@ -33,6 +33,8 @@ #include "gtkeventcontrollerprivate.h" #include "gtkbindings.h" +#include "gtkshortcut.h" +#include "gtkwidgetprivate.h" #include <gdk/gdk.h> @@ -58,17 +60,40 @@ gtk_shortcut_controller_finalize (GObject *object) } static gboolean +gtk_shortcut_controller_trigger_shortcut (GtkShortcutController *self, + GtkShortcut *shortcut, + const GdkEvent *event) +{ + if (!gtk_shortcut_trigger (shortcut, event)) + return FALSE; + + return gtk_shortcut_activate (shortcut, gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self))); +} + +static gboolean gtk_shortcut_controller_handle_event (GtkEventController *controller, GdkEvent *event, double x, double y) { + GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (controller); GdkEventType event_type = gdk_event_get_event_type (event); + GtkWidget *widget; + const GSList *l; + widget = gtk_event_controller_get_widget (controller); if (event_type == GDK_KEY_PRESS || event_type == GDK_KEY_RELEASE) - return gtk_bindings_activate_event (G_OBJECT (gtk_event_controller_get_widget (controller)), - event); + { + if (gtk_bindings_activate_event (G_OBJECT (widget), event)) + return TRUE; + } + + for (l = gtk_widget_class_get_shortcuts (GTK_WIDGET_GET_CLASS (widget)); l; l = l->next) + { + if (gtk_shortcut_controller_trigger_shortcut (self, l->data, event)) + return TRUE; + } return FALSE; } diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 7dea10fc67..3f19f11f0c 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -59,6 +59,7 @@ #include "gtknativeprivate.h" #include "gtkscrollable.h" #include "gtksettingsprivate.h" +#include "gtkshortcut.h" #include "gtkshortcutcontroller.h" #include "gtksizegroup-private.h" #include "gtksnapshotprivate.h" @@ -494,6 +495,7 @@ typedef struct { struct _GtkWidgetClassPrivate { GtkWidgetTemplate *template; + GSList *shortcuts; GType accessible_type; AtkRole accessible_role; GQuark css_name; @@ -1719,6 +1721,7 @@ static void gtk_widget_base_class_finalize (GtkWidgetClass *klass) { template_data_free (klass->priv->template); + g_slist_free_full (klass->priv->shortcuts, g_object_unref); } static void @@ -4314,6 +4317,91 @@ gtk_widget_real_size_allocate (GtkWidget *widget, { } +/** + * gtk_widget_class_add_binding_signal: (skip) + * @widget_class: the class to add the binding to + * @mods: key modifier of binding to install + * @keyval: key value of binding to install + * @signal: the signal to execute + * @format_string: GVariant format string for arguments or %NULL for + * no arguments + * @...: arguments, as given by format string. + * + * Creates a new shortcut for @widget_class that emits the given action + * @signal with arguments read according to @format_string. + * The arguments and format string must be provided in the same way as + * with g_variant_new(). + * + * This function is a convenience wrapper around + * gtk_widget_class_add_shortcut() and must be called during class + * initialization. + */ +void +gtk_widget_class_add_binding_signal (GtkWidgetClass *widget_class, + GdkModifierType mods, + guint keyval, + const gchar *signal, + const gchar *format_string, + ...) +{ + GtkShortcut *shortcut; + + g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); + g_return_if_fail (g_signal_lookup (signal, G_TYPE_FROM_CLASS (widget_class))); + /* XXX: validate variant format for signal */ + + shortcut = gtk_shortcut_new (); + gtk_shortcut_set_keyval (shortcut, mods, keyval); + gtk_shortcut_set_signal (shortcut, signal); + if (format_string) + { + va_list args; + va_start (args, format_string); + gtk_shortcut_set_arguments (shortcut, + g_variant_new_va (format_string, NULL, &args)); + va_end (args); + } + + gtk_widget_class_add_shortcut (widget_class, shortcut); + + g_object_unref (shortcut); +} + +/** + * gtk_widget_class_add_shortcut: + * @widget_class: the class to add the shortcut to + * @shortcut: (transfer none): the #GtkShortcut to add + * + * Installs a shortcut in @widget_class. Every instance created for + * @widget_class or its subclasses will inherit this shortcut and + * trigger it. + * + * Shortcuts added this way will be triggered in the @GTK_PHASE_BUBBLE + * phase, which means they may also trigger if child widgets have focus. + * + * This function must only be used in class initialization functions + * otherwise it is not guaranteed that the shortcut will be installed. + **/ +void +gtk_widget_class_add_shortcut (GtkWidgetClass *widget_class, + GtkShortcut *shortcut) +{ + GtkWidgetClassPrivate *priv; + + g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class)); + g_return_if_fail (GTK_IS_SHORTCUT (shortcut)); + + priv = widget_class->priv; + + priv->shortcuts = g_slist_prepend (priv->shortcuts, g_object_ref (shortcut)); +} + +const GSList * +gtk_widget_class_get_shortcuts (GtkWidgetClass *widget_class) +{ + return widget_class->priv->shortcuts; +} + static gboolean gtk_widget_real_can_activate_accel (GtkWidget *widget, guint signal_id) diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h index 9121d5bb7e..6513fc311f 100644 --- a/gtk/gtkwidget.h +++ b/gtk/gtkwidget.h @@ -374,6 +374,18 @@ GDK_AVAILABLE_IN_ALL GType gtk_widget_class_get_layout_manager_type (GtkWidgetClass *widget_class); GDK_AVAILABLE_IN_ALL +void gtk_widget_class_add_binding_signal + (GtkWidgetClass *widget_class, + GdkModifierType mods, + guint keyval, + const gchar *signal, + const gchar *format_string, + ...); +GDK_AVAILABLE_IN_ALL +void gtk_widget_class_add_shortcut (GtkWidgetClass *widget_class, + GtkShortcut *shortcut); + +GDK_AVAILABLE_IN_ALL void gtk_widget_add_accelerator (GtkWidget *widget, const gchar *accel_signal, GtkAccelGroup *accel_group, diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h index 1018c9c915..9b5bed504a 100644 --- a/gtk/gtkwidgetprivate.h +++ b/gtk/gtkwidgetprivate.h @@ -232,6 +232,7 @@ void _gtk_widget_remove_attached_window (GtkWidget *widget, const gchar* _gtk_widget_get_accel_path (GtkWidget *widget, gboolean *locked); +const GSList * gtk_widget_class_get_shortcuts (GtkWidgetClass *widget_class); AtkObject * _gtk_widget_peek_accessible (GtkWidget *widget); |