mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-11 11:20:12 +00:00
entry: Use gestures to handle pointer/touch events
Similarly to GtkTextView, a GtkGestureMultiPress gesture handles button/touch presses to initiate one selection mode or other, and a GtkGestureDrag is used to handle text selection and DnD checks. The code from button press/release, motion, and grab_notify handlers has been shuffled into the actions triggered by those gestures.
This commit is contained in:
parent
d559cade42
commit
e580c29f07
709
gtk/gtkentry.c
709
gtk/gtkentry.c
@ -143,8 +143,6 @@ struct _GtkEntryPrivate
|
||||
GtkIMContext *im_context;
|
||||
GtkWidget *popup_menu;
|
||||
|
||||
GdkDevice *device;
|
||||
|
||||
GdkWindow *text_area;
|
||||
|
||||
PangoLayout *cached_layout;
|
||||
@ -167,6 +165,9 @@ struct _GtkEntryPrivate
|
||||
GtkWidget *magnifier_popover;
|
||||
GtkWidget *magnifier;
|
||||
|
||||
GtkGesture *drag_gesture;
|
||||
GtkGesture *multipress_gesture;
|
||||
|
||||
gfloat xalign;
|
||||
|
||||
gint ascent; /* font ascent in pango units */
|
||||
@ -185,7 +186,6 @@ struct _GtkEntryPrivate
|
||||
|
||||
gunichar invisible_char;
|
||||
|
||||
guint button;
|
||||
guint blink_time; /* time in msec the cursor has blinked since last user event */
|
||||
guint blink_timeout;
|
||||
guint recompute_idle;
|
||||
@ -385,16 +385,12 @@ static void gtk_entry_draw_progress (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static gint gtk_entry_draw (GtkWidget *widget,
|
||||
cairo_t *cr);
|
||||
static gint gtk_entry_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gint gtk_entry_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event);
|
||||
static gboolean gtk_entry_event (GtkWidget *widget,
|
||||
GdkEvent *event);
|
||||
static gint gtk_entry_enter_notify (GtkWidget *widget,
|
||||
GdkEventCrossing *event);
|
||||
static gint gtk_entry_leave_notify (GtkWidget *widget,
|
||||
GdkEventCrossing *event);
|
||||
static gint gtk_entry_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event);
|
||||
static gint gtk_entry_key_press (GtkWidget *widget,
|
||||
GdkEventKey *event);
|
||||
static gint gtk_entry_key_release (GtkWidget *widget,
|
||||
@ -524,6 +520,21 @@ static gboolean gtk_entry_delete_surrounding_cb (GtkIMContext *context,
|
||||
gint n_chars,
|
||||
GtkEntry *entry);
|
||||
|
||||
/* Event controller callbacks */
|
||||
static void gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
|
||||
gint n_press,
|
||||
gdouble x,
|
||||
gdouble y,
|
||||
GtkEntry *entry);
|
||||
static void gtk_entry_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
GtkEntry *entry);
|
||||
static void gtk_entry_drag_gesture_end (GtkGestureDrag *gesture,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
GtkEntry *entry);
|
||||
|
||||
/* Internal routines
|
||||
*/
|
||||
static void gtk_entry_enter_text (GtkEntry *entry,
|
||||
@ -566,11 +577,9 @@ static void gtk_entry_paste (GtkEntry *entry,
|
||||
GdkAtom selection);
|
||||
static void gtk_entry_update_primary_selection (GtkEntry *entry);
|
||||
static void gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event);
|
||||
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);
|
||||
@ -696,9 +705,7 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->draw = gtk_entry_draw;
|
||||
widget_class->enter_notify_event = gtk_entry_enter_notify;
|
||||
widget_class->leave_notify_event = gtk_entry_leave_notify;
|
||||
widget_class->button_press_event = gtk_entry_button_press;
|
||||
widget_class->button_release_event = gtk_entry_button_release;
|
||||
widget_class->motion_notify_event = gtk_entry_motion_notify;
|
||||
widget_class->event = gtk_entry_event;
|
||||
widget_class->key_press_event = gtk_entry_key_press;
|
||||
widget_class->key_release_event = gtk_entry_key_release;
|
||||
widget_class->focus_in_event = gtk_entry_focus_in;
|
||||
@ -712,7 +719,6 @@ gtk_entry_class_init (GtkEntryClass *class)
|
||||
widget_class->state_flags_changed = gtk_entry_state_flags_changed;
|
||||
widget_class->screen_changed = gtk_entry_screen_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;
|
||||
@ -2687,6 +2693,22 @@ gtk_entry_init (GtkEntry *entry)
|
||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_ENTRY);
|
||||
|
||||
gtk_entry_update_cached_style_values (entry);
|
||||
|
||||
priv->drag_gesture = gtk_gesture_drag_new (GTK_WIDGET (entry));
|
||||
g_signal_connect (priv->drag_gesture, "drag-update",
|
||||
G_CALLBACK (gtk_entry_drag_gesture_update), entry);
|
||||
g_signal_connect (priv->drag_gesture, "drag-end",
|
||||
G_CALLBACK (gtk_entry_drag_gesture_end), entry);
|
||||
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->drag_gesture), FALSE);
|
||||
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->drag_gesture), TRUE);
|
||||
gtk_gesture_attach (priv->drag_gesture, GTK_PHASE_TARGET);
|
||||
|
||||
priv->multipress_gesture = gtk_gesture_multi_press_new (GTK_WIDGET (entry));
|
||||
g_signal_connect (priv->multipress_gesture, "pressed",
|
||||
G_CALLBACK (gtk_entry_multipress_gesture_pressed), entry);
|
||||
gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (priv->multipress_gesture), FALSE);
|
||||
gtk_gesture_single_set_exclusive (GTK_GESTURE_SINGLE (priv->multipress_gesture), TRUE);
|
||||
gtk_gesture_attach (priv->multipress_gesture, GTK_PHASE_TARGET);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -4178,55 +4200,164 @@ gtk_entry_update_handles (GtkEntry *entry,
|
||||
cursor, 0, height);
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_entry_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
static gboolean
|
||||
gtk_entry_event (GtkWidget *widget,
|
||||
GdkEvent *event)
|
||||
{
|
||||
GtkEntry *entry = GTK_ENTRY (widget);
|
||||
GtkEditable *editable = GTK_EDITABLE (widget);
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
GtkEntryPrivate *priv = GTK_ENTRY (widget)->priv;
|
||||
EntryIconInfo *icon_info = NULL;
|
||||
gint tmp_pos;
|
||||
gint sel_start, sel_end;
|
||||
gint i;
|
||||
|
||||
gtk_entry_selection_bubble_popup_unset (entry);
|
||||
if (event->type == GDK_MOTION_NOTIFY &&
|
||||
priv->mouse_cursor_obscured &&
|
||||
event->any.window == priv->text_area)
|
||||
{
|
||||
GdkCursor *cursor;
|
||||
|
||||
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget), GDK_XTERM);
|
||||
gdk_window_set_cursor (priv->text_area, cursor);
|
||||
g_object_unref (cursor);
|
||||
priv->mouse_cursor_obscured = FALSE;
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_ICONS; i++)
|
||||
{
|
||||
icon_info = priv->icons[i];
|
||||
|
||||
if (!icon_info || icon_info->insensitive)
|
||||
continue;
|
||||
|
||||
if (event->window == icon_info->window)
|
||||
if (priv->icons[i] &&
|
||||
priv->icons[i]->window == event->any.window)
|
||||
{
|
||||
if (should_prelight (entry, i))
|
||||
{
|
||||
icon_info->prelight = FALSE;
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
priv->start_x = event->x;
|
||||
priv->start_y = event->y;
|
||||
icon_info->pressed = TRUE;
|
||||
|
||||
if (!icon_info->nonactivatable)
|
||||
g_signal_emit (entry, signals[ICON_PRESS], 0, i, event);
|
||||
|
||||
return TRUE;
|
||||
icon_info = priv->icons[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->window != priv->text_area ||
|
||||
(priv->button && event->button != priv->button))
|
||||
return FALSE;
|
||||
if (!icon_info)
|
||||
return GDK_EVENT_PROPAGATE;
|
||||
|
||||
if (icon_info->insensitive)
|
||||
return GDK_EVENT_STOP;
|
||||
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
case GDK_2BUTTON_PRESS:
|
||||
case GDK_3BUTTON_PRESS:
|
||||
if (should_prelight (GTK_ENTRY (widget), i))
|
||||
{
|
||||
icon_info->prelight = FALSE;
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
priv->start_x = event->button.x;
|
||||
priv->start_y = event->button.y;
|
||||
icon_info->pressed = TRUE;
|
||||
|
||||
if (!icon_info->nonactivatable)
|
||||
g_signal_emit (widget, signals[ICON_PRESS], 0, i, event);
|
||||
|
||||
break;
|
||||
case GDK_MOTION_NOTIFY:
|
||||
if (icon_info->pressed &&
|
||||
icon_info->target_list != NULL &&
|
||||
gtk_drag_check_threshold (widget,
|
||||
priv->start_x,
|
||||
priv->start_y,
|
||||
event->motion.x,
|
||||
event->motion.y))
|
||||
{
|
||||
icon_info->in_drag = TRUE;
|
||||
icon_info->pressed = FALSE;
|
||||
gtk_drag_begin_with_coordinates (widget,
|
||||
icon_info->target_list,
|
||||
icon_info->actions,
|
||||
1,
|
||||
event,
|
||||
priv->start_x,
|
||||
priv->start_y);
|
||||
}
|
||||
|
||||
break;
|
||||
case GDK_BUTTON_RELEASE:
|
||||
icon_info->pressed = FALSE;
|
||||
|
||||
if (should_prelight (GTK_ENTRY (widget), i) &&
|
||||
event->button.x >= 0 && event->button.y >= 0 &&
|
||||
event->button.x < gdk_window_get_width (icon_info->window) &&
|
||||
event->button.y < gdk_window_get_height (icon_info->window))
|
||||
{
|
||||
icon_info->prelight = TRUE;
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
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 (GtkGestureSingle *gesture,
|
||||
GtkEntry *entry,
|
||||
gint *x,
|
||||
gint *y)
|
||||
{
|
||||
GtkAllocation primary, secondary;
|
||||
gint frame_x, frame_y, tx, ty;
|
||||
GdkEventSequence *sequence;
|
||||
gdouble px, py;
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (gesture);
|
||||
gtk_gesture_get_point (GTK_GESTURE (gesture), sequence, &px, &py);
|
||||
get_text_area_size (entry, &tx, &ty, NULL, NULL);
|
||||
get_icon_allocations (entry, &primary, &secondary);
|
||||
get_frame_size (entry, FALSE, &frame_x, &frame_y, NULL, NULL);
|
||||
|
||||
if (gtk_widget_get_direction (GTK_WIDGET (entry)) == GTK_TEXT_DIR_RTL)
|
||||
tx += secondary.width;
|
||||
else
|
||||
tx += primary.width;
|
||||
|
||||
tx += frame_x;
|
||||
ty += frame_y;
|
||||
|
||||
if (x)
|
||||
*x = px - tx;
|
||||
if (y)
|
||||
*y = py - ty;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_entry_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
|
||||
gint n_press,
|
||||
gdouble widget_x,
|
||||
gdouble widget_y,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
GtkEditable *editable = GTK_EDITABLE (entry);
|
||||
GtkWidget *widget = GTK_WIDGET (entry);
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
GdkEventSequence *current;
|
||||
const GdkEvent *event;
|
||||
gint x, y, sel_start, sel_end;
|
||||
guint button;
|
||||
gint tmp_pos;
|
||||
|
||||
gtk_entry_selection_bubble_popup_unset (entry);
|
||||
|
||||
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
|
||||
current = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), current);
|
||||
|
||||
gtk_gesture_set_sequence_state (GTK_GESTURE (gesture), current,
|
||||
GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y);
|
||||
gtk_entry_reset_blink_time (entry);
|
||||
|
||||
priv->button = event->button;
|
||||
priv->device = gdk_event_get_device ((GdkEvent *) event);
|
||||
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
{
|
||||
priv->in_click = TRUE;
|
||||
@ -4234,233 +4365,127 @@ gtk_entry_button_press (GtkWidget *widget,
|
||||
priv->in_click = FALSE;
|
||||
}
|
||||
|
||||
tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset);
|
||||
tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset);
|
||||
|
||||
if (gdk_event_triggers_context_menu ((GdkEvent *) event))
|
||||
{
|
||||
gtk_entry_do_popup (entry, event);
|
||||
priv->button = 0; /* Don't wait for release, since the menu will gtk_grab_add */
|
||||
priv->device = NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->button == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
|
||||
gboolean is_touchscreen;
|
||||
GdkDevice *source;
|
||||
|
||||
source = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
is_touchscreen = test_touchscreen ||
|
||||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
|
||||
|
||||
if (is_touchscreen)
|
||||
gtk_entry_ensure_text_handles (entry);
|
||||
|
||||
priv->select_words = FALSE;
|
||||
priv->select_lines = FALSE;
|
||||
|
||||
if (event->state &
|
||||
gtk_widget_get_modifier_mask (widget,
|
||||
GDK_MODIFIER_INTENT_EXTEND_SELECTION))
|
||||
{
|
||||
gtk_entry_reset_im_context (entry);
|
||||
|
||||
if (!have_selection) /* select from the current position to the clicked position */
|
||||
sel_start = sel_end = priv->current_pos;
|
||||
|
||||
if (tmp_pos > sel_start && tmp_pos < sel_end)
|
||||
{
|
||||
/* Truncate current selection, but keep it as big as possible */
|
||||
if (tmp_pos - sel_start > sel_end - tmp_pos)
|
||||
gtk_entry_set_positions (entry, sel_start, tmp_pos);
|
||||
else
|
||||
gtk_entry_set_positions (entry, tmp_pos, sel_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean extend_to_left;
|
||||
gint start, end;
|
||||
|
||||
/* Figure out what click selects and extend current selection */
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
gtk_entry_set_positions (entry, tmp_pos, tmp_pos);
|
||||
break;
|
||||
|
||||
case GDK_2BUTTON_PRESS:
|
||||
priv->select_words = TRUE;
|
||||
gtk_entry_select_word (entry);
|
||||
break;
|
||||
|
||||
case GDK_3BUTTON_PRESS:
|
||||
priv->select_lines = TRUE;
|
||||
gtk_entry_select_line (entry);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
start = MIN (priv->current_pos, priv->selection_bound);
|
||||
start = MIN (sel_start, start);
|
||||
|
||||
end = MAX (priv->current_pos, priv->selection_bound);
|
||||
end = MAX (sel_end, end);
|
||||
|
||||
if (tmp_pos == sel_start || tmp_pos == sel_end)
|
||||
extend_to_left = (tmp_pos == start);
|
||||
else
|
||||
extend_to_left = (end == sel_end);
|
||||
|
||||
if (extend_to_left)
|
||||
gtk_entry_set_positions (entry, start, end);
|
||||
else
|
||||
gtk_entry_set_positions (entry, end, start);
|
||||
}
|
||||
}
|
||||
else /* no shift key */
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_PRESS:
|
||||
if (in_selection (entry, event->x + priv->scroll_offset))
|
||||
{
|
||||
/* Click inside the selection - we'll either start a drag, or
|
||||
* clear the selection
|
||||
*/
|
||||
priv->in_drag = TRUE;
|
||||
priv->drag_start_x = event->x + priv->scroll_offset;
|
||||
priv->drag_start_y = event->y;
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_editable_set_position (editable, tmp_pos);
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_NONE);
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_2BUTTON_PRESS:
|
||||
/* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
|
||||
* receiving a GDK_2BUTTON_PRESS so we need to reset
|
||||
* priv->in_drag which may have been set above
|
||||
*/
|
||||
priv->in_drag = FALSE;
|
||||
priv->select_words = TRUE;
|
||||
gtk_entry_select_word (entry);
|
||||
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION);
|
||||
break;
|
||||
|
||||
case GDK_3BUTTON_PRESS:
|
||||
/* We ALWAYS receive a GDK_BUTTON_PRESS immediately before
|
||||
* receiving a GDK_3BUTTON_PRESS so we need to reset
|
||||
* priv->in_drag which may have been set above
|
||||
*/
|
||||
priv->in_drag = FALSE;
|
||||
priv->select_lines = TRUE;
|
||||
gtk_entry_select_line (entry);
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_SELECTION);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->type == GDK_BUTTON_PRESS &&
|
||||
event->button == GDK_BUTTON_MIDDLE &&
|
||||
else if (n_press == 1 && button == GDK_BUTTON_MIDDLE &&
|
||||
get_middle_click_paste (entry))
|
||||
{
|
||||
if (priv->editable)
|
||||
{
|
||||
priv->insert_pos = tmp_pos;
|
||||
gtk_entry_paste (entry, GDK_SELECTION_PRIMARY);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_error_bell (widget);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_entry_button_release (GtkWidget *widget,
|
||||
GdkEventButton *event)
|
||||
{
|
||||
GtkEntry *entry = GTK_ENTRY (widget);
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
EntryIconInfo *icon_info = NULL;
|
||||
gboolean is_touchscreen;
|
||||
GdkDevice *source;
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < MAX_ICONS; i++)
|
||||
else if (button == GDK_BUTTON_PRIMARY)
|
||||
{
|
||||
icon_info = priv->icons[i];
|
||||
gboolean have_selection = gtk_editable_get_selection_bounds (editable, &sel_start, &sel_end);
|
||||
GtkTextHandleMode mode = GTK_TEXT_HANDLE_MODE_NONE;
|
||||
gboolean is_touchscreen, extend_selection;
|
||||
GdkDevice *source;
|
||||
|
||||
if (!icon_info || icon_info->insensitive)
|
||||
continue;
|
||||
|
||||
if (event->window == icon_info->window)
|
||||
{
|
||||
icon_info->pressed = FALSE;
|
||||
|
||||
if (should_prelight (entry, i) &&
|
||||
event->x >= 0 && event->y >= 0 &&
|
||||
event->x < gdk_window_get_width (icon_info->window) &&
|
||||
event->y < gdk_window_get_height (icon_info->window))
|
||||
{
|
||||
icon_info->prelight = TRUE;
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
|
||||
if (!icon_info->nonactivatable)
|
||||
g_signal_emit (entry, signals[ICON_RELEASE], 0, i, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (event->window != priv->text_area || priv->button != event->button)
|
||||
return FALSE;
|
||||
|
||||
source = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
is_touchscreen = (test_touchscreen ||
|
||||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN);
|
||||
|
||||
if (priv->in_drag)
|
||||
{
|
||||
gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x);
|
||||
|
||||
gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
|
||||
source = gdk_event_get_source_device (event);
|
||||
is_touchscreen = test_touchscreen ||
|
||||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
|
||||
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
|
||||
gtk_entry_ensure_text_handles (entry);
|
||||
|
||||
priv->in_drag = 0;
|
||||
}
|
||||
else if (is_touchscreen)
|
||||
{
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
|
||||
gtk_entry_selection_bubble_popup_set (entry);
|
||||
if (priv->magnifier_popover)
|
||||
gtk_widget_hide (priv->magnifier_popover);
|
||||
priv->in_drag = FALSE;
|
||||
priv->select_words = FALSE;
|
||||
priv->select_lines = FALSE;
|
||||
|
||||
extend_selection =
|
||||
(event->button.state &
|
||||
gtk_widget_get_modifier_mask (widget,
|
||||
GDK_MODIFIER_INTENT_EXTEND_SELECTION));
|
||||
|
||||
switch (n_press)
|
||||
{
|
||||
case 1:
|
||||
if (in_selection (entry, x + priv->scroll_offset))
|
||||
{
|
||||
/* Click inside the selection - we'll either start a drag, or
|
||||
* clear the selection
|
||||
*/
|
||||
priv->in_drag = TRUE;
|
||||
priv->drag_start_x = x + priv->scroll_offset;
|
||||
priv->drag_start_y = y;
|
||||
}
|
||||
else if (!extend_selection)
|
||||
{
|
||||
gtk_editable_set_position (editable, tmp_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_entry_reset_im_context (entry);
|
||||
|
||||
if (!have_selection) /* select from the current position to the clicked position */
|
||||
sel_start = sel_end = priv->current_pos;
|
||||
|
||||
if (tmp_pos > sel_start && tmp_pos < sel_end)
|
||||
{
|
||||
/* Truncate current selection, but keep it as big as possible */
|
||||
if (tmp_pos - sel_start > sel_end - tmp_pos)
|
||||
gtk_entry_set_positions (entry, sel_start, tmp_pos);
|
||||
else
|
||||
gtk_entry_set_positions (entry, tmp_pos, sel_end);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
priv->select_words = TRUE;
|
||||
gtk_entry_select_word (entry);
|
||||
mode = GTK_TEXT_HANDLE_MODE_SELECTION;
|
||||
break;
|
||||
case 3:
|
||||
priv->select_lines = TRUE;
|
||||
gtk_entry_select_line (entry);
|
||||
mode = GTK_TEXT_HANDLE_MODE_SELECTION;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (extend_selection)
|
||||
{
|
||||
gboolean extend_to_left;
|
||||
gint start, end;
|
||||
|
||||
start = MIN (priv->current_pos, priv->selection_bound);
|
||||
start = MIN (sel_start, start);
|
||||
|
||||
end = MAX (priv->current_pos, priv->selection_bound);
|
||||
end = MAX (sel_end, end);
|
||||
|
||||
if (tmp_pos == sel_start || tmp_pos == sel_end)
|
||||
extend_to_left = (tmp_pos == start);
|
||||
else
|
||||
extend_to_left = (end == sel_end);
|
||||
|
||||
if (extend_to_left)
|
||||
gtk_entry_set_positions (entry, start, end);
|
||||
else
|
||||
gtk_entry_set_positions (entry, end, start);
|
||||
}
|
||||
|
||||
gtk_gesture_set_state (priv->drag_gesture,
|
||||
GTK_EVENT_SEQUENCE_CLAIMED);
|
||||
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, mode);
|
||||
}
|
||||
|
||||
priv->button = 0;
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_entry_update_primary_selection (entry);
|
||||
|
||||
return TRUE;
|
||||
if (n_press >= 3)
|
||||
gtk_event_controller_reset (GTK_EVENT_CONTROLLER (gesture));
|
||||
}
|
||||
|
||||
static gchar *
|
||||
@ -4508,47 +4533,21 @@ gtk_entry_show_magnifier (GtkEntry *entry,
|
||||
gtk_widget_show (priv->magnifier_popover);
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_entry_motion_notify (GtkWidget *widget,
|
||||
GdkEventMotion *event)
|
||||
static void
|
||||
gtk_entry_drag_gesture_update (GtkGestureDrag *gesture,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
GtkEntry *entry = GTK_ENTRY (widget);
|
||||
GtkWidget *widget = GTK_WIDGET (entry);
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
EntryIconInfo *icon_info = NULL;
|
||||
gint tmp_pos;
|
||||
gint i;
|
||||
GdkEventSequence *sequence;
|
||||
const GdkEvent *event;
|
||||
gint x, y;
|
||||
|
||||
for (i = 0; i < MAX_ICONS; i++)
|
||||
{
|
||||
icon_info = priv->icons[i];
|
||||
|
||||
if (!icon_info || icon_info->insensitive)
|
||||
continue;
|
||||
|
||||
if (event->window == icon_info->window)
|
||||
{
|
||||
if (icon_info->pressed &&
|
||||
icon_info->target_list != NULL &&
|
||||
gtk_drag_check_threshold (widget,
|
||||
priv->start_x,
|
||||
priv->start_y,
|
||||
event->x,
|
||||
event->y))
|
||||
{
|
||||
icon_info->in_drag = TRUE;
|
||||
icon_info->pressed = FALSE;
|
||||
gtk_drag_begin_with_coordinates (widget,
|
||||
icon_info->target_list,
|
||||
icon_info->actions,
|
||||
1,
|
||||
(GdkEvent*)event,
|
||||
priv->start_x,
|
||||
priv->start_y);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
gesture_get_current_point (GTK_GESTURE_SINGLE (gesture), entry, &x, &y);
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
|
||||
|
||||
if (priv->mouse_cursor_obscured)
|
||||
{
|
||||
@ -4560,20 +4559,15 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
priv->mouse_cursor_obscured = FALSE;
|
||||
}
|
||||
|
||||
if (event->window != priv->text_area || priv->button != GDK_BUTTON_PRIMARY)
|
||||
return FALSE;
|
||||
|
||||
if (priv->select_lines)
|
||||
return TRUE;
|
||||
|
||||
gdk_event_request_motions (event);
|
||||
return;
|
||||
|
||||
if (priv->in_drag)
|
||||
{
|
||||
if (gtk_entry_get_display_mode (entry) == DISPLAY_NORMAL &&
|
||||
gtk_drag_check_threshold (widget,
|
||||
priv->drag_start_x, priv->drag_start_y,
|
||||
event->x + priv->scroll_offset, event->y))
|
||||
x + priv->scroll_offset, y))
|
||||
{
|
||||
gint *ranges;
|
||||
gint n_ranges;
|
||||
@ -4582,6 +4576,7 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
guint actions = priv->editable ? GDK_ACTION_COPY | GDK_ACTION_MOVE : GDK_ACTION_COPY;
|
||||
gchar *text = NULL;
|
||||
cairo_surface_t *surface;
|
||||
guint button;
|
||||
|
||||
gtk_target_list_add_text_targets (target_list, 0);
|
||||
|
||||
@ -4593,8 +4588,9 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
-(priv->drag_start_x - ranges[0]),
|
||||
-(priv->drag_start_y));
|
||||
|
||||
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
|
||||
context = gtk_drag_begin_with_coordinates (widget, target_list, actions,
|
||||
priv->button, (GdkEvent *)event,
|
||||
button, (GdkEvent*) event,
|
||||
priv->drag_start_x + ranges[0],
|
||||
priv->drag_start_y);
|
||||
g_free (ranges);
|
||||
@ -4603,14 +4599,12 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
gtk_drag_set_icon_surface (context, surface);
|
||||
else
|
||||
gtk_drag_set_icon_default (context);
|
||||
|
||||
|
||||
if (surface)
|
||||
cairo_surface_destroy (surface);
|
||||
g_free (text);
|
||||
|
||||
priv->in_drag = FALSE;
|
||||
priv->button = 0;
|
||||
priv->device = NULL;
|
||||
|
||||
gtk_target_list_unref (target_list);
|
||||
}
|
||||
@ -4620,17 +4614,18 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
GdkInputSource input_source;
|
||||
GdkDevice *source;
|
||||
guint length;
|
||||
gint tmp_pos;
|
||||
|
||||
length = gtk_entry_buffer_get_length (get_buffer (entry));
|
||||
|
||||
if (event->y < 0)
|
||||
if (y < 0)
|
||||
tmp_pos = 0;
|
||||
else if (event->y >= gdk_window_get_height (priv->text_area))
|
||||
else if (y >= gdk_window_get_height (priv->text_area))
|
||||
tmp_pos = length;
|
||||
else
|
||||
tmp_pos = gtk_entry_find_position (entry, event->x + priv->scroll_offset);
|
||||
tmp_pos = gtk_entry_find_position (entry, x + priv->scroll_offset);
|
||||
|
||||
source = gdk_event_get_source_device ((GdkEvent *) event);
|
||||
source = gdk_event_get_source_device (event);
|
||||
input_source = gdk_device_get_source (source);
|
||||
|
||||
if (priv->select_words)
|
||||
@ -4638,32 +4633,32 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
gint min, max;
|
||||
gint old_min, old_max;
|
||||
gint pos, bound;
|
||||
|
||||
|
||||
min = gtk_entry_move_backward_word (entry, tmp_pos, TRUE);
|
||||
max = gtk_entry_move_forward_word (entry, tmp_pos, TRUE);
|
||||
|
||||
pos = priv->current_pos;
|
||||
bound = priv->selection_bound;
|
||||
|
||||
old_min = MIN(priv->current_pos, priv->selection_bound);
|
||||
old_max = MAX(priv->current_pos, priv->selection_bound);
|
||||
|
||||
old_min = MIN (priv->current_pos, priv->selection_bound);
|
||||
old_max = MAX (priv->current_pos, priv->selection_bound);
|
||||
|
||||
if (min < old_min)
|
||||
{
|
||||
pos = min;
|
||||
bound = old_max;
|
||||
}
|
||||
else if (old_max < max)
|
||||
else if (old_max < max)
|
||||
{
|
||||
pos = max;
|
||||
bound = old_min;
|
||||
}
|
||||
else if (pos == old_min)
|
||||
else if (pos == old_min)
|
||||
{
|
||||
if (priv->current_pos != min)
|
||||
pos = max;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
if (priv->current_pos != max)
|
||||
pos = min;
|
||||
@ -4677,22 +4672,59 @@ gtk_entry_motion_notify (GtkWidget *widget,
|
||||
/* Update touch handles' position */
|
||||
if (test_touchscreen || input_source == GDK_SOURCE_TOUCHSCREEN)
|
||||
{
|
||||
gint x, y;
|
||||
|
||||
gtk_entry_ensure_text_handles (entry);
|
||||
gtk_entry_update_handles (entry,
|
||||
(priv->current_pos == priv->selection_bound) ?
|
||||
GTK_TEXT_HANDLE_MODE_CURSOR :
|
||||
GTK_TEXT_HANDLE_MODE_SELECTION);
|
||||
|
||||
gtk_entry_get_text_area_size (entry, &x, &y, NULL, NULL);
|
||||
x += event->x;
|
||||
y += event->y;
|
||||
gtk_entry_show_magnifier (entry, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
static void
|
||||
gtk_entry_drag_gesture_end (GtkGestureDrag *gesture,
|
||||
gdouble offset_x,
|
||||
gdouble offset_y,
|
||||
GtkEntry *entry)
|
||||
{
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
gboolean in_drag, is_touchscreen;
|
||||
GdkEventSequence *sequence;
|
||||
const GdkEvent *event;
|
||||
GdkDevice *source;
|
||||
|
||||
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
|
||||
in_drag = priv->in_drag;
|
||||
priv->in_drag = FALSE;
|
||||
|
||||
if (priv->magnifier_popover)
|
||||
gtk_widget_hide (priv->magnifier_popover);
|
||||
|
||||
/* Check whether the drag was cancelled rather than finished */
|
||||
if (!gtk_gesture_handles_sequence (GTK_GESTURE (gesture), sequence))
|
||||
return;
|
||||
|
||||
event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
|
||||
source = gdk_event_get_source_device (event);
|
||||
is_touchscreen = (test_touchscreen ||
|
||||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN);
|
||||
|
||||
if (in_drag)
|
||||
{
|
||||
gint tmp_pos = gtk_entry_find_position (entry, priv->drag_start_x);
|
||||
|
||||
gtk_editable_set_position (GTK_EDITABLE (entry), tmp_pos);
|
||||
|
||||
if (is_touchscreen)
|
||||
gtk_entry_update_handles (entry, GTK_TEXT_HANDLE_MODE_CURSOR);
|
||||
}
|
||||
else if (is_touchscreen)
|
||||
{
|
||||
gtk_entry_selection_bubble_popup_set (entry);
|
||||
}
|
||||
|
||||
gtk_entry_update_primary_selection (entry);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -7147,8 +7179,11 @@ paste_received (GtkClipboard *clipboard,
|
||||
GtkEntry *entry = GTK_ENTRY (data);
|
||||
GtkEditable *editable = GTK_EDITABLE (entry);
|
||||
GtkEntryPrivate *priv = entry->priv;
|
||||
guint button;
|
||||
|
||||
if (priv->button == GDK_BUTTON_MIDDLE)
|
||||
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (priv->multipress_gesture));
|
||||
|
||||
if (button == GDK_BUTTON_MIDDLE)
|
||||
{
|
||||
gint pos, start, end;
|
||||
pos = priv->insert_pos;
|
||||
@ -9314,26 +9349,6 @@ gtk_entry_mnemonic_activate (GtkWidget *widget,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_entry_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed)
|
||||
{
|
||||
GtkEntryPrivate *priv;
|
||||
|
||||
priv = GTK_ENTRY (widget)->priv;
|
||||
|
||||
if (priv->device &&
|
||||
gtk_widget_device_is_shadowed (widget, priv->device))
|
||||
{
|
||||
/* Unset button so we don't expect
|
||||
* a button release anymore
|
||||
*/
|
||||
priv->button = 0;
|
||||
priv->device = NULL;
|
||||
priv->in_drag = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
append_action_signal (GtkEntry *entry,
|
||||
GtkWidget *menu,
|
||||
@ -9415,7 +9430,7 @@ popup_position_func (GtkMenu *menu,
|
||||
typedef struct
|
||||
{
|
||||
GtkEntry *entry;
|
||||
gint button;
|
||||
guint button;
|
||||
guint time;
|
||||
GdkDevice *device;
|
||||
} PopupInfo;
|
||||
@ -9497,7 +9512,7 @@ popup_targets_received (GtkClipboard *clipboard,
|
||||
|
||||
static void
|
||||
gtk_entry_do_popup (GtkEntry *entry,
|
||||
GdkEventButton *event)
|
||||
const GdkEvent *event)
|
||||
{
|
||||
PopupInfo *info = g_slice_new (PopupInfo);
|
||||
|
||||
@ -9509,9 +9524,9 @@ gtk_entry_do_popup (GtkEntry *entry,
|
||||
|
||||
if (event)
|
||||
{
|
||||
info->button = event->button;
|
||||
info->time = event->time;
|
||||
info->device = event->device;
|
||||
gdk_event_get_button (event, &info->button);
|
||||
info->time = gdk_event_get_time (event);
|
||||
info->device = gdk_event_get_device (event);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user