[gtk/wip/ebassi/shortcut: 15/85] shortcut: Add gtk_shortcut_set_callback()



commit cd8c71d20fcf4c616befb52c7dd332ea646480fa
Author: Benjamin Otte <otte redhat com>
Date:   Wed Aug 8 19:10:27 2018 +0200

    shortcut: Add gtk_shortcut_set_callback()
    
    ... and gtk_widget_class_add_binding() to go with it.
    
    This allows shortcuts to invoke manually added callbacks.

 docs/reference/gtk/gtk4-sections.txt |  3 ++
 gtk/gtkshortcut.c                    | 92 +++++++++++++++++++++++++++++++++++-
 gtk/gtkshortcut.h                    | 11 +++++
 gtk/gtkwidget.c                      | 50 ++++++++++++++++++++
 gtk/gtkwidget.h                      |  8 ++++
 5 files changed, 162 insertions(+), 2 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 37ef3f0b5b..66d90a9c0c 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -4291,6 +4291,7 @@ gtk_widget_remove_tick_callback
 gtk_widget_size_allocate
 gtk_widget_allocate
 gtk_widget_class_add_shortcut
+gtk_widget_class_add_binding
 gtk_widget_class_add_binding_signal
 gtk_widget_add_accelerator
 gtk_widget_remove_accelerator
@@ -6431,6 +6432,8 @@ gtk_shortcut_get_arguments
 gtk_shortcut_set_arguments
 gtk_shortcut_get_signal
 gtk_shortcut_set_signal
+gtk_shortcut_has_callback
+gtk_shortcut_set_callback
 
 <SUBSECTION Standard>
 GTK_TYPE_SHORTCUT
diff --git a/gtk/gtkshortcut.c b/gtk/gtkshortcut.c
index 90df956e1f..69e087603b 100644
--- a/gtk/gtkshortcut.c
+++ b/gtk/gtkshortcut.c
@@ -56,6 +56,9 @@ struct _GtkShortcut
 
   GtkShortcutTrigger *trigger;
   char *signal;
+  GtkShortcutFunc callback;
+  gpointer user_data;
+  GDestroyNotify destroy_notify;
   GVariant *args;
 };
 
@@ -63,6 +66,7 @@ enum
 {
   PROP_0,
   PROP_ARGUMENTS,
+  PROP_CALLBACK,
   PROP_SIGNAL,
   PROP_TRIGGER,
 
@@ -81,6 +85,15 @@ gtk_shortcut_dispose (GObject *object)
   g_clear_pointer (&self->trigger, gtk_shortcut_trigger_unref);
   g_clear_pointer (&self->signal, g_free);
   g_clear_pointer (&self->args, g_variant_unref);
+  if (self->callback)
+    {
+      if (self->destroy_notify)
+        self->destroy_notify (self->user_data);
+
+      self->callback = NULL;
+      self->user_data = NULL;
+      self->destroy_notify = NULL;
+    }
 
   G_OBJECT_CLASS (gtk_shortcut_parent_class)->dispose (object);
 }
@@ -99,6 +112,10 @@ gtk_shortcut_get_property (GObject    *object,
       g_value_set_variant (value, self->args);
       break;
 
+    case PROP_CALLBACK:
+      g_value_set_boolean (value, self->callback != NULL);
+      break;
+
     case PROP_SIGNAL:
       g_value_set_string (value, self->signal);
       break;
@@ -163,6 +180,18 @@ gtk_shortcut_class_init (GtkShortcutClass *klass)
                           NULL,
                           G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
 
+  /**
+   * GtkShortcut:callback:
+   *
+   * Whether a callback is used for shortcut activation
+   */
+  properties[PROP_CALLBACK] =
+    g_param_spec_boolean ("callback",
+                          P_("Callback"),
+                          P_("Whether a callback is used for shortcut activation"),
+                          FALSE,
+                          G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
   /**
    * GtkShortcut:signal:
    *
@@ -223,7 +252,11 @@ gtk_shortcut_activate (GtkShortcut *self,
   g_return_val_if_fail (GTK_IS_SHORTCUT (self), FALSE);
   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 
-  if (self->signal)
+  if (self->callback)
+    {
+      return self->callback (widget, self->args, self->user_data);
+    }
+  else if (self->signal)
     {
       GError *error = NULL;
       gboolean handled;
@@ -320,6 +353,28 @@ gtk_shortcut_set_arguments (GtkShortcut *self,
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ARGUMENTS]);
 }
 
+static void
+gtk_shortcut_clear_activation (GtkShortcut *self)
+{
+  if (self->signal)
+    {
+      g_clear_pointer (&self->signal, g_free);
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIGNAL]);
+    }
+
+  if (self->callback)
+    {
+      if (self->destroy_notify)
+        self->destroy_notify (self->user_data);
+
+      self->callback = NULL;
+      self->user_data = NULL;
+      self->destroy_notify = NULL;
+
+      g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CALLBACK]);
+    }
+}
+
 const char *
 gtk_shortcut_get_signal (GtkShortcut *self)
 {
@@ -337,9 +392,42 @@ gtk_shortcut_set_signal (GtkShortcut *self,
   if (g_strcmp0 (self->signal, signal) == 0)
     return;
   
-  g_clear_pointer (&self->signal, g_free);
+  g_object_freeze_notify (G_OBJECT (self));
+
+  gtk_shortcut_clear_activation (self);
   self->signal = g_strdup (signal);
 
   g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SIGNAL]);
+
+  g_object_thaw_notify (G_OBJECT (self));
+}
+
+gboolean
+gtk_shortcut_has_callback (GtkShortcut *self)
+{
+  g_return_val_if_fail (GTK_IS_SHORTCUT (self), FALSE);
+
+  return self->callback != NULL;
+}
+
+void
+gtk_shortcut_set_callback (GtkShortcut     *self,
+                           GtkShortcutFunc  callback,
+                           gpointer         data,
+                           GDestroyNotify   destroy)
+{
+  g_return_if_fail (GTK_IS_SHORTCUT (self));
+
+  g_object_freeze_notify (G_OBJECT (self));
+
+  gtk_shortcut_clear_activation (self);
+
+  self->callback = callback;
+  self->user_data = data;
+  self->destroy_notify = destroy;
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_CALLBACK]);
+
+  g_object_thaw_notify (G_OBJECT (self));
 }
 
diff --git a/gtk/gtkshortcut.h b/gtk/gtkshortcut.h
index 5cc18c6738..8df123597d 100644
--- a/gtk/gtkshortcut.h
+++ b/gtk/gtkshortcut.h
@@ -24,6 +24,10 @@
 
 G_BEGIN_DECLS
 
+typedef gboolean (* GtkShortcutFunc) (GtkWidget *widget,
+                                      GVariant  *args,
+                                      gpointer   user_data);
+
 #define GTK_TYPE_SHORTCUT         (gtk_shortcut_get_type ())
 
 GDK_AVAILABLE_IN_ALL
@@ -56,6 +60,13 @@ const char *    gtk_shortcut_get_signal                         (GtkShortcut
 GDK_AVAILABLE_IN_ALL
 void            gtk_shortcut_set_signal                         (GtkShortcut            *self,
                                                                  const gchar            *signal);
+GDK_AVAILABLE_IN_ALL
+gboolean        gtk_shortcut_has_callback                       (GtkShortcut            *self);
+GDK_AVAILABLE_IN_ALL
+void            gtk_shortcut_set_callback                       (GtkShortcut            *self,
+                                                                 GtkShortcutFunc         callback,
+                                                                 gpointer                data,
+                                                                 GDestroyNotify          destroy);
 
 G_END_DECLS
 
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 73d53f265c..5900a66bf5 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -4372,6 +4372,56 @@ gtk_widget_adjust_size_allocation (GtkWidget         *widget,
     }
 }
 
+/**
+ * gtk_widget_class_add_binding: (skip)
+ * @widget_class: the class to add the binding to
+ * @keyval: key value of binding to install
+ * @mods: key modifier of binding to install
+ * @callback: the callback to call upon activation
+ * @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 calls the given @callback
+ * 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. It does not provide for user_data, if you need that,
+ * you will have to use gtk_widget_class_add_shortcut() with a custom
+ * shortcut.
+ **/
+void
+gtk_widget_class_add_binding (GtkWidgetClass  *widget_class,
+                              guint            keyval,
+                              GdkModifierType  mods,
+                              GtkShortcutFunc  func,
+                              const gchar     *format_string,
+                              ...)
+{
+  GtkShortcut *shortcut;
+
+  g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
+
+  shortcut = gtk_shortcut_new ();
+  gtk_shortcut_set_trigger (shortcut, gtk_keyval_trigger_new (keyval, mods));
+  gtk_shortcut_set_callback (shortcut, func, NULL, NULL);
+  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_binding_signal: (skip)
  * @widget_class: the class to add the binding to
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index b0209967ee..9ddb5fe22e 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -33,6 +33,7 @@
 #include <gsk/gsk.h>
 #include <gtk/gtkaccelgroup.h>
 #include <gtk/gtkborder.h>
+#include <gtk/gtkshortcut.h>
 #include <gtk/gtktypes.h>
 #include <atk/atk.h>
 
@@ -370,6 +371,13 @@ 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   (GtkWidgetClass      *widget_class,
+                                           guint                keyval,
+                                           GdkModifierType      mods,
+                                           GtkShortcutFunc      callback,
+                                           const gchar         *format_string,
+                                           ...);
 GDK_AVAILABLE_IN_ALL
 void       gtk_widget_class_add_binding_signal
                                           (GtkWidgetClass      *widget_class,


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