[gtk/wip/chergert/action-parent: 1/4] widget: add gtk_widget_set_action_parent()




commit 25937d238656800c0876a7acf55b51552b417c51
Author: Christian Hergert <chergert redhat com>
Date:   Mon May 2 14:36:26 2022 -0700

    widget: add gtk_widget_set_action_parent()
    
    This adds a new function to the 4.8 ABI that allows setting an action
    parent for a widget. The action parent affects the action muxing so that
    instead of using the widgets direct ancestor, an alternate widget's
    action muxer may be used.
    
    You may not set an action parent for a widget that is a direct descendant
    of your widget as that would cause cycles in action resolution.
    
    You might find this API useful for situations where you want menus in
    headerbars to route through action muxers for the current document as
    well as toolbars or sidebars.
    
    Fixes #4860

 gtk/gtkwidget.c        | 66 ++++++++++++++++++++++++++++++++++++++++++++++++--
 gtk/gtkwidget.h        |  3 +++
 gtk/gtkwidgetprivate.h |  1 +
 3 files changed, 68 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index afe7e9224e..ca5ee20ed3 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -7390,6 +7390,8 @@ gtk_widget_dispose (GObject *object)
   GSList *sizegroups;
   GtkATContext *at_context;
 
+  g_clear_object (&priv->action_parent);
+
   if (priv->muxer != NULL)
     g_object_run_dispose (G_OBJECT (priv->muxer));
 
@@ -10808,13 +10810,20 @@ void
 _gtk_widget_update_parent_muxer (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GtkActionMuxer *parent_muxer;
   GtkWidget *child;
 
   if (priv->muxer == NULL)
     return;
 
-  gtk_action_muxer_set_parent (priv->muxer,
-                               gtk_widget_get_parent_muxer (widget, FALSE));
+  if (priv->action_parent != NULL &&
+      !gtk_widget_is_ancestor (priv->action_parent, widget))
+    parent_muxer = _gtk_widget_get_action_muxer (priv->action_parent, FALSE);
+  else
+    parent_muxer = gtk_widget_get_parent_muxer (widget, FALSE);
+
+  gtk_action_muxer_set_parent (priv->muxer, parent_muxer);
+
   for (child = gtk_widget_get_first_child (widget);
        child != NULL;
        child = gtk_widget_get_next_sibling (child))
@@ -12934,3 +12943,56 @@ gtk_widget_set_active_state (GtkWidget *widget,
         gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_ACTIVE);
     }
 }
+
+/**
+ * gtk_widget_set_action_parent:
+ * @widget: a [class@Gtk.Widget]
+ * @action_parent: (nullable): a [class@Gtk.Widget]
+ *
+ * Sets the action parent for @widget.
+ *
+ * Actions will resolve through @action_parent for @widget and all of
+ * it's descendants unless otherwise specified with
+ * [method@Gtk.Widget.set_action_parent].
+ *
+ * Setting an action parent can be useful when you want actions within
+ * a menu or toolbar to resolve through a document widget.
+ *
+ * To unset an action parent, use `NULL` for @action_parent and the widget
+ * will resume using the parent widget as the action parent.
+ *
+ * Since: 4.8
+ */
+void
+gtk_widget_set_action_parent (GtkWidget *widget,
+                              GtkWidget *action_parent)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+  GtkActionMuxer *muxer;
+  GtkActionMuxer *parent_muxer;
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+  g_return_if_fail (action_parent != widget);
+  g_return_if_fail (!action_parent || GTK_IS_WIDGET (action_parent));
+  g_return_if_fail (!action_parent || !gtk_widget_is_ancestor (action_parent, widget));
+
+  muxer = _gtk_widget_get_action_muxer (widget, FALSE);
+
+  if (action_parent == NULL)
+    {
+      if (muxer != NULL)
+        {
+          parent_muxer = gtk_widget_get_parent_muxer (widget, FALSE);
+          gtk_action_muxer_set_parent (muxer, parent_muxer);
+        }
+    }
+  else
+    {
+      if (muxer == NULL)
+        muxer = _gtk_widget_get_action_muxer (widget, TRUE);
+      parent_muxer = _gtk_widget_get_action_muxer (action_parent, TRUE);
+      gtk_action_muxer_set_parent (muxer, parent_muxer);
+    }
+
+  g_set_object (&priv->action_parent, action_parent);
+}
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 0788fcdd81..1a9793f296 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -924,6 +924,9 @@ char **                 gtk_widget_get_css_classes      (GtkWidget   *widget);
 GDK_AVAILABLE_IN_ALL
 void                    gtk_widget_set_css_classes      (GtkWidget   *widget,
                                                          const char **classes);
+GDK_AVAILABLE_IN_4_8
+void                    gtk_widget_set_action_parent    (GtkWidget   *widget,
+                                                         GtkWidget   *action_parent);
 
 
 
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index e1e336e6e6..b8f17c8f23 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -185,6 +185,7 @@ struct _GtkWidgetPrivate
   GtkListListModel *children_observer;
   GtkListListModel *controller_observer;
   GtkActionMuxer *muxer;
+  GtkWidget *action_parent;
 
   GtkWidget *focus_child;
 


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