[gtk/wip/baedert/for-master: 1/2] menubutton: Add a create_popup_func



commit 96778c6dc7ee3cf4f2164f783d12d36afafbeb2c
Author: Timm Bäder <mail baedert org>
Date:   Thu Aug 22 09:06:43 2019 +0200

    menubutton: Add a create_popup_func
    
    Some use cases require a menu button to create the popup on demand.

 docs/reference/gtk/gtk4-sections.txt |   1 +
 gtk/gtkmenubutton.c                  | 118 ++++++++++++++++++++++-------------
 gtk/gtkmenubutton.h                  |  17 +++++
 gtk/gtkmenubuttonprivate.h           |   7 ---
 gtk/gtkmenutoolbutton.c              |  10 +--
 5 files changed, 96 insertions(+), 57 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index b72906d7ab..477c0b4b9c 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -1866,6 +1866,7 @@ gtk_menu_button_set_relief
 gtk_menu_button_get_relief
 gtk_menu_button_popup
 gtk_menu_button_popdown
+gtk_menu_button_set_create_popup_func
 <SUBSECTION Standard>
 GTK_TYPE_MENU_BUTTON
 GTK_MENU_BUTTON
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index ba5e66fe9b..33a16903ef 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -150,8 +150,9 @@ struct _GtkMenuButtonPrivate
   GtkWidget *popover; /* Only one at a time can be set */
   GMenuModel *model;
 
-  GtkMenuButtonShowMenuCallback func;
-  gpointer user_data;
+  GtkMenuButtonCreatePopupFunc create_popup_func;
+  gpointer create_popup_user_data;
+  GDestroyNotify create_popup_destroy_notify;
 
   GtkWidget *align_widget;
   GtkWidget *arrow_widget;
@@ -289,9 +290,6 @@ popup_menu (GtkMenuButton *menu_button,
   GdkGravity widget_anchor = GDK_GRAVITY_SOUTH_WEST;
   GdkGravity menu_anchor = GDK_GRAVITY_NORTH_WEST;
 
-  if (priv->func)
-    priv->func (priv->user_data);
-
   if (!priv->menu)
     return;
 
@@ -446,7 +444,13 @@ static void
 gtk_menu_button_toggled (GtkMenuButton *menu_button)
 {
   GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
-  gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
+  const gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->button));
+
+  /* Might set a new menu/popover */
+  if (active && priv->create_popup_func)
+    {
+      priv->create_popup_func (menu_button, priv->create_popup_user_data);
+    }
 
   if (priv->menu)
     {
@@ -755,26 +759,34 @@ update_sensitivity (GtkMenuButton *menu_button)
   GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
 
   gtk_widget_set_sensitive (GTK_WIDGET (menu_button),
-                            priv->menu != NULL || priv->popover != NULL);
+                            priv->menu != NULL ||
+                            priv->popover != NULL ||
+                            priv->create_popup_func != NULL);
 }
 
-/* This function is used in GtkMenuToolButton, the call back will
- * be called when GtkMenuToolButton would have emitted the “show-menu”
- * signal.
+/**
+ * gtk_menu_button_set_popup:
+ * @menu_button: a #GtkMenuButton
+ * @menu: (nullable): a #GtkMenu, or %NULL to unset and disable the button
+ *
+ * Sets the #GtkMenu that will be popped up when the @menu_button is clicked, or
+ * %NULL to dissociate any existing menu and disable the button.
+ *
+ * If #GtkMenuButton:menu-model or #GtkMenuButton:popover are set, those objects
+ * are dissociated from the @menu_button, and those properties are set to %NULL.
  */
 void
-_gtk_menu_button_set_popup_with_func (GtkMenuButton                 *menu_button,
-                                      GtkWidget                     *menu,
-                                      GtkMenuButtonShowMenuCallback  func,
-                                      gpointer                       user_data)
+gtk_menu_button_set_popup (GtkMenuButton *menu_button,
+                           GtkWidget     *menu)
 {
   GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
 
   g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
   g_return_if_fail (GTK_IS_MENU (menu) || menu == NULL);
 
-  priv->func = func;
-  priv->user_data = user_data;
+  g_object_freeze_notify (G_OBJECT (menu_button));
+
+  g_clear_object (&priv->model);
 
   if (priv->menu == GTK_WIDGET (menu))
     return;
@@ -803,37 +815,8 @@ _gtk_menu_button_set_popup_with_func (GtkMenuButton                 *menu_button
                                 G_CALLBACK (menu_deactivate_cb), menu_button);
     }
 
-  update_sensitivity (menu_button);
-
   g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_POPUP]);
   g_object_notify_by_pspec (G_OBJECT (menu_button), menu_button_props[PROP_MENU_MODEL]);
-}
-
-/**
- * gtk_menu_button_set_popup:
- * @menu_button: a #GtkMenuButton
- * @menu: (nullable): a #GtkMenu, or %NULL to unset and disable the button
- *
- * Sets the #GtkMenu that will be popped up when the @menu_button is clicked, or
- * %NULL to dissociate any existing menu and disable the button.
- *
- * If #GtkMenuButton:menu-model or #GtkMenuButton:popover are set, those objects
- * are dissociated from the @menu_button, and those properties are set to %NULL.
- */
-void
-gtk_menu_button_set_popup (GtkMenuButton *menu_button,
-                           GtkWidget     *menu)
-{
-  GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
-
-  g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
-  g_return_if_fail (GTK_IS_MENU (menu) || menu == NULL);
-
-  g_object_freeze_notify (G_OBJECT (menu_button));
-
-  g_clear_object (&priv->model);
-
-  _gtk_menu_button_set_popup_with_func (menu_button, menu, NULL, NULL);
 
   if (menu && priv->popover)
     gtk_menu_button_set_popover (menu_button, NULL);
@@ -1129,6 +1112,9 @@ gtk_menu_button_dispose (GObject *object)
   g_clear_object (&priv->model);
   g_clear_pointer (&priv->button, gtk_widget_unparent);
 
+  if (priv->create_popup_destroy_notify)
+    priv->create_popup_destroy_notify (priv->create_popup_user_data);
+
   G_OBJECT_CLASS (gtk_menu_button_parent_class)->dispose (object);
 }
 
@@ -1447,3 +1433,45 @@ gtk_menu_button_add_child (GtkMenuButton *menu_button,
 
   gtk_container_add (GTK_CONTAINER (priv->button), new_child);
 }
+
+/**
+ * gtk_menu_button_set_create_popup_func:
+ * @menu_button: a #GtkMenuButton
+ * @func: (nullable): function to call when a popuop is about to
+ *   be shown, but none has been provided via other means, or %NULL
+ *   to reset to default behavior.
+ * @user_data: (nullable): user data to pass to @callback
+ * @destroy_notify: (nullable): destroy notify for @user_data
+ *
+ * Sets @func to be called when a popup is about to be shown.
+ * @func should use one of
+ *
+ *  - gtk_menu_button_set_popup()
+ *  - gtk_menu_button_set_popover()
+ *  - gtk_menu_button_set_menu_model()
+ *
+ * to set a popoup for @menu_button.
+ * If @func is non-%NULL, @menu_button will always be sensitive.
+ *
+ * Using this function will NOT reset the menu widget attached to @menu_button.
+ * Instead, this can be done manually in @func.
+ */
+void
+gtk_menu_button_set_create_popup_func (GtkMenuButton                *menu_button,
+                                       GtkMenuButtonCreatePopupFunc  func,
+                                       gpointer                      user_data,
+                                       GDestroyNotify                destroy_notify)
+{
+  GtkMenuButtonPrivate *priv = gtk_menu_button_get_instance_private (menu_button);
+
+  g_return_if_fail (GTK_IS_MENU_BUTTON (menu_button));
+
+  if (priv->create_popup_destroy_notify)
+    priv->create_popup_destroy_notify (priv->create_popup_user_data);
+
+  priv->create_popup_func = func;
+  priv->create_popup_user_data = user_data;
+  priv->create_popup_destroy_notify = destroy_notify;
+
+  update_sensitivity (menu_button);
+}
diff --git a/gtk/gtkmenubutton.h b/gtk/gtkmenubutton.h
index ad97d2b4fe..4ec73d39ff 100644
--- a/gtk/gtkmenubutton.h
+++ b/gtk/gtkmenubutton.h
@@ -37,6 +37,18 @@ G_BEGIN_DECLS
 
 typedef struct _GtkMenuButton        GtkMenuButton;
 
+/**
+ * GtkMenuButtonCreatePopupFunc:
+ * @menu_button: the #GtkMenuButton
+ *
+ * User-provided callback function to create a popup for @menu_button on demand.
+ * This function is called when the popoup of @menu_button is shown, but none has
+ * been provided via gtk_menu_buton_set_popup(), gtk_menu_button_set_popover()
+ * or gtk_menu_button_set_menu_model().
+ */
+typedef void  (*GtkMenuButtonCreatePopupFunc) (GtkMenuButton *menu_button,
+                                               gpointer       user_data);
+
 GDK_AVAILABLE_IN_ALL
 GType        gtk_menu_button_get_type       (void) G_GNUC_CONST;
 GDK_AVAILABLE_IN_ALL
@@ -102,6 +114,11 @@ void          gtk_menu_button_popup (GtkMenuButton *menu_button);
 GDK_AVAILABLE_IN_ALL
 void          gtk_menu_button_popdown (GtkMenuButton *menu_button);
 
+GDK_AVAILABLE_IN_ALL
+void          gtk_menu_button_set_create_popup_func (GtkMenuButton                *menu_button,
+                                                     GtkMenuButtonCreatePopupFunc  func,
+                                                     gpointer                      user_data,
+                                                     GDestroyNotify                destroy_notify);
 
 G_END_DECLS
 
diff --git a/gtk/gtkmenubuttonprivate.h b/gtk/gtkmenubuttonprivate.h
index 85114c3318..aaddeea39b 100644
--- a/gtk/gtkmenubuttonprivate.h
+++ b/gtk/gtkmenubuttonprivate.h
@@ -25,13 +25,6 @@
 
 G_BEGIN_DECLS
 
-typedef void (* GtkMenuButtonShowMenuCallback) (gpointer user_data);
-
-void       _gtk_menu_button_set_popup_with_func (GtkMenuButton                 *menu_button,
-                                                 GtkWidget                     *menu,
-                                                 GtkMenuButtonShowMenuCallback  func,
-                                                 gpointer                       user_data);
-
 void   gtk_menu_button_add_child (GtkMenuButton *button,
                                   GtkWidget     *child);
 
diff --git a/gtk/gtkmenutoolbutton.c b/gtk/gtkmenutoolbutton.c
index ec8448d86a..cfcb1127cf 100644
--- a/gtk/gtkmenutoolbutton.c
+++ b/gtk/gtkmenutoolbutton.c
@@ -363,7 +363,8 @@ gtk_menu_tool_button_new (GtkWidget   *icon_widget,
 }
 
 static void
-_show_menu_emit (gpointer user_data)
+_show_menu_emit (GtkMenuButton *menu_button,
+                 gpointer       user_data)
 {
   GtkMenuToolButton *button = (GtkMenuToolButton *) user_data;
   g_signal_emit (button, signals[SHOW_MENU], 0);
@@ -388,10 +389,9 @@ gtk_menu_tool_button_set_menu (GtkMenuToolButton *button,
 
   priv = button->priv;
 
-  _gtk_menu_button_set_popup_with_func (GTK_MENU_BUTTON (priv->arrow_button),
-                                        menu,
-                                        _show_menu_emit,
-                                        button);
+  gtk_menu_button_set_popup (GTK_MENU_BUTTON (priv->arrow_button), menu);
+  gtk_menu_button_set_create_popup_func (GTK_MENU_BUTTON (priv->arrow_button),
+                                         _show_menu_emit, NULL, NULL);
 
   g_object_notify (G_OBJECT (button), "menu");
 }


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