[gtk/wip/otte/shortcut] shortcutcontroller: Add GtkShortcutScope



commit 73700ebf7e6fda7eca937d6131dc109f51c42f2d
Author: Benjamin Otte <otte redhat com>
Date:   Mon Aug 13 16:02:27 2018 +0200

    shortcutcontroller: Add GtkShortcutScope
    
    This allows marking a controller as global, so that its shortcuts get
    triggered by the root widget (usually the GtkWindow). This is meant to
    replace accelerators.

 docs/reference/gtk/gtk4-sections.txt |   3 +
 gtk/gtkenums.h                       |  19 ++++
 gtk/gtkshortcutcontroller.c          | 174 ++++++++++++++++++++++++++++++++++-
 gtk/gtkshortcutcontroller.h          |   6 ++
 gtk/gtkshortcutcontrollerprivate.h   |   3 +
 gtk/gtkwidget.c                      |  18 ++++
 6 files changed, 222 insertions(+), 1 deletion(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index b26ef5f630..2434c8b5bf 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -6529,6 +6529,9 @@ gtk_shortcut_get_type
 <TITLE>GtkShortcutController</TITLE>
 GtkShortcutController
 gtk_shortcut_controller_new
+GtkShortcutScope
+gtk_shortcut_controller_set_scope
+gtk_shortcut_controller_get_scope
 gtk_shortcut_controller_add_shortcut
 gtk_shortcut_controller_remove_shortcut
 
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 0dd737e418..9f0a16757d 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -1001,6 +1001,25 @@ typedef enum
   GTK_PAN_DIRECTION_DOWN
 } GtkPanDirection;
 
+/**
+ * GtkShortcutScope:
+ * @GTK_SHORTCUT_SCOPE_LOCAL: Shortcuts are handled inside
+ *     the widget hte controller belongs to.
+ * @GTK_SHORTCUT_SCOPE_MANAGED: Shortcuts are handled by
+ *     the first ancestor that is a #GtkShortcutManager
+ * @GTK_SHORTCUT_SCOPE_GLOBAL: Shortcuts are handled by
+ *     the root widget.
+ *
+ * Describes where #GtkShortcuts added to a
+ * #GtkShortcutController get handled.
+ */
+typedef enum
+{
+  GTK_SHORTCUT_SCOPE_LOCAL,
+  GTK_SHORTCUT_SCOPE_MANAGED,
+  GTK_SHORTCUT_SCOPE_GLOBAL
+} GtkShortcutScope;
+
 /**
  * GtkPopoverConstraint:
  * @GTK_POPOVER_CONSTRAINT_NONE: Don't constrain the popover position
diff --git a/gtk/gtkshortcutcontroller.c b/gtk/gtkshortcutcontroller.c
index d17e36a077..0e6bb3460c 100644
--- a/gtk/gtkshortcutcontroller.c
+++ b/gtk/gtkshortcutcontroller.c
@@ -32,7 +32,9 @@
 #include "gtkshortcutcontrollerprivate.h"
 
 #include "gtkeventcontrollerprivate.h"
+#include "gtkintl.h"
 #include "gtkshortcut.h"
+#include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
 
 #include <gdk/gdk.h>
@@ -42,6 +44,7 @@ struct _GtkShortcutController
   GtkEventController parent_instance;
 
   GSList *shortcuts;
+  GtkShortcutScope scope;
 
   guint run_class : 1;
 };
@@ -51,9 +54,67 @@ struct _GtkShortcutControllerClass
   GtkEventControllerClass parent_class;
 };
 
+enum {
+  PROP_0,
+  PROP_SCOPE,
+
+  N_PROPS
+};
+
+static GParamSpec *properties[N_PROPS] = { NULL, };
+
 G_DEFINE_TYPE (GtkShortcutController, gtk_shortcut_controller,
                GTK_TYPE_EVENT_CONTROLLER)
 
+static gboolean
+gtk_shortcut_controller_is_rooted (GtkShortcutController *self)
+{
+  GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (self));
+
+  if (widget == NULL)
+    return FALSE;
+
+  return gtk_widget_get_root (widget) != NULL;
+}
+
+static void
+gtk_shortcut_controller_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (object);
+
+  switch (prop_id)
+    {
+    case PROP_SCOPE:
+      gtk_shortcut_controller_set_scope (self, g_value_get_enum (value));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+gtk_shortcut_controller_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (object);
+
+  switch (prop_id)
+    {
+    case PROP_SCOPE:
+      g_value_set_enum (value, self->scope);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
 static void
 gtk_event_controller_dispose (GObject *object)
 {
@@ -104,14 +165,59 @@ gtk_shortcut_controller_handle_event (GtkEventController *controller,
   return FALSE;
 }
 
+static void
+gtk_shortcut_controller_set_widget (GtkEventController *controller,
+                                    GtkWidget          *widget)
+{
+  GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (controller);
+
+  GTK_EVENT_CONTROLLER_CLASS (gtk_shortcut_controller_parent_class)->set_widget (controller, widget);
+
+  if (_gtk_widget_get_root (widget))
+    gtk_shortcut_controller_root (self);
+}
+
+static void
+gtk_shortcut_controller_unset_widget (GtkEventController *controller)
+{
+  GtkShortcutController *self = GTK_SHORTCUT_CONTROLLER (controller);
+  GtkWidget *widget = gtk_event_controller_get_widget (controller);
+
+  if (_gtk_widget_get_root (widget))
+    gtk_shortcut_controller_unroot (self);
+
+  GTK_EVENT_CONTROLLER_CLASS (gtk_shortcut_controller_parent_class)->unset_widget (controller);
+}
+
 static void
 gtk_shortcut_controller_class_init (GtkShortcutControllerClass *klass)
 {
-  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
   GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
 
   object_class->dispose = gtk_event_controller_dispose;
+  object_class->set_property = gtk_shortcut_controller_set_property;
+  object_class->get_property = gtk_shortcut_controller_get_property;
+
   controller_class->handle_event = gtk_shortcut_controller_handle_event;
+  controller_class->set_widget = gtk_shortcut_controller_set_widget;
+  controller_class->unset_widget = gtk_shortcut_controller_unset_widget;
+
+  /**
+   * GtkShortcutController:scope:
+   *
+   * What scope the shortcuts will be handled in.
+   */
+  properties[PROP_SCOPE] =
+      g_param_spec_enum ("scope",
+                         P_("Scope"),
+                         P_("What scope the shortcuts will be handled in"),
+                         GTK_TYPE_SHORTCUT_SCOPE,
+                         GTK_SHORTCUT_SCOPE_LOCAL,
+                         G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPS, properties);
+
 }
 
 static void
@@ -119,6 +225,18 @@ gtk_shortcut_controller_init (GtkShortcutController *controller)
 {
 }
 
+void
+gtk_shortcut_controller_root (GtkShortcutController *controller)
+{
+  g_print ("rooting controller %p\n", controller);
+}
+
+void
+gtk_shortcut_controller_unroot (GtkShortcutController *controller)
+{
+  g_print ("unrooting controller %p\n", controller);
+}
+
 GtkEventController *
 gtk_shortcut_controller_new (void)
 {
@@ -182,3 +300,57 @@ gtk_shortcut_controller_remove_shortcut (GtkShortcutController  *self,
   self->shortcuts = g_slist_delete_link (self->shortcuts, l);
   g_object_unref (shortcut);
 }
+
+/**
+ * gtk_shortcut_controller_set_scope:
+ * @self: a #GtkShortcutController
+ * @scope: the new scope to use
+ *
+ * Sets the controller to have the given @scope.
+ *
+ * The scope allows shortcuts to be activated outside of the normal
+ * event propagation. In particular, it allows installing global
+ * keyboard shortcuts that can be activated even when a widget does
+ * not have focus.
+ **/
+void
+gtk_shortcut_controller_set_scope (GtkShortcutController *self,
+                                   GtkShortcutScope       scope)
+{
+  gboolean rooted;
+
+  g_return_if_fail (GTK_IS_SHORTCUT_CONTROLLER (self));
+
+  if (self->scope == scope)
+    return;
+
+  rooted = gtk_shortcut_controller_is_rooted (self);
+
+  if (rooted)
+    gtk_shortcut_controller_unroot (self);
+
+  self->scope = scope;
+
+  if (rooted)
+    gtk_shortcut_controller_root (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SCOPE]);
+}
+
+/**
+ * gtk_shortcut_controller_get_scope:
+ * @self: a #GtkShortcutController
+ *
+ * Gets the scope for when this controller activates its shortcuts. See
+ * gtk_shortcut_controller_set_scope() for details.
+ *
+ * Returns: the controller's scope
+ **/
+GtkShortcutScope
+gtk_shortcut_controller_get_scope (GtkShortcutController *self)
+{
+  g_return_val_if_fail (GTK_IS_SHORTCUT_CONTROLLER (self), GTK_SHORTCUT_SCOPE_LOCAL);
+
+  return self->scope;
+}
+
diff --git a/gtk/gtkshortcutcontroller.h b/gtk/gtkshortcutcontroller.h
index e078e3241a..3a6359d520 100644
--- a/gtk/gtkshortcutcontroller.h
+++ b/gtk/gtkshortcutcontroller.h
@@ -45,6 +45,12 @@ GType                   gtk_shortcut_controller_get_type                (void) G
 GDK_AVAILABLE_IN_ALL
 GtkEventController *    gtk_shortcut_controller_new                     (void);
 
+GDK_AVAILABLE_IN_ALL
+void                    gtk_shortcut_controller_set_scope               (GtkShortcutController  *controller,
+                                                                         GtkShortcutScope        scope);
+GDK_AVAILABLE_IN_ALL
+GtkShortcutScope        gtk_shortcut_controller_get_scope               (GtkShortcutController  *controller);
+
 GDK_AVAILABLE_IN_ALL
 void                    gtk_shortcut_controller_add_shortcut            (GtkShortcutController  *controller,
                                                                          GtkShortcut            *shortcut);
diff --git a/gtk/gtkshortcutcontrollerprivate.h b/gtk/gtkshortcutcontrollerprivate.h
index 945e526e66..29e771f9af 100644
--- a/gtk/gtkshortcutcontrollerprivate.h
+++ b/gtk/gtkshortcutcontrollerprivate.h
@@ -25,4 +25,7 @@
 void                    gtk_shortcut_controller_set_run_class           (GtkShortcutController  *controller,
                                                                          gboolean                run_class);
 
+void                    gtk_shortcut_controller_root                    (GtkShortcutController  *controller);
+void                    gtk_shortcut_controller_unroot                  (GtkShortcutController  *controller);
+
 #endif /* __GTK_SHORTCUT_CONTROLLER_H__ */
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 8744ec0e74..1a37c57947 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -864,12 +864,30 @@ gtk_widget_real_grab_notify (GtkWidget *widget,
 static void
 gtk_widget_real_root (GtkWidget *widget)
 {
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GList *l;
+
   gtk_widget_forall (widget, (GtkCallback) gtk_widget_root, NULL);
+
+  for (l = priv->event_controllers; l; l = l->next)
+    {
+      if (GTK_IS_SHORTCUT_CONTROLLER (l->data))
+        gtk_shortcut_controller_root (GTK_SHORTCUT_CONTROLLER (l->data));
+    }
 }
 
 static void
 gtk_widget_real_unroot (GtkWidget *widget)
 {
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GList *l;
+
+  for (l = priv->event_controllers; l; l = l->next)
+    {
+      if (GTK_IS_SHORTCUT_CONTROLLER (l->data))
+        gtk_shortcut_controller_unroot (GTK_SHORTCUT_CONTROLLER (l->data));
+    }
+
   gtk_widget_forall (widget, (GtkCallback) gtk_widget_unroot, NULL);
 }
 


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