forked from AuroraMiddleware/gtk
Merge branch 'wip/matthiasc/context-menu' into 'master'
context menu api See merge request GNOME/gtk!539
This commit is contained in:
commit
121011b05b
@ -8,8 +8,8 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static GtkWidget *window = NULL;
|
||||
static GtkWidget *menu = NULL;
|
||||
static GtkWidget *notebook = NULL;
|
||||
static GSimpleActionGroup *actions = NULL;
|
||||
|
||||
static guint search_progress_id = 0;
|
||||
static guint finish_search_id = 0;
|
||||
@ -83,69 +83,42 @@ stop_search (GtkButton *button,
|
||||
}
|
||||
|
||||
static void
|
||||
clear_entry (GtkEntry *entry)
|
||||
clear_entry (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_editable_set_text (GTK_EDITABLE (entry), "");
|
||||
GtkEditable *editable = user_data;
|
||||
|
||||
gtk_editable_set_text (editable, "");
|
||||
}
|
||||
|
||||
static void
|
||||
search_by_name (GtkWidget *item,
|
||||
GtkEntry *entry)
|
||||
set_search_by (GSimpleAction *action,
|
||||
GVariant *value,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_entry_set_icon_tooltip_text (entry,
|
||||
GTK_ENTRY_ICON_PRIMARY,
|
||||
"Search by name\n"
|
||||
"Click here to change the search type");
|
||||
gtk_entry_set_placeholder_text (entry, "name");
|
||||
}
|
||||
GtkEntry *entry = user_data;
|
||||
const char *term;
|
||||
|
||||
static void
|
||||
search_by_description (GtkWidget *item,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
term = g_variant_get_string (value, NULL);
|
||||
|
||||
gtk_entry_set_icon_tooltip_text (entry,
|
||||
GTK_ENTRY_ICON_PRIMARY,
|
||||
"Search by description\n"
|
||||
"Click here to change the search type");
|
||||
gtk_entry_set_placeholder_text (entry, "description");
|
||||
}
|
||||
g_simple_action_set_state (action, value);
|
||||
|
||||
static void
|
||||
search_by_file (GtkWidget *item,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
gtk_entry_set_icon_tooltip_text (entry,
|
||||
GTK_ENTRY_ICON_PRIMARY,
|
||||
"Search by file name\n"
|
||||
"Click here to change the search type");
|
||||
gtk_entry_set_placeholder_text (entry, "file name");
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
create_search_menu (GtkWidget *entry)
|
||||
{
|
||||
GtkWidget *menu;
|
||||
GtkWidget *item;
|
||||
|
||||
menu = gtk_menu_new ();
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic ("Search by _name");
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (search_by_name), entry);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic ("Search by _description");
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (search_by_description), entry);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic ("Search by _file name");
|
||||
g_signal_connect (item, "activate",
|
||||
G_CALLBACK (search_by_file), entry);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
|
||||
return menu;
|
||||
if (g_str_equal (term, "name"))
|
||||
{
|
||||
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by name");
|
||||
gtk_entry_set_placeholder_text (entry, "name");
|
||||
}
|
||||
else if (g_str_equal (term, "description"))
|
||||
{
|
||||
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by description");
|
||||
gtk_entry_set_placeholder_text (entry, "description");
|
||||
}
|
||||
else if (g_str_equal (term, "filename"))
|
||||
{
|
||||
gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_PRIMARY, "Search by file name");
|
||||
gtk_entry_set_placeholder_text (entry, "file name");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -154,7 +127,28 @@ icon_press_cb (GtkEntry *entry,
|
||||
gpointer data)
|
||||
{
|
||||
if (position == GTK_ENTRY_ICON_PRIMARY)
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
|
||||
{
|
||||
GAction *action;
|
||||
GVariant *state;
|
||||
GVariant *new_state;
|
||||
const char *s;
|
||||
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "search-by");
|
||||
state = g_action_get_state (action);
|
||||
s = g_variant_get_string (state, NULL);
|
||||
|
||||
if (g_str_equal (s, "name"))
|
||||
new_state = g_variant_new_string ("description");
|
||||
else if (g_str_equal (s, "description"))
|
||||
new_state = g_variant_new_string ("filename");
|
||||
else if (g_str_equal (s, "filename"))
|
||||
new_state = g_variant_new_string ("name");
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
|
||||
g_action_change_state (action, new_state);
|
||||
g_variant_unref (state);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -165,7 +159,6 @@ activate_cb (GtkEntry *entry,
|
||||
return;
|
||||
|
||||
start_search (button, entry);
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
@ -187,32 +180,62 @@ search_entry_destroyed (GtkWidget *widget)
|
||||
}
|
||||
|
||||
static void
|
||||
entry_populate_popup (GtkEntry *entry,
|
||||
GtkMenu *menu,
|
||||
gpointer user_data)
|
||||
text_changed (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GtkWidget *item;
|
||||
GtkWidget *search_menu;
|
||||
GtkEntry *entry = GTK_ENTRY (object);
|
||||
GActionMap *actions = data;
|
||||
GAction *action;
|
||||
gboolean has_text;
|
||||
|
||||
has_text = gtk_entry_get_text_length (entry) > 0;
|
||||
|
||||
item = gtk_separator_menu_item_new ();
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
action = g_action_map_lookup_action (actions, "clear");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_text);
|
||||
}
|
||||
|
||||
item = gtk_menu_item_new_with_mnemonic ("C_lear");
|
||||
gtk_widget_show (item);
|
||||
g_signal_connect_swapped (item, "activate",
|
||||
G_CALLBACK (clear_entry), entry);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
gtk_widget_set_sensitive (item, has_text);
|
||||
static GMenuModel *
|
||||
create_search_menu_model (void)
|
||||
{
|
||||
GMenu *menu = g_menu_new ();
|
||||
g_menu_append (menu, _("Name"), "search.search-by::name");
|
||||
g_menu_append (menu, _("Description"), "search.search-by::description");
|
||||
g_menu_append (menu, _("File Name"), "search.search-by::filename");
|
||||
|
||||
search_menu = create_search_menu (GTK_WIDGET (entry));
|
||||
item = gtk_menu_item_new_with_label ("Search by");
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), search_menu);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
|
||||
return G_MENU_MODEL (menu);
|
||||
}
|
||||
|
||||
static void
|
||||
entry_add_to_context_menu (GtkEntry *entry)
|
||||
{
|
||||
GMenu *menu;
|
||||
GActionEntry entries[] = {
|
||||
{ "clear", clear_entry, NULL, NULL, NULL },
|
||||
{ "search-by", NULL, "s", "'name'", set_search_by }
|
||||
};
|
||||
GMenuModel *submenu;
|
||||
GMenuItem *item;
|
||||
|
||||
actions = g_simple_action_group_new ();
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS(entries), entry);
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (entry), "search", G_ACTION_GROUP (actions));
|
||||
|
||||
menu = g_menu_new ();
|
||||
item = g_menu_item_new (_("C_lear"), "search.clear");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-clear-symbolic");
|
||||
g_menu_append_item (G_MENU (menu), item);
|
||||
g_object_unref (item);
|
||||
|
||||
submenu = create_search_menu_model ();
|
||||
g_menu_append_submenu (menu, _("Search By"), submenu);
|
||||
g_object_unref (submenu);
|
||||
|
||||
gtk_entry_set_extra_menu (entry, G_MENU_MODEL (menu));
|
||||
|
||||
g_object_unref (menu);
|
||||
|
||||
g_signal_connect (entry, "notify::text", G_CALLBACK (text_changed), actions);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
@ -271,29 +294,25 @@ do_search_entry (GtkWidget *do_widget)
|
||||
gtk_widget_show (cancel_button);
|
||||
|
||||
/* Set up the search icon */
|
||||
search_by_name (NULL, GTK_ENTRY (entry));
|
||||
GVariant *value = g_variant_ref_sink (g_variant_new_string ("name"));
|
||||
set_search_by (NULL, value, entry);
|
||||
g_variant_unref (value);
|
||||
|
||||
/* Set up the clear icon */
|
||||
g_signal_connect (entry, "icon-press",
|
||||
G_CALLBACK (icon_press_cb), NULL);
|
||||
g_signal_connect (entry, "activate",
|
||||
G_CALLBACK (activate_cb), NULL);
|
||||
gtk_entry_set_icon_activatable (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, TRUE);
|
||||
gtk_entry_set_icon_sensitive (GTK_ENTRY (entry), GTK_ENTRY_ICON_PRIMARY, TRUE);
|
||||
|
||||
/* Create the menu */
|
||||
menu = create_search_menu (entry);
|
||||
gtk_menu_attach_to_widget (GTK_MENU (menu), entry, NULL);
|
||||
g_signal_connect (entry, "icon-press", G_CALLBACK (icon_press_cb), NULL);
|
||||
g_signal_connect (entry, "activate", G_CALLBACK (activate_cb), NULL);
|
||||
|
||||
/* add accessible alternatives for icon functionality */
|
||||
g_object_set (entry, "populate-all", TRUE, NULL);
|
||||
g_signal_connect (entry, "populate-popup",
|
||||
G_CALLBACK (entry_populate_popup), NULL);
|
||||
entry_add_to_context_menu (GTK_ENTRY (entry));
|
||||
}
|
||||
|
||||
if (!gtk_widget_get_visible (window))
|
||||
gtk_widget_show (window);
|
||||
else
|
||||
{
|
||||
gtk_widget_destroy (menu);
|
||||
g_clear_object (&actions);
|
||||
gtk_widget_destroy (window);
|
||||
}
|
||||
|
||||
|
@ -1303,96 +1303,113 @@ page_combo_separator_func (GtkTreeModel *model,
|
||||
}
|
||||
|
||||
static void
|
||||
activate_item (GtkWidget *item, GtkTextView *tv)
|
||||
toggle_format (GSimpleAction *action,
|
||||
GVariant *value,
|
||||
gpointer user_data)
|
||||
{
|
||||
const gchar *tag;
|
||||
GtkTextView *text_view = user_data;
|
||||
GtkTextIter start, end;
|
||||
gboolean active;
|
||||
const char *name;
|
||||
|
||||
g_object_get (item, "active", &active, NULL);
|
||||
tag = (const gchar *)g_object_get_data (G_OBJECT (item), "tag");
|
||||
gtk_text_buffer_get_selection_bounds (gtk_text_view_get_buffer (tv), &start, &end);
|
||||
if (active)
|
||||
gtk_text_buffer_apply_tag_by_name (gtk_text_view_get_buffer (tv), tag, &start, &end);
|
||||
name = g_action_get_name (G_ACTION (action));
|
||||
|
||||
g_simple_action_set_state (action, value);
|
||||
|
||||
gtk_text_buffer_get_selection_bounds (gtk_text_view_get_buffer (text_view), &start, &end);
|
||||
if (g_variant_get_boolean (value))
|
||||
gtk_text_buffer_apply_tag_by_name (gtk_text_view_get_buffer (text_view), name, &start, &end);
|
||||
else
|
||||
gtk_text_buffer_remove_tag_by_name (gtk_text_view_get_buffer (tv), tag, &start, &end);
|
||||
gtk_text_buffer_remove_tag_by_name (gtk_text_view_get_buffer (text_view), name, &start, &end);
|
||||
}
|
||||
|
||||
static void
|
||||
add_item (GtkTextView *tv,
|
||||
GtkWidget *popup,
|
||||
const gchar *text,
|
||||
const gchar *tag,
|
||||
gboolean set)
|
||||
{
|
||||
GtkWidget *item, *label;
|
||||
|
||||
if (GTK_IS_MENU (popup))
|
||||
{
|
||||
item = gtk_check_menu_item_new ();
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), set);
|
||||
g_signal_connect (item, "toggled", G_CALLBACK (activate_item), tv);
|
||||
}
|
||||
else
|
||||
{
|
||||
item = gtk_check_button_new ();
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), set);
|
||||
gtk_widget_set_focus_on_click (item, FALSE);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (activate_item), tv);
|
||||
}
|
||||
|
||||
label = gtk_label_new ("");
|
||||
gtk_label_set_xalign (GTK_LABEL (label), 0);
|
||||
gtk_label_set_markup (GTK_LABEL (label), text);
|
||||
gtk_widget_show (label);
|
||||
gtk_container_add (GTK_CONTAINER (item), label);
|
||||
g_object_set_data (G_OBJECT (item), "tag", (gpointer)tag);
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (popup), item);
|
||||
}
|
||||
static GActionGroup *actions;
|
||||
|
||||
static void
|
||||
populate_popup (GtkTextView *tv,
|
||||
GtkWidget *popup)
|
||||
text_changed (GtkTextBuffer *buffer)
|
||||
{
|
||||
gboolean has_selection;
|
||||
GtkWidget *item;
|
||||
GtkTextIter start, end, iter;
|
||||
GAction *bold;
|
||||
GAction *italic;
|
||||
GAction *underline;
|
||||
GtkTextIter iter;
|
||||
GtkTextTagTable *tags;
|
||||
GtkTextTag *bold, *italic, *underline;
|
||||
GtkTextTag *bold_tag, *italic_tag, *underline_tag;
|
||||
gboolean all_bold, all_italic, all_underline;
|
||||
GtkTextIter start, end;
|
||||
gboolean has_selection;
|
||||
|
||||
has_selection = gtk_text_buffer_get_selection_bounds (gtk_text_view_get_buffer (tv), &start, &end);
|
||||
bold = g_action_map_lookup_action (G_ACTION_MAP (actions), "bold");
|
||||
italic = g_action_map_lookup_action (G_ACTION_MAP (actions), "italic");
|
||||
underline = g_action_map_lookup_action (G_ACTION_MAP (actions), "underline");
|
||||
|
||||
has_selection = gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (bold), has_selection);
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (italic), has_selection);
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (underline), has_selection);
|
||||
if (!has_selection)
|
||||
return;
|
||||
|
||||
tags = gtk_text_buffer_get_tag_table (gtk_text_view_get_buffer (tv));
|
||||
bold = gtk_text_tag_table_lookup (tags, "bold");
|
||||
italic = gtk_text_tag_table_lookup (tags, "italic");
|
||||
underline = gtk_text_tag_table_lookup (tags, "underline");
|
||||
tags = gtk_text_buffer_get_tag_table (buffer);
|
||||
bold_tag = gtk_text_tag_table_lookup (tags, "bold");
|
||||
italic_tag = gtk_text_tag_table_lookup (tags, "italic");
|
||||
underline_tag = gtk_text_tag_table_lookup (tags, "underline");
|
||||
all_bold = TRUE;
|
||||
all_italic = TRUE;
|
||||
all_underline = TRUE;
|
||||
gtk_text_iter_assign (&iter, &start);
|
||||
while (!gtk_text_iter_equal (&iter, &end))
|
||||
{
|
||||
all_bold &= gtk_text_iter_has_tag (&iter, bold);
|
||||
all_italic &= gtk_text_iter_has_tag (&iter, italic);
|
||||
all_underline &= gtk_text_iter_has_tag (&iter, underline);
|
||||
all_bold &= gtk_text_iter_has_tag (&iter, bold_tag);
|
||||
all_italic &= gtk_text_iter_has_tag (&iter, italic_tag);
|
||||
all_underline &= gtk_text_iter_has_tag (&iter, underline_tag);
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
}
|
||||
|
||||
if (GTK_IS_MENU (popup))
|
||||
{
|
||||
item = gtk_separator_menu_item_new ();
|
||||
gtk_widget_show (item);
|
||||
gtk_container_add (GTK_CONTAINER (popup), item);
|
||||
}
|
||||
g_simple_action_set_state (G_SIMPLE_ACTION (bold), g_variant_new_boolean (all_bold));
|
||||
g_simple_action_set_state (G_SIMPLE_ACTION (italic), g_variant_new_boolean (all_italic));
|
||||
g_simple_action_set_state (G_SIMPLE_ACTION (underline), g_variant_new_boolean (all_underline));
|
||||
}
|
||||
|
||||
add_item (tv, popup, "<b>Bold</b>", "bold", all_bold);
|
||||
add_item (tv, popup, "<i>Italics</i>", "italic", all_italic);
|
||||
add_item (tv, popup, "<u>Underline</u>", "underline", all_underline);
|
||||
static void
|
||||
text_view_add_to_context_menu (GtkTextView *text_view)
|
||||
{
|
||||
GMenu *menu;
|
||||
GActionEntry entries[] = {
|
||||
{ "bold", NULL, NULL, "false", toggle_format },
|
||||
{ "italic", NULL, NULL, "false", toggle_format },
|
||||
{ "underline", NULL, NULL, "false", toggle_format },
|
||||
};
|
||||
GMenuItem *item;
|
||||
GAction *action;
|
||||
|
||||
actions = G_ACTION_GROUP (g_simple_action_group_new ());
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), text_view);
|
||||
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "bold");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "italic");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "underline");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (text_view), "format", G_ACTION_GROUP (actions));
|
||||
|
||||
menu = g_menu_new ();
|
||||
item = g_menu_item_new (_("Bold"), "format.bold");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "format-text-bold-symbolic");
|
||||
g_menu_append_item (G_MENU (menu), item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("Italics"), "format.italic");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "format-text-italic-symbolic");
|
||||
g_menu_append_item (G_MENU (menu), item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("Underline"), "format.underline");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "format-text-underline-symbolic");
|
||||
g_menu_append_item (G_MENU (menu), item);
|
||||
|
||||
gtk_text_view_set_extra_menu (text_view, G_MENU_MODEL (menu));
|
||||
|
||||
g_signal_connect (gtk_text_view_get_buffer (text_view), "changed", G_CALLBACK (text_changed), NULL);
|
||||
g_signal_connect (gtk_text_view_get_buffer (text_view), "mark-set", G_CALLBACK (text_changed), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1877,8 +1894,7 @@ activate (GApplication *app)
|
||||
g_object_set_data (G_OBJECT (widget), "osd", widget2);
|
||||
|
||||
widget = (GtkWidget *)gtk_builder_get_object (builder, "textview1");
|
||||
g_signal_connect (widget, "populate-popup",
|
||||
G_CALLBACK (populate_popup), NULL);
|
||||
text_view_add_to_context_menu (GTK_TEXT_VIEW (widget));
|
||||
|
||||
widget = (GtkWidget *)gtk_builder_get_object (builder, "open_popover");
|
||||
widget2 = (GtkWidget *)gtk_builder_get_object (builder, "open_popover_entry");
|
||||
|
@ -1207,7 +1207,6 @@ Suspendisse feugiat quam quis dolor accumsan cursus.</property>
|
||||
<property name="wrap-mode">2</property>
|
||||
<property name="left-margin">10</property>
|
||||
<property name="right-margin">10</property>
|
||||
<property name="populate-all">1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
@ -893,6 +893,8 @@ gtk_text_get_attributes
|
||||
gtk_text_set_tabs
|
||||
gtk_text_get_tabs
|
||||
gtk_text_grab_focus_without_selecting
|
||||
gtk_text_set_extra_menu
|
||||
gtk_text_get_extra_menu
|
||||
<SUBSECTION Private>
|
||||
gtk_text_get_type
|
||||
</SECTION>
|
||||
@ -963,6 +965,8 @@ GtkInputHints
|
||||
gtk_entry_set_input_hints
|
||||
gtk_entry_get_input_hints
|
||||
gtk_entry_grab_focus_without_selecting
|
||||
gtk_entry_set_extra_menu
|
||||
gtk_entry_get_extra_menu
|
||||
|
||||
<SUBSECTION Standard>
|
||||
GTK_ENTRY
|
||||
@ -985,6 +989,8 @@ GtkPasswordEntry
|
||||
gtk_password_entry_new
|
||||
gtk_password_entry_set_show_peek_icon
|
||||
gtk_password_entry_get_show_peek_icon
|
||||
gtk_password_entry_set_extra_menu
|
||||
gtk_password_entry_get_extra_menu
|
||||
<SUBSECTION Private>
|
||||
gtk_password_entry_get_type
|
||||
</SECTION>
|
||||
@ -1713,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
|
||||
@ -3089,6 +3098,9 @@ gtk_text_view_set_input_hints
|
||||
gtk_text_view_get_input_hints
|
||||
gtk_text_view_set_monospace
|
||||
gtk_text_view_get_monospace
|
||||
gtk_text_view_set_extra_menu
|
||||
gtk_text_view_get_extra_menu
|
||||
|
||||
GTK_TEXT_VIEW_PRIORITY_VALIDATE
|
||||
<SUBSECTION Standard>
|
||||
GTK_TEXT_VIEW
|
||||
|
@ -205,7 +205,6 @@ struct _GtkCellRendererTextPrivate
|
||||
guint align_set : 1;
|
||||
|
||||
gulong focus_out_id;
|
||||
gulong populate_popup_id;
|
||||
gulong entry_menu_popdown_timeout;
|
||||
};
|
||||
|
||||
@ -1778,12 +1777,6 @@ gtk_cell_renderer_text_editing_done (GtkCellEditable *entry,
|
||||
priv->focus_out_id = 0;
|
||||
}
|
||||
|
||||
if (priv->populate_popup_id > 0)
|
||||
{
|
||||
g_signal_handler_disconnect (entry, priv->populate_popup_id);
|
||||
priv->populate_popup_id = 0;
|
||||
}
|
||||
|
||||
if (priv->entry_menu_popdown_timeout)
|
||||
{
|
||||
g_source_remove (priv->entry_menu_popdown_timeout);
|
||||
@ -1804,70 +1797,14 @@ gtk_cell_renderer_text_editing_done (GtkCellEditable *entry,
|
||||
g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
popdown_timeout (gpointer data)
|
||||
{
|
||||
GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (data);
|
||||
GtkCellRendererTextPrivate *priv = gtk_cell_renderer_text_get_instance_private (celltext);
|
||||
|
||||
priv->entry_menu_popdown_timeout = 0;
|
||||
|
||||
if (!gtk_widget_has_focus (priv->entry))
|
||||
gtk_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_renderer_text_popup_unmap (GtkMenu *menu,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (data);
|
||||
GtkCellRendererTextPrivate *priv = gtk_cell_renderer_text_get_instance_private (celltext);
|
||||
|
||||
priv->in_entry_menu = FALSE;
|
||||
|
||||
if (priv->entry_menu_popdown_timeout)
|
||||
return;
|
||||
|
||||
priv->entry_menu_popdown_timeout = g_timeout_add (500, popdown_timeout, data);
|
||||
g_source_set_name_by_id (priv->entry_menu_popdown_timeout, "[gtk] popdown_timeout");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_renderer_text_populate_popup (GtkEntry *entry,
|
||||
GtkMenu *menu,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (data);
|
||||
GtkCellRendererTextPrivate *priv = gtk_cell_renderer_text_get_instance_private (celltext);
|
||||
|
||||
if (priv->entry_menu_popdown_timeout)
|
||||
{
|
||||
g_source_remove (priv->entry_menu_popdown_timeout);
|
||||
priv->entry_menu_popdown_timeout = 0;
|
||||
}
|
||||
|
||||
priv->in_entry_menu = TRUE;
|
||||
|
||||
g_signal_connect (menu, "unmap",
|
||||
G_CALLBACK (gtk_cell_renderer_text_popup_unmap), data);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_cell_renderer_text_focus_changed (GtkWidget *entry,
|
||||
GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
GtkCellRendererText *celltext = GTK_CELL_RENDERER_TEXT (data);
|
||||
GtkCellRendererTextPrivate *priv = gtk_cell_renderer_text_get_instance_private (celltext);
|
||||
|
||||
if (gtk_widget_has_focus (entry))
|
||||
return;
|
||||
|
||||
if (priv->in_entry_menu)
|
||||
return;
|
||||
|
||||
g_object_set (entry,
|
||||
"editing-canceled", TRUE,
|
||||
NULL);
|
||||
@ -1921,11 +1858,6 @@ gtk_cell_renderer_text_start_editing (GtkCellRenderer *cell,
|
||||
priv->focus_out_id = g_signal_connect_after (priv->entry, "notify::has-focus",
|
||||
G_CALLBACK (gtk_cell_renderer_text_focus_changed),
|
||||
celltext);
|
||||
priv->populate_popup_id =
|
||||
g_signal_connect (priv->entry, "populate-popup",
|
||||
G_CALLBACK (gtk_cell_renderer_text_populate_popup),
|
||||
celltext);
|
||||
|
||||
gtk_widget_show (priv->entry);
|
||||
|
||||
return GTK_CELL_EDITABLE (priv->entry);
|
||||
|
@ -90,6 +90,8 @@ struct _GtkColorChooserWidgetPrivate
|
||||
gboolean has_default_palette;
|
||||
|
||||
GSettings *settings;
|
||||
|
||||
GActionMap *context_actions;
|
||||
};
|
||||
|
||||
enum
|
||||
@ -134,31 +136,6 @@ select_swatch (GtkColorChooserWidget *cc,
|
||||
g_object_notify (G_OBJECT (cc), "rgba");
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_activate (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
_gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_customize (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GtkColorChooserWidgetPrivate *priv = gtk_color_chooser_widget_get_instance_private (cc);
|
||||
GdkRGBA color;
|
||||
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (priv->palette);
|
||||
gtk_widget_show (priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_selected (GtkColorSwatch *swatch,
|
||||
GtkStateFlags previous,
|
||||
@ -176,31 +153,14 @@ static void
|
||||
connect_swatch_signals (GtkWidget *p,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_connect (p, "activate", G_CALLBACK (swatch_activate), data);
|
||||
g_signal_connect (p, "customize", G_CALLBACK (swatch_customize), data);
|
||||
g_signal_connect (p, "state-flags-changed", G_CALLBACK (swatch_selected), data);
|
||||
}
|
||||
|
||||
static void
|
||||
button_activate (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
{
|
||||
GtkColorChooserWidgetPrivate *priv = gtk_color_chooser_widget_get_instance_private (cc);
|
||||
/* somewhat random, makes the hairline nicely visible */
|
||||
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (priv->palette);
|
||||
gtk_widget_show (priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
connect_button_signals (GtkWidget *p,
|
||||
gpointer data)
|
||||
{
|
||||
g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
|
||||
// g_signal_connect (p, "activate", G_CALLBACK (button_activate), data);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -532,6 +492,57 @@ add_default_palette (GtkColorChooserWidget *cc)
|
||||
priv->has_default_palette = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
customize_color (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkColorChooserWidget *cc = user_data;
|
||||
GtkColorChooserWidgetPrivate *priv = gtk_color_chooser_widget_get_instance_private (cc);
|
||||
GdkRGBA color;
|
||||
|
||||
g_variant_get (parameter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha);
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (priv->palette);
|
||||
gtk_widget_show (priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
select_color (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkColorChooserWidget *cc = user_data;
|
||||
GdkRGBA color;
|
||||
|
||||
g_variant_get (parameter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha);
|
||||
|
||||
_gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_add_context_actions (GtkColorChooserWidget *cc)
|
||||
{
|
||||
GtkColorChooserWidgetPrivate *priv = gtk_color_chooser_widget_get_instance_private (cc);
|
||||
|
||||
GActionEntry entries[] = {
|
||||
{ "select", select_color, "(dddd)", NULL, NULL },
|
||||
{ "customize", customize_color, "(dddd)", NULL, NULL },
|
||||
};
|
||||
|
||||
GSimpleActionGroup *actions = g_simple_action_group_new ();
|
||||
|
||||
priv->context_actions = G_ACTION_MAP (actions);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), cc);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (cc), "color", G_ACTION_GROUP (actions));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
|
||||
{
|
||||
@ -623,6 +634,8 @@ gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
|
||||
priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
gtk_size_group_add_widget (priv->size_group, priv->palette);
|
||||
gtk_size_group_add_widget (priv->size_group, box);
|
||||
|
||||
gtk_color_chooser_widget_add_context_actions (cc);
|
||||
}
|
||||
|
||||
/* GObject implementation {{{1 */
|
||||
|
@ -33,7 +33,7 @@
|
||||
#include "gtkintl.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmodelbutton.h"
|
||||
#include "gtkpopover.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtksnapshot.h"
|
||||
#include "gtkstylecontextprivate.h"
|
||||
@ -76,16 +76,6 @@ enum
|
||||
PROP_HAS_MENU
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ACTIVATE,
|
||||
CUSTOMIZE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL];
|
||||
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkColorSwatch, gtk_color_swatch, GTK_TYPE_WIDGET)
|
||||
|
||||
#define INTENSITY(r, g, b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
|
||||
@ -231,6 +221,32 @@ swatch_drag_data_received (GtkWidget *widget,
|
||||
gtk_color_swatch_set_rgba (GTK_COLOR_SWATCH (widget), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
activate_color (GtkColorSwatch *swatch)
|
||||
{
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
gtk_widget_activate_action (GTK_WIDGET (swatch),
|
||||
"color.select",
|
||||
g_variant_new ("(dddd)",
|
||||
priv->color.red,
|
||||
priv->color.green,
|
||||
priv->color.blue,
|
||||
priv->color.alpha));
|
||||
}
|
||||
|
||||
static void
|
||||
customize_color (GtkColorSwatch *swatch)
|
||||
{
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
gtk_widget_activate_action (GTK_WIDGET (swatch),
|
||||
"color.customize",
|
||||
g_variant_new ("(dddd)",
|
||||
priv->color.red,
|
||||
priv->color.green,
|
||||
priv->color.blue,
|
||||
priv->color.alpha));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
key_controller_key_pressed (GtkEventControllerKey *controller,
|
||||
guint keyval,
|
||||
@ -252,40 +268,51 @@ key_controller_key_pressed (GtkEventControllerKey *controller,
|
||||
(gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_SELECTED) == 0)
|
||||
gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_SELECTED, FALSE);
|
||||
else
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
customize_color (swatch);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
emit_customize (GtkColorSwatch *swatch)
|
||||
static GMenuModel *
|
||||
gtk_color_swatch_get_menu_model (GtkColorSwatch *swatch)
|
||||
{
|
||||
g_signal_emit (swatch, signals[CUSTOMIZE], 0);
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
GMenu *menu, *section;
|
||||
GMenuItem *item;
|
||||
|
||||
menu = g_menu_new ();
|
||||
|
||||
section = g_menu_new ();
|
||||
item = g_menu_item_new (_("Customize"), NULL);
|
||||
g_menu_item_set_action_and_target_value (item, "color.customize",
|
||||
g_variant_new ("(dddd)",
|
||||
priv->color.red,
|
||||
priv->color.green,
|
||||
priv->color.blue,
|
||||
priv->color.alpha));
|
||||
|
||||
g_menu_append_item (section, item);
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
|
||||
g_object_unref (item);
|
||||
g_object_unref (section);
|
||||
|
||||
return G_MENU_MODEL (menu);
|
||||
}
|
||||
|
||||
static void
|
||||
do_popup (GtkColorSwatch *swatch)
|
||||
{
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
GMenuModel *model;
|
||||
|
||||
if (priv->popover == NULL)
|
||||
{
|
||||
GtkWidget *box;
|
||||
GtkWidget *item;
|
||||
g_clear_pointer (&priv->popover, gtk_widget_unparent);
|
||||
|
||||
priv->popover = gtk_popover_new (GTK_WIDGET (swatch));
|
||||
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||||
gtk_container_add (GTK_CONTAINER (priv->popover), box);
|
||||
g_object_set (box, "margin", 10, NULL);
|
||||
item = g_object_new (GTK_TYPE_MODEL_BUTTON,
|
||||
"text", _("C_ustomize"),
|
||||
NULL);
|
||||
g_signal_connect_swapped (item, "clicked",
|
||||
G_CALLBACK (emit_customize), swatch);
|
||||
gtk_container_add (GTK_CONTAINER (box), item);
|
||||
}
|
||||
model = gtk_color_swatch_get_menu_model (swatch);
|
||||
priv->popover = gtk_popover_menu_new_from_model (GTK_WIDGET (swatch), model);
|
||||
g_object_unref (model);
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (priv->popover));
|
||||
}
|
||||
@ -300,7 +327,7 @@ swatch_primary_action (GtkColorSwatch *swatch)
|
||||
flags = gtk_widget_get_state_flags (widget);
|
||||
if (!priv->has_color)
|
||||
{
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
customize_color (swatch);
|
||||
return TRUE;
|
||||
}
|
||||
else if (priv->selectable &&
|
||||
@ -340,7 +367,7 @@ tap_action (GtkGestureClick *gesture,
|
||||
if (n_press == 1)
|
||||
swatch_primary_action (swatch);
|
||||
else if (n_press > 1)
|
||||
g_signal_emit (swatch, signals[ACTIVATE], 0);
|
||||
activate_color (swatch);
|
||||
}
|
||||
else if (button == GDK_BUTTON_SECONDARY)
|
||||
{
|
||||
@ -505,7 +532,7 @@ swatch_dispose (GObject *object)
|
||||
GtkColorSwatch *swatch = GTK_COLOR_SWATCH (object);
|
||||
GtkColorSwatchPrivate *priv = gtk_color_swatch_get_instance_private (swatch);
|
||||
|
||||
g_clear_pointer (&priv->popover, gtk_widget_destroy);
|
||||
g_clear_pointer (&priv->popover, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (gtk_color_swatch_parent_class)->dispose (object);
|
||||
}
|
||||
@ -530,20 +557,6 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
|
||||
widget_class->size_allocate = swatch_size_allocate;
|
||||
widget_class->state_flags_changed = swatch_state_flags_changed;
|
||||
|
||||
signals[ACTIVATE] =
|
||||
g_signal_new (I_("activate"),
|
||||
GTK_TYPE_COLOR_SWATCH,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkColorSwatchClass, activate),
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
signals[CUSTOMIZE] =
|
||||
g_signal_new (I_("customize"),
|
||||
GTK_TYPE_COLOR_SWATCH,
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkColorSwatchClass, customize),
|
||||
NULL, NULL, NULL, G_TYPE_NONE, 0);
|
||||
|
||||
g_object_class_install_property (object_class, PROP_RGBA,
|
||||
g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
|
||||
GDK_TYPE_RGBA, GTK_PARAM_READWRITE));
|
||||
@ -569,6 +582,10 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
|
||||
priv->use_alpha = TRUE;
|
||||
priv->selectable = TRUE;
|
||||
priv->has_menu = TRUE;
|
||||
priv->color.red = 0.75;
|
||||
priv->color.green = 0.25;
|
||||
priv->color.blue = 0.25;
|
||||
priv->color.alpha = 1.0;
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
|
||||
gtk_widget_set_overflow (GTK_WIDGET (swatch), GTK_OVERFLOW_HIDDEN);
|
||||
|
@ -222,8 +222,8 @@ enum {
|
||||
PROP_INPUT_PURPOSE,
|
||||
PROP_INPUT_HINTS,
|
||||
PROP_ATTRIBUTES,
|
||||
PROP_POPULATE_ALL,
|
||||
PROP_TABS,
|
||||
PROP_EXTRA_MENU,
|
||||
PROP_SHOW_EMOJI_ICON,
|
||||
PROP_ENABLE_EMOJI_COMPLETION,
|
||||
PROP_EDITING_CANCELED,
|
||||
@ -798,19 +798,6 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
PANGO_TYPE_ATTR_LIST,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkEntry:populate-all:
|
||||
*
|
||||
* If :populate-all is %TRUE, the #GtkEntry::populate-popup
|
||||
* signal is also emitted for touch popups.
|
||||
*/
|
||||
entry_props[PROP_POPULATE_ALL] =
|
||||
g_param_spec_boolean ("populate-all",
|
||||
P_("Populate all"),
|
||||
P_("Whether to emit ::populate-popup for touch popups"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkEntry::tabs:
|
||||
*
|
||||
@ -836,6 +823,19 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkEntry:extra-menu:
|
||||
*
|
||||
* A menu model whose contents will be appended to
|
||||
* the context menu.
|
||||
*/
|
||||
entry_props[PROP_EXTRA_MENU] =
|
||||
g_param_spec_object ("extra-menu",
|
||||
P_("Extra menu"),
|
||||
P_("Model menu to append to the context menu"),
|
||||
G_TYPE_MENU_MODEL,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
entry_props[PROP_ENABLE_EMOJI_COMPLETION] =
|
||||
g_param_spec_boolean ("enable-emoji-completion",
|
||||
P_("Enable Emoji completion"),
|
||||
@ -944,7 +944,6 @@ gtk_entry_set_property (GObject *object,
|
||||
case PROP_INPUT_PURPOSE:
|
||||
case PROP_INPUT_HINTS:
|
||||
case PROP_ATTRIBUTES:
|
||||
case PROP_POPULATE_ALL:
|
||||
case PROP_TABS:
|
||||
case PROP_ENABLE_EMOJI_COMPLETION:
|
||||
g_object_set_property (G_OBJECT (priv->text), pspec->name, value);
|
||||
@ -1062,6 +1061,10 @@ gtk_entry_set_property (GObject *object,
|
||||
set_show_emoji_icon (entry, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
gtk_entry_set_extra_menu (entry, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1096,7 +1099,6 @@ gtk_entry_get_property (GObject *object,
|
||||
case PROP_INPUT_PURPOSE:
|
||||
case PROP_INPUT_HINTS:
|
||||
case PROP_ATTRIBUTES:
|
||||
case PROP_POPULATE_ALL:
|
||||
case PROP_TABS:
|
||||
case PROP_ENABLE_EMOJI_COMPLETION:
|
||||
g_object_get_property (G_OBJECT (priv->text), pspec->name, value);
|
||||
@ -1219,6 +1221,10 @@ gtk_entry_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->show_emoji_icon);
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
g_value_set_object (value, gtk_entry_get_extra_menu (entry));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -3471,6 +3477,8 @@ set_show_emoji_icon (GtkEntry *entry,
|
||||
gboolean value)
|
||||
{
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
GActionGroup *actions;
|
||||
GAction *action;
|
||||
|
||||
if (priv->show_emoji_icon == value)
|
||||
return;
|
||||
@ -3512,6 +3520,12 @@ set_show_emoji_icon (GtkEntry *entry,
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (entry), entry_props[PROP_SHOW_EMOJI_ICON]);
|
||||
gtk_widget_queue_resize (GTK_WIDGET (entry));
|
||||
|
||||
actions = gtk_widget_get_action_group (priv->text, "context");
|
||||
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "insert-emoji");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
priv->show_emoji_icon ||
|
||||
(gtk_entry_get_input_hints (entry) & GTK_INPUT_HINT_NO_EMOJI) == 0);
|
||||
}
|
||||
|
||||
GtkEventController *
|
||||
@ -3529,3 +3543,42 @@ gtk_entry_get_text_widget (GtkEntry *entry)
|
||||
|
||||
return GTK_TEXT (priv->text);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_entry_set_extra_menu:
|
||||
* @entry: a #GtkEntry
|
||||
* @model: (allow-none): a #GMenuModel
|
||||
*
|
||||
* Sets a menu model to add when constructing
|
||||
* the context menu for @entry.
|
||||
*/
|
||||
void
|
||||
gtk_entry_set_extra_menu (GtkEntry *entry,
|
||||
GMenuModel *model)
|
||||
{
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
|
||||
g_return_if_fail (GTK_IS_ENTRY (entry));
|
||||
|
||||
gtk_text_set_extra_menu (GTK_TEXT (priv->text), model);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (entry), entry_props[PROP_EXTRA_MENU]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_entry_get_extra_menu:
|
||||
* @self: a #GtkText
|
||||
*
|
||||
* Gets the menu model set with gtk_entry_set_extra_menu().
|
||||
*
|
||||
* Returns: (transfer none): (nullable): the menu model
|
||||
*/
|
||||
GMenuModel *
|
||||
gtk_entry_get_extra_menu (GtkEntry *entry)
|
||||
{
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_ENTRY (entry), NULL);
|
||||
|
||||
return gtk_text_get_extra_menu (GTK_TEXT (priv->text));
|
||||
}
|
||||
|
@ -77,9 +77,6 @@ struct _GtkEntry
|
||||
/**
|
||||
* GtkEntryClass:
|
||||
* @parent_class: The parent class.
|
||||
* @populate_popup: Class handler for the #GtkEntry::populate-popup signal. If
|
||||
* non-%NULL, this will be called to add additional entries to the context
|
||||
* menu when it is displayed.
|
||||
* @activate: Class handler for the #GtkEntry::activate signal. The default
|
||||
* implementation activates the gtk.activate-default action.
|
||||
* @move_cursor: Class handler for the #GtkEntry::move-cursor signal. The
|
||||
@ -310,6 +307,12 @@ PangoTabArray *gtk_entry_get_tabs (GtkEntry
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_grab_focus_without_selecting (GtkEntry *entry);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_entry_set_extra_menu (GtkEntry *entry,
|
||||
GMenuModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GMenuModel * gtk_entry_get_extra_menu (GtkEntry *entry);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_ENTRY_H__ */
|
||||
|
461
gtk/gtklabel.c
461
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);
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkLabel *label,
|
||||
GtkWidget *menu,
|
||||
const gchar *text,
|
||||
const gchar *signal,
|
||||
gboolean sensitive)
|
||||
{
|
||||
GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (text);
|
||||
|
||||
g_object_set_qdata (G_OBJECT (menuitem), quark_gtk_signal, (char *)signal);
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (activate_cb), label);
|
||||
|
||||
gtk_widget_set_sensitive (menuitem, sensitive);
|
||||
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_menu_detach (GtkWidget *attach_widget,
|
||||
GtkMenu *menu)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (attach_widget);
|
||||
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
|
||||
copy_link_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (user_data);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkLabelLink *link = priv->select_info->context_link;
|
||||
|
||||
if (link)
|
||||
{
|
||||
GdkClipboard *clipboard;
|
||||
|
||||
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
|
||||
gtk_label_update_clipboard_actions (GtkLabel *label)
|
||||
{
|
||||
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);
|
||||
|
||||
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);
|
||||
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);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (label), "context", G_ACTION_GROUP (actions));
|
||||
}
|
||||
|
||||
static GMenuModel *
|
||||
gtk_label_get_menu_model (GtkLabel *label)
|
||||
{
|
||||
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,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
|
||||
gtk_label_update_clipboard_actions (label);
|
||||
gtk_label_update_link_actions (label);
|
||||
|
||||
if (!priv->popup_menu)
|
||||
{
|
||||
GMenuModel *model;
|
||||
|
||||
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);
|
||||
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (priv->popup_menu), FALSE);
|
||||
gtk_widget_set_halign (priv->popup_menu, GTK_ALIGN_START);
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
if (x != -1 && y != -1)
|
||||
{
|
||||
GdkRectangle rect = { x, y, 1, 1 };
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &rect);
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
gtk_label_do_popup (GTK_LABEL (widget), NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_do_popup (GtkLabel *label,
|
||||
const GdkEvent *event)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkWidget *menuitem;
|
||||
GtkWidget *menu;
|
||||
gboolean have_selection;
|
||||
GtkLabelLink *link;
|
||||
|
||||
if (!priv->select_info)
|
||||
return;
|
||||
return FALSE;
|
||||
|
||||
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;
|
||||
|
||||
if (event)
|
||||
{
|
||||
if (priv->select_info->link_clicked)
|
||||
link = priv->select_info->active_link;
|
||||
else
|
||||
link = NULL;
|
||||
}
|
||||
if (priv->select_info->link_clicked)
|
||||
priv->select_info->context_link = priv->select_info->active_link;
|
||||
else
|
||||
link = gtk_label_get_focus_link (label);
|
||||
priv->select_info->context_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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
g_signal_emit (label, signals[POPULATE_POPUP], 0, menu);
|
||||
|
||||
if (event && gdk_event_triggers_context_menu (event))
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (menu), event);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup_at_widget (GTK_MENU (menu),
|
||||
GTK_WIDGET (label),
|
||||
GDK_GRAVITY_SOUTH,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
event);
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -60,8 +60,7 @@
|
||||
#include "gtklabel.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtkmenu.h"
|
||||
#include "gtkmenuitem.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkshow.h"
|
||||
#include "gtksizerequest.h"
|
||||
@ -97,6 +96,7 @@ struct _GtkLinkButtonPrivate
|
||||
|
||||
gboolean visited;
|
||||
|
||||
GActionMap *context_actions;
|
||||
GtkWidget *popup_menu;
|
||||
};
|
||||
|
||||
@ -223,6 +223,43 @@ gtk_link_button_class_init (GtkLinkButtonClass *klass)
|
||||
gtk_widget_class_set_css_name (widget_class, I_("button"));
|
||||
}
|
||||
|
||||
static void copy_activate_cb (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data);
|
||||
|
||||
static void
|
||||
gtk_link_button_add_context_actions (GtkLinkButton *link_button)
|
||||
{
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
|
||||
GActionEntry entries[] = {
|
||||
{ "copy-clipboard", copy_activate_cb, NULL, NULL, NULL },
|
||||
};
|
||||
|
||||
GSimpleActionGroup *actions = g_simple_action_group_new ();
|
||||
|
||||
priv->context_actions = G_ACTION_MAP (actions);
|
||||
|
||||
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), link_button);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (link_button), "context", G_ACTION_GROUP (actions));
|
||||
}
|
||||
|
||||
static GMenuModel *
|
||||
gtk_link_button_get_menu_model (void)
|
||||
{
|
||||
GMenu *menu, *section;
|
||||
|
||||
menu = g_menu_new ();
|
||||
|
||||
section = g_menu_new ();
|
||||
g_menu_append (section, _("_Copy URL"), "context.copy-clipboard");
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
|
||||
g_object_unref (section);
|
||||
|
||||
return G_MENU_MODEL (menu);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_button_init (GtkLinkButton *link_button)
|
||||
{
|
||||
@ -261,6 +298,7 @@ gtk_link_button_init (GtkLinkButton *link_button)
|
||||
gtk_style_context_add_class (context, "link");
|
||||
|
||||
gtk_widget_set_cursor_from_name (GTK_WIDGET (link_button), "pointer");
|
||||
gtk_link_button_add_context_actions (link_button);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -270,7 +308,10 @@ gtk_link_button_finalize (GObject *object)
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
|
||||
g_free (priv->uri);
|
||||
|
||||
|
||||
g_clear_object (&priv->context_actions);
|
||||
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
|
||||
|
||||
G_OBJECT_CLASS (gtk_link_button_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -320,19 +361,11 @@ gtk_link_button_set_property (GObject *object,
|
||||
}
|
||||
|
||||
static void
|
||||
popup_menu_detach (GtkWidget *attach_widget,
|
||||
GtkMenu *menu)
|
||||
{
|
||||
GtkLinkButton *link_button = GTK_LINK_BUTTON (attach_widget);
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
|
||||
priv->popup_menu = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
copy_activate_cb (GtkWidget *widget,
|
||||
GtkLinkButton *link_button)
|
||||
copy_activate_cb (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkLinkButton *link_button = user_data;
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
|
||||
gdk_clipboard_set_text (gtk_widget_get_clipboard (GTK_WIDGET (link_button)),
|
||||
@ -340,45 +373,35 @@ copy_activate_cb (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_link_button_do_popup (GtkLinkButton *link_button,
|
||||
const GdkEvent *event)
|
||||
gtk_link_button_do_popup (GtkLinkButton *link_button,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
|
||||
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (link_button)))
|
||||
if (!priv->popup_menu)
|
||||
{
|
||||
GtkWidget *menu_item;
|
||||
GMenuModel *model;
|
||||
|
||||
if (priv->popup_menu)
|
||||
gtk_widget_destroy (priv->popup_menu);
|
||||
model = gtk_link_button_get_menu_model ();
|
||||
priv->popup_menu = gtk_popover_menu_new_from_model (GTK_WIDGET (link_button), model);
|
||||
gtk_popover_set_position (GTK_POPOVER (priv->popup_menu), GTK_POS_BOTTOM);
|
||||
|
||||
priv->popup_menu = gtk_menu_new ();
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (priv->popup_menu),
|
||||
GTK_STYLE_CLASS_CONTEXT_MENU);
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (priv->popup_menu), FALSE);
|
||||
gtk_widget_set_halign (priv->popup_menu, GTK_ALIGN_START);
|
||||
|
||||
gtk_menu_attach_to_widget (GTK_MENU (priv->popup_menu),
|
||||
GTK_WIDGET (link_button),
|
||||
popup_menu_detach);
|
||||
|
||||
menu_item = gtk_menu_item_new_with_mnemonic (_("Copy URL"));
|
||||
g_signal_connect (menu_item, "activate",
|
||||
G_CALLBACK (copy_activate_cb), link_button);
|
||||
gtk_widget_show (menu_item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menu_item);
|
||||
|
||||
if (event && gdk_event_triggers_context_menu (event))
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), event);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup_at_widget (GTK_MENU (priv->popup_menu),
|
||||
GTK_WIDGET (link_button),
|
||||
GDK_GRAVITY_SOUTH,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
event);
|
||||
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
|
||||
}
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
if (x != -1 && y != -1)
|
||||
{
|
||||
GdkRectangle rect = { x, y, 1, 1 };
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &rect);
|
||||
}
|
||||
else
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), NULL);
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (priv->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -399,7 +422,7 @@ gtk_link_button_pressed_cb (GtkGestureClick *gesture,
|
||||
if (gdk_event_triggers_context_menu (event) &&
|
||||
priv->uri != NULL)
|
||||
{
|
||||
gtk_link_button_do_popup (link_button, event);
|
||||
gtk_link_button_do_popup (link_button, x, y);
|
||||
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
}
|
||||
else
|
||||
@ -445,9 +468,8 @@ gtk_link_button_clicked (GtkButton *button)
|
||||
static gboolean
|
||||
gtk_link_button_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), NULL);
|
||||
|
||||
return TRUE;
|
||||
gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), -1, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -58,6 +58,7 @@ typedef struct {
|
||||
GtkWidget *icon;
|
||||
GtkWidget *peek_icon;
|
||||
GdkKeymap *keymap;
|
||||
GMenuModel *extra_menu;
|
||||
} GtkPasswordEntryPrivate;
|
||||
|
||||
struct _GtkPasswordEntryClass
|
||||
@ -69,6 +70,7 @@ enum {
|
||||
PROP_PLACEHOLDER_TEXT = 1,
|
||||
PROP_ACTIVATES_DEFAULT,
|
||||
PROP_SHOW_PEEK_ICON,
|
||||
PROP_EXTRA_MENU,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@ -105,7 +107,7 @@ focus_changed (GtkWidget *widget)
|
||||
if (priv->keymap)
|
||||
keymap_state_changed (priv->keymap, widget);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gtk_password_entry_toggle_peek (GtkPasswordEntry *entry)
|
||||
{
|
||||
@ -125,27 +127,6 @@ gtk_password_entry_toggle_peek (GtkPasswordEntry *entry)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
populate_popup (GtkText *text,
|
||||
GtkWidget *popup,
|
||||
GtkPasswordEntry *entry)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
if (priv->peek_icon != NULL)
|
||||
{
|
||||
GtkWidget *item;
|
||||
|
||||
item = gtk_check_menu_item_new_with_mnemonic (_("_Show text"));
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
|
||||
gtk_text_get_visibility (text));
|
||||
g_signal_connect_swapped (item, "activate",
|
||||
G_CALLBACK (gtk_password_entry_toggle_peek), entry);
|
||||
gtk_widget_show (item);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (popup), item);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
{
|
||||
@ -156,7 +137,6 @@ gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
gtk_widget_set_parent (priv->entry, GTK_WIDGET (entry));
|
||||
gtk_editable_init_delegate (GTK_EDITABLE (entry));
|
||||
g_signal_connect_swapped (priv->entry, "notify::has-focus", G_CALLBACK (focus_changed), entry);
|
||||
g_signal_connect (priv->entry, "populate-popup", G_CALLBACK (populate_popup), entry);
|
||||
|
||||
priv->icon = gtk_image_new_from_icon_name ("caps-lock-symbolic");
|
||||
gtk_widget_set_tooltip_text (priv->icon, _("Caps Lock is on"));
|
||||
@ -165,6 +145,8 @@ gtk_password_entry_init (GtkPasswordEntry *entry)
|
||||
gtk_widget_set_parent (priv->icon, GTK_WIDGET (entry));
|
||||
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (entry)), I_("password"));
|
||||
|
||||
gtk_password_entry_set_extra_menu (entry, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -195,6 +177,7 @@ gtk_password_entry_dispose (GObject *object)
|
||||
g_clear_pointer (&priv->entry, gtk_widget_unparent);
|
||||
g_clear_pointer (&priv->icon, gtk_widget_unparent);
|
||||
g_clear_pointer (&priv->peek_icon, gtk_widget_unparent);
|
||||
g_clear_object (&priv->extra_menu);
|
||||
|
||||
G_OBJECT_CLASS (gtk_password_entry_parent_class)->dispose (object);
|
||||
}
|
||||
@ -235,6 +218,10 @@ gtk_password_entry_set_property (GObject *object,
|
||||
gtk_password_entry_set_show_peek_icon (entry, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
gtk_password_entry_set_extra_menu (entry, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -267,6 +254,10 @@ gtk_password_entry_get_property (GObject *object,
|
||||
g_value_set_boolean (value, gtk_password_entry_get_show_peek_icon (entry));
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
g_value_set_object (value, priv->extra_menu);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -389,7 +380,6 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
|
||||
widget_class->get_accessible = gtk_password_entry_get_accessible;
|
||||
widget_class->grab_focus = gtk_password_entry_grab_focus;
|
||||
widget_class->mnemonic_activate = gtk_password_entry_mnemonic_activate;
|
||||
|
||||
props[PROP_PLACEHOLDER_TEXT] =
|
||||
g_param_spec_string ("placeholder-text",
|
||||
P_("Placeholder text"),
|
||||
@ -411,6 +401,19 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkPasswordEntry:extra-menu:
|
||||
*
|
||||
* A menu model whose contents will be appended to
|
||||
* the context menu.
|
||||
*/
|
||||
props[PROP_EXTRA_MENU] =
|
||||
g_param_spec_object ("extra-menu",
|
||||
P_("Extra menu"),
|
||||
P_("Model menu to append to the context menu"),
|
||||
G_TYPE_MENU_MODEL,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
|
||||
gtk_editable_install_properties (object_class, NUM_PROPERTIES);
|
||||
|
||||
@ -509,3 +512,64 @@ gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry)
|
||||
|
||||
return priv->peek_icon != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_password_entry_set_extra_menu:
|
||||
* @entry: a #GtkPasswordEntry
|
||||
* @model: (allow-none): a #GMenuModel
|
||||
*
|
||||
* Sets a menu model to add when constructing
|
||||
* the context menu for @entry.
|
||||
*/
|
||||
void
|
||||
gtk_password_entry_set_extra_menu (GtkPasswordEntry *entry,
|
||||
GMenuModel *model)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
GMenu *menu;
|
||||
GMenu *section;
|
||||
GMenuItem *item;
|
||||
|
||||
g_return_if_fail (GTK_IS_PASSWORD_ENTRY (entry));
|
||||
|
||||
if (!g_set_object (&priv->extra_menu, model))
|
||||
return;
|
||||
|
||||
menu = g_menu_new ();
|
||||
|
||||
section = g_menu_new ();
|
||||
item = g_menu_item_new (_("_Show Text"), "context.toggle-visibility");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "eye-not-looking-symbolic");
|
||||
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 (model)
|
||||
g_menu_append_section (menu, NULL, model);
|
||||
|
||||
gtk_text_set_extra_menu (GTK_TEXT (priv->entry), G_MENU_MODEL (menu));
|
||||
|
||||
g_object_unref (menu);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (entry), props[PROP_EXTRA_MENU]);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_password_entry_get_extra_menu:
|
||||
* @self: a #GtkText
|
||||
*
|
||||
* Gets the menu model set with gtk_password_entry_set_extra_menu().
|
||||
*
|
||||
* Returns: (transfer none): (nullable): the menu model
|
||||
*/
|
||||
GMenuModel *
|
||||
gtk_password_entry_get_extra_menu (GtkPasswordEntry *entry)
|
||||
{
|
||||
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_PASSWORD_ENTRY (entry), NULL);
|
||||
|
||||
return priv->extra_menu;
|
||||
}
|
||||
|
@ -53,6 +53,12 @@ void gtk_password_entry_set_show_peek_icon (GtkPasswordEntry *entry,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_password_entry_get_show_peek_icon (GtkPasswordEntry *entry);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_password_entry_set_extra_menu (GtkPasswordEntry *entry,
|
||||
GMenuModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GMenuModel * gtk_password_entry_get_extra_menu (GtkPasswordEntry *entry);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_PASSWORD_ENTRY_H__ */
|
||||
|
@ -228,7 +228,6 @@ struct _GtkPlacesSidebarClass {
|
||||
|
||||
enum {
|
||||
OPEN_LOCATION,
|
||||
POPULATE_POPUP,
|
||||
SHOW_ERROR_MESSAGE,
|
||||
SHOW_ENTER_LOCATION,
|
||||
DRAG_ACTION_REQUESTED,
|
||||
@ -251,7 +250,6 @@ enum {
|
||||
PROP_SHOW_STARRED_LOCATION,
|
||||
PROP_LOCAL_ONLY,
|
||||
PROP_SHOW_OTHER_LOCATIONS,
|
||||
PROP_POPULATE_ALL,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@ -3663,33 +3661,6 @@ create_row_popover (GtkPlacesSidebar *sidebar,
|
||||
|
||||
/* Update everything! */
|
||||
check_popover_sensitivity (row, &data);
|
||||
|
||||
if (sidebar->populate_all)
|
||||
{
|
||||
gchar *uri;
|
||||
GVolume *volume;
|
||||
GFile *file;
|
||||
|
||||
g_object_get (row,
|
||||
"uri", &uri,
|
||||
"volume", &volume,
|
||||
NULL);
|
||||
|
||||
if (uri)
|
||||
file = g_file_new_for_uri (uri);
|
||||
else
|
||||
file = NULL;
|
||||
|
||||
g_signal_emit (sidebar, places_sidebar_signals[POPULATE_POPUP], 0,
|
||||
box, file, volume);
|
||||
|
||||
if (file)
|
||||
g_object_unref (file);
|
||||
|
||||
g_free (uri);
|
||||
if (volume)
|
||||
g_object_unref (volume);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4235,14 +4206,6 @@ gtk_places_sidebar_set_property (GObject *obj,
|
||||
gtk_places_sidebar_set_local_only (sidebar, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
if (sidebar->populate_all != g_value_get_boolean (value))
|
||||
{
|
||||
sidebar->populate_all = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (obj, pspec);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
|
||||
break;
|
||||
@ -4295,10 +4258,6 @@ gtk_places_sidebar_get_property (GObject *obj,
|
||||
g_value_set_boolean (value, gtk_places_sidebar_get_local_only (sidebar));
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
g_value_set_boolean (value, sidebar->populate_all);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
|
||||
break;
|
||||
@ -4496,53 +4455,6 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
|
||||
G_TYPE_OBJECT,
|
||||
GTK_TYPE_PLACES_OPEN_FLAGS);
|
||||
|
||||
/*
|
||||
* GtkPlacesSidebar::populate-popup:
|
||||
* @sidebar: the object which received the signal.
|
||||
* @container: (type Gtk.Widget): a #GtkMenu or another #GtkContainer
|
||||
* @selected_item: (type Gio.File) (nullable): #GFile with the item to which
|
||||
* the popup should refer, or %NULL in the case of a @selected_volume.
|
||||
* @selected_volume: (type Gio.Volume) (nullable): #GVolume if the selected
|
||||
* item is a volume, or %NULL if it is a file.
|
||||
*
|
||||
* The places sidebar emits this signal when the user invokes a contextual
|
||||
* popup on one of its items. In the signal handler, the application may
|
||||
* add extra items to the menu as appropriate. For example, a file manager
|
||||
* may want to add a "Properties" command to the menu.
|
||||
*
|
||||
* It is not necessary to store the @selected_item for each menu item;
|
||||
* during their callbacks, the application can use gtk_places_sidebar_get_location()
|
||||
* to get the file to which the item refers.
|
||||
*
|
||||
* The @selected_item argument may be %NULL in case the selection refers to
|
||||
* a volume. In this case, @selected_volume will be non-%NULL. In this case,
|
||||
* the calling application will have to g_object_ref() the @selected_volume and
|
||||
* keep it around to use it in the callback.
|
||||
*
|
||||
* The @container and all its contents are destroyed after the user
|
||||
* dismisses the popup. The popup is re-created (and thus, this signal is
|
||||
* emitted) every time the user activates the contextual menu.
|
||||
*
|
||||
* Before 3.18, the @container always was a #GtkMenu, and you were expected
|
||||
* to add your items as #GtkMenuItems. The popup may be implemented
|
||||
* as a #GtkPopover, in which case @container will be something else, e.g. a
|
||||
* #GtkBox, to which you may add #GtkModelButtons or other widgets, such as
|
||||
* #GtkEntries, #GtkSpinButtons, etc. If your application can deal with this
|
||||
* situation, you can set #GtkPlacesSidebar::populate-all to %TRUE to request
|
||||
* that this signal is emitted for populating popovers as well.
|
||||
*/
|
||||
places_sidebar_signals [POPULATE_POPUP] =
|
||||
g_signal_new (I_("populate-popup"),
|
||||
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (GtkPlacesSidebarClass, populate_popup),
|
||||
NULL, NULL,
|
||||
_gtk_marshal_VOID__OBJECT_OBJECT_OBJECT,
|
||||
G_TYPE_NONE, 3,
|
||||
GTK_TYPE_WIDGET,
|
||||
G_TYPE_FILE,
|
||||
G_TYPE_VOLUME);
|
||||
|
||||
/*
|
||||
* GtkPlacesSidebar::show-error-message:
|
||||
* @sidebar: the object which received the signal.
|
||||
@ -4802,20 +4714,6 @@ gtk_places_sidebar_class_init (GtkPlacesSidebarClass *class)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE);
|
||||
|
||||
|
||||
/*
|
||||
* GtkPlacesSidebar:populate-all:
|
||||
*
|
||||
* If :populate-all is %TRUE, the #GtkPlacesSidebar::populate-popup signal
|
||||
* is also emitted for popovers.
|
||||
*/
|
||||
properties[PROP_POPULATE_ALL] =
|
||||
g_param_spec_boolean (I_("populate-all"),
|
||||
P_("Populate all"),
|
||||
P_("Whether to emit ::populate-popup for popups that are not menus"),
|
||||
FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, properties);
|
||||
|
||||
gtk_widget_class_set_css_name (widget_class, I_("placessidebar"));
|
||||
@ -4954,10 +4852,7 @@ gtk_places_sidebar_set_location (GtkPlacesSidebar *sidebar,
|
||||
* been called with a location that is not among the sidebar’s list of places to
|
||||
* show.
|
||||
*
|
||||
* You can use this function to get the selection in the @sidebar. Also, if you
|
||||
* connect to the #GtkPlacesSidebar::populate-popup signal, you can use this
|
||||
* function to get the location that is being referred to during the callbacks
|
||||
* for your menu items.
|
||||
* You can use this function to get the selection in the @sidebar.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a #GFile with the selected location, or
|
||||
* %NULL if nothing is visually selected.
|
||||
|
624
gtk/gtktext.c
624
gtk/gtktext.c
@ -23,6 +23,7 @@
|
||||
|
||||
#include "gtktextprivate.h"
|
||||
|
||||
#include "gtkactionable.h"
|
||||
#include "gtkadjustment.h"
|
||||
#include "gtkbindings.h"
|
||||
#include "gtkbox.h"
|
||||
@ -51,7 +52,7 @@
|
||||
#include "gtkmenu.h"
|
||||
#include "gtkmenuitem.h"
|
||||
#include "gtkpango.h"
|
||||
#include "gtkpopover.h"
|
||||
#include "gtkpopovermenu.h"
|
||||
#include "gtkprivate.h"
|
||||
#include "gtkseparatormenuitem.h"
|
||||
#include "gtkselection.h"
|
||||
@ -145,7 +146,6 @@ struct _GtkTextPrivate
|
||||
{
|
||||
GtkEntryBuffer *buffer;
|
||||
GtkIMContext *im_context;
|
||||
GtkWidget *popup_menu;
|
||||
|
||||
int text_baseline;
|
||||
|
||||
@ -174,6 +174,10 @@ struct _GtkTextPrivate
|
||||
GtkCssNode *block_cursor_node;
|
||||
GtkCssNode *undershoot_node[2];
|
||||
|
||||
GActionMap *context_actions;
|
||||
GtkWidget *popup_menu;
|
||||
GMenuModel *extra_menu;
|
||||
|
||||
float xalign;
|
||||
|
||||
int ascent; /* font ascent in pango units */
|
||||
@ -233,7 +237,6 @@ struct _GtkTextPasswordHint
|
||||
|
||||
enum {
|
||||
ACTIVATE,
|
||||
POPULATE_POPUP,
|
||||
MOVE_CURSOR,
|
||||
INSERT_AT_CURSOR,
|
||||
DELETE_FROM_CURSOR,
|
||||
@ -263,10 +266,10 @@ enum {
|
||||
PROP_INPUT_PURPOSE,
|
||||
PROP_INPUT_HINTS,
|
||||
PROP_ATTRIBUTES,
|
||||
PROP_POPULATE_ALL,
|
||||
PROP_TABS,
|
||||
PROP_ENABLE_EMOJI_COMPLETION,
|
||||
PROP_PROPAGATE_TEXT_WIDTH,
|
||||
PROP_EXTRA_MENU,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@ -383,6 +386,7 @@ static void gtk_text_set_alignment (GtkText *self,
|
||||
|
||||
/* Default signal handlers
|
||||
*/
|
||||
static GMenuModel *gtk_text_get_menu_model (GtkText *self);
|
||||
static gboolean gtk_text_popup_menu (GtkWidget *widget);
|
||||
static void gtk_text_move_cursor (GtkText *self,
|
||||
GtkMovementStep step,
|
||||
@ -512,8 +516,6 @@ static void gtk_text_paste (GtkText *self,
|
||||
GdkClipboard *clipboard);
|
||||
static void gtk_text_update_primary_selection (GtkText *self);
|
||||
static void gtk_text_schedule_im_reset (GtkText *self);
|
||||
static void gtk_text_do_popup (GtkText *self,
|
||||
const GdkEvent *event);
|
||||
static gboolean gtk_text_mnemonic_activate (GtkWidget *widget,
|
||||
gboolean group_cycling);
|
||||
static void gtk_text_check_cursor_blink (GtkText *self);
|
||||
@ -540,6 +542,10 @@ static void begin_change (GtkText *self);
|
||||
static void end_change (GtkText *self);
|
||||
static void emit_changed (GtkText *self);
|
||||
|
||||
static void gtk_text_add_context_actions (GtkText *self);
|
||||
static void gtk_text_update_clipboard_actions (GtkText *self);
|
||||
static void gtk_text_update_emoji_action (GtkText *self);
|
||||
|
||||
|
||||
/* GtkTextContent implementation
|
||||
*/
|
||||
@ -859,20 +865,7 @@ gtk_text_class_init (GtkTextClass *class)
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkText:populate-all:
|
||||
*
|
||||
* If :populate-all is %TRUE, the #GtkText::populate-popup
|
||||
* signal is also emitted for touch popups.
|
||||
*/
|
||||
text_props[PROP_POPULATE_ALL] =
|
||||
g_param_spec_boolean ("populate-all",
|
||||
P_("Populate all"),
|
||||
P_("Whether to emit ::populate-popup for touch popups"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkText::tabs:
|
||||
* GtkText:tabs:
|
||||
*
|
||||
* A list of tabstops to apply to the text of the self.
|
||||
*/
|
||||
@ -904,38 +897,23 @@ gtk_text_class_init (GtkTextClass *class)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkText:extra-menu:
|
||||
*
|
||||
* A menu model whose contents will be appended to
|
||||
* the context menu.
|
||||
*/
|
||||
text_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, text_props);
|
||||
|
||||
gtk_editable_install_properties (gobject_class, NUM_PROPERTIES);
|
||||
|
||||
/**
|
||||
* GtkText::populate-popup:
|
||||
* @self: The self on which the signal is emitted
|
||||
* @widget: the container that is being populated
|
||||
*
|
||||
* The ::populate-popup signal gets emitted before showing the
|
||||
* context menu of the self.
|
||||
*
|
||||
* If you need to add items to the context menu, connect
|
||||
* to this signal and append your items to the @widget, which
|
||||
* will be a #GtkMenu in this case.
|
||||
*
|
||||
* If #GtkText:populate-all is %TRUE, this signal will
|
||||
* also be emitted to populate touch popups. In this case,
|
||||
* @widget will be a different container, e.g. a #GtkToolbar.
|
||||
* The signal handler should not make assumptions about the
|
||||
* type of @widget.
|
||||
*/
|
||||
signals[POPULATE_POPUP] =
|
||||
g_signal_new (I_("populate-popup"),
|
||||
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkTextClass, populate_popup),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_WIDGET);
|
||||
|
||||
/* Action signals */
|
||||
|
||||
/**
|
||||
@ -1505,14 +1483,6 @@ gtk_text_set_property (GObject *object,
|
||||
gtk_text_set_attributes (self, g_value_get_boxed (value));
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
if (priv->populate_all != g_value_get_boolean (value))
|
||||
{
|
||||
priv->populate_all = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_TABS:
|
||||
gtk_text_set_tabs (self, g_value_get_boxed (value));
|
||||
break;
|
||||
@ -1530,6 +1500,10 @@ gtk_text_set_property (GObject *object,
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
gtk_text_set_extra_menu (self, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1633,10 +1607,6 @@ gtk_text_get_property (GObject *object,
|
||||
g_value_set_boxed (value, priv->attrs);
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
g_value_set_boolean (value, priv->populate_all);
|
||||
break;
|
||||
|
||||
case PROP_TABS:
|
||||
g_value_set_boxed (value, priv->tabs);
|
||||
break;
|
||||
@ -1649,6 +1619,10 @@ gtk_text_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->propagate_text_width);
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
g_value_set_object (value, priv->extra_menu);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -1746,6 +1720,7 @@ gtk_text_init (GtkText *self)
|
||||
}
|
||||
|
||||
set_text_cursor (GTK_WIDGET (self));
|
||||
gtk_text_add_context_actions (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1791,6 +1766,10 @@ gtk_text_dispose (GObject *object)
|
||||
keymap = gdk_display_get_keymap (gtk_widget_get_display (GTK_WIDGET (object)));
|
||||
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
|
||||
|
||||
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_text_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@ -2056,12 +2035,6 @@ gtk_text_unrealize (GtkWidget *widget)
|
||||
if (gdk_clipboard_get_content (clipboard) == priv->selection_content)
|
||||
gdk_clipboard_set_content (clipboard, NULL);
|
||||
|
||||
if (priv->popup_menu)
|
||||
{
|
||||
gtk_widget_destroy (priv->popup_menu);
|
||||
priv->popup_menu = NULL;
|
||||
}
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_text_parent_class)->unrealize (widget);
|
||||
}
|
||||
|
||||
@ -2200,6 +2173,9 @@ gtk_text_size_allocate (GtkWidget *widget,
|
||||
|
||||
if (priv->magnifier_popover)
|
||||
gtk_native_check_resize (GTK_NATIVE (priv->magnifier_popover));
|
||||
|
||||
if (priv->popup_menu)
|
||||
gtk_native_check_resize (GTK_NATIVE (priv->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -2448,6 +2424,40 @@ gesture_get_current_point_in_layout (GtkGestureSingle *gesture,
|
||||
*y = py - ty;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_do_popup (GtkText *self,
|
||||
double x,
|
||||
double y)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
gtk_text_update_clipboard_actions (self);
|
||||
|
||||
if (!priv->popup_menu)
|
||||
{
|
||||
GMenuModel *model;
|
||||
|
||||
model = gtk_text_get_menu_model (self);
|
||||
priv->popup_menu = gtk_popover_menu_new_from_model (GTK_WIDGET (self), model);
|
||||
gtk_popover_set_position (GTK_POPOVER (priv->popup_menu), GTK_POS_BOTTOM);
|
||||
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (priv->popup_menu), FALSE);
|
||||
gtk_widget_set_halign (priv->popup_menu, GTK_ALIGN_START);
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
if (x != -1 && y != -1)
|
||||
{
|
||||
GdkRectangle rect = { x, y, 1, 1 };
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &rect);
|
||||
}
|
||||
else
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), NULL);
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (priv->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
int n_press,
|
||||
@ -2483,7 +2493,7 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
|
||||
|
||||
if (gdk_event_triggers_context_menu (event))
|
||||
{
|
||||
gtk_text_do_popup (self, event);
|
||||
gtk_text_do_popup (self, x, y);
|
||||
}
|
||||
else if (n_press == 1 && button == GDK_BUTTON_MIDDLE &&
|
||||
get_middle_click_paste (self))
|
||||
@ -5251,10 +5261,15 @@ gtk_text_set_visibility (GtkText *self,
|
||||
|
||||
if (priv->visible != visible)
|
||||
{
|
||||
GAction *action;
|
||||
|
||||
priv->visible = visible;
|
||||
|
||||
g_object_notify (G_OBJECT (self), "visibility");
|
||||
gtk_text_recompute (self);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "toggle-visibility");
|
||||
g_simple_action_set_state (G_SIMPLE_ACTION (action), g_variant_new_boolean (visible));
|
||||
}
|
||||
}
|
||||
|
||||
@ -5590,18 +5605,213 @@ gtk_text_set_alignment (GtkText *self,
|
||||
}
|
||||
}
|
||||
|
||||
/* Quick hack of a popup menu
|
||||
*/
|
||||
static void
|
||||
activate_cb (GtkWidget *menuitem,
|
||||
GtkText *self)
|
||||
hide_selection_bubble (GtkText *self)
|
||||
{
|
||||
const char *signal;
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
signal = g_object_get_qdata (G_OBJECT (menuitem), quark_gtk_signal);
|
||||
g_signal_emit_by_name (self, signal);
|
||||
if (priv->selection_bubble && gtk_widget_get_visible (priv->selection_bubble))
|
||||
gtk_widget_hide (priv->selection_bubble);
|
||||
}
|
||||
|
||||
static void
|
||||
cut_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_signal_emit_by_name (user_data, "cut-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
copy_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_signal_emit_by_name (user_data, "copy-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
paste_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_signal_emit_by_name (user_data, "paste-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
delete_selection_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_text_delete_cb (GTK_TEXT (user_data));
|
||||
hide_selection_bubble (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
select_all_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_text_select_all (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
insert_emoji_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
gtk_text_insert_emoji (GTK_TEXT (user_data));
|
||||
hide_selection_bubble (GTK_TEXT (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
toggle_visibility (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkText *text = GTK_TEXT (user_data);
|
||||
gtk_text_set_visibility (text, !gtk_text_get_visibility (text));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_add_context_actions (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
GActionEntry entries[] = {
|
||||
{ "cut-clipboard", cut_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "copy-clipboard", copy_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "paste-clipboard", paste_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "delete-selection", delete_selection_activated, NULL, NULL, NULL },
|
||||
{ "select-all", select_all_activated, NULL, NULL, NULL },
|
||||
{ "insert-emoji", insert_emoji_activated, NULL, NULL, NULL },
|
||||
{ "toggle-visibility", toggle_visibility, NULL, "true", 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), self);
|
||||
|
||||
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), "insert-emoji");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (self), "context", G_ACTION_GROUP (actions));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_update_clipboard_actions (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
DisplayMode mode;
|
||||
GdkClipboard *clipboard;
|
||||
gboolean has_clipboard;
|
||||
GAction *action;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (self));
|
||||
has_clipboard = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), G_TYPE_STRING);
|
||||
mode = gtk_text_get_display_mode (self);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "cut-clipboard");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
mode == DISPLAY_NORMAL &&
|
||||
priv->editable &&
|
||||
priv->current_pos != priv->selection_bound);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "copy-clipboard");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
mode == DISPLAY_NORMAL &&
|
||||
priv->current_pos != priv->selection_bound);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "paste-clipboard");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
priv->editable && has_clipboard);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "delete-selection");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
priv->editable &&
|
||||
priv->current_pos != priv->selection_bound);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "select-all");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
priv->buffer && (gtk_entry_buffer_get_length (priv->buffer) > 0));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_update_emoji_action (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GAction *action;
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "insert-emoji");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
(gtk_text_get_input_hints (self) & GTK_INPUT_HINT_NO_EMOJI) == 0);
|
||||
}
|
||||
|
||||
static GMenuModel *
|
||||
gtk_text_get_menu_model (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GMenu *menu, *section;
|
||||
GMenuItem *item;
|
||||
|
||||
menu = g_menu_new ();
|
||||
|
||||
section = g_menu_new ();
|
||||
item = g_menu_item_new (_("Cu_t"), "context.cut-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-cut-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Copy"), "context.copy-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-copy-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Paste"), "context.paste-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-paste-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Delete"), "context.delete-selection");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-delete-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
|
||||
g_object_unref (section);
|
||||
|
||||
section = g_menu_new ();
|
||||
|
||||
item = g_menu_item_new (_("Select _All"), "context.select-all");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-select-all-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
|
||||
item = g_menu_item_new ( _("Insert _Emoji"), "context.insert-emoji");
|
||||
g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "face-smile-symbolic");
|
||||
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 gboolean
|
||||
gtk_text_mnemonic_activate (GtkWidget *widget,
|
||||
@ -5611,132 +5821,11 @@ gtk_text_mnemonic_activate (GtkWidget *widget,
|
||||
return GDK_EVENT_STOP;
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkText *self,
|
||||
GtkWidget *menu,
|
||||
const char *label,
|
||||
const char *signal,
|
||||
gboolean sensitive)
|
||||
{
|
||||
GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (label);
|
||||
|
||||
g_object_set_qdata (G_OBJECT (menuitem), quark_gtk_signal, (char *)signal);
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (activate_cb), self);
|
||||
|
||||
gtk_widget_set_sensitive (menuitem, sensitive);
|
||||
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_menu_detach (GtkWidget *attach_widget,
|
||||
GtkMenu *menu)
|
||||
{
|
||||
GtkText *self_attach = GTK_TEXT (attach_widget);
|
||||
GtkTextPrivate *priv_attach = gtk_text_get_instance_private (self_attach);
|
||||
|
||||
priv_attach->popup_menu = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_do_popup (GtkText *self,
|
||||
const GdkEvent *event)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkEvent *trigger_event;
|
||||
|
||||
/* In order to know what entries we should make sensitive, we
|
||||
* ask for the current targets of the clipboard, and when
|
||||
* we get them, then we actually pop up the menu.
|
||||
*/
|
||||
trigger_event = event ? gdk_event_copy (event) : gtk_get_current_event ();
|
||||
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (self)))
|
||||
{
|
||||
DisplayMode mode;
|
||||
gboolean clipboard_contains_text;
|
||||
GtkWidget *menu;
|
||||
GtkWidget *menuitem;
|
||||
|
||||
clipboard_contains_text = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (gtk_widget_get_clipboard (GTK_WIDGET (self))),
|
||||
G_TYPE_STRING);
|
||||
if (priv->popup_menu)
|
||||
gtk_widget_destroy (priv->popup_menu);
|
||||
|
||||
priv->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 (self), popup_menu_detach);
|
||||
|
||||
mode = gtk_text_get_display_mode (self);
|
||||
append_action_signal (self, menu, _("Cu_t"), "cut-clipboard",
|
||||
priv->editable && mode == DISPLAY_NORMAL &&
|
||||
priv->current_pos != priv->selection_bound);
|
||||
|
||||
append_action_signal (self, menu, _("_Copy"), "copy-clipboard",
|
||||
mode == DISPLAY_NORMAL &&
|
||||
priv->current_pos != priv->selection_bound);
|
||||
|
||||
append_action_signal (self, menu, _("_Paste"), "paste-clipboard",
|
||||
priv->editable && clipboard_contains_text);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete"));
|
||||
gtk_widget_set_sensitive (menuitem, priv->editable && priv->current_pos != priv->selection_bound);
|
||||
g_signal_connect_swapped (menuitem, "activate",
|
||||
G_CALLBACK (gtk_text_delete_cb), self);
|
||||
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"));
|
||||
gtk_widget_set_sensitive (menuitem, gtk_entry_buffer_get_length (priv->buffer) > 0);
|
||||
g_signal_connect_swapped (menuitem, "activate",
|
||||
G_CALLBACK (gtk_text_select_all), self);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
|
||||
if ((gtk_text_get_input_hints (self) & GTK_INPUT_HINT_NO_EMOJI) == 0)
|
||||
{
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Insert _Emoji"));
|
||||
gtk_widget_set_sensitive (menuitem,
|
||||
mode == DISPLAY_NORMAL &&
|
||||
priv->editable);
|
||||
g_signal_connect_swapped (menuitem, "activate",
|
||||
G_CALLBACK (gtk_text_insert_emoji), self);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
}
|
||||
|
||||
g_signal_emit (self, signals[POPULATE_POPUP], 0, menu);
|
||||
|
||||
if (trigger_event && gdk_event_triggers_context_menu (trigger_event))
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (menu), trigger_event);
|
||||
else
|
||||
{
|
||||
gtk_menu_popup_at_widget (GTK_MENU (menu),
|
||||
GTK_WIDGET (self),
|
||||
GDK_GRAVITY_SOUTH_EAST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
trigger_event);
|
||||
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
g_clear_object (&trigger_event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_text_do_popup (GTK_TEXT (widget), NULL);
|
||||
return GDK_EVENT_STOP;
|
||||
gtk_text_do_popup (GTK_TEXT (widget), -1, -1);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5766,40 +5855,56 @@ show_or_hide_handles (GtkWidget *popover,
|
||||
}
|
||||
|
||||
static void
|
||||
activate_bubble_cb (GtkWidget *item,
|
||||
GtkText *self)
|
||||
append_bubble_item (GtkText *self,
|
||||
GtkWidget *toolbar,
|
||||
GMenuModel *model,
|
||||
int index)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
const char *signal;
|
||||
|
||||
signal = g_object_get_qdata (G_OBJECT (item), quark_gtk_signal);
|
||||
gtk_widget_hide (priv->selection_bubble);
|
||||
if (strcmp (signal, "select-all") == 0)
|
||||
gtk_text_select_all (self);
|
||||
else
|
||||
g_signal_emit_by_name (self, signal);
|
||||
}
|
||||
|
||||
static void
|
||||
append_bubble_action (GtkText *self,
|
||||
GtkWidget *toolbar,
|
||||
const char *label,
|
||||
const char *icon_name,
|
||||
const char *signal,
|
||||
gboolean sensitive)
|
||||
{
|
||||
GtkWidget *item, *image;
|
||||
GVariant *att;
|
||||
const char *icon_name;
|
||||
const char *action_name;
|
||||
GAction *action;
|
||||
GMenuModel *link;
|
||||
|
||||
link = g_menu_model_get_item_link (model, index, "section");
|
||||
if (link)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < g_menu_model_get_n_items (link); i++)
|
||||
append_bubble_item (self, toolbar, link, i);
|
||||
g_object_unref (link);
|
||||
return;
|
||||
}
|
||||
|
||||
att = g_menu_model_get_item_attribute_value (model, index, "touch-icon", G_VARIANT_TYPE_STRING);
|
||||
if (att == NULL)
|
||||
return;
|
||||
|
||||
icon_name = g_variant_get_string (att, NULL);
|
||||
g_variant_unref (att);
|
||||
|
||||
att = g_menu_model_get_item_attribute_value (model, index, "action", G_VARIANT_TYPE_STRING);
|
||||
if (att == NULL)
|
||||
return;
|
||||
action_name = g_variant_get_string (att, NULL);
|
||||
g_variant_unref (att);
|
||||
|
||||
if (g_str_has_prefix (action_name, "context."))
|
||||
{
|
||||
action = g_action_map_lookup_action (priv->context_actions, action_name + strlen ("context."));
|
||||
if (action && !g_action_get_enabled (action))
|
||||
return;
|
||||
}
|
||||
|
||||
item = gtk_button_new ();
|
||||
gtk_widget_set_focus_on_click (item, FALSE);
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_widget_show (image);
|
||||
gtk_container_add (GTK_CONTAINER (item), image);
|
||||
gtk_widget_set_tooltip_text (item, label);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (item), "image-button");
|
||||
g_object_set_qdata (G_OBJECT (item), quark_gtk_signal, (char *)signal);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), self);
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive);
|
||||
gtk_actionable_set_action_name (GTK_ACTIONABLE (item), action_name);
|
||||
gtk_widget_show (GTK_WIDGET (item));
|
||||
gtk_container_add (GTK_CONTAINER (toolbar), item);
|
||||
}
|
||||
@ -5811,21 +5916,19 @@ gtk_text_selection_bubble_popup_show (gpointer user_data)
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
cairo_rectangle_int_t rect;
|
||||
GtkAllocation allocation;
|
||||
int start_x, end_x;
|
||||
gboolean has_selection;
|
||||
gboolean has_clipboard;
|
||||
gboolean all_selected;
|
||||
DisplayMode mode;
|
||||
int start_x, end_x;
|
||||
GtkWidget *box;
|
||||
GtkWidget *toolbar;
|
||||
int length;
|
||||
GtkAllocation text_allocation;
|
||||
GMenuModel *model;
|
||||
int i;
|
||||
|
||||
gtk_text_update_clipboard_actions (self);
|
||||
|
||||
gtk_text_get_text_allocation (self, &text_allocation);
|
||||
|
||||
has_selection = priv->selection_bound != priv->current_pos;
|
||||
length = gtk_entry_buffer_get_length (get_buffer (self));
|
||||
all_selected = (priv->selection_bound == 0) && (priv->current_pos == length);
|
||||
|
||||
if (!has_selection && !priv->editable)
|
||||
{
|
||||
@ -5851,24 +5954,12 @@ gtk_text_selection_bubble_popup_show (gpointer user_data)
|
||||
gtk_container_add (GTK_CONTAINER (priv->selection_bubble), box);
|
||||
gtk_container_add (GTK_CONTAINER (box), toolbar);
|
||||
|
||||
has_clipboard = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (gtk_widget_get_clipboard (GTK_WIDGET (self))),
|
||||
G_TYPE_STRING);
|
||||
mode = gtk_text_get_display_mode (self);
|
||||
model = gtk_text_get_menu_model (self);
|
||||
|
||||
if (priv->editable && has_selection && mode == DISPLAY_NORMAL)
|
||||
append_bubble_action (self, toolbar, _("Select all"), "edit-select-all-symbolic", "select-all", !all_selected);
|
||||
for (i = 0; i < g_menu_model_get_n_items (model); i++)
|
||||
append_bubble_item (self, toolbar, model, i);
|
||||
|
||||
if (priv->editable && has_selection && mode == DISPLAY_NORMAL)
|
||||
append_bubble_action (self, toolbar, _("Cut"), "edit-cut-symbolic", "cut-clipboard", TRUE);
|
||||
|
||||
if (has_selection && mode == DISPLAY_NORMAL)
|
||||
append_bubble_action (self, toolbar, _("Copy"), "edit-copy-symbolic", "copy-clipboard", TRUE);
|
||||
|
||||
if (priv->editable)
|
||||
append_bubble_action (self, toolbar, _("Paste"), "edit-paste-symbolic", "paste-clipboard", has_clipboard);
|
||||
|
||||
if (priv->populate_all)
|
||||
g_signal_emit (self, signals[POPULATE_POPUP], 0, box);
|
||||
g_object_unref (model);
|
||||
|
||||
gtk_widget_get_allocation (GTK_WIDGET (self), &allocation);
|
||||
|
||||
@ -5944,7 +6035,7 @@ gtk_text_drag_begin (GtkWidget *widget,
|
||||
|
||||
text = _gtk_text_get_selected_text (self);
|
||||
|
||||
if (text)
|
||||
if (self)
|
||||
{
|
||||
int *ranges, n_ranges;
|
||||
GdkPaintable *paintable;
|
||||
@ -6492,6 +6583,7 @@ gtk_text_set_input_hints (GtkText *self,
|
||||
NULL);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), text_props[PROP_INPUT_HINTS]);
|
||||
gtk_text_update_emoji_action (self);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6686,3 +6778,45 @@ gtk_text_get_key_controller (GtkText *self)
|
||||
|
||||
return priv->key_controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_set_extra_menu:
|
||||
* @self: a #GtkText
|
||||
* @model: (allow-none): a #GMenuModel
|
||||
*
|
||||
* Sets a menu model to add when constructing
|
||||
* the context menu for @self.
|
||||
*/
|
||||
void
|
||||
gtk_text_set_extra_menu (GtkText *self,
|
||||
GMenuModel *model)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT (self));
|
||||
|
||||
if (g_set_object (&priv->extra_menu, model))
|
||||
{
|
||||
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
|
||||
|
||||
g_object_notify_by_pspec (G_OBJECT (self), text_props[PROP_EXTRA_MENU]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_get_extra_menu:
|
||||
* @self: a #GtkText
|
||||
*
|
||||
* Gets the menu model set with gtk_text_set_extra_menu().
|
||||
*
|
||||
* Returns: (transfer none): (nullable): the menu model
|
||||
*/
|
||||
GMenuModel *
|
||||
gtk_text_get_extra_menu (GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT (self), NULL);
|
||||
|
||||
return priv->extra_menu;
|
||||
}
|
||||
|
@ -134,6 +134,12 @@ PangoTabArray * gtk_text_get_tabs (GtkText *self);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_text_grab_focus_without_selecting (GtkText *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_text_set_extra_menu (GtkText *self,
|
||||
GMenuModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GMenuModel * gtk_text_get_extra_menu (GtkText *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_TEXT_H__ */
|
||||
|
@ -34,9 +34,6 @@ typedef struct _GtkTextClass GtkTextClass;
|
||||
/*<private>
|
||||
* GtkTextClass:
|
||||
* @parent_class: The parent class.
|
||||
* @populate_popup: Class handler for the #GtkText::populate-popup signal. If
|
||||
* non-%NULL, this will be called to add additional entries to the context
|
||||
* menu when it is displayed.
|
||||
* @activate: Class handler for the #GtkText::activate signal. The default
|
||||
* implementation activates the gtk.activate-default action.
|
||||
* @move_cursor: Class handler for the #GtkText::move-cursor signal. The
|
||||
@ -70,10 +67,6 @@ struct _GtkTextClass
|
||||
{
|
||||
GtkWidgetClass parent_class;
|
||||
|
||||
/* Hook to customize right-click popup */
|
||||
void (* populate_popup) (GtkText *self,
|
||||
GtkWidget *popup);
|
||||
|
||||
/* Action signals
|
||||
*/
|
||||
void (* activate) (GtkText *self);
|
||||
|
@ -58,6 +58,8 @@
|
||||
#include "gtkemojichooser.h"
|
||||
#include "gtkpango.h"
|
||||
#include "gtknative.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
#include "gtkactionmuxerprivate.h"
|
||||
|
||||
#include "a11y/gtktextviewaccessibleprivate.h"
|
||||
|
||||
@ -180,6 +182,8 @@ struct _GtkTextViewPrivate
|
||||
GtkAdjustment *hadjustment;
|
||||
GtkAdjustment *vadjustment;
|
||||
|
||||
GActionMap *context_actions;
|
||||
|
||||
/* X offset between widget coordinates and buffer coordinates
|
||||
* taking left_padding in account
|
||||
*/
|
||||
@ -219,6 +223,7 @@ struct _GtkTextViewPrivate
|
||||
|
||||
GtkIMContext *im_context;
|
||||
GtkWidget *popup_menu;
|
||||
GMenuModel *extra_menu;
|
||||
|
||||
GSList *children;
|
||||
|
||||
@ -273,7 +278,6 @@ struct _GtkTextViewPrivate
|
||||
guint vscroll_policy : 1;
|
||||
guint cursor_handle_dragged : 1;
|
||||
guint selection_handle_dragged : 1;
|
||||
guint populate_all : 1;
|
||||
};
|
||||
|
||||
struct _GtkTextPendingScroll
|
||||
@ -294,7 +298,6 @@ typedef enum
|
||||
|
||||
enum
|
||||
{
|
||||
POPULATE_POPUP,
|
||||
MOVE_CURSOR,
|
||||
PAGE_HORIZONTALLY,
|
||||
SET_ANCHOR,
|
||||
@ -340,8 +343,8 @@ enum
|
||||
PROP_VSCROLL_POLICY,
|
||||
PROP_INPUT_PURPOSE,
|
||||
PROP_INPUT_HINTS,
|
||||
PROP_POPULATE_ALL,
|
||||
PROP_MONOSPACE
|
||||
PROP_MONOSPACE,
|
||||
PROP_EXTRA_MENU
|
||||
};
|
||||
|
||||
static GQuark quark_text_selection_data = 0;
|
||||
@ -443,7 +446,6 @@ static void gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
GtkSelectionData *selection_data);
|
||||
|
||||
static gboolean gtk_text_view_popup_menu (GtkWidget *widget);
|
||||
|
||||
static void gtk_text_view_move_cursor (GtkTextView *text_view,
|
||||
GtkMovementStep step,
|
||||
gint count,
|
||||
@ -593,6 +595,10 @@ static void extend_selection (GtkTextView *text_view,
|
||||
GtkTextIter *start,
|
||||
GtkTextIter *end);
|
||||
|
||||
static void gtk_text_view_add_context_actions (GtkTextView *text_view);
|
||||
static void gtk_text_view_update_clipboard_actions (GtkTextView *text_view);
|
||||
static void gtk_text_view_update_emoji_action (GtkTextView *text_view);
|
||||
|
||||
|
||||
|
||||
/* FIXME probably need the focus methods. */
|
||||
@ -958,22 +964,9 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
GTK_INPUT_HINT_NONE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* GtkTextView:populate-all:
|
||||
*
|
||||
* If :populate-all is %TRUE, the #GtkTextView::populate-popup
|
||||
* signal is also emitted for touch popups.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_POPULATE_ALL,
|
||||
g_param_spec_boolean ("populate-all",
|
||||
P_("Populate all"),
|
||||
P_("Whether to emit ::populate-popup for touch popups"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
/**
|
||||
* GtkTextview:monospace:
|
||||
* GtkTextView:monospace:
|
||||
*
|
||||
* If %TRUE, set the %GTK_STYLE_CLASS_MONOSPACE style class on the
|
||||
* text view to indicate that a monospace font is desired.
|
||||
@ -986,7 +979,13 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
|
||||
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
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));
|
||||
|
||||
/* GtkScrollable interface */
|
||||
g_object_class_override_property (gobject_class, PROP_HADJUSTMENT, "hadjustment");
|
||||
@ -1244,36 +1243,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
NULL,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
/**
|
||||
* GtkTextView::populate-popup:
|
||||
* @text_view: The text view on which the signal is emitted
|
||||
* @popup: the container that is being populated
|
||||
*
|
||||
* The ::populate-popup signal gets emitted before showing the
|
||||
* context menu of the text view.
|
||||
*
|
||||
* If you need to add items to the context menu, connect
|
||||
* to this signal and append your items to the @popup, which
|
||||
* will be a #GtkMenu in this case.
|
||||
*
|
||||
* If #GtkTextView:populate-all is %TRUE, this signal will
|
||||
* also be emitted to populate touch popups. In this case,
|
||||
* @popup will be a different container, e.g. a #GtkToolbar.
|
||||
*
|
||||
* The signal handler should not make assumptions about the
|
||||
* type of @widget, but check whether @popup is a #GtkMenu
|
||||
* or #GtkToolbar or another kind of container.
|
||||
*/
|
||||
signals[POPULATE_POPUP] =
|
||||
g_signal_new (I_("populate-popup"),
|
||||
G_OBJECT_CLASS_TYPE (gobject_class),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GtkTextViewClass, populate_popup),
|
||||
NULL, NULL,
|
||||
NULL,
|
||||
G_TYPE_NONE, 1,
|
||||
GTK_TYPE_WIDGET);
|
||||
|
||||
/**
|
||||
* GtkTextView::select-all:
|
||||
* @text_view: the object which received the signal
|
||||
@ -1725,6 +1694,8 @@ gtk_text_view_init (GtkTextView *text_view)
|
||||
gtk_css_node_get_state (priv->text_window->css_node) & ~GTK_STATE_FLAG_DROP_ACTIVE);
|
||||
gtk_css_node_set_visible (priv->selection_node, FALSE);
|
||||
g_object_unref (priv->selection_node);
|
||||
|
||||
gtk_text_view_add_context_actions (text_view);
|
||||
}
|
||||
|
||||
GtkCssNode *
|
||||
@ -3645,6 +3616,10 @@ gtk_text_view_finalize (GObject *object)
|
||||
|
||||
g_free (priv->im_module);
|
||||
|
||||
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
|
||||
g_clear_object (&priv->context_actions);
|
||||
g_clear_object (&priv->extra_menu);
|
||||
|
||||
G_OBJECT_CLASS (gtk_text_view_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -3767,17 +3742,14 @@ gtk_text_view_set_property (GObject *object,
|
||||
gtk_text_view_set_input_hints (text_view, g_value_get_flags (value));
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
if (text_view->priv->populate_all != g_value_get_boolean (value))
|
||||
{
|
||||
text_view->priv->populate_all = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
case PROP_MONOSPACE:
|
||||
gtk_text_view_set_monospace (text_view, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
gtk_text_view_set_extra_menu (text_view, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -3890,14 +3862,14 @@ gtk_text_view_get_property (GObject *object,
|
||||
g_value_set_flags (value, gtk_text_view_get_input_hints (text_view));
|
||||
break;
|
||||
|
||||
case PROP_POPULATE_ALL:
|
||||
g_value_set_boolean (value, priv->populate_all);
|
||||
break;
|
||||
|
||||
case PROP_MONOSPACE:
|
||||
g_value_set_boolean (value, gtk_text_view_get_monospace (text_view));
|
||||
break;
|
||||
|
||||
case PROP_EXTRA_MENU:
|
||||
g_value_set_object (value, gtk_text_view_get_extra_menu (text_view));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@ -4191,6 +4163,9 @@ gtk_text_view_size_allocate (GtkWidget *widget,
|
||||
|
||||
if (priv->magnifier_popover)
|
||||
gtk_native_check_resize (GTK_NATIVE (priv->magnifier_popover));
|
||||
|
||||
if (priv->popup_menu)
|
||||
gtk_native_check_resize (GTK_NATIVE (priv->popup_menu));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4500,11 +4475,7 @@ gtk_text_view_unrealize (GtkWidget *widget)
|
||||
|
||||
gtk_text_view_remove_validate_idles (text_view);
|
||||
|
||||
if (priv->popup_menu)
|
||||
{
|
||||
gtk_widget_destroy (priv->popup_menu);
|
||||
priv->popup_menu = NULL;
|
||||
}
|
||||
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
|
||||
|
||||
gtk_im_context_set_client_widget (priv->im_context, NULL);
|
||||
|
||||
@ -8458,35 +8429,40 @@ gtk_text_view_set_virtual_cursor_pos (GtkTextView *text_view,
|
||||
text_view->priv->virtual_cursor_y = (y == -1) ? pos.y + pos.height / 2 : y;
|
||||
}
|
||||
|
||||
/* Quick hack of a popup menu
|
||||
*/
|
||||
static void
|
||||
activate_cb (GtkWidget *menuitem,
|
||||
GtkTextView *text_view)
|
||||
hide_selection_bubble (GtkTextView *text_view)
|
||||
{
|
||||
const gchar *signal;
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
|
||||
signal = g_object_get_qdata (G_OBJECT (menuitem), quark_gtk_signal);
|
||||
g_signal_emit_by_name (text_view, signal);
|
||||
if (priv->selection_bubble && gtk_widget_get_visible (priv->selection_bubble))
|
||||
gtk_widget_hide (priv->selection_bubble);
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkTextView *text_view,
|
||||
GtkWidget *menu,
|
||||
const gchar *label,
|
||||
const gchar *signal,
|
||||
gboolean sensitive)
|
||||
cut_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkWidget *menuitem = gtk_menu_item_new_with_mnemonic (label);
|
||||
g_signal_emit_by_name (user_data, "cut-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT_VIEW (user_data));
|
||||
}
|
||||
|
||||
g_object_set_qdata (G_OBJECT (menuitem), quark_gtk_signal, (char *)signal);
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (activate_cb), text_view);
|
||||
static void
|
||||
copy_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_signal_emit_by_name (user_data, "copy-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT_VIEW (user_data));
|
||||
}
|
||||
|
||||
gtk_widget_set_sensitive (menuitem, sensitive);
|
||||
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menuitem);
|
||||
static void
|
||||
paste_clipboard_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_signal_emit_by_name (user_data, "paste-clipboard");
|
||||
hide_selection_bubble (GTK_TEXT_VIEW (user_data));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -8512,24 +8488,32 @@ gtk_text_view_select_all (GtkWidget *widget,
|
||||
}
|
||||
|
||||
static void
|
||||
select_all_cb (GtkWidget *menuitem,
|
||||
GtkTextView *text_view)
|
||||
select_all_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkTextView *text_view = user_data;
|
||||
|
||||
gtk_text_view_select_all (GTK_WIDGET (text_view), TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
delete_cb (GtkTextView *text_view)
|
||||
delete_selection_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GtkTextView *text_view = user_data;
|
||||
|
||||
gtk_text_buffer_delete_selection (get_buffer (text_view), TRUE,
|
||||
text_view->priv->editable);
|
||||
}
|
||||
|
||||
static void
|
||||
popup_menu_detach (GtkWidget *attach_widget,
|
||||
GtkMenu *menu)
|
||||
insert_emoji_activated (GSimpleAction *action,
|
||||
GVariant *parameter,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTK_TEXT_VIEW (attach_widget)->priv->popup_menu = NULL;
|
||||
gtk_text_view_insert_emoji (GTK_TEXT_VIEW (user_data));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@ -8550,6 +8534,147 @@ range_contains_editable_text (const GtkTextIter *start,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_add_context_actions (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
|
||||
GActionEntry entries[] = {
|
||||
{ "cut-clipboard", cut_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "copy-clipboard", copy_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "paste-clipboard", paste_clipboard_activated, NULL, NULL, NULL },
|
||||
{ "delete-selection", delete_selection_activated, NULL, NULL, NULL },
|
||||
{ "select-all", select_all_activated, NULL, NULL, NULL },
|
||||
{ "insert-emoji", insert_emoji_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), text_view);
|
||||
|
||||
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), "insert-emoji");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
|
||||
|
||||
gtk_widget_insert_action_group (GTK_WIDGET (text_view), "context", G_ACTION_GROUP (actions));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_update_clipboard_actions (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GdkClipboard *clipboard;
|
||||
gboolean have_selection;
|
||||
gboolean can_paste, can_insert;
|
||||
GAction *action;
|
||||
GtkTextIter iter, sel_start, sel_end;
|
||||
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view));
|
||||
can_paste = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), G_TYPE_STRING);
|
||||
|
||||
have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
|
||||
&sel_start, &sel_end);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
|
||||
&iter,
|
||||
gtk_text_buffer_get_insert (get_buffer (text_view)));
|
||||
|
||||
can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "cut-clipboard");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
have_selection &&
|
||||
range_contains_editable_text (&sel_start, &sel_end, priv->editable));
|
||||
|
||||
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, "paste-clipboard");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), can_insert && can_paste);
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "delete-selection");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
have_selection &&
|
||||
range_contains_editable_text (&sel_start, &sel_end, priv->editable));
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "select-all");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
gtk_text_buffer_get_char_count (priv->buffer) > 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_update_emoji_action (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GAction *action;
|
||||
|
||||
action = g_action_map_lookup_action (priv->context_actions, "insert-emoji");
|
||||
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
|
||||
(gtk_text_view_get_input_hints (text_view) & GTK_INPUT_HINT_NO_EMOJI) == 0);
|
||||
}
|
||||
|
||||
static GMenuModel *
|
||||
gtk_text_view_get_menu_model (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GMenu *menu, *section;
|
||||
GMenuItem *item;
|
||||
|
||||
menu = g_menu_new ();
|
||||
|
||||
section = g_menu_new ();
|
||||
item = g_menu_item_new (_("Cu_t"), "context.cut-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-cut-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Copy"), "context.copy-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-copy-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Paste"), "context.paste-clipboard");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-paste-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
item = g_menu_item_new (_("_Delete"), "context.delete-selection");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-delete-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
|
||||
g_object_unref (section);
|
||||
|
||||
section = g_menu_new ();
|
||||
|
||||
item = g_menu_item_new (_("Select _All"), "context.select-all");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-select-all-symbolic");
|
||||
g_menu_append_item (section, item);
|
||||
g_object_unref (item);
|
||||
|
||||
item = g_menu_item_new ( _("Insert _Emoji"), "context.insert-emoji");
|
||||
g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
|
||||
g_menu_item_set_attribute (item, "touch-icon", "s", "face-smile-symbolic");
|
||||
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_text_view_do_popup (GtkTextView *text_view,
|
||||
const GdkEvent *event)
|
||||
@ -8557,134 +8682,95 @@ gtk_text_view_do_popup (GtkTextView *text_view,
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
GdkEvent *trigger_event;
|
||||
|
||||
if (!gtk_widget_get_realized (GTK_WIDGET (text_view)))
|
||||
return;
|
||||
|
||||
if (event)
|
||||
trigger_event = gdk_event_copy (event);
|
||||
else
|
||||
trigger_event = gtk_get_current_event ();
|
||||
|
||||
if (gtk_widget_get_realized (GTK_WIDGET (text_view)))
|
||||
gtk_text_view_update_clipboard_actions (text_view);
|
||||
|
||||
if (!priv->popup_menu)
|
||||
{
|
||||
GMenuModel *model;
|
||||
|
||||
model = gtk_text_view_get_menu_model (text_view);
|
||||
priv->popup_menu = gtk_popover_menu_new_from_model (GTK_WIDGET (text_view), model);
|
||||
gtk_popover_set_position (GTK_POPOVER (priv->popup_menu), GTK_POS_BOTTOM);
|
||||
|
||||
gtk_popover_set_has_arrow (GTK_POPOVER (priv->popup_menu), FALSE);
|
||||
gtk_widget_set_halign (priv->popup_menu, GTK_ALIGN_START);
|
||||
|
||||
g_object_unref (model);
|
||||
}
|
||||
|
||||
if (trigger_event && gdk_event_triggers_context_menu (trigger_event))
|
||||
{
|
||||
GdkDevice *device;
|
||||
GdkRectangle rect = { 0, 0, 1, 1 };
|
||||
|
||||
device = gdk_event_get_device (trigger_event);
|
||||
|
||||
if (device && gdk_device_get_source (device) == GDK_SOURCE_KEYBOARD)
|
||||
device = gdk_device_get_associated_device (device);
|
||||
|
||||
if (device)
|
||||
{
|
||||
GdkSurface *surface;
|
||||
double px, py;
|
||||
|
||||
surface = gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (text_view)));
|
||||
gdk_surface_get_device_position (surface, device, &px, &py, NULL);
|
||||
rect.x = round (px);
|
||||
rect.y = round (py);
|
||||
|
||||
gtk_widget_translate_coordinates (GTK_WIDGET (gtk_widget_get_native (GTK_WIDGET (text_view))),
|
||||
GTK_WIDGET (text_view),
|
||||
rect.x, rect.y,
|
||||
&rect.x, &rect.y);
|
||||
}
|
||||
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &rect);
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkWidget *menuitem;
|
||||
gboolean have_selection;
|
||||
gboolean can_insert, can_paste;
|
||||
GtkTextIter iter;
|
||||
GtkTextIter sel_start, sel_end;
|
||||
GdkRectangle iter_location;
|
||||
GdkRectangle visible_rect;
|
||||
gboolean is_visible;
|
||||
|
||||
if (priv->popup_menu)
|
||||
gtk_widget_destroy (priv->popup_menu);
|
||||
gtk_text_view_get_iter_location (text_view, &iter, &iter_location);
|
||||
gtk_text_view_get_visible_rect (text_view, &visible_rect);
|
||||
|
||||
priv->popup_menu = gtk_menu_new ();
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (priv->popup_menu),
|
||||
GTK_STYLE_CLASS_CONTEXT_MENU);
|
||||
is_visible = (iter_location.x + iter_location.width > visible_rect.x &&
|
||||
iter_location.x < visible_rect.x + visible_rect.width &&
|
||||
iter_location.y + iter_location.height > visible_rect.y &&
|
||||
iter_location.y < visible_rect.y + visible_rect.height);
|
||||
|
||||
gtk_menu_attach_to_widget (GTK_MENU (priv->popup_menu),
|
||||
GTK_WIDGET (text_view),
|
||||
popup_menu_detach);
|
||||
|
||||
have_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
|
||||
&sel_start, &sel_end);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view),
|
||||
&iter,
|
||||
gtk_text_buffer_get_insert (get_buffer (text_view)));
|
||||
|
||||
can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
|
||||
can_paste = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (gtk_widget_get_clipboard (GTK_WIDGET (text_view))),
|
||||
GTK_TYPE_TEXT_BUFFER);
|
||||
|
||||
append_action_signal (text_view, priv->popup_menu, _("Cu_t"), "cut-clipboard",
|
||||
have_selection &&
|
||||
range_contains_editable_text (&sel_start, &sel_end,
|
||||
priv->editable));
|
||||
append_action_signal (text_view, priv->popup_menu, _("_Copy"), "copy-clipboard",
|
||||
have_selection);
|
||||
append_action_signal (text_view, priv->popup_menu, _("_Paste"), "paste-clipboard",
|
||||
can_insert && can_paste);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("_Delete"));
|
||||
gtk_widget_set_sensitive (menuitem,
|
||||
have_selection &&
|
||||
range_contains_editable_text (&sel_start, &sel_end,
|
||||
priv->editable));
|
||||
g_signal_connect_swapped (menuitem, "activate",
|
||||
G_CALLBACK (delete_cb), text_view);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
|
||||
|
||||
menuitem = gtk_separator_menu_item_new ();
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
|
||||
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Select _All"));
|
||||
gtk_widget_set_sensitive (menuitem,
|
||||
gtk_text_buffer_get_char_count (priv->buffer) > 0);
|
||||
g_signal_connect (menuitem, "activate",
|
||||
G_CALLBACK (select_all_cb), text_view);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
|
||||
|
||||
if ((gtk_text_view_get_input_hints (text_view) & GTK_INPUT_HINT_NO_EMOJI) == 0)
|
||||
if (is_visible)
|
||||
{
|
||||
menuitem = gtk_menu_item_new_with_mnemonic (_("Insert _Emoji"));
|
||||
gtk_widget_set_sensitive (menuitem, can_insert);
|
||||
g_signal_connect_swapped (menuitem, "activate",
|
||||
G_CALLBACK (gtk_text_view_insert_emoji), text_view);
|
||||
gtk_widget_show (menuitem);
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->popup_menu), menuitem);
|
||||
}
|
||||
gtk_text_view_buffer_to_surface_coords (text_view,
|
||||
GTK_TEXT_WINDOW_WIDGET,
|
||||
iter_location.x,
|
||||
iter_location.y,
|
||||
&iter_location.x,
|
||||
&iter_location.y);
|
||||
|
||||
g_signal_emit (text_view, signals[POPULATE_POPUP],
|
||||
0, priv->popup_menu);
|
||||
|
||||
if (trigger_event && gdk_event_triggers_context_menu (trigger_event))
|
||||
gtk_menu_popup_at_pointer (GTK_MENU (priv->popup_menu), trigger_event);
|
||||
else
|
||||
{
|
||||
gtk_text_view_get_iter_location (text_view, &iter, &iter_location);
|
||||
gtk_text_view_get_visible_rect (text_view, &visible_rect);
|
||||
|
||||
is_visible = (iter_location.x + iter_location.width > visible_rect.x &&
|
||||
iter_location.x < visible_rect.x + visible_rect.width &&
|
||||
iter_location.y + iter_location.height > visible_rect.y &&
|
||||
iter_location.y < visible_rect.y + visible_rect.height);
|
||||
|
||||
if (is_visible)
|
||||
{
|
||||
gtk_text_view_buffer_to_surface_coords (text_view,
|
||||
GTK_TEXT_WINDOW_WIDGET,
|
||||
iter_location.x,
|
||||
iter_location.y,
|
||||
&iter_location.x,
|
||||
&iter_location.y);
|
||||
|
||||
gtk_menu_popup_at_rect (GTK_MENU (priv->popup_menu),
|
||||
gtk_native_get_surface (gtk_widget_get_native (GTK_WIDGET (text_view))),
|
||||
&iter_location,
|
||||
GDK_GRAVITY_SOUTH_EAST,
|
||||
GDK_GRAVITY_NORTH_WEST,
|
||||
trigger_event);
|
||||
}
|
||||
else
|
||||
gtk_menu_popup_at_widget (GTK_MENU (priv->popup_menu),
|
||||
GTK_WIDGET (text_view),
|
||||
GDK_GRAVITY_CENTER,
|
||||
GDK_GRAVITY_CENTER,
|
||||
trigger_event);
|
||||
|
||||
gtk_menu_shell_select_first (GTK_MENU_SHELL (priv->popup_menu), FALSE);
|
||||
gtk_popover_set_pointing_to (GTK_POPOVER (priv->popup_menu), &iter_location);
|
||||
}
|
||||
}
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (priv->popup_menu));
|
||||
|
||||
g_clear_object (&trigger_event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_popup_menu (GtkWidget *widget)
|
||||
{
|
||||
gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);
|
||||
gtk_text_view_do_popup (GTK_TEXT_VIEW (widget), NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -8741,32 +8827,81 @@ show_or_hide_handles (GtkWidget *popover,
|
||||
}
|
||||
|
||||
static void
|
||||
activate_bubble_cb (GtkWidget *item,
|
||||
GtkTextView *text_view)
|
||||
append_bubble_item (GtkTextView *text_view,
|
||||
GtkWidget *toolbar,
|
||||
GMenuModel *model,
|
||||
int index)
|
||||
{
|
||||
const gchar *signal;
|
||||
GtkWidget *item, *image;
|
||||
GVariant *att;
|
||||
const char *icon_name;
|
||||
const char *action_name;
|
||||
GMenuModel *link;
|
||||
char **split = NULL;
|
||||
gboolean is_toggle_action = FALSE;
|
||||
|
||||
signal = g_object_get_qdata (G_OBJECT (item), quark_gtk_signal);
|
||||
gtk_widget_hide (text_view->priv->selection_bubble);
|
||||
g_signal_emit_by_name (text_view, signal);
|
||||
}
|
||||
link = g_menu_model_get_item_link (model, index, "section");
|
||||
if (link)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < g_menu_model_get_n_items (link); i++)
|
||||
append_bubble_item (text_view, toolbar, link, i);
|
||||
g_object_unref (link);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
append_bubble_action (GtkTextView *text_view,
|
||||
GtkWidget *toolbar,
|
||||
const gchar *label,
|
||||
const gchar *icon_name,
|
||||
const gchar *signal,
|
||||
gboolean sensitive)
|
||||
{
|
||||
GtkWidget *item;
|
||||
att = g_menu_model_get_item_attribute_value (model, index, "touch-icon", G_VARIANT_TYPE_STRING);
|
||||
if (att == NULL)
|
||||
return;
|
||||
|
||||
item = gtk_button_new_from_icon_name (icon_name);
|
||||
icon_name = g_variant_get_string (att, NULL);
|
||||
g_variant_unref (att);
|
||||
|
||||
att = g_menu_model_get_item_attribute_value (model, index, "action", G_VARIANT_TYPE_STRING);
|
||||
if (att == NULL)
|
||||
return;
|
||||
action_name = g_variant_get_string (att, NULL);
|
||||
g_variant_unref (att);
|
||||
|
||||
split = g_strsplit (action_name, ".", 2);
|
||||
if (split[0] && split[1])
|
||||
{
|
||||
GActionGroup *group = NULL;
|
||||
gboolean enabled;
|
||||
const GVariantType *param_type;
|
||||
const GVariantType *state_type;
|
||||
GtkActionMuxer *muxer;
|
||||
|
||||
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (text_view), FALSE);
|
||||
if (muxer)
|
||||
group = gtk_action_muxer_lookup (muxer, split[0]);
|
||||
if (group)
|
||||
{
|
||||
g_action_group_query_action (group, split[1], &enabled, ¶m_type, &state_type, NULL, NULL);
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
if (param_type == NULL &&
|
||||
state_type != NULL &&
|
||||
g_variant_type_equal (state_type, G_VARIANT_TYPE_BOOLEAN))
|
||||
is_toggle_action = TRUE;
|
||||
}
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
if (is_toggle_action)
|
||||
item = gtk_toggle_button_new ();
|
||||
else
|
||||
item = gtk_button_new ();
|
||||
gtk_widget_set_focus_on_click (item, FALSE);
|
||||
gtk_widget_set_tooltip_text (item, label);
|
||||
g_object_set_qdata (G_OBJECT (item), quark_gtk_signal, (char *)signal);
|
||||
g_signal_connect (item, "clicked", G_CALLBACK (activate_bubble_cb), text_view);
|
||||
gtk_widget_set_sensitive (GTK_WIDGET (item), sensitive);
|
||||
image = gtk_image_new_from_icon_name (icon_name);
|
||||
gtk_widget_show (image);
|
||||
gtk_container_add (GTK_CONTAINER (item), image);
|
||||
gtk_style_context_add_class (gtk_widget_get_style_context (item), "image-button");
|
||||
gtk_actionable_set_action_name (GTK_ACTIONABLE (item), action_name);
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (item));
|
||||
gtk_container_add (GTK_CONTAINER (toolbar), item);
|
||||
}
|
||||
|
||||
@ -8776,24 +8911,14 @@ gtk_text_view_selection_bubble_popup_show (gpointer user_data)
|
||||
GtkTextView *text_view = user_data;
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
cairo_rectangle_int_t rect;
|
||||
GdkClipboard *clipboard;
|
||||
gboolean has_selection;
|
||||
gboolean has_clipboard;
|
||||
gboolean can_insert;
|
||||
gboolean all_selected;
|
||||
GtkTextIter iter;
|
||||
GtkTextIter sel_start, sel_end;
|
||||
GtkTextIter start, end;
|
||||
GtkWidget *box;
|
||||
GtkWidget *toolbar;
|
||||
GMenuModel *model;
|
||||
int i;
|
||||
|
||||
gtk_text_view_update_clipboard_actions (text_view);
|
||||
|
||||
priv->selection_bubble_timeout_id = 0;
|
||||
has_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
|
||||
&sel_start, &sel_end);
|
||||
gtk_text_buffer_get_bounds (get_buffer (text_view), &start, &end);
|
||||
|
||||
all_selected = gtk_text_iter_equal (&start, &sel_start) &&
|
||||
gtk_text_iter_equal (&end, &sel_end);
|
||||
|
||||
g_clear_pointer (&priv->selection_bubble, gtk_widget_unparent);
|
||||
|
||||
@ -8813,25 +8938,12 @@ gtk_text_view_selection_bubble_popup_show (gpointer user_data)
|
||||
gtk_container_add (GTK_CONTAINER (priv->selection_bubble), box);
|
||||
gtk_container_add (GTK_CONTAINER (box), toolbar);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (get_buffer (text_view), &iter,
|
||||
gtk_text_buffer_get_insert (get_buffer (text_view)));
|
||||
can_insert = gtk_text_iter_can_insert (&iter, priv->editable);
|
||||
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (text_view));
|
||||
has_clipboard = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), GTK_TYPE_TEXT_BUFFER);
|
||||
model = gtk_text_view_get_menu_model (text_view);
|
||||
|
||||
append_bubble_action (text_view, toolbar, _("Select all"), "edit-select-all-symbolic", "select-all", !all_selected);
|
||||
for (i = 0; i < g_menu_model_get_n_items (model); i++)
|
||||
append_bubble_item (text_view, toolbar, model, i);
|
||||
|
||||
if (range_contains_editable_text (&sel_start, &sel_end, priv->editable) && has_selection)
|
||||
append_bubble_action (text_view, toolbar, _("Cut"), "edit-cut-symbolic", "cut-clipboard", TRUE);
|
||||
|
||||
if (has_selection)
|
||||
append_bubble_action (text_view, toolbar, _("Copy"), "edit-copy-symbolic", "copy-clipboard", TRUE);
|
||||
|
||||
if (can_insert)
|
||||
append_bubble_action (text_view, toolbar, _("Paste"), "edit-paste-symbolic", "paste-clipboard", has_clipboard);
|
||||
|
||||
if (priv->populate_all)
|
||||
g_signal_emit (text_view, signals[POPULATE_POPUP], 0, box);
|
||||
g_object_unref (model);
|
||||
|
||||
gtk_text_view_get_selection_rect (text_view, &rect);
|
||||
rect.x -= priv->xoffset;
|
||||
@ -9782,6 +9894,7 @@ gtk_text_view_set_input_hints (GtkTextView *text_view,
|
||||
NULL);
|
||||
|
||||
g_object_notify (G_OBJECT (text_view), "input-hints");
|
||||
gtk_text_view_update_emoji_action (text_view);
|
||||
}
|
||||
}
|
||||
|
||||
@ -9891,3 +10004,44 @@ gtk_text_view_insert_emoji (GtkTextView *text_view)
|
||||
|
||||
gtk_popover_popup (GTK_POPOVER (chooser));
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_view_set_extra_menu:
|
||||
* @text_view: a #GtkTextView
|
||||
* @model: (allow-none): a #GMenuModel
|
||||
*
|
||||
* Sets a menu model to add when constructing
|
||||
* the context menu for @text_view.
|
||||
*/
|
||||
void
|
||||
gtk_text_view_set_extra_menu (GtkTextView *text_view,
|
||||
GMenuModel *model)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_VIEW (text_view));
|
||||
|
||||
if (g_set_object (&priv->extra_menu, model))
|
||||
{
|
||||
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
|
||||
g_object_notify (G_OBJECT (text_view), "extra-menu");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_view_get_extra_menu:
|
||||
* @text_view: a #GtkTextView
|
||||
*
|
||||
* Gets the menu model set with gtk_text_view_set_extra_menu().
|
||||
*
|
||||
* Returns: (transfer none): (nullable): the menu model
|
||||
*/
|
||||
GMenuModel *
|
||||
gtk_text_view_get_extra_menu (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextViewPrivate *priv = text_view->priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_VIEW (text_view), NULL);
|
||||
|
||||
return priv->extra_menu;
|
||||
}
|
||||
|
@ -120,8 +120,6 @@ struct _GtkTextView
|
||||
/**
|
||||
* GtkTextViewClass:
|
||||
* @parent_class: The object class structure needs to be the first
|
||||
* @populate_popup: The class handler for the #GtkTextView::populate-popup
|
||||
* signal.
|
||||
* @move_cursor: The class handler for the #GtkTextView::move-cursor
|
||||
* keybinding signal.
|
||||
* @set_anchor: The class handler for the #GtkTextView::set-anchor
|
||||
@ -159,8 +157,6 @@ struct _GtkTextViewClass
|
||||
|
||||
/*< public >*/
|
||||
|
||||
void (* populate_popup) (GtkTextView *text_view,
|
||||
GtkWidget *popup);
|
||||
void (* move_cursor) (GtkTextView *text_view,
|
||||
GtkMovementStep step,
|
||||
gint count,
|
||||
@ -431,6 +427,12 @@ void gtk_text_view_set_monospace (GtkTextView *text_vi
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_text_view_get_monospace (GtkTextView *text_view);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_text_view_set_extra_menu (GtkTextView *text_view,
|
||||
GMenuModel *model);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GMenuModel * gtk_text_view_get_extra_menu (GtkTextView *text_view);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_TEXT_VIEW_H__ */
|
||||
|
@ -841,9 +841,6 @@ static void gtk_tree_view_search_window_hide (GtkWidget *searc
|
||||
static void gtk_tree_view_search_position_func (GtkTreeView *tree_view,
|
||||
GtkWidget *search_window,
|
||||
gpointer user_data);
|
||||
static void gtk_tree_view_search_disable_popdown (GtkEntry *entry,
|
||||
GtkMenu *menu,
|
||||
gpointer data);
|
||||
static void gtk_tree_view_search_preedit_changed (GtkText *text,
|
||||
const char *preedit,
|
||||
GtkTreeView *tree_view);
|
||||
@ -851,9 +848,6 @@ static void gtk_tree_view_search_changed (GtkEditable *edita
|
||||
GtkTreeView *tree_view);
|
||||
static void gtk_tree_view_search_activate (GtkEntry *entry,
|
||||
GtkTreeView *tree_view);
|
||||
static gboolean gtk_tree_view_real_search_enable_popdown(gpointer data);
|
||||
static void gtk_tree_view_search_enable_popdown (GtkWidget *widget,
|
||||
gpointer data);
|
||||
static void gtk_tree_view_search_pressed_cb (GtkGesture *gesture,
|
||||
int n_press,
|
||||
double x,
|
||||
@ -10235,8 +10229,6 @@ gtk_tree_view_ensure_interactive_directory (GtkTreeView *tree_view)
|
||||
|
||||
/* add entry */
|
||||
tree_view->priv->search_entry = gtk_text_new ();
|
||||
g_signal_connect (tree_view->priv->search_entry, "populate-popup",
|
||||
G_CALLBACK (gtk_tree_view_search_disable_popdown), tree_view);
|
||||
g_signal_connect (tree_view->priv->search_entry, "activate",
|
||||
G_CALLBACK (gtk_tree_view_search_activate), tree_view);
|
||||
g_signal_connect (tree_view->priv->search_entry, "preedit-changed",
|
||||
@ -13791,18 +13783,6 @@ gtk_tree_view_search_position_func (GtkTreeView *tree_view,
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_search_disable_popdown (GtkEntry *entry,
|
||||
GtkMenu *menu,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTreeView *tree_view = (GtkTreeView *)data;
|
||||
|
||||
tree_view->priv->disable_popdown = 1;
|
||||
g_signal_connect (menu, "hide",
|
||||
G_CALLBACK (gtk_tree_view_search_enable_popdown), data);
|
||||
}
|
||||
|
||||
/* Because we're visible but offscreen, we just set a flag in the preedit
|
||||
* callback.
|
||||
*/
|
||||
@ -13855,27 +13835,6 @@ gtk_tree_view_search_activate (GtkEntry *entry,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_tree_view_real_search_enable_popdown (gpointer data)
|
||||
{
|
||||
GtkTreeView *tree_view = (GtkTreeView *)data;
|
||||
|
||||
tree_view->priv->disable_popdown = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_search_enable_popdown (GtkWidget *widget,
|
||||
gpointer data)
|
||||
{
|
||||
guint id = g_timeout_add_full (G_PRIORITY_HIGH, 200,
|
||||
gtk_tree_view_real_search_enable_popdown,
|
||||
g_object_ref (data),
|
||||
g_object_unref);
|
||||
g_source_set_name_by_id (id, "[gtk] gtk_tree_view_real_search_enable_popdown");
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_search_pressed_cb (GtkGesture *gesture,
|
||||
int n_press,
|
||||
|
Loading…
Reference in New Issue
Block a user