[gtk/wip/matthiasc/context-menu: 4/13] label: Redo context menus



commit 964b2574cff262ed24fb4de92def082552b16dd1
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Jan 27 16:43:54 2019 -0500

    label: Redo context menus
    
    Drop the ::populate-popup signal and implement
    the new context menu api. Things are a bit more
    complicated here, since we have different menus
    on links and selectable text.

 docs/reference/gtk/gtk4-sections.txt |   3 +
 gtk/gtklabel.c                       | 419 +++++++++++++++++++++--------------
 gtk/gtklabel.h                       |   7 +
 3 files changed, 264 insertions(+), 165 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 3d7fcdcd54..1e265b63b0 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -1719,6 +1719,9 @@ gtk_label_set_single_line_mode
 gtk_label_get_current_uri
 gtk_label_set_track_visited_links
 gtk_label_get_track_visited_links
+gtk_label_set_extra_menu
+gtk_label_get_extra_menu
+
 <SUBSECTION Standard>
 GTK_LABEL
 GTK_IS_LABEL
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index ffc6d05e6e..6bc134edc2 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -55,6 +55,8 @@
 #include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
 #include "gtkwindow.h"
+#include "gtkpopovermenu.h"
+#include "gtknative.h"
 
 #include "a11y/gtklabelaccessibleprivate.h"
 
@@ -269,9 +271,6 @@ struct _GtkLabelClass
                             gboolean        extend_selection);
   void (* copy_clipboard)  (GtkLabel       *label);
 
-  void (* populate_popup)   (GtkLabel       *label,
-                             GtkMenu        *menu);
-
   gboolean (*activate_link) (GtkLabel       *label,
                              const gchar    *uri);
 };
@@ -286,6 +285,10 @@ struct _GtkLabelPrivate
   PangoAttrList *markup_attrs;
   PangoLayout   *layout;
 
+  GActionMap *context_actions;
+  GtkWidget *popup_menu;
+  GMenuModel *extra_menu;
+
   gchar   *label;
   gchar   *text;
 
@@ -355,12 +358,12 @@ struct _GtkLabelSelectionInfo
 {
   gint selection_anchor;
   gint selection_end;
-  GtkWidget *popup_menu;
   GtkCssNode *selection_node;
   GdkContentProvider *provider;
 
   GList *links;
   GtkLabelLink *active_link;
+  GtkLabelLink *context_link;
 
   GtkGesture *drag_gesture;
   GtkGesture *click_gesture;
@@ -378,7 +381,6 @@ struct _GtkLabelSelectionInfo
 enum {
   MOVE_CURSOR,
   COPY_CLIPBOARD,
-  POPULATE_POPUP,
   ACTIVATE_LINK,
   ACTIVATE_CURRENT_LINK,
   LAST_SIGNAL
@@ -407,6 +409,7 @@ enum {
   PROP_LINES,
   PROP_XALIGN,
   PROP_YALIGN,
+  PROP_EXTRA_MENU,
   NUM_PROPERTIES
 };
 
@@ -444,7 +447,6 @@ static gboolean gtk_label_focus         (GtkWidget         *widget,
 
 static void gtk_label_realize           (GtkWidget        *widget);
 static void gtk_label_unrealize         (GtkWidget        *widget);
-static void gtk_label_unmap             (GtkWidget        *widget);
 
 static void gtk_label_motion            (GtkEventControllerMotion *controller,
                                          double                    x,
@@ -483,6 +485,9 @@ static void gtk_label_recalculate                (GtkLabel      *label);
 static void gtk_label_root                       (GtkWidget     *widget);
 static void gtk_label_unroot                     (GtkWidget     *widget);
 static gboolean gtk_label_popup_menu             (GtkWidget     *widget);
+static void gtk_label_do_popup                   (GtkLabel      *label,
+                                                  double         x,
+                                                  double         y);
 
 static void gtk_label_set_selectable_hint (GtkLabel *label);
 static void gtk_label_ensure_select_info  (GtkLabel *label);
@@ -536,8 +541,6 @@ static void gtk_label_move_cursor        (GtkLabel        *label,
                                          gboolean         extend_selection);
 static void gtk_label_copy_clipboard     (GtkLabel        *label);
 static void gtk_label_select_all         (GtkLabel        *label);
-static void gtk_label_do_popup           (GtkLabel        *label,
-                                         const GdkEvent  *event);
 static gint gtk_label_move_forward_word  (GtkLabel        *label,
                                          gint             start);
 static gint gtk_label_move_backward_word (GtkLabel        *label,
@@ -572,6 +575,9 @@ static void   gtk_label_drag_gesture_update         (GtkGestureDrag *gesture,
                                                      gdouble         offset_y,
                                                      GtkLabel       *label);
 
+static void      gtk_label_add_context_actions (GtkLabel *label);
+static void      gtk_label_update_clipboard_actions (GtkLabel *label);
+
 static GtkSizeRequestMode gtk_label_get_request_mode                (GtkWidget           *widget);
 static void     gtk_label_measure (GtkWidget     *widget,
                                    GtkOrientation  orientation,
@@ -581,6 +587,8 @@ static void     gtk_label_measure (GtkWidget     *widget,
                                    int            *minimum_baseline,
                                    int            *natural_baseline);
 
+
+
 static GtkBuildableIface *buildable_parent_iface = NULL;
 
 G_DEFINE_TYPE_WITH_CODE (GtkLabel, gtk_label, GTK_TYPE_WIDGET,
@@ -630,13 +638,12 @@ gtk_label_class_init (GtkLabelClass *class)
   widget_class->snapshot = gtk_label_snapshot;
   widget_class->realize = gtk_label_realize;
   widget_class->unrealize = gtk_label_unrealize;
-  widget_class->unmap = gtk_label_unmap;
   widget_class->root = gtk_label_root;
   widget_class->unroot = gtk_label_unroot;
   widget_class->mnemonic_activate = gtk_label_mnemonic_activate;
+  widget_class->popup_menu = gtk_label_popup_menu;
   widget_class->drag_data_get = gtk_label_drag_data_get;
   widget_class->grab_focus = gtk_label_grab_focus;
-  widget_class->popup_menu = gtk_label_popup_menu;
   widget_class->focus = gtk_label_focus;
   widget_class->get_request_mode = gtk_label_get_request_mode;
   widget_class->measure = gtk_label_measure;
@@ -701,28 +708,6 @@ gtk_label_class_init (GtkLabelClass *class)
                  NULL,
                  G_TYPE_NONE, 0);
   
-  /**
-   * GtkLabel::populate-popup:
-   * @label: The label on which the signal is emitted
-   * @menu: the menu that is being populated
-   *
-   * The ::populate-popup signal gets emitted before showing the
-   * context menu of the label. Note that only selectable labels
-   * have context menus.
-   *
-   * If you need to add items to the context menu, connect
-   * to this signal and append your menuitems to the @menu.
-   */
-  signals[POPULATE_POPUP] =
-    g_signal_new (I_("populate-popup"),
-                 G_OBJECT_CLASS_TYPE (gobject_class),
-                 G_SIGNAL_RUN_LAST,
-                 G_STRUCT_OFFSET (GtkLabelClass, populate_popup),
-                 NULL, NULL,
-                 NULL,
-                 G_TYPE_NONE, 1,
-                 GTK_TYPE_MENU);
-
     /**
      * GtkLabel::activate-current-link:
      * @label: The label on which the signal was emitted
@@ -1019,6 +1004,19 @@ gtk_label_class_init (GtkLabelClass *class)
                         -1,
                         GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkLabel:extra-menu:
+   *
+   * A menu model whose contents will be appended to
+   * the context menu.
+   */
+  label_props[PROP_EXTRA_MENU] =
+      g_param_spec_object ("extra-menu",
+                          P_("Extra menu"),
+                          P_("Menu model to append to the context menu"),
+                          G_TYPE_MENU_MODEL,
+                          GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, label_props);
 
   /*
@@ -1211,6 +1209,9 @@ gtk_label_set_property (GObject      *object,
     case PROP_YALIGN:
       gtk_label_set_yalign (label, g_value_get_float (value));
       break;
+    case PROP_EXTRA_MENU:
+      gtk_label_set_extra_menu (label, g_value_get_object (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1288,6 +1289,9 @@ gtk_label_get_property (GObject     *object,
     case PROP_YALIGN:
       g_value_set_float (value, gtk_label_get_yalign (label));
       break;
+    case PROP_EXTRA_MENU:
+      g_value_set_object (value, gtk_label_get_extra_menu (label));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1326,6 +1330,8 @@ gtk_label_init (GtkLabel *label)
   priv->mnemonic_window = NULL;
 
   priv->mnemonics_visible = TRUE;
+
+  gtk_label_add_context_actions (label);
 }
 
 
@@ -3199,6 +3205,10 @@ gtk_label_finalize (GObject *object)
   gtk_label_clear_links (label);
   g_free (priv->select_info);
 
+  g_clear_object (&priv->context_actions);
+  g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
+  g_clear_object (&priv->extra_menu);
+
   G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
 }
 
@@ -3681,6 +3691,9 @@ gtk_label_size_allocate (GtkWidget *widget,
       else
         pango_layout_set_width (priv->layout, -1);
     }
+
+  if (priv->popup_menu)
+    gtk_native_check_resize (GTK_NATIVE (priv->popup_menu));
 }
 
 static void
@@ -4115,24 +4128,6 @@ gtk_label_unrealize (GtkWidget *widget)
   GTK_WIDGET_CLASS (gtk_label_parent_class)->unrealize (widget);
 }
 
-static void
-gtk_label_unmap (GtkWidget *widget)
-{
-  GtkLabel *label = GTK_LABEL (widget);
-  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
-
-  if (priv->select_info)
-    {
-      if (priv->select_info->popup_menu)
-        {
-          gtk_widget_destroy (priv->select_info->popup_menu);
-          priv->select_info->popup_menu = NULL;
-        }
-    }
-
-  GTK_WIDGET_CLASS (gtk_label_parent_class)->unmap (widget);
-}
-
 static gboolean
 get_layout_index (GtkLabel *label,
                   gint      x,
@@ -4471,7 +4466,7 @@ gtk_label_click_gesture_pressed (GtkGestureClick *gesture,
         {
           info->link_clicked = 1;
           update_link_state (label);
-          gtk_label_do_popup (label, event);
+          gtk_label_do_popup (label, widget_x, widget_y);
           return;
         }
       else if (button == GDK_BUTTON_PRIMARY)
@@ -4494,7 +4489,7 @@ gtk_label_click_gesture_pressed (GtkGestureClick *gesture,
   info->select_words = FALSE;
 
   if (gdk_event_triggers_context_menu (event))
-    gtk_label_do_popup (label, event);
+    gtk_label_do_popup (label, widget_x, widget_y);
   else if (button == GDK_BUTTON_PRIMARY)
     {
       if (!gtk_widget_has_focus (widget))
@@ -5972,167 +5967,220 @@ gtk_label_select_all (GtkLabel *label)
   gtk_label_select_region_index (label, 0, strlen (priv->text));
 }
 
-/* Quick hack of a popup menu
- */
 static void
-activate_cb (GtkWidget *menuitem,
-            GtkLabel  *label)
+open_link_activated (GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
 {
-  const gchar *signal = g_object_get_qdata (G_OBJECT (menuitem), quark_gtk_signal);
-  g_signal_emit_by_name (label, signal);
+  GtkLabel *label = GTK_LABEL (user_data);
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  GtkLabelLink *link = priv->select_info->context_link;
+
+  if (link)
+    emit_activate_link (label, link);
 }
 
 static void
-append_action_signal (GtkLabel     *label,
-                     GtkWidget    *menu,
-                     const gchar  *text,
-                     const gchar  *signal,
-                      gboolean      sensitive)
+copy_link_activated (GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
 {
-  GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (text);
+  GtkLabel *label = GTK_LABEL (user_data);
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  GtkLabelLink *link = priv->select_info->context_link;
 
-  g_object_set_qdata (G_OBJECT (menuitem), quark_gtk_signal, (char *)signal);
-  g_signal_connect (menuitem, "activate",
-                   G_CALLBACK (activate_cb), label);
+  if (link)
+    {
+      GdkClipboard *clipboard;
 
-  gtk_widget_set_sensitive (menuitem, sensitive);
-  
-  gtk_widget_show (menuitem);
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+      clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label));
+      gdk_clipboard_set_text (clipboard, link->uri);
+    }
+}
+
+static void
+copy_clipboard_activated (GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
+{
+  g_signal_emit_by_name (user_data, "copy-clipboard");
+}
+
+static void
+select_all_activated (GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+  gtk_label_select_all (GTK_LABEL (user_data));
 }
 
 static void
-popup_menu_detach (GtkWidget *attach_widget,
-                  GtkMenu   *menu)
+gtk_label_update_clipboard_actions (GtkLabel *label)
 {
-  GtkLabel *label = GTK_LABEL (attach_widget);
   GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  gboolean have_selection = FALSE;
+  GAction *action;
 
   if (priv->select_info)
-    priv->select_info->popup_menu = NULL;
+    have_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
+
+  action = g_action_map_lookup_action (priv->context_actions, "copy-clipboard");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_selection);
+  action = g_action_map_lookup_action (priv->context_actions, "select-all");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), gtk_label_get_selectable (label));
 }
 
 static void
-open_link_activate_cb (GtkMenuItem *menuitem,
-                       GtkLabel    *label)
+gtk_label_update_link_actions (GtkLabel *label)
 {
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  gboolean have_selection = FALSE;
+  GAction *action;
   GtkLabelLink *link;
 
-  link = g_object_get_qdata (G_OBJECT (menuitem), quark_link);
-  emit_activate_link (label, link);
+  have_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
+  if (priv->select_info->link_clicked)
+    link = priv->select_info->active_link;
+  else
+    link = gtk_label_get_focus_link (label);
+
+  action = g_action_map_lookup_action (priv->context_actions, "open-link");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !have_selection && link);
+  action = g_action_map_lookup_action (priv->context_actions, "copy-link");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), !have_selection && link);
 }
 
 static void
-copy_link_activate_cb (GtkMenuItem *menuitem,
-                       GtkLabel    *label)
+gtk_label_add_context_actions (GtkLabel *label)
 {
-  GtkLabelLink *link;
-  GdkClipboard *clipboard;
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+
+  GActionEntry entries[] = {
+    { "cut-clipboard", NULL, NULL, NULL, NULL },
+    { "copy-clipboard", copy_clipboard_activated, NULL, NULL, NULL },
+    { "paste-clipboard", NULL, NULL, NULL, NULL },
+    { "delete-selection", NULL, NULL, NULL, NULL },
+    { "select-all", select_all_activated, NULL, NULL, NULL },
+    { "open-link", open_link_activated, NULL, NULL, NULL },
+    { "copy-link", copy_link_activated, NULL, NULL, NULL },
+  };
+
+  GSimpleActionGroup *actions = g_simple_action_group_new ();
+  GAction *action;
+
+  priv->context_actions = G_ACTION_MAP (actions);
+
+  g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), label);
+
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "cut-clipboard");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-clipboard");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "paste-clipboard");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "delete-selection");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "select-all");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "open-link");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
+  action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-link");
+  g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
 
-  link = g_object_get_qdata (G_OBJECT (menuitem), quark_link);
-  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label));
-  gdk_clipboard_set_text (clipboard, link->uri);
+  gtk_widget_insert_action_group (GTK_WIDGET (label), "context", G_ACTION_GROUP (actions));
 }
 
-static gboolean
-gtk_label_popup_menu (GtkWidget *widget)
+static GMenuModel *
+gtk_label_get_menu_model (GtkLabel *label)
 {
-  gtk_label_do_popup (GTK_LABEL (widget), NULL);
-
-  return TRUE;
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  GMenu *menu, *section;
+  GMenuItem *item;
+
+  menu = g_menu_new ();
+
+  section = g_menu_new ();
+  g_menu_append (section, _("Cu_t"), "context.cut-clipboard");
+  g_menu_append (section, _("_Copy"), "context.copy-clipboard");
+  g_menu_append (section, _("_Paste"), "context.paste-clipboard");
+  g_menu_append (section, _("_Delete"), "context.delete-selection");
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
+  g_object_unref (section);
+
+  section = g_menu_new ();
+  g_menu_append (section, _("Select _All"), "context.select-all");
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
+  g_object_unref (section);
+
+  section = g_menu_new ();
+  item = g_menu_item_new (_("_Open Link"), "context.open-link");
+  g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
+  g_menu_append_item (section, item);
+  g_object_unref (item);
+  item = g_menu_item_new (_("Copy _Link Address"), "context.copy-link");
+  g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
+  g_menu_append_item (section, item);
+  g_object_unref (item);
+  g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
+  g_object_unref (section);
+
+  if (priv->extra_menu)
+    g_menu_append_section (menu, NULL, priv->extra_menu);
+
+  return G_MENU_MODEL (menu);
 }
 
 static void
-gtk_label_do_popup (GtkLabel       *label,
-                    const GdkEvent *event)
+gtk_label_do_popup (GtkLabel *label,
+                    double    x,
+                    double    y)
 {
   GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
-  GtkWidget *menuitem;
-  GtkWidget *menu;
-  gboolean have_selection;
-  GtkLabelLink *link;
 
-  if (!priv->select_info)
-    return;
+  gtk_label_update_clipboard_actions (label);
+  gtk_label_update_link_actions (label);
 
-  if (priv->select_info->popup_menu)
-    gtk_widget_destroy (priv->select_info->popup_menu);
-
-  priv->select_info->popup_menu = menu = gtk_menu_new ();
-  gtk_style_context_add_class (gtk_widget_get_style_context (menu),
-                               GTK_STYLE_CLASS_CONTEXT_MENU);
+  if (!priv->popup_menu)
+    {
+      GMenuModel *model;
 
-  gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (label), popup_menu_detach);
+      model = gtk_label_get_menu_model (label);
+      priv->popup_menu = gtk_popover_menu_new_from_model (GTK_WIDGET (label), model);
+      gtk_popover_set_position (GTK_POPOVER (priv->popup_menu), GTK_POS_BOTTOM);
 
-  have_selection =
-    priv->select_info->selection_anchor != priv->select_info->selection_end;
+      gtk_popover_set_has_arrow (GTK_POPOVER (priv->popup_menu), FALSE);
+      gtk_widget_set_halign (priv->popup_menu, GTK_ALIGN_START);
 
-  if (event)
-    {
-      if (priv->select_info->link_clicked)
-        link = priv->select_info->active_link;
-      else
-        link = NULL;
+      g_object_unref (model);
     }
-  else
-    link = gtk_label_get_focus_link (label);
 
-  if (!have_selection && link)
+  if (x != -1 && y != -1)
     {
-      /* Open Link */
-      menuitem = gtk_menu_item_new_with_mnemonic (_("_Open Link"));
-      g_object_set_qdata (G_OBJECT (menuitem), quark_link, link);
-      gtk_widget_show (menuitem);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-
-      g_signal_connect (G_OBJECT (menuitem), "activate",
-                        G_CALLBACK (open_link_activate_cb), label);
-
-      /* Copy Link Address */
-      menuitem = gtk_menu_item_new_with_mnemonic (_("Copy _Link Address"));
-      g_object_set_qdata (G_OBJECT (menuitem), quark_link, link);
-      gtk_widget_show (menuitem);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-
-      g_signal_connect (G_OBJECT (menuitem), "activate",
-                        G_CALLBACK (copy_link_activate_cb), label);
+      GdkRectangle rect = { x, y, 1, 1 };
+      gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &rect);
     }
   else
-    {
-      append_action_signal (label, menu, _("Cu_t"), "cut-clipboard", FALSE);
-      append_action_signal (label, menu, _("_Copy"), "copy-clipboard", have_selection);
-      append_action_signal (label, menu, _("_Paste"), "paste-clipboard", FALSE);
-  
-      menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete"));
-      gtk_widget_set_sensitive (menuitem, FALSE);
-      gtk_widget_show (menuitem);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-
-      menuitem = gtk_separator_menu_item_new ();
-      gtk_widget_show (menuitem);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-
-      menuitem = gtk_menu_item_new_with_mnemonic (_("Select _All"));
-      g_signal_connect_swapped (menuitem, "activate",
-                               G_CALLBACK (gtk_label_select_all), label);
-      gtk_widget_show (menuitem);
-      gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
-    }
+    gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), NULL);
+
+  gtk_popover_popup (GTK_POPOVER (priv->popup_menu));
+}
+
+static gboolean
+gtk_label_popup_menu (GtkWidget *widget)
+{
+  GtkLabel *label = GTK_LABEL (widget);
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
 
-  g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
+  if (!priv->select_info)
+    return FALSE;
 
-  if (event && gdk_event_triggers_context_menu (event))
-    gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
+  if (priv->select_info->link_clicked)
+    priv->select_info->context_link = priv->select_info->active_link;
   else
-    {
-      gtk_menu_popup_at_widget (GTK_MENU (menu),
-                                GTK_WIDGET (label),
-                                GDK_GRAVITY_SOUTH,
-                                GDK_GRAVITY_NORTH_WEST,
-                                event);
+    priv->select_info->context_link = gtk_label_get_focus_link (label);
 
-      gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
-    }
+  gtk_label_do_popup (label, -1, -1);
+  return TRUE;
 }
 
 static void
@@ -6646,3 +6694,44 @@ gtk_label_get_yalign (GtkLabel *label)
 
   return priv->yalign;
 }
+
+/**
+ * gtk_label_set_extra_menu:
+ * @label: a #GtkLabel
+ * @model: (allow-none): a #GMenuModel
+ *
+ * Sets a menu model to add when constructing
+ * the context menu for @label.
+ */
+void
+gtk_label_set_extra_menu (GtkLabel   *label,
+                          GMenuModel *model)
+{
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+
+  g_return_if_fail (GTK_IS_LABEL (label));
+
+  if (g_set_object (&priv->extra_menu, model))
+    {
+      g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
+      g_object_notify_by_pspec (G_OBJECT (label), label_props[PROP_EXTRA_MENU]);
+    }
+}
+
+/**
+ * gtk_label_get_extra_menu:
+ * @label: a #GtkLabel
+ *
+ * Gets the menu model set with gtk_label_set_extra_menu().
+ *
+ * Returns: (transfer none): (nullable): the menu model
+ */
+GMenuModel *
+gtk_label_get_extra_menu (GtkLabel *label)
+{
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+
+  g_return_val_if_fail (GTK_IS_LABEL (label), NULL);
+
+  return priv->extra_menu;
+}
diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h
index 6ccc389b73..c2b8bfe8e4 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -176,6 +176,13 @@ void         gtk_label_set_yalign (GtkLabel *label,
 GDK_AVAILABLE_IN_ALL
 gfloat       gtk_label_get_yalign (GtkLabel *label);
 
+GDK_AVAILABLE_IN_ALL
+void         gtk_label_set_extra_menu (GtkLabel   *label,
+                                       GMenuModel *model);
+GDK_AVAILABLE_IN_ALL
+GMenuModel * gtk_label_get_extra_menu (GtkLabel   *label);
+
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkLabel, g_object_unref)
 
 G_END_DECLS


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