[gtk/wip/matthiasc/shortcut: 18/117] widget: Add gtk_widget_class_add_shortcut()



commit e19b49f5aaabd2a89e77b950c9e6fc232f3d5895
Author: Benjamin Otte <otte redhat com>
Date:   Sat Aug 4 12:16:00 2018 +0200

    widget: Add gtk_widget_class_add_shortcut()
    
    This allows adding shortcuts as a replacement for keybindings.

 docs/reference/gtk/gtk4-sections.txt |  2 +
 gtk/gtkshortcutcontroller.c          | 29 +++++++++++-
 gtk/gtkwidget.c                      | 88 ++++++++++++++++++++++++++++++++++++
 gtk/gtkwidget.h                      | 12 +++++
 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>
 
@@ -57,18 +59,41 @@ gtk_shortcut_controller_finalize (GObject *object)
   G_OBJECT_CLASS (gtk_shortcut_controller_parent_class)->finalize (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
@@ -373,6 +373,18 @@ void                    gtk_widget_class_set_layout_manager_type        (GtkWidg
 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,
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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]