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




commit b29df126917eae764c3a0223190e5fd02db45f1b
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        | 63 ++++++++++++++++++++++++++++++++++++++++++++++++--
 gtk/gtkwidget.h        |  3 +++
 gtk/gtkwidgetprivate.h |  1 +
 3 files changed, 65 insertions(+), 2 deletions(-)
---
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index afe7e9224e..0b97edc6d0 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,53 @@ gtk_widget_set_active_state (GtkWidget *widget,
         gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_ACTIVE);
     }
 }
+
+/**
+ * gtk_widget_set_action_parent:
+ * @widget: a #Gtkwidget
+ * @action_parent: (nullable): a #GtkWidget or %NULL
+ *
+ * Sets the action parent for @widget meaning that actions that are not
+ * attached to @widget will be resolved through @action_parent instead
+ * of the widgets parent.
+ *
+ * Setting an action parent can be particularly 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 || 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]