[gtk/wip/matthiasc/context-menu: 13/38] label: Redo context menus
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/matthiasc/context-menu: 13/38] label: Redo context menus
- Date: Thu, 13 Jun 2019 00:22:07 +0000 (UTC)
commit 320f4e7ac47d522c9893a5e8beed67bb74ab2cb4
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.
gtk/gtklabel.c | 289 ++++++++++++++++++++++++++++++++++-----------------------
gtk/gtklabel.h | 1 +
2 files changed, 173 insertions(+), 117 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index ffc6d05e6e..8cb67ed8bf 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -269,9 +269,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 +283,8 @@ struct _GtkLabelPrivate
PangoAttrList *markup_attrs;
PangoLayout *layout;
+ GActionMap *context_actions;
+
gchar *label;
gchar *text;
@@ -378,7 +377,6 @@ struct _GtkLabelSelectionInfo
enum {
MOVE_CURSOR,
COPY_CLIPBOARD,
- POPULATE_POPUP,
ACTIVATE_LINK,
ACTIVATE_CURRENT_LINK,
LAST_SIGNAL
@@ -483,6 +481,7 @@ 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 GMenuModel * gtk_label_get_default_menu (void);
static void gtk_label_set_selectable_hint (GtkLabel *label);
static void gtk_label_ensure_select_info (GtkLabel *label);
@@ -572,6 +571,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 +583,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,
@@ -701,28 +705,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
@@ -1298,6 +1280,7 @@ static void
gtk_label_init (GtkLabel *label)
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
+ GMenuModel *menu;
priv->width_chars = -1;
priv->max_width_chars = -1;
@@ -1326,6 +1309,11 @@ gtk_label_init (GtkLabel *label)
priv->mnemonic_window = NULL;
priv->mnemonics_visible = TRUE;
+
+ gtk_label_add_context_actions (label);
+ menu = gtk_label_get_default_menu ();
+ gtk_widget_set_context_menu (GTK_WIDGET (label), menu);
+ g_object_unref (menu);
}
@@ -3199,6 +3187,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);
}
@@ -5972,74 +5962,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)
+{
+ 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)
{
- const gchar *signal = g_object_get_qdata (G_OBJECT (menuitem), quark_gtk_signal);
- g_signal_emit_by_name (label, signal);
+ 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));
+}
+
+static GMenuModel *
+gtk_label_get_default_menu (void)
+{
+ 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
@@ -6047,26 +6138,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)
@@ -6078,48 +6163,18 @@ 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 = g_object_ref (gtk_widget_get_context_menu (GTK_WIDGET (label)));
+
+ priv->select_info->popup_menu = menu = gtk_menu_new_from_model (model);
- g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
+ g_object_unref (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 6ccc389b73..f9a9a37148 100644
--- a/gtk/gtklabel.h
+++ b/gtk/gtklabel.h
@@ -176,6 +176,7 @@ void gtk_label_set_yalign (GtkLabel *label,
GDK_AVAILABLE_IN_ALL
gfloat gtk_label_get_yalign (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]