[gtk/wip/matthiasc/context-menu: 3/6] label: Redo context menus



commit 00832b6405059cfb427e1321dd72de3ef11d6ec7
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 add
    gtk_label_get_default_context_menu(), as was done
    in GtkEntry.

 gtk/gtklabel.c | 283 ++++++++++++++++++++++++++++++++++-----------------------
 gtk/gtklabel.h |   8 +-
 2 files changed, 174 insertions(+), 117 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 57db38485b..61cd416059 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -260,6 +260,8 @@ struct _GtkLabelPrivate
   PangoAttrList *markup_attrs;
   PangoLayout   *layout;
 
+  GActionMap *context_actions;
+
   gchar   *label;
   gchar   *text;
 
@@ -352,7 +354,6 @@ struct _GtkLabelSelectionInfo
 enum {
   MOVE_CURSOR,
   COPY_CLIPBOARD,
-  POPULATE_POPUP,
   ACTIVATE_LINK,
   ACTIVATE_CURRENT_LINK,
   LAST_SIGNAL
@@ -545,6 +546,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,
@@ -554,6 +558,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,
@@ -674,28 +680,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
@@ -1301,6 +1285,8 @@ gtk_label_init (GtkLabel *label)
   priv->mnemonic_window = NULL;
 
   priv->mnemonics_visible = TRUE;
+
+  gtk_label_add_context_actions (label);
 }
 
 
@@ -3183,6 +3169,8 @@ gtk_label_finalize (GObject *object)
   gtk_label_clear_links (label);
   g_free (priv->select_info);
 
+  g_clear_object (&priv->context_actions);
+
   G_OBJECT_CLASS (gtk_label_parent_class)->finalize (object);
 }
 
@@ -5968,74 +5956,175 @@ 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)
+popup_menu_detach (GtkWidget *attach_widget,
+                  GtkMenu   *menu)
 {
-  const gchar *signal = g_object_get_qdata (G_OBJECT (menuitem), quark_gtk_signal);
-  g_signal_emit_by_name (label, signal);
+  GtkLabel *label = GTK_LABEL (attach_widget);
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+
+  if (priv->select_info)
+    priv->select_info->popup_menu = NULL;
+}
+
+static gboolean
+gtk_label_popup_menu (GtkWidget *widget)
+{
+  gtk_label_do_popup (GTK_LABEL (widget), NULL);
+
+  return TRUE;
 }
 
 static void
-append_action_signal (GtkLabel     *label,
-                     GtkWidget    *menu,
-                     const gchar  *text,
-                     const gchar  *signal,
-                      gboolean      sensitive)
+open_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 = NULL;
+  int pos = g_variant_get_int32 (parameter);
 
-  g_object_set_qdata (G_OBJECT (menuitem), quark_gtk_signal, (char *)signal);
-  g_signal_connect (menuitem, "activate",
-                   G_CALLBACK (activate_cb), label);
+  link = g_list_nth_data (priv->select_info->links, pos);
+  if (link == NULL)
+    return;
 
-  gtk_widget_set_sensitive (menuitem, sensitive);
-  
-  gtk_widget_show (menuitem);
-  gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
+  emit_activate_link (label, link);
 }
 
 static void
-popup_menu_detach (GtkWidget *attach_widget,
-                  GtkMenu   *menu)
+copy_link_activated (GSimpleAction *action,
+                     GVariant      *parameter,
+                     gpointer       user_data)
 {
-  GtkLabel *label = GTK_LABEL (attach_widget);
+  GtkLabel *label = GTK_LABEL (user_data);
   GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  GtkLabelLink *link = NULL;
+  int pos = g_variant_get_int32 (parameter);
+  GdkClipboard *clipboard;
 
-  if (priv->select_info)
-    priv->select_info->popup_menu = NULL;
+  link = g_list_nth_data (priv->select_info->links, pos);
+  if (link == NULL)
+    return;
+
+  clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label));
+  gdk_clipboard_set_text (clipboard, link->uri);
 }
 
 static void
-open_link_activate_cb (GtkMenuItem *menuitem,
-                       GtkLabel    *label)
+copy_clipboard_activated (GSimpleAction *action,
+                          GVariant      *parameter,
+                          gpointer       user_data)
 {
-  GtkLabelLink *link;
+  g_signal_emit_by_name (user_data, "copy-clipboard");
+}
 
-  link = g_object_get_qdata (G_OBJECT (menuitem), quark_link);
-  emit_activate_link (label, link);
+static void
+select_all_activated (GSimpleAction *action,
+                      GVariant      *parameter,
+                      gpointer       user_data)
+{
+  gtk_label_select_all (GTK_LABEL (user_data));
 }
 
 static void
-copy_link_activate_cb (GtkMenuItem *menuitem,
-                       GtkLabel    *label)
+gtk_label_update_clipboard_actions (GtkLabel *label)
 {
-  GtkLabelLink *link;
-  GdkClipboard *clipboard;
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  gboolean have_selection = FALSE;
+  GAction *action;
 
-  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);
+  if (priv->select_info)
+    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 gboolean
-gtk_label_popup_menu (GtkWidget *widget)
+static void
+gtk_label_add_context_actions (GtkLabel *label)
 {
-  gtk_label_do_popup (GTK_LABEL (widget), NULL);
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
 
-  return TRUE;
+  GActionEntry entries[] = {
+    { "open-link", open_link_activated, "i", NULL, NULL },
+    { "copy-link", copy_link_activated, "i", NULL, NULL },
+    { "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 },
+  };
+
+  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);
+
+  gtk_widget_insert_action_group (GTK_WIDGET (label), "context", G_ACTION_GROUP (actions));
+}
+
+GMenuModel *
+gtk_label_get_default_context_menu (GtkLabel *label)
+{
+  GMenu *menu, *section;
+
+  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);
+
+  return G_MENU_MODEL (menu);
+}
+
+static GMenuModel *
+get_link_context_menu (GtkLabel     *label,
+                       GtkLabelLink *link)
+{
+  GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+  GMenu *menu;
+  GMenuItem *item;
+  int index;
+
+  index = g_list_index (priv->select_info->links, link);
+
+  menu = g_menu_new ();
+  item = g_menu_item_new (_("_Open Link"), "context.open-link");
+  g_menu_item_set_attribute (item, "target", "i", index);
+  g_menu_append_item (menu, item);
+  g_object_unref (item);
+
+  item = g_menu_item_new (_("_Copy Link Address"), "context.copy-link");
+  g_menu_item_set_attribute (item, "target", "i", index);
+  g_menu_append_item (menu, item);
+  g_object_unref (item);
+
+  return G_MENU_MODEL (menu);
 }
 
 static void
@@ -6043,26 +6132,20 @@ gtk_label_do_popup (GtkLabel       *label,
                     const GdkEvent *event)
 {
   GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
-  GtkWidget *menuitem;
   GtkWidget *menu;
-  gboolean have_selection;
+  GMenuModel *model;
   GtkLabelLink *link;
+  gboolean have_selection;
 
   if (!priv->select_info)
     return;
 
+  gtk_label_update_clipboard_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);
-
-  gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (label), popup_menu_detach);
-
-  have_selection =
-    priv->select_info->selection_anchor != priv->select_info->selection_end;
-
+  have_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
   if (event)
     {
       if (priv->select_info->link_clicked)
@@ -6074,48 +6157,22 @@ gtk_label_do_popup (GtkLabel       *label,
     link = gtk_label_get_focus_link (label);
 
   if (!have_selection && link)
-    {
-      /* 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);
-    }
+    model = get_link_context_menu (label, link);
   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);
+    { 
+      model = gtk_widget_get_context_menu (GTK_WIDGET (label));
+      if (model)
+        g_object_ref (model);
+      else
+        model = gtk_label_get_default_context_menu (label);
     }
 
-  g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
+  priv->select_info->popup_menu = menu = gtk_menu_new_from_model (model);
+
+  g_object_set_data (G_OBJECT (menu), "link", link);
+
+  gtk_style_context_add_class (gtk_widget_get_style_context (menu), GTK_STYLE_CLASS_CONTEXT_MENU);
+  gtk_menu_attach_to_widget (GTK_MENU (menu), GTK_WIDGET (label), popup_menu_detach);
 
   if (event && gdk_event_triggers_context_menu (event))
     gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
diff --git a/gtk/gtklabel.h b/gtk/gtklabel.h
index 834caa1fc4..2b97e90f3c 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -64,10 +64,6 @@ struct _GtkLabelClass
                            gboolean        extend_selection);
   void (* copy_clipboard)  (GtkLabel       *label);
 
-  /* Hook to customize right-click popup for selectable labels */
-  void (* populate_popup)   (GtkLabel       *label,
-                             GtkMenu        *menu);
-
   gboolean (*activate_link) (GtkLabel       *label,
                              const gchar    *uri);
 
@@ -217,6 +213,10 @@ void         gtk_label_set_yalign (GtkLabel *label,
 GDK_AVAILABLE_IN_ALL
 gfloat       gtk_label_get_yalign (GtkLabel *label);
 
+GDK_AVAILABLE_IN_ALL
+GMenuModel * gtk_label_get_default_context_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]