gtkentry: Use gestures for entry icons

Instead of doing all handling manually in the ::event vfunc,
set up drag/multipress gestures on icon images, and implement
emission of ::icon-press/release and DnD there.

As a side effect, the GdkEvent field in ::icon-press/release
signals has been dropped. Callers that might be interested on it
may still use gtk_get_current_event*().
This commit is contained in:
Carlos Garnacho 2018-06-06 13:52:08 +02:00
parent 7048362e6e
commit e08e15ba51
7 changed files with 110 additions and 173 deletions

View File

@ -77,7 +77,6 @@ entry_size_allocate_cb (GtkEntry *entry,
static void
entry_icon_press_cb (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
GtkWidget *popover = user_data;

View File

@ -151,11 +151,10 @@ create_search_menu (GtkWidget *entry)
static void
icon_press_cb (GtkEntry *entry,
gint position,
GdkEventButton *event,
gpointer data)
{
if (position == GTK_ENTRY_ICON_PRIMARY)
gtk_menu_popup_at_pointer (GTK_MENU (menu), (GdkEvent *) event);
gtk_menu_popup_at_pointer (GTK_MENU (menu), NULL);
}
static void

View File

@ -353,7 +353,6 @@ update_pulse_time (GtkAdjustment *adjustment, GtkWidget *widget)
static void
on_entry_icon_release (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
gpointer user_data)
{
if (icon_pos != GTK_ENTRY_ICON_SECONDARY)

View File

@ -221,8 +221,6 @@ gtk_entry_icon_accessible_do_action (AtkAction *action,
GtkEntryIconAccessible *icon = (GtkEntryIconAccessible *)action;
GtkWidget *widget;
GtkEntry *gtk_entry;
GdkEvent *event;
GdkRectangle icon_area;
widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (icon->entry));
if (widget == NULL)
@ -240,18 +238,7 @@ gtk_entry_icon_accessible_do_action (AtkAction *action,
!gtk_entry_get_icon_activatable (gtk_entry, icon->pos))
return FALSE;
gtk_entry_get_icon_area (gtk_entry, icon->pos, &icon_area);
event = gdk_event_new (GDK_BUTTON_PRESS);
event->any.surface = g_object_ref (gtk_widget_get_surface (widget));
event->button.button = 1;
event->any.send_event = TRUE;
event->button.time = GDK_CURRENT_TIME;
event->button.x = icon_area.x;
event->button.y = icon_area.y;
g_signal_emit_by_name (widget, "icon-press", 0, icon->pos, event);
g_object_unref (event);
g_signal_emit_by_name (widget, "icon-press", 0, icon->pos);
return TRUE;
}

View File

@ -284,12 +284,9 @@ struct _EntryIconInfo
gchar *tooltip;
guint nonactivatable : 1;
guint in_drag : 1;
guint pressed : 1;
GdkDragAction actions;
GdkContentFormats *target_list;
GdkEventSequence *current_sequence;
GdkDevice *device;
};
struct _GtkEntryPasswordHint
@ -418,8 +415,6 @@ static void gtk_entry_size_allocate (GtkWidget *widget,
int baseline);
static void gtk_entry_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot);
static gboolean gtk_entry_event (GtkWidget *widget,
GdkEvent *event);
static void gtk_entry_focus_in (GtkWidget *widget);
static void gtk_entry_focus_out (GtkWidget *widget);
static void gtk_entry_grab_focus (GtkWidget *widget);
@ -594,8 +589,6 @@ static void gtk_entry_do_popup (GtkEntry *entry,
const GdkEvent *event);
static gboolean gtk_entry_mnemonic_activate (GtkWidget *widget,
gboolean group_cycling);
static void gtk_entry_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
static void gtk_entry_check_cursor_blink (GtkEntry *entry);
static void gtk_entry_pend_cursor_blink (GtkEntry *entry);
static void gtk_entry_reset_blink_time (GtkEntry *entry);
@ -790,7 +783,6 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class->measure = gtk_entry_measure;
widget_class->size_allocate = gtk_entry_size_allocate;
widget_class->snapshot = gtk_entry_snapshot;
widget_class->event = gtk_entry_event;
widget_class->grab_focus = gtk_entry_grab_focus;
widget_class->style_updated = gtk_entry_style_updated;
widget_class->query_tooltip = gtk_entry_query_tooltip;
@ -800,7 +792,6 @@ gtk_entry_class_init (GtkEntryClass *class)
widget_class->state_flags_changed = gtk_entry_state_flags_changed;
widget_class->display_changed = gtk_entry_display_changed;
widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
widget_class->grab_notify = gtk_entry_grab_notify;
widget_class->drag_drop = gtk_entry_drag_drop;
widget_class->drag_motion = gtk_entry_drag_motion;
@ -1651,7 +1642,6 @@ gtk_entry_class_init (GtkEntryClass *class)
* GtkEntry::icon-press:
* @entry: The entry on which the signal is emitted
* @icon_pos: The position of the clicked icon
* @event: (type Gdk.EventButton): the button press event
*
* The ::icon-press signal is emitted when an activatable icon
* is clicked.
@ -1662,16 +1652,14 @@ gtk_entry_class_init (GtkEntryClass *class)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
_gtk_marshal_VOID__ENUM_OBJECT,
G_TYPE_NONE, 2,
GTK_TYPE_ENTRY_ICON_POSITION,
GDK_TYPE_EVENT);
g_cclosure_marshal_VOID__ENUM,
G_TYPE_NONE, 1,
GTK_TYPE_ENTRY_ICON_POSITION);
/**
* GtkEntry::icon-release:
* @entry: The entry on which the signal is emitted
* @icon_pos: The position of the clicked icon
* @event: (type Gdk.EventButton): the button release event
*
* The ::icon-release signal is emitted on the button release from a
* mouse click over an activatable icon.
@ -1682,10 +1670,9 @@ gtk_entry_class_init (GtkEntryClass *class)
G_SIGNAL_RUN_LAST,
0,
NULL, NULL,
_gtk_marshal_VOID__ENUM_OBJECT,
G_TYPE_NONE, 2,
GTK_TYPE_ENTRY_ICON_POSITION,
GDK_TYPE_EVENT);
g_cclosure_marshal_VOID__ENUM,
G_TYPE_NONE, 1,
GTK_TYPE_ENTRY_ICON_POSITION);
/**
* GtkEntry::preedit-changed:
@ -2965,6 +2952,91 @@ update_node_ordering (GtkEntry *entry)
gtk_css_node_insert_before (parent, gtk_widget_get_css_node (icon_info->widget), NULL);
}
static GtkEntryIconPosition
get_icon_position_from_controller (GtkEntry *entry,
GtkEventController *controller)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
GtkWidget *widget = gtk_event_controller_get_widget (controller);
if (priv->icons[GTK_ENTRY_ICON_PRIMARY] &&
priv->icons[GTK_ENTRY_ICON_PRIMARY]->widget == widget)
return GTK_ENTRY_ICON_PRIMARY;
else if (priv->icons[GTK_ENTRY_ICON_SECONDARY] &&
priv->icons[GTK_ENTRY_ICON_SECONDARY]->widget == widget)
return GTK_ENTRY_ICON_SECONDARY;
g_assert_not_reached ();
return -1;
}
static void
icon_pressed_cb (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkEntry *entry)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
GtkEntryIconPosition pos;
EntryIconInfo *icon_info;
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
icon_info = priv->icons[pos];
if (!icon_info->nonactivatable)
g_signal_emit (entry, signals[ICON_PRESS], 0, pos);
gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
}
static void
icon_released_cb (GtkGestureMultiPress *gesture,
gint n_press,
gdouble x,
gdouble y,
GtkEntry *entry)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
GtkEntryIconPosition pos;
EntryIconInfo *icon_info;
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
icon_info = priv->icons[pos];
if (!icon_info->nonactivatable)
g_signal_emit (entry, signals[ICON_RELEASE], 0, pos);
}
static void
icon_drag_update_cb (GtkGestureDrag *gesture,
gdouble x,
gdouble y,
GtkEntry *entry)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
gdouble start_x, start_y;
GtkEntryIconPosition pos;
EntryIconInfo *icon_info;
gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
pos = get_icon_position_from_controller (entry, GTK_EVENT_CONTROLLER (gesture));
icon_info = priv->icons[pos];
if (icon_info->target_list != NULL &&
gtk_drag_check_threshold (icon_info->widget,
start_x, start_y,
x, y))
{
icon_info->in_drag = TRUE;
gtk_drag_begin_with_coordinates (GTK_WIDGET (entry),
gtk_gesture_get_device (GTK_GESTURE (gesture)),
icon_info->target_list,
icon_info->actions,
start_x, start_y);
}
}
static EntryIconInfo*
construct_icon_info (GtkWidget *widget,
GtkEntryIconPosition icon_pos)
@ -2972,6 +3044,7 @@ construct_icon_info (GtkWidget *widget,
GtkEntry *entry = GTK_ENTRY (widget);
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
EntryIconInfo *icon_info;
GtkGesture *drag, *press;
g_return_val_if_fail (priv->icons[icon_pos] == NULL, NULL);
@ -2985,6 +3058,20 @@ construct_icon_info (GtkWidget *widget,
update_icon_style (widget, icon_pos);
update_node_ordering (entry);
press = gtk_gesture_multi_press_new ();
g_signal_connect (press, "pressed",
G_CALLBACK (icon_pressed_cb), entry);
g_signal_connect (press, "released",
G_CALLBACK (icon_released_cb), entry);
gtk_widget_add_controller (icon_info->widget, GTK_EVENT_CONTROLLER (press));
drag = gtk_gesture_drag_new ();
g_signal_connect (drag, "drag-update",
G_CALLBACK (icon_drag_update_cb), entry);
gtk_widget_add_controller (icon_info->widget, GTK_EVENT_CONTROLLER (drag));
gtk_gesture_group (press, drag);
return icon_info;
}
@ -3511,108 +3598,6 @@ gtk_entry_update_handles (GtkEntry *entry,
cursor, 0, text_allocation.height);
}
static gboolean
gtk_entry_event (GtkWidget *widget,
GdkEvent *event)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (GTK_ENTRY (widget));
EntryIconInfo *icon_info = NULL;
GdkEventSequence *sequence;
GdkDevice *device;
gdouble x, y;
gint i = 0;
if (!gdk_event_get_coords (event, &x, &y))
return GDK_EVENT_PROPAGATE;
for (i = 0; i < MAX_ICONS; i++)
{
if (priv->icons[i])
{
int icon_x, icon_y;
gtk_widget_translate_coordinates (widget, priv->icons[i]->widget,
x, y, &icon_x, &icon_y);
if (gtk_widget_contains (priv->icons[i]->widget, icon_x, icon_y))
{
icon_info = priv->icons[i];
break;
}
}
}
if (!icon_info)
return GDK_EVENT_PROPAGATE;
if (!gtk_widget_get_sensitive (icon_info->widget))
return GDK_EVENT_STOP;
sequence = gdk_event_get_event_sequence (event);
device = gdk_event_get_device (event);
switch ((guint) gdk_event_get_event_type (event))
{
case GDK_TOUCH_BEGIN:
if (icon_info->current_sequence)
break;
icon_info->current_sequence = sequence;
/* Fall through */
case GDK_BUTTON_PRESS:
priv->start_x = x;
priv->start_y = y;
icon_info->pressed = TRUE;
icon_info->device = device;
if (!icon_info->nonactivatable) {
g_signal_emit (widget, signals[ICON_PRESS], 0, i, event);
}
break;
case GDK_TOUCH_UPDATE:
if (icon_info->device != device ||
icon_info->current_sequence != sequence)
break;
/* Fall through */
case GDK_MOTION_NOTIFY:
if (icon_info->pressed &&
icon_info->target_list != NULL &&
gtk_drag_check_threshold (widget,
priv->start_x,
priv->start_y,
x, y))
{
icon_info->in_drag = TRUE;
gtk_drag_begin_with_coordinates (widget,
device,
icon_info->target_list,
icon_info->actions,
priv->start_x,
priv->start_y);
}
break;
case GDK_TOUCH_END:
if (icon_info->device != device ||
icon_info->current_sequence != sequence)
break;
icon_info->current_sequence = NULL;
/* Fall through */
case GDK_BUTTON_RELEASE:
icon_info->pressed = FALSE;
icon_info->device = NULL;
if (!icon_info->nonactivatable)
g_signal_emit (widget, signals[ICON_RELEASE], 0, i, event);
break;
default:
return GDK_EVENT_PROPAGATE;
}
return GDK_EVENT_STOP;
}
static void
gesture_get_current_point_in_layout (GtkGestureSingle *gesture,
GtkEntry *entry,
@ -7683,8 +7668,6 @@ gtk_entry_set_icon_sensitive (GtkEntry *entry,
{
gtk_widget_set_sensitive (icon_info->widget, sensitive);
icon_info->pressed = FALSE;
g_object_notify_by_pspec (G_OBJECT (entry),
entry_props[icon_pos == GTK_ENTRY_ICON_PRIMARY
? PROP_SENSITIVE_PRIMARY
@ -8168,35 +8151,6 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
return GDK_EVENT_STOP;
}
static void
check_undo_icon_grab (GtkEntry *entry,
EntryIconInfo *info)
{
if (!info->device ||
!gtk_widget_device_is_shadowed (GTK_WIDGET (entry), info->device))
return;
info->pressed = FALSE;
info->current_sequence = NULL;
info->device = NULL;
}
static void
gtk_entry_grab_notify (GtkWidget *widget,
gboolean was_grabbed)
{
GtkEntryPrivate *priv = gtk_entry_get_instance_private (GTK_ENTRY (widget));
gint i;
GTK_WIDGET_CLASS (gtk_entry_parent_class)->grab_notify (widget, was_grabbed);
for (i = 0; i < MAX_ICONS; i++)
{
if (priv->icons[i])
check_undo_icon_grab (GTK_ENTRY (widget), priv->icons[i]);
}
}
static void
append_action_signal (GtkEntry *entry,
GtkWidget *menu,

View File

@ -1816,7 +1816,6 @@ out:
static void
on_address_entry_show_help_pressed (GtkPlacesView *view,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
GtkEntry *entry)
{
GtkPlacesViewPrivate *priv;

View File

@ -2,7 +2,7 @@
#include <stdio.h>
static void
clear_pressed (GtkEntry *entry, gint icon, GdkEvent *event, gpointer data)
clear_pressed (GtkEntry *entry, gint icon, gpointer data)
{
if (icon == GTK_ENTRY_ICON_SECONDARY)
gtk_entry_set_text (entry, "");