Compare commits

...

12 Commits

Author SHA1 Message Date
Matthias Clasen
07364bc597 window: Add a focus.move action
This is a first step towards redoing bindings with actions.
2019-06-18 15:36:29 +00:00
Matthias Clasen
8634082fe3 widget: Turn popup-menu binding into action
This is a trial for seeing how this works in practice.
2019-06-18 15:36:29 +00:00
Matthias Clasen
f4f09d15a8 widget: Add api to bind accels to actions
This is meant to be used at class-init time,
and will replace bindings, eventually.

We are reusing GtkApplicationAccels here.
It should probably be renamed.
2019-06-18 15:36:23 +00:00
Matthias Clasen
c173b54195 Docs: expand actions chapter 2019-06-18 15:30:26 +00:00
Matthias Clasen
7d7e592183 color chooser widget: Use the new action machinery 2019-06-18 15:30:26 +00:00
Matthias Clasen
615e5a7575 link button: Use the new action machinery 2019-06-18 15:30:26 +00:00
Matthias Clasen
e01fa6234e window: Use the new action machinery
Change the default.activate action to use the
new action machinery.
2019-06-18 15:30:00 +00:00
Matthias Clasen
2ecf4b3049 textview: Use the new action machinery
Port GtkTextView to use widget class actions.

Note that this also changes the names of
the GtkTextView actions away from a generic
"context" prefix.
2019-06-18 15:30:00 +00:00
Matthias Clasen
b1650d5988 label: Use the new action machinery
Port GtkLabel to use widget class actions.

Note that this also changes the names of
the GtkLabel actions away from a generic
"context" prefix.
2019-06-18 13:55:58 +00:00
Matthias Clasen
259c264fd0 password entry: Adapt to action name change
Also fix updating the icon when changing visibility
via the context menu.
2019-06-18 13:55:58 +00:00
Matthias Clasen
859595d1cd text: Use the new action machinery
Port GtkText to use widget class actions.

Note that this also changes the names of
the GtkText actions away from a generic
"context" prefix.
2019-06-18 13:55:58 +00:00
Matthias Clasen
e06cdcdf16 Allow registering actions per-class
Add a facility to register and install actions
at class init time. The intended use for these
actions is for

a) context and other model-based menus
b) key bindings

Most of these actions are going to be stateless,
so add separate apis for the simple and stateful
cases.

We avoid creating an action group for these by
teaching the action muxer about these actions.
The action muxer also maintains the enabled
state for these actions.
2019-06-18 13:55:57 +00:00
14 changed files with 1014 additions and 476 deletions

View File

@@ -258,9 +258,11 @@
</para>
<para>
Actions are added to their relevant scope (application or
window) either using the GActionMap interface, or by using
gtk_widget_insert_action_group().
Actions are added to their relevant scope (application,
window or widget) either using the GActionMap interface,
or by using gtk_widget_insert_action_group(). Actions that
will be the same for all instances of a widget class can
be added globally using gtk_widget_class_install_action().
</para>
</refsect2>
@@ -317,8 +319,8 @@
</para>
<para>
Another of obtaining widgets that are connected to actions is
to create a menu using a GMenu menu model. GMenu provides an
Another way of obtaining widgets that are connected to actions
is to create a menu using a GMenu menu model. GMenu provides an
abstract way to describe typical menus: nested groups of items
where each item can have a label, and icon, and an action.
</para>
@@ -364,6 +366,25 @@
(typically a GtkWindow, GtkDialog or GtkPopover)
</para></listitem>
</varlistentry>
<varlistentry>
<term>clipboard.cut, clipboard.copy, clipboard.paste</term>
<listitem><para>Clipboard operations on entries, text view
and labels, typically used in the context menu
</para></listitem>
</varlistentry>
<varlistentry>
<term>selection.delete, selection.select-all</term>
<listitem><para>Selection operations on entries, text view
and labels
</para></listitem>
</varlistentry>
<varlistentry>
<term>color.select, color.customize</term>
<listitem><para>Operations on colors in GtkColorChooserWidget.
These actions are unusual in that they have the non-trivial
parameter type (dddd).
</para></listitem>
</varlistentry>
</variablelist>
</para>
@@ -371,3 +392,4 @@
</refsect1>
</refentry>
</varlistentry>

View File

@@ -4549,10 +4549,6 @@ gtk_widget_get_opacity
gtk_widget_set_opacity
gtk_widget_get_overflow
gtk_widget_set_overflow
gtk_widget_insert_action_group
gtk_widget_list_action_prefixes
gtk_widget_activate_action
gtk_widget_activate_default
gtk_widget_measure
gtk_widget_snapshot_child
gtk_widget_get_next_sibling
@@ -4629,6 +4625,19 @@ gtk_widget_class_set_connect_func
gtk_widget_observe_children
gtk_widget_observe_controllers
<SUBSECTION Actions>
gtk_widget_insert_action_group
gtk_widget_activate_action
gtk_widget_activate_default
GtkWidgetActionActivateFunc
GtkWidgetActionSetStateFunc
GtkWidgetActionGetStateFunc
gtk_widget_class_install_action
gtk_widget_class_install_stateful_action
gtk_widget_notify_class_action_enabled
gtk_widget_notify_class_action_state
gtk_widget_class_bind_action
<SUBSECTION Standard>
GTK_WIDGET
GTK_IS_WIDGET

View File

@@ -72,6 +72,8 @@ struct _GtkActionMuxer
GtkActionMuxer *parent;
GtkWidget *widget;
GPtrArray *widget_actions;
gboolean *widget_actions_enabled;
};
G_DEFINE_TYPE_WITH_CODE (GtkActionMuxer, gtk_action_muxer, G_TYPE_OBJECT,
@@ -83,6 +85,7 @@ enum
PROP_0,
PROP_PARENT,
PROP_WIDGET,
PROP_WIDGET_ACTIONS,
NUM_PROPERTIES
};
@@ -108,7 +111,7 @@ typedef struct
static void
gtk_action_muxer_append_group_actions (const char *prefix,
Group *group,
GArray *actions)
GHashTable *actions)
{
gchar **group_actions;
gchar **action;
@@ -116,10 +119,8 @@ gtk_action_muxer_append_group_actions (const char *prefix,
group_actions = g_action_group_list_actions (group->group);
for (action = group_actions; *action; action++)
{
gchar *fullname;
fullname = g_strconcat (prefix, ".", *action, NULL);
g_array_append_val (actions, fullname);
char *name = g_strconcat (prefix, ".", *action, NULL);
g_hash_table_add (actions, name);
}
g_strfreev (group_actions);
@@ -129,9 +130,11 @@ static gchar **
gtk_action_muxer_list_actions (GActionGroup *action_group)
{
GtkActionMuxer *muxer = GTK_ACTION_MUXER (action_group);
GArray *actions;
GHashTable *actions;
char **keys;
actions = g_array_new (TRUE, FALSE, sizeof (gchar *));
actions = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL);
for ( ; muxer != NULL; muxer = muxer->parent)
{
@@ -139,12 +142,28 @@ gtk_action_muxer_list_actions (GActionGroup *action_group)
const char *prefix;
Group *group;
if (muxer->widget_actions)
{
int i;
for (i = 0; i < muxer->widget_actions->len; i++)
{
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
g_hash_table_add (actions, g_strdup (action->name));
}
}
g_hash_table_iter_init (&iter, muxer->groups);
while (g_hash_table_iter_next (&iter, (gpointer *)&prefix, (gpointer *)&group))
gtk_action_muxer_append_group_actions (prefix, group, actions);
}
return (gchar **)(void *) g_array_free (actions, FALSE);
keys = (char **)g_hash_table_get_keys_as_array (actions, NULL);
g_hash_table_steal_all (actions);
g_hash_table_unref (actions);
return (char **)keys;
}
static Group *
@@ -183,7 +202,7 @@ gtk_action_muxer_find (GtkActionMuxer *muxer,
return group->group;
}
static void
void
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
const gchar *action_name,
gboolean enabled)
@@ -191,6 +210,19 @@ gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
Action *action;
GSList *node;
if (muxer->widget_actions)
{
int i;
for (i = 0; i < muxer->widget_actions->len; i++)
{
GtkWidgetAction *a = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (a->name, action_name) == 0)
{
muxer->widget_actions_enabled[i] = enabled;
break;
}
}
}
action = g_hash_table_lookup (muxer->observed_actions, action_name);
for (node = action ? action->watchers : NULL; node; node = node->next)
gtk_action_observer_action_enabled_changed (node->data, GTK_ACTION_OBSERVABLE (muxer), action_name, enabled);
@@ -223,7 +255,7 @@ gtk_action_muxer_parent_action_enabled_changed (GActionGroup *action_group,
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
static void
void
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
const gchar *action_name,
GVariant *state)
@@ -401,6 +433,46 @@ gtk_action_muxer_query_action (GActionGroup *action_group,
Group *group;
const gchar *unprefixed_name;
if (muxer->widget_actions)
{
int i;
for (i = 0; i < muxer->widget_actions->len; i++)
{
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0)
{
if (enabled)
*enabled = muxer->widget_actions_enabled[i];
if (parameter_type)
*parameter_type = action->parameter_type;
if (state_hint)
*state_hint = NULL;
if (state_type)
*state_type = NULL;
if (state)
*state = NULL;
if (action->get_state)
{
GVariant *s;
s = g_variant_ref_sink (action->get_state (muxer->widget, action->name));
if (state_type)
*state_type = g_variant_get_type (s);
if (state)
*state = g_variant_ref (s);
g_variant_unref (s);
}
return TRUE;
}
}
}
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
@@ -424,6 +496,22 @@ gtk_action_muxer_activate_action (GActionGroup *action_group,
Group *group;
const gchar *unprefixed_name;
if (muxer->widget_actions)
{
int i;
for (i = 0; i < muxer->widget_actions->len; i++)
{
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0)
{
action->activate (muxer->widget, action->name, parameter);
return;
}
}
}
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
@@ -441,6 +529,23 @@ gtk_action_muxer_change_action_state (GActionGroup *action_group,
Group *group;
const gchar *unprefixed_name;
if (muxer->widget_actions)
{
int i;
for (i = 0; i < muxer->widget_actions->len; i++)
{
GtkWidgetAction *action = g_ptr_array_index (muxer->widget_actions, i);
if (strcmp (action->name, action_name) == 0)
{
if (action->set_state)
action->set_state (muxer->widget, action->name, state);
return;
}
}
}
group = gtk_action_muxer_find_group (muxer, action_name, &unprefixed_name);
if (group)
@@ -600,6 +705,10 @@ gtk_action_muxer_get_property (GObject *object,
g_value_set_object (value, muxer->widget);
break;
case PROP_WIDGET_ACTIONS:
g_value_set_boxed (value, muxer->widget_actions);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -623,6 +732,18 @@ gtk_action_muxer_set_property (GObject *object,
muxer->widget = g_value_get_object (value);
break;
case PROP_WIDGET_ACTIONS:
muxer->widget_actions = g_value_get_boxed (value);
if (muxer->widget_actions)
{
int i;
muxer->widget_actions_enabled = g_new (gboolean, muxer->widget_actions->len);
for (i = 0; i < muxer->widget_actions->len; i++)
muxer->widget_actions_enabled[i] = TRUE;
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
@@ -683,6 +804,13 @@ gtk_action_muxer_class_init (GObjectClass *class)
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
properties[PROP_WIDGET_ACTIONS] = g_param_spec_boxed ("widget-actions", "Widget actions",
"Widget actions",
G_TYPE_PTR_ARRAY,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (class, NUM_PROPERTIES, properties);
}
@@ -791,14 +919,17 @@ gtk_action_muxer_lookup (GtkActionMuxer *muxer,
/*< private >
* gtk_action_muxer_new:
* @widget: the widget to which the muxer belongs
* @actions: widget actions
*
* Creates a new #GtkActionMuxer.
*/
GtkActionMuxer *
gtk_action_muxer_new (GtkWidget *widget)
gtk_action_muxer_new (GtkWidget *widget,
GPtrArray *actions)
{
return g_object_new (GTK_TYPE_ACTION_MUXER,
"widget", widget,
"widget-actions", actions,
NULL);
}

View File

@@ -31,10 +31,21 @@ G_BEGIN_DECLS
#define GTK_IS_ACTION_MUXER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
GTK_TYPE_ACTION_MUXER))
typedef struct {
char *name;
GVariantType *parameter_type;
GtkWidgetActionActivateFunc activate;
GtkWidgetActionSetStateFunc set_state;
GtkWidgetActionGetStateFunc get_state;
} GtkWidgetAction;
typedef struct _GtkActionMuxer GtkActionMuxer;
GType gtk_action_muxer_get_type (void);
GtkActionMuxer * gtk_action_muxer_new (GtkWidget *widget);
GtkActionMuxer * gtk_action_muxer_new (GtkWidget *widget,
GPtrArray *actions);
void gtk_action_muxer_insert (GtkActionMuxer *muxer,
const gchar *prefix,
@@ -59,6 +70,16 @@ void gtk_action_muxer_set_primary_accel (GtkActi
const gchar * gtk_action_muxer_get_primary_accel (GtkActionMuxer *muxer,
const gchar *action_and_target);
void
gtk_action_muxer_action_enabled_changed (GtkActionMuxer *muxer,
const char *action_name,
gboolean enabled);
void
gtk_action_muxer_action_state_changed (GtkActionMuxer *muxer,
const gchar *action_name,
GVariant *state);
/* No better place for these... */
gchar * gtk_print_action_and_target (const gchar *action_namespace,
const gchar *action_name,

View File

@@ -394,7 +394,7 @@ gtk_application_init (GtkApplication *application)
{
GtkApplicationPrivate *priv = gtk_application_get_instance_private (application);
priv->muxer = gtk_action_muxer_new (NULL);
priv->muxer = gtk_action_muxer_new (NULL, NULL);
priv->accels = gtk_application_accels_new ();
}

View File

@@ -90,8 +90,6 @@ struct _GtkColorChooserWidgetPrivate
gboolean has_default_palette;
GSettings *settings;
GActionMap *context_actions;
};
enum
@@ -493,11 +491,11 @@ add_default_palette (GtkColorChooserWidget *cc)
}
static void
customize_color (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_color_chooser_widget_activate_color_customize (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
GtkColorChooserWidget *cc = user_data;
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (widget);
GtkColorChooserWidgetPrivate *priv = gtk_color_chooser_widget_get_instance_private (cc);
GdkRGBA color;
@@ -511,11 +509,11 @@ customize_color (GSimpleAction *action,
}
static void
select_color (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_color_chooser_widget_activate_color_select (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
GtkColorChooserWidget *cc = user_data;
GtkColorChooserWidget *cc = GTK_COLOR_CHOOSER_WIDGET (widget);
GdkRGBA color;
g_variant_get (parameter, "(dddd)", &color.red, &color.green, &color.blue, &color.alpha);
@@ -523,26 +521,6 @@ select_color (GSimpleAction *action,
_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)
{
@@ -634,8 +612,6 @@ 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 */
@@ -736,6 +712,13 @@ gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
FALSE, GTK_PARAM_READWRITE));
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("colorchooser"));
gtk_widget_class_install_stateful_action (GTK_WIDGET_CLASS (class), "color.select",
gtk_color_chooser_widget_activate_color_select,
"(dddd)", NULL, NULL);
gtk_widget_class_install_stateful_action (GTK_WIDGET_CLASS (class), "color.customize",
gtk_color_chooser_widget_activate_color_customize,
"(dddd)", NULL, NULL);
}
/* GtkColorChooser implementation {{{1 */

View File

@@ -285,7 +285,6 @@ struct _GtkLabelPrivate
PangoAttrList *markup_attrs;
PangoLayout *layout;
GActionMap *context_actions;
GtkWidget *popup_menu;
GMenuModel *extra_menu;
@@ -575,8 +574,25 @@ 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);
/* Actions */
static void gtk_label_activate_clipboard_copy (GtkWidget *label,
const char *name,
GVariant *parameter);
static void gtk_label_activate_selection_select_all (GtkWidget *label,
const char *name,
GVariant *parameter);
static void gtk_label_activate_link_open (GtkWidget *label,
const char *name,
GVariant *parameter);
static void gtk_label_activate_link_copy (GtkWidget *label,
const char *name,
GVariant *parameter);
static void gtk_label_nop (GtkWidget *label,
const char *name,
GVariant *parameter);
static void gtk_label_update_actions (GtkLabel *label);
static GtkSizeRequestMode gtk_label_get_request_mode (GtkWidget *widget);
static void gtk_label_measure (GtkWidget *widget,
@@ -1143,6 +1159,21 @@ gtk_label_class_init (GtkLabelClass *class)
quark_mnemonics_visible_connected = g_quark_from_static_string ("gtk-label-mnemonics-visible-connected");
quark_gtk_signal = g_quark_from_static_string ("gtk-signal");
quark_link = g_quark_from_static_string ("link");
gtk_widget_class_install_action (widget_class, "clipboard.cut",
gtk_label_nop);
gtk_widget_class_install_action (widget_class, "clipboard.copy",
gtk_label_activate_clipboard_copy);
gtk_widget_class_install_action (widget_class, "clipboard.paste",
gtk_label_nop);
gtk_widget_class_install_action (widget_class, "selection.delete",
gtk_label_nop);
gtk_widget_class_install_action (widget_class, "selection.select-all",
gtk_label_activate_selection_select_all);
gtk_widget_class_install_action (widget_class, "link.open",
gtk_label_activate_link_open);
gtk_widget_class_install_action (widget_class, "link.copy",
gtk_label_activate_link_copy);
}
static void
@@ -1330,8 +1361,6 @@ gtk_label_init (GtkLabel *label)
priv->mnemonic_window = NULL;
priv->mnemonics_visible = TRUE;
gtk_label_add_context_actions (label);
}
@@ -3205,7 +3234,6 @@ 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);
@@ -4854,6 +4882,8 @@ gtk_label_update_active_link (GtkWidget *widget,
gtk_widget_queue_draw (widget);
}
}
gtk_label_update_actions (label);
}
}
@@ -5295,6 +5325,8 @@ gtk_label_select_region_index (GtkLabel *label,
}
}
gtk_label_update_actions (label);
gtk_widget_queue_draw (GTK_WIDGET (label));
g_object_thaw_notify (G_OBJECT (label));
@@ -5968,24 +6000,24 @@ gtk_label_select_all (GtkLabel *label)
}
static void
open_link_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_label_activate_link_open (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
GtkLabel *label = GTK_LABEL (user_data);
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
GtkLabelLink *link = priv->select_info->context_link;
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)
gtk_label_activate_link_copy (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
GtkLabel *label = GTK_LABEL (user_data);
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
GtkLabelLink *link = priv->select_info->context_link;
@@ -5993,101 +6025,60 @@ copy_link_activated (GSimpleAction *action,
{
GdkClipboard *clipboard;
clipboard = gtk_widget_get_clipboard (GTK_WIDGET (label));
clipboard = gtk_widget_get_clipboard (widget);
gdk_clipboard_set_text (clipboard, link->uri);
}
else
g_print ("no link ?!\n");
}
static void
copy_clipboard_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_label_activate_clipboard_copy (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
g_signal_emit_by_name (user_data, "copy-clipboard");
g_signal_emit_by_name (widget, "copy-clipboard");
}
static void
select_all_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_label_activate_selection_select_all (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
gtk_label_select_all (GTK_LABEL (user_data));
gtk_label_select_all (GTK_LABEL (widget));
}
static void
gtk_label_update_clipboard_actions (GtkLabel *label)
gtk_label_nop (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
}
static void
gtk_label_update_actions (GtkLabel *label)
{
GtkWidget *widget = GTK_WIDGET (label);
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
gboolean have_selection = FALSE;
GAction *action;
if (priv->select_info)
have_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
action = g_action_map_lookup_action (priv->context_actions, "copy-clipboard");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), have_selection);
action = g_action_map_lookup_action (priv->context_actions, "select-all");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), gtk_label_get_selectable (label));
}
static void
gtk_label_update_link_actions (GtkLabel *label)
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
gboolean have_selection = FALSE;
GAction *action;
gboolean has_selection;
GtkLabelLink *link;
have_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
if (priv->select_info)
has_selection = priv->select_info->selection_anchor != priv->select_info->selection_end;
else
has_selection = FALSE;
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);
}
gtk_widget_notify_class_action_enabled (widget, "clipboard.copy", has_selection);
gtk_widget_notify_class_action_enabled (widget, "selection.select-all",
gtk_label_get_selectable (label));
static void
gtk_label_add_context_actions (GtkLabel *label)
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
GActionEntry entries[] = {
{ "cut-clipboard", NULL, NULL, NULL, NULL },
{ "copy-clipboard", copy_clipboard_activated, NULL, NULL, NULL },
{ "paste-clipboard", NULL, NULL, NULL, NULL },
{ "delete-selection", NULL, NULL, NULL, NULL },
{ "select-all", select_all_activated, NULL, NULL, NULL },
{ "open-link", open_link_activated, NULL, NULL, NULL },
{ "copy-link", copy_link_activated, NULL, NULL, NULL },
};
GSimpleActionGroup *actions = g_simple_action_group_new ();
GAction *action;
priv->context_actions = G_ACTION_MAP (actions);
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), label);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "cut-clipboard");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-clipboard");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "paste-clipboard");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "delete-selection");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "select-all");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "open-link");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
action = g_action_map_lookup_action (G_ACTION_MAP (actions), "copy-link");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action), FALSE);
gtk_widget_insert_action_group (GTK_WIDGET (label), "context", G_ACTION_GROUP (actions));
gtk_widget_notify_class_action_enabled (widget, "link.open", !has_selection && link);
gtk_widget_notify_class_action_enabled (widget, "link.copy", !has_selection && link);
}
static GMenuModel *
@@ -6100,24 +6091,24 @@ gtk_label_get_menu_model (GtkLabel *label)
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, _("Cu_t"), "clipboard.cut");
g_menu_append (section, _("_Copy"), "clipboard.copy");
g_menu_append (section, _("_Paste"), "clipboard.paste");
g_menu_append (section, _("_Delete"), "selection.delete");
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, _("Select _All"), "selection.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");
item = g_menu_item_new (_("_Open Link"), "link.open");
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");
item = g_menu_item_new (_("Copy _Link Address"), "link.copy");
g_menu_item_set_attribute (item, "hidden-when", "s", "action-disabled");
g_menu_append_item (section, item);
g_object_unref (item);
@@ -6137,8 +6128,15 @@ gtk_label_do_popup (GtkLabel *label,
{
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
gtk_label_update_clipboard_actions (label);
gtk_label_update_link_actions (label);
if (!priv->select_info)
return;
if (priv->select_info->link_clicked)
priv->select_info->context_link = priv->select_info->active_link;
else
priv->select_info->context_link = gtk_label_get_focus_link (label);
gtk_label_update_actions (label);
if (!priv->popup_menu)
{
@@ -6169,15 +6167,6 @@ static gboolean
gtk_label_popup_menu (GtkWidget *widget)
{
GtkLabel *label = GTK_LABEL (widget);
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
if (!priv->select_info)
return FALSE;
if (priv->select_info->link_clicked)
priv->select_info->context_link = priv->select_info->active_link;
else
priv->select_info->context_link = gtk_label_get_focus_link (label);
gtk_label_do_popup (label, -1, -1);
return TRUE;

View File

@@ -96,7 +96,6 @@ struct _GtkLinkButtonPrivate
gboolean visited;
GActionMap *context_actions;
GtkWidget *popup_menu;
};
@@ -152,6 +151,17 @@ static guint link_signals[LAST_SIGNAL] = { 0, };
G_DEFINE_TYPE_WITH_PRIVATE (GtkLinkButton, gtk_link_button, GTK_TYPE_BUTTON)
static void
gtk_link_button_activate_clipboard_copy (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
GtkLinkButton *link_button = GTK_LINK_BUTTON (widget);
GtkLinkButtonPrivate *priv = gtk_link_button_get_instance_private (link_button);
gdk_clipboard_set_text (gtk_widget_get_clipboard (widget), priv->uri);
}
static void
gtk_link_button_class_init (GtkLinkButtonClass *klass)
{
@@ -221,28 +231,9 @@ gtk_link_button_class_init (GtkLinkButtonClass *klass)
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_LINK_BUTTON_ACCESSIBLE);
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));
gtk_widget_class_install_action (widget_class, "clipboard.copy",
gtk_link_button_activate_clipboard_copy);
}
static GMenuModel *
@@ -298,7 +289,6 @@ 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
@@ -309,7 +299,6 @@ gtk_link_button_finalize (GObject *object)
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);
@@ -360,18 +349,6 @@ gtk_link_button_set_property (GObject *object,
}
}
static void
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)),
priv->uri);
}
static void
gtk_link_button_do_popup (GtkLinkButton *link_button,
double x,

View File

@@ -110,20 +110,30 @@ focus_changed (GtkWidget *widget)
static void
gtk_password_entry_toggle_peek (GtkPasswordEntry *entry)
{
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
gboolean visibility;
visibility = gtk_text_get_visibility (GTK_TEXT (priv->entry));
gtk_text_set_visibility (GTK_TEXT (priv->entry), !visibility);
}
static void
visibility_toggled (GObject *object,
GParamSpec *pspec,
GtkPasswordEntry *entry)
{
GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
if (gtk_text_get_visibility (GTK_TEXT (priv->entry)))
{
gtk_text_set_visibility (GTK_TEXT (priv->entry), FALSE);
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-not-looking-symbolic");
gtk_widget_set_tooltip_text (priv->peek_icon, _("Show text"));
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-open-negative-filled-symbolic");
gtk_widget_set_tooltip_text (priv->peek_icon, _("Hide text"));
}
else
{
gtk_text_set_visibility (GTK_TEXT (priv->entry), TRUE);
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-open-negative-filled-symbolic");
gtk_widget_set_tooltip_text (priv->peek_icon, _("Hide text"));
gtk_image_set_from_icon_name (GTK_IMAGE (priv->peek_icon), "eye-not-looking-symbolic");
gtk_widget_set_tooltip_text (priv->peek_icon, _("Show text"));
}
}
@@ -482,11 +492,18 @@ gtk_password_entry_set_show_peek_icon (GtkPasswordEntry *entry,
g_signal_connect_swapped (press, "released",
G_CALLBACK (gtk_password_entry_toggle_peek), entry);
gtk_widget_add_controller (priv->peek_icon, GTK_EVENT_CONTROLLER (press));
g_signal_connect (priv->entry, "notify::visibility",
G_CALLBACK (visibility_toggled), entry);
visibility_toggled (G_OBJECT (priv->entry), NULL, entry);
}
else
{
g_clear_pointer (&priv->peek_icon, gtk_widget_unparent);
gtk_text_set_visibility (GTK_TEXT (priv->entry), FALSE);
g_signal_handlers_disconnect_by_func (priv->entry,
visibility_toggled,
entry);
}
keymap_state_changed (priv->keymap, GTK_WIDGET (entry));
@@ -532,13 +549,17 @@ gtk_password_entry_set_extra_menu (GtkPasswordEntry *entry,
g_return_if_fail (GTK_IS_PASSWORD_ENTRY (entry));
if (!g_set_object (&priv->extra_menu, model))
return;
/* bypass this check for the initial call from init */
if (priv->extra_menu)
{
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");
item = g_menu_item_new (_("_Show Text"), "misc.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);

View File

@@ -68,6 +68,7 @@
#include "gtkwidgetprivate.h"
#include "gtkwindow.h"
#include "gtknative.h"
#include "gtkactionmuxerprivate.h"
#include "a11y/gtktextaccessible.h"
@@ -174,7 +175,6 @@ struct _GtkTextPrivate
GtkCssNode *block_cursor_node;
GtkCssNode *undershoot_node[2];
GActionMap *context_actions;
GtkWidget *popup_menu;
GMenuModel *extra_menu;
@@ -542,10 +542,35 @@ 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);
static void gtk_text_activate_clipboard_cut (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_clipboard_copy (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_clipboard_paste (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_selection_delete (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_selection_select_all (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_activate_misc_toggle_visibility (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_set_misc_toggle_visibility (GtkWidget *widget,
const char *action_name,
GVariant *state);
static GVariant *gtk_text_get_misc_toggle_visibility (GtkWidget *widget,
const char *action_name);
/* GtkTextContent implementation
*/
@@ -706,7 +731,7 @@ gtk_text_class_init (GtkTextClass *class)
class->toggle_overwrite = gtk_text_toggle_overwrite;
class->insert_emoji = gtk_text_insert_emoji;
class->activate = gtk_text_real_activate;
quark_password_hint = g_quark_from_static_string ("gtk-entry-password-hint");
quark_gtk_signal = g_quark_from_static_string ("gtk-signal");
@@ -1336,6 +1361,24 @@ gtk_text_class_init (GtkTextClass *class)
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_TEXT_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, I_("text"));
gtk_widget_class_install_action (widget_class, "clipboard.cut",
gtk_text_activate_clipboard_cut);
gtk_widget_class_install_action (widget_class, "clipboard.copy",
gtk_text_activate_clipboard_copy);
gtk_widget_class_install_action (widget_class, "clipboard.paste",
gtk_text_activate_clipboard_paste);
gtk_widget_class_install_action (widget_class, "selection.delete",
gtk_text_activate_selection_delete);
gtk_widget_class_install_action (widget_class, "selection.select-all",
gtk_text_activate_selection_select_all);
gtk_widget_class_install_action (widget_class, "misc.insert-emoji",
gtk_text_activate_misc_insert_emoji);
gtk_widget_class_install_stateful_action (widget_class, "misc.toggle-visibility",
gtk_text_activate_misc_toggle_visibility,
NULL,
gtk_text_set_misc_toggle_visibility,
gtk_text_get_misc_toggle_visibility);
}
static void
@@ -1720,7 +1763,6 @@ gtk_text_init (GtkText *self)
}
set_text_cursor (GTK_WIDGET (self));
gtk_text_add_context_actions (self);
}
static void
@@ -1766,7 +1808,7 @@ 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->selection_bubble, gtk_widget_unparent);
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
g_clear_object (&priv->extra_menu);
@@ -1783,7 +1825,6 @@ gtk_text_finalize (GObject *object)
g_clear_object (&priv->cached_layout);
g_clear_object (&priv->im_context);
g_clear_pointer (&priv->selection_bubble, gtk_widget_unparent);
g_clear_pointer (&priv->magnifier_popover, gtk_widget_destroy);
g_clear_object (&priv->text_handle);
g_free (priv->im_module);
@@ -2176,6 +2217,9 @@ gtk_text_size_allocate (GtkWidget *widget,
if (priv->popup_menu)
gtk_native_check_resize (GTK_NATIVE (priv->popup_menu));
if (priv->selection_bubble)
gtk_native_check_resize (GTK_NATIVE (priv->selection_bubble));
}
static void
@@ -4047,6 +4091,7 @@ gtk_text_set_positions (GtkText *self,
if (changed)
{
gtk_text_update_clipboard_actions (self);
gtk_text_recompute (self);
}
}
@@ -5261,15 +5306,14 @@ 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));
gtk_text_update_clipboard_actions (self);
gtk_widget_notify_class_action_state (GTK_WIDGET (self), "misc.toggle-visibility",
g_variant_new_boolean (visible));
}
}
@@ -5615,152 +5659,129 @@ hide_selection_bubble (GtkText *self)
}
static void
cut_clipboard_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_clipboard_cut (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
g_signal_emit_by_name (user_data, "cut-clipboard");
hide_selection_bubble (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
g_signal_emit_by_name (self, "cut-clipboard");
hide_selection_bubble (self);
}
static void
copy_clipboard_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_clipboard_copy (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
g_signal_emit_by_name (user_data, "copy-clipboard");
hide_selection_bubble (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
g_signal_emit_by_name (self, "copy-clipboard");
hide_selection_bubble (self);
}
static void
paste_clipboard_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_clipboard_paste (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
g_signal_emit_by_name (user_data, "paste-clipboard");
hide_selection_bubble (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
g_signal_emit_by_name (self, "paste-clipboard");
hide_selection_bubble (self);
}
static void
delete_selection_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_selection_delete (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gtk_text_delete_cb (GTK_TEXT (user_data));
hide_selection_bubble (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
gtk_text_delete_cb (self);
hide_selection_bubble (self);
}
static void
select_all_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_selection_select_all (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gtk_text_select_all (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
gtk_text_select_all (self);
}
static void
insert_emoji_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gtk_text_insert_emoji (GTK_TEXT (user_data));
hide_selection_bubble (GTK_TEXT (user_data));
GtkText *self = GTK_TEXT (widget);
gtk_text_insert_emoji (self);
hide_selection_bubble (self);
}
static void
toggle_visibility (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
gtk_text_activate_misc_toggle_visibility (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GtkText *text = GTK_TEXT (user_data);
gtk_text_set_visibility (text, !gtk_text_get_visibility (text));
GtkText *self = GTK_TEXT (widget);
gtk_text_set_visibility (self, !gtk_text_get_visibility (self));
}
static GVariant *
gtk_text_get_misc_toggle_visibility (GtkWidget *widget,
const char *action_name)
{
GtkText *self = GTK_TEXT (widget);
DisplayMode mode = gtk_text_get_display_mode (self);
return g_variant_new_boolean (mode == DISPLAY_NORMAL);
}
static void
gtk_text_add_context_actions (GtkText *self)
gtk_text_set_misc_toggle_visibility (GtkWidget *widget,
const char *action_name,
GVariant *state)
{
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));
GtkText *self = GTK_TEXT (widget);
gboolean visible = g_variant_get_boolean (state);
gtk_text_set_visibility (self, visible);
}
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;
gboolean has_selection;
gboolean has_content;
gboolean visible;
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);
has_clipboard = gdk_content_formats_contain_gtype (gdk_clipboard_get_formats (clipboard), G_TYPE_STRING);
has_selection = priv->current_pos != priv->selection_bound;
has_content = priv->buffer && (gtk_entry_buffer_get_length (priv->buffer) > 0);
visible = mode == DISPLAY_NORMAL;
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);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "clipboard.cut",
visible && priv->editable && has_selection);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "clipboard.copy",
visible && has_selection);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "clipboard.paste",
priv->editable && has_clipboard);
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));
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "selection.delete",
priv->editable && has_selection);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "selection.select-all",
has_content);
}
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);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (self), "misc.insert-emoji",
(gtk_text_get_input_hints (self) & GTK_INPUT_HINT_NO_EMOJI) == 0);
}
static GMenuModel *
@@ -5773,19 +5794,19 @@ gtk_text_get_menu_model (GtkText *self)
menu = g_menu_new ();
section = g_menu_new ();
item = g_menu_item_new (_("Cu_t"), "context.cut-clipboard");
item = g_menu_item_new (_("Cu_t"), "clipboard.cut");
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");
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
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");
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
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");
item = g_menu_item_new (_("_Delete"), "selection.delete");
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-delete-symbolic");
g_menu_append_item (section, item);
g_object_unref (item);
@@ -5794,12 +5815,12 @@ gtk_text_get_menu_model (GtkText *self)
section = g_menu_new ();
item = g_menu_item_new (_("Select _All"), "context.select-all");
item = g_menu_item_new (_("Select _All"), "selection.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");
item = g_menu_item_new ( _("Insert _Emoji"), "misc.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);
@@ -5860,12 +5881,11 @@ append_bubble_item (GtkText *self,
GMenuModel *model,
int index)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkActionMuxer *muxer;
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");
@@ -5891,12 +5911,9 @@ append_bubble_item (GtkText *self,
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;
}
muxer = _gtk_widget_get_action_muxer (GTK_WIDGET (self), FALSE);
if (!g_action_group_get_action_enabled (G_ACTION_GROUP (muxer), action_name))
return;
item = gtk_button_new ();
gtk_widget_set_focus_on_click (item, FALSE);
@@ -5990,7 +6007,7 @@ gtk_text_selection_bubble_popup_show (gpointer user_data)
rect.height += 10;
gtk_popover_set_pointing_to (GTK_POPOVER (priv->selection_bubble), &rect);
gtk_widget_show (priv->selection_bubble);
gtk_popover_popup (GTK_POPOVER (priv->selection_bubble));
priv->selection_bubble_timeout_id = 0;

View File

@@ -182,8 +182,6 @@ struct _GtkTextViewPrivate
GtkAdjustment *hadjustment;
GtkAdjustment *vadjustment;
GActionMap *context_actions;
/* X offset between widget coordinates and buffer coordinates
* taking left_padding in account
*/
@@ -595,10 +593,28 @@ 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);
static void gtk_text_view_activate_clipboard_cut (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_view_activate_clipboard_copy (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_view_activate_clipboard_paste (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_view_activate_selection_delete (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_view_activate_selection_select_all (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_text_view_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
/* FIXME probably need the focus methods. */
@@ -1585,6 +1601,19 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
quark_text_selection_data = g_quark_from_static_string ("gtk-text-view-text-selection-data");
quark_gtk_signal = g_quark_from_static_string ("gtk-signal");
quark_text_view_child = g_quark_from_static_string ("gtk-text-view-child");
gtk_widget_class_install_action (widget_class, "clipboard.cut",
gtk_text_view_activate_clipboard_cut);
gtk_widget_class_install_action (widget_class, "clipboard.copy",
gtk_text_view_activate_clipboard_copy);
gtk_widget_class_install_action (widget_class, "clipboard.paste",
gtk_text_view_activate_clipboard_paste);
gtk_widget_class_install_action (widget_class, "selection.delete",
gtk_text_view_activate_selection_delete);
gtk_widget_class_install_action (widget_class, "selection.select-all",
gtk_text_view_activate_selection_select_all);
gtk_widget_class_install_action (widget_class, "misc.insert-emoji",
gtk_text_view_activate_misc_insert_emoji);
}
static void
@@ -1694,8 +1723,6 @@ 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 *
@@ -3617,7 +3644,6 @@ 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);
@@ -8438,33 +8464,6 @@ hide_selection_bubble (GtkTextView *text_view)
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_VIEW (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_VIEW (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_VIEW (user_data));
}
static void
gtk_text_view_select_all (GtkWidget *widget,
gboolean select)
@@ -8487,34 +8486,6 @@ gtk_text_view_select_all (GtkWidget *widget,
}
}
static void
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_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
insert_emoji_activated (GSimpleAction *action,
GVariant *parameter,
gpointer user_data)
{
gtk_text_view_insert_emoji (GTK_TEXT_VIEW (user_data));
}
static gboolean
range_contains_editable_text (const GtkTextIter *start,
@@ -8535,40 +8506,60 @@ range_contains_editable_text (const GtkTextIter *start,
}
static void
gtk_text_view_add_context_actions (GtkTextView *text_view)
gtk_text_view_activate_clipboard_cut (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GtkTextViewPrivate *priv = text_view->priv;
GtkTextView *self = GTK_TEXT_VIEW (widget);
g_signal_emit_by_name (self, "cut-clipboard");
hide_selection_bubble (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 },
};
static void
gtk_text_view_activate_clipboard_copy (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GtkTextView *self = GTK_TEXT_VIEW (widget);
g_signal_emit_by_name (self, "copy-clipboard");
hide_selection_bubble (self);
}
GSimpleActionGroup *actions = g_simple_action_group_new ();
GAction *action;
static void
gtk_text_view_activate_clipboard_paste (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GtkTextView *self = GTK_TEXT_VIEW (widget);
g_signal_emit_by_name (self, "paste-clipboard");
hide_selection_bubble (self);
}
priv->context_actions = G_ACTION_MAP (actions);
static void
gtk_text_view_activate_selection_select_all (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gtk_text_view_select_all (widget, TRUE);
}
g_action_map_add_action_entries (G_ACTION_MAP (actions), entries, G_N_ELEMENTS (entries), text_view);
static void
gtk_text_view_activate_selection_delete (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
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_text_buffer_delete_selection (get_buffer (text_view), TRUE,
text_view->priv->editable);
}
gtk_widget_insert_action_group (GTK_WIDGET (text_view), "context", G_ACTION_GROUP (actions));
static void
gtk_text_view_activate_misc_insert_emoji (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gtk_text_view_insert_emoji (GTK_TEXT_VIEW (widget));
}
static void
@@ -8578,7 +8569,6 @@ gtk_text_view_update_clipboard_actions (GtkTextView *text_view)
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));
@@ -8593,36 +8583,25 @@ gtk_text_view_update_clipboard_actions (GtkTextView *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);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "clipboard.cut",
have_selection &&
range_contains_editable_text (&sel_start, &sel_end, priv->editable));
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "clipboard.copy",
have_selection);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "clipboard.paste",
can_insert && can_paste);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "selection.delete",
have_selection &&
range_contains_editable_text (&sel_start, &sel_end, priv->editable));
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "selection.select-all",
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);
gtk_widget_notify_class_action_enabled (GTK_WIDGET (text_view), "misc.insert-emoji",
(gtk_text_view_get_input_hints (text_view) & GTK_INPUT_HINT_NO_EMOJI) == 0);
}
static GMenuModel *
@@ -8635,19 +8614,19 @@ gtk_text_view_get_menu_model (GtkTextView *text_view)
menu = g_menu_new ();
section = g_menu_new ();
item = g_menu_item_new (_("Cu_t"), "context.cut-clipboard");
item = g_menu_item_new (_("Cu_t"), "clipboard.cut");
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");
item = g_menu_item_new (_("_Copy"), "clipboard.copy");
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");
item = g_menu_item_new (_("_Paste"), "clipboard.paste");
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");
item = g_menu_item_new (_("_Delete"), "selection.delete");
g_menu_item_set_attribute (item, "touch-icon", "s", "edit-delete-symbolic");
g_menu_append_item (section, item);
g_object_unref (item);
@@ -8656,12 +8635,12 @@ gtk_text_view_get_menu_model (GtkTextView *text_view)
section = g_menu_new ();
item = g_menu_item_new (_("Select _All"), "context.select-all");
item = g_menu_item_new (_("Select _All"), "selection.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");
item = g_menu_item_new ( _("Insert _Emoji"), "misc.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);

View File

@@ -73,6 +73,7 @@
#include "gtkwindowgroup.h"
#include "gtkwindowprivate.h"
#include "gtknativeprivate.h"
#include "gtkapplicationaccelsprivate.h"
#include "a11y/gtkwidgetaccessible.h"
#include "inspector/window.h"
@@ -501,6 +502,8 @@ struct _GtkWidgetClassPrivate
AtkRole accessible_role;
const char *css_name;
GType layout_manager_type;
GPtrArray *actions;
GtkApplicationAccels *accels;
};
enum {
@@ -712,6 +715,13 @@ static gboolean gtk_widget_class_get_visible_by_default (GtkWidgetClass *widget_
static void remove_parent_surface_transform_changed_listener (GtkWidget *widget);
static void add_parent_surface_transform_changed_listener (GtkWidget *widget);
static gboolean gtk_widget_activate_accels (GtkWidget *widget,
const GdkEvent *event);
static void gtk_widget_activate_menu_popup (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
/* --- variables --- */
static gint GtkWidget_private_offset = 0;
@@ -864,7 +874,6 @@ static void
gtk_widget_class_init (GtkWidgetClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkBindingSet *binding_set;
g_type_class_adjust_private_offset (klass, &GtkWidget_private_offset);
gtk_widget_parent_class = g_type_class_peek_parent (klass);
@@ -2120,11 +2129,11 @@ gtk_widget_class_init (GtkWidgetClass *klass)
G_TYPE_FROM_CLASS (klass),
_gtk_marshal_BOOLEAN__UINTv);
binding_set = gtk_binding_set_by_class (klass);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK,
"popup-menu", 0);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_Menu, 0,
"popup-menu", 0);
gtk_widget_class_install_action (klass, "menu.popup",
gtk_widget_activate_menu_popup);
gtk_widget_class_bind_action (klass, GDK_KEY_Menu, 0, "menu.popup", NULL);
gtk_widget_class_bind_action (klass, GDK_KEY_Menu, GDK_SHIFT_MASK, "menu.popup", NULL);
gtk_widget_class_set_accessible_type (klass, GTK_TYPE_WIDGET_ACCESSIBLE);
gtk_widget_class_set_css_name (klass, I_("widget"));
@@ -5359,6 +5368,11 @@ gtk_widget_event_internal (GtkWidget *widget,
event->any.type == GDK_KEY_RELEASE))
return_val |= gtk_bindings_activate_event (G_OBJECT (widget), (GdkEventKey *) event);
if (return_val == FALSE &&
(event->any.type == GDK_KEY_PRESS ||
event->any.type == GDK_KEY_RELEASE))
return_val = gtk_widget_activate_accels (widget, event);
return return_val;
}
@@ -11897,14 +11911,16 @@ _gtk_widget_get_action_muxer (GtkWidget *widget,
gboolean create)
{
GtkActionMuxer *muxer;
GtkWidgetClass *widget_class = GTK_WIDGET_GET_CLASS (widget);
GtkWidgetClassPrivate *priv = widget_class->priv;
muxer = (GtkActionMuxer*)g_object_get_qdata (G_OBJECT (widget), quark_action_muxer);
if (muxer)
return muxer;
if (create)
if (create || priv->actions)
{
muxer = gtk_action_muxer_new (widget);
muxer = gtk_action_muxer_new (widget, priv->actions);
g_object_set_qdata_full (G_OBJECT (widget),
quark_action_muxer,
muxer,
@@ -12455,6 +12471,17 @@ gtk_widget_activate_default (GtkWidget *widget)
gtk_widget_activate_action (widget, "default.activate", NULL);
}
static void
gtk_widget_activate_menu_popup (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
gboolean handled;
g_signal_emit (widget, widget_signals[POPUP_MENU], 0, &handled);
}
void
gtk_widget_cancel_event_sequence (GtkWidget *widget,
GtkGesture *gesture,
@@ -13427,3 +13454,282 @@ gtk_widget_should_layout (GtkWidget *widget)
return TRUE;
}
/*
* gtk_widget_class_install_action:
* @widget_class: a #GtkWidgetClass
* @action_name: a prefixed action name, such as "clipboard.paste"
* @activate: callback to use when the action is activated
*
* This should be called at class initialization time to specify
* actions to be added for all instances of this class.
*
* Actions installed by this function are stateless. The only state
* they have is whether they are enabled or not. For more complicated
* actions, see gtk_widget_class_install_stateful_action().
*/
void
gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *action_name,
GtkWidgetActionActivateFunc activate)
{
gtk_widget_class_install_stateful_action (widget_class, action_name, activate,
NULL, NULL, NULL);
}
/*
* gtk_widget_class_install_stateful_action:
* @widget_class: a #GtkWidgetClass
* @action_name: a prefixed action name, such as "clipboard.paste"
* @activate: callback to use when the action is activated
* @parameter_type: (allow-none): the parameter type, or %NULL
* @query: (allow-none): callback to use when the action properties
are queried, or %NULL for always-enabled stateless actions
* @query_state: (allow-none): callback to use when the action state
is queried, or %NULL for stateless actions
*
* This should be called at class initialization time to specify
* actions to be added for all instances of this class.
*
* Actions installed in this way can be simple or stateful.
* See the #GAction documentation for more information.
*/
void
gtk_widget_class_install_stateful_action (GtkWidgetClass *widget_class,
const char *action_name,
GtkWidgetActionActivateFunc activate,
const char *parameter_type,
GtkWidgetActionSetStateFunc set_state,
GtkWidgetActionGetStateFunc get_state)
{
GtkWidgetClassPrivate *priv = widget_class->priv;
GtkWidgetAction *action;
g_return_if_fail (GTK_IS_WIDGET_CLASS (widget_class));
if (priv->actions == NULL)
priv->actions = g_ptr_array_new ();
else if (GTK_IS_WIDGET_CLASS (&widget_class->parent_class))
{
GtkWidgetClass *parent_class = GTK_WIDGET_CLASS (&widget_class->parent_class);
GtkWidgetClassPrivate *parent_priv = parent_class->priv;
GPtrArray *parent_actions = parent_priv->actions;
if (priv->actions == parent_actions)
{
int i;
priv->actions = g_ptr_array_new ();
for (i = 0; i < parent_actions->len; i++)
g_ptr_array_add (priv->actions, g_ptr_array_index (parent_actions, i));
}
}
action = g_new0 (GtkWidgetAction, 1);
action->name = g_strdup (action_name);
action->activate = activate;
action->parameter_type = parameter_type ? g_variant_type_new (parameter_type) : NULL;
action->set_state = set_state;
action->get_state = get_state;
GTK_NOTE(ACTIONS,
g_message ("%sClass: Adding %s action\n",
g_type_name (G_TYPE_FROM_CLASS (widget_class)),
action_name));
g_ptr_array_add (priv->actions, action);
}
/**
* gtk_widget_notify_class_action_enabled:
* @widget: a #GtkWidget
* @action_name: a prefixed action name, such as "clipboard.paste"
* @enabled: whether the action is now enabled
*
* Convenience API to notify when an action installed
* with gtk_widget_class_install_action() changes its
* enabled state. It must be called after the change
* has taken place (we expect the @query callback to
* already return the new state).
*
* This function is a more convenient alternative
* to calling g_action_group_action_enabled_changed()
* directly.
*/
void
gtk_widget_notify_class_action_enabled (GtkWidget *widget,
const char *action_name,
gboolean enabled)
{
GtkActionMuxer *muxer;
g_return_if_fail (GTK_IS_WIDGET (widget));
muxer = _gtk_widget_get_action_muxer (widget, TRUE);
gtk_action_muxer_action_enabled_changed (muxer, action_name, enabled);
}
/**
* gtk_widget_notify_class_action_state:
* @widget: a #GtkWidget
* @action_name: a prefixed action name, such as "clipboard.paste"
* @state: the new state
*
* Convenience API to notify when an action installed
* with gtk_widget_class_install_action() changes its
* state. It must be called after the change has taken
* place (we expect the @query callback to already
* return the new state).
*
* This function is a more convenient alternative
* to calling g_action_group_action_state_changed()
* directly.
*/
void
gtk_widget_notify_class_action_state (GtkWidget *widget,
const char *action_name,
GVariant *state)
{
GtkActionMuxer *muxer;
g_return_if_fail (GTK_IS_WIDGET (widget));
muxer = _gtk_widget_get_action_muxer (widget, TRUE);
gtk_action_muxer_action_state_changed (muxer, action_name, state);
}
static void
gtk_widget_class_add_accel_for_action (GtkWidgetClass *widget_class,
const char *detailed_action,
const char *accel)
{
GtkWidgetClassPrivate *priv = widget_class->priv;
char **accels;
int n;
if (priv->accels == NULL)
priv->accels = gtk_application_accels_new ();
accels = gtk_application_accels_get_accels_for_action (priv->accels, detailed_action);
if (accels)
{
n = g_strv_length (accels);
accels = g_renew (char *, accels, n + 2);
}
else
{
n = 0;
accels = g_new (char *, 2);
}
accels[n] = g_strdup (accel);
accels[n + 1] = NULL;
gtk_application_accels_set_accels_for_action (priv->accels, detailed_action, (const char **)accels);
}
/**
* gtk_widget_class_bind_action:
* @widget_class: a #GtkWidgetClass
* @keyval: key value of the binding
* @modifiers: key modifiers of the binding
* @action_name: the name of the action to bind
* @format_string: (allow-none): GVariant format string for
* the parameters, or %NULL
*
* Binds the @keyval, @modifiers shortcut to
* trigger the action named @action_name with the
* given parameters.
*
* This function should be called at class-init time.
*
* The action must be defined using
* gtk_widget_class_install_action() and the parameters
* must match the @parameter_type passed to that function.
*/
void
gtk_widget_class_bind_action (GtkWidgetClass *widget_class,
guint keyval,
GdkModifierType modifiers,
const char *action_name,
const char *format_string,
...)
{
GtkWidgetClassPrivate *priv = widget_class->priv;
gboolean found = FALSE;
GVariantType *type = NULL;
GVariant *parameters = NULL;
char *detailed_action = NULL;
char *accel = NULL;
if (priv->actions)
{
int i;
for (i = 0; i < priv->actions->len; i++)
{
GtkWidgetAction *action = g_ptr_array_index (priv->actions, i);
if (strcmp (action->name, action_name) == 0)
{
type = action->parameter_type;
found = TRUE;
break;
}
}
}
if (!found)
{
g_warning ("Widget action %s not found", action_name);
return;
}
if (format_string)
{
va_list args;
va_start (args, format_string);
parameters = g_variant_ref_sink (g_variant_new_va (format_string, NULL, &args));
va_end (args);
}
if (parameters && !g_variant_is_of_type (parameters, type))
{
g_warning ("Parameters don't match expected type for action %s", action_name);
g_variant_unref (parameters);
return;
}
detailed_action = g_action_print_detailed_name (action_name, parameters);
accel = gtk_accelerator_name (keyval, modifiers);
gtk_widget_class_add_accel_for_action (widget_class, detailed_action, accel);
g_free (detailed_action);
g_free (accel);
}
static gboolean
gtk_widget_activate_accels (GtkWidget *widget,
const GdkEvent *event)
{
GtkWidgetClass *class = GTK_WIDGET_GET_CLASS (widget);
GtkWidgetClassPrivate *priv = class->priv;
GtkApplicationAccels *accels = priv->accels;
GtkActionMuxer *muxer;
guint keyval;
GdkModifierType modifiers;
if (!accels)
return FALSE;
muxer = _gtk_widget_get_action_muxer (widget, FALSE);
if (!muxer)
return FALSE;
gdk_event_get_keyval ((GdkEvent *)event, &keyval);
gdk_event_get_state ((GdkEvent *)event, &modifiers);
return gtk_application_accels_activate (accels,
G_ACTION_GROUP (muxer),
keyval, modifiers);
}

View File

@@ -1023,6 +1023,84 @@ GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_should_layout (GtkWidget *widget);
/**
* GtkWidgetActionActivateFunc:
* @widget: the widget to which the action belongs
* @action_name: the action name
* @parameter: parameter for activation
*
* The type of the callback functions used for activating
* actions installed with gtk_widget_class_install_action().
*
* The @parameter must match the @parameter_type of the action.
*/
typedef void (* GtkWidgetActionActivateFunc) (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
/**
* GtkWidgetActionGetStateFunc:
* @widget: the widget to which the action belongs
* @action_name: the action name
*
* The type of the callback functions used to query the state
* of stateful actions installed with gtk_widget_class_install_action().
*
* See the #GAction documentation for more details about the
* meaning of these properties.
*/
typedef GVariant * (* GtkWidgetActionGetStateFunc) (GtkWidget *widget,
const char *action_name);
/**
* GtkWidgetActionSetStateFunc:
* @widget: the widget to which the action belongs
* @action_name: the action name
* @state: the new state
*
* The type of the callback functions used to change the
* state of actions installed with gtk_widget_class_install_action().
*
* The @state must match the @state_type of the action.
*
* This callback is used when the action state is
* changed via the #GActionGroup API.
*/
typedef void (*GtkWidgetActionSetStateFunc) (GtkWidget *widget,
const char *action_name,
GVariant *state);
GDK_AVAILABLE_IN_ALL
void gtk_widget_class_install_action (GtkWidgetClass *widget_class,
const char *action_name,
GtkWidgetActionActivateFunc activate);
GDK_AVAILABLE_IN_ALL
void gtk_widget_class_install_stateful_action (GtkWidgetClass *widget_class,
const char *action_name,
GtkWidgetActionActivateFunc activate,
const char *parameter_type,
GtkWidgetActionSetStateFunc set_state,
GtkWidgetActionGetStateFunc get_state);
GDK_AVAILABLE_IN_ALL
void gtk_widget_notify_class_action_enabled (GtkWidget *widget,
const char *action_name,
gboolean enabled);
GDK_AVAILABLE_IN_ALL
void gtk_widget_notify_class_action_state (GtkWidget *widget,
const char *action_name,
GVariant *state);
GDK_AVAILABLE_IN_ALL
void gtk_widget_class_bind_action (GtkWidgetClass *widget_class,
guint keyval,
GdkModifierType modifiers,
const char *action_name,
const char *format_string,
...);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRequisition, gtk_requisition_free)

View File

@@ -492,6 +492,13 @@ static void gtk_window_on_theme_variant_changed (GtkSettings *settings,
#endif
static void gtk_window_set_theme_variant (GtkWindow *window);
static void gtk_window_activate_default_activate (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_window_activate_focus_move (GtkWidget *widget,
const char *action_name,
GVariant *parameter);
static void gtk_window_do_popup (GtkWindow *window,
GdkEventButton *event);
static void gtk_window_style_updated (GtkWidget *widget);
@@ -1196,6 +1203,12 @@ gtk_window_class_init (GtkWindowClass *klass)
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_WINDOW_ACCESSIBLE);
gtk_widget_class_set_css_name (widget_class, I_("window"));
gtk_widget_class_install_action (widget_class, "default.activate",
gtk_window_activate_default_activate);
gtk_widget_class_install_stateful_action (widget_class, "focus.move",
gtk_window_activate_focus_move,
"i", NULL, NULL);
}
/**
@@ -1766,28 +1779,22 @@ gtk_window_capture_motion (GtkWidget *widget,
}
static void
activate_default_cb (GSimpleAction *action,
GVariant *parameter,
gpointer data)
gtk_window_activate_default_activate (GtkWidget *widget,
const char *name,
GVariant *parameter)
{
gtk_window_real_activate_default (GTK_WINDOW (data));
gtk_window_real_activate_default (GTK_WINDOW (widget));
}
static void
add_actions (GtkWindow *window)
gtk_window_activate_focus_move (GtkWidget *widget,
const char *action_name,
GVariant *parameter)
{
GActionEntry entries[] = {
{ "activate", activate_default_cb, NULL, NULL, NULL },
};
GActionGroup *actions;
actions = G_ACTION_GROUP (g_simple_action_group_new ());
g_action_map_add_action_entries (G_ACTION_MAP (actions),
entries, G_N_ELEMENTS (entries),
window);
gtk_widget_insert_action_group (GTK_WIDGET (window), "default", actions);
g_object_unref (actions);
gtk_window_move_focus (widget,
CLAMP (g_variant_get_int32 (parameter),
GTK_DIR_TAB_FORWARD,
GTK_DIR_RIGHT));
}
static void
@@ -1879,8 +1886,6 @@ gtk_window_init (GtkWindow *window)
g_signal_connect_swapped (priv->key_controller, "focus-out",
G_CALLBACK (gtk_window_focus_out), window);
gtk_widget_add_controller (widget, priv->key_controller);
add_actions (window);
}
static GtkGesture *