gtktexthandle: Refactor and use native surfaces

Instead of being a GObject managing two GtkWidgets, make GtkTextHandle
a GtkWidget subclass, representing a single handle.

From the perspective of users (GtkText and GtkTextView), this is not a
big leap since they have to be aware of a great deal of text handles'
state. It actually makes things more direct and simple.

With text handles being widgets, those can be actual children of the
widget, and may have their own GdkSurface that we move around at will.
This is the second major aspect of this refactor.
This commit is contained in:
Carlos Garnacho 2020-02-03 15:59:49 +01:00
parent 2747dd5c9f
commit 0264a64f29
4 changed files with 723 additions and 1103 deletions

View File

@ -140,6 +140,13 @@
static GQuark quark_password_hint = 0;
enum
{
TEXT_HANDLE_CURSOR,
TEXT_HANDLE_SELECTION_BOUND,
TEXT_HANDLE_N_HANDLES
};
typedef struct _GtkTextPasswordHint GtkTextPasswordHint;
typedef struct _GtkTextPrivate GtkTextPrivate;
@ -159,7 +166,7 @@ struct _GtkTextPrivate
char *im_module;
GtkWidget *emoji_completion;
GtkTextHandle *text_handle;
GtkTextHandle *text_handles[TEXT_HANDLE_N_HANDLES];
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
@ -229,6 +236,7 @@ struct _GtkTextPrivate
guint selection_handle_dragged : 1;
guint populate_all : 1;
guint propagate_text_width : 1;
guint text_handles_enabled : 1;
};
struct _GtkTextPasswordHint
@ -464,15 +472,12 @@ static gboolean gtk_text_key_controller_key_pressed (GtkEventControllerKey *c
/* GtkTextHandle handlers */
static void gtk_text_handle_drag_started (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkText *self);
static void gtk_text_handle_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos,
int x,
int y,
GtkText *self);
static void gtk_text_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkText *self);
/* Internal routines
@ -539,6 +544,7 @@ static void emit_changed (GtkText *self);
static void gtk_text_update_clipboard_actions (GtkText *self);
static void gtk_text_update_emoji_action (GtkText *self);
static void gtk_text_update_handles (GtkText *self);
static void gtk_text_activate_clipboard_cut (GtkWidget *widget,
const char *action_name,
@ -1701,6 +1707,26 @@ gtk_text_get_property (GObject *object,
}
}
static void
gtk_text_ensure_text_handles (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
int i;
for (i = 0; i < TEXT_HANDLE_N_HANDLES; i++)
{
if (priv->text_handles[i])
continue;
priv->text_handles[i] = gtk_text_handle_new (GTK_WIDGET (self));
g_signal_connect (priv->text_handles[i], "drag-started",
G_CALLBACK (gtk_text_handle_drag_started), self);
g_signal_connect (priv->text_handles[i], "handle-dragged",
G_CALLBACK (gtk_text_handle_dragged), self);
g_signal_connect (priv->text_handles[i], "drag-finished",
G_CALLBACK (gtk_text_handle_drag_finished), self);
}
}
static void
gtk_text_init (GtkText *self)
{
@ -1852,6 +1878,8 @@ gtk_text_dispose (GObject *object)
g_clear_pointer (&priv->selection_bubble, gtk_widget_unparent);
g_clear_pointer (&priv->popup_menu, gtk_widget_unparent);
g_clear_pointer ((GtkWidget **) &priv->text_handles[TEXT_HANDLE_CURSOR], gtk_widget_unparent);
g_clear_pointer ((GtkWidget **) &priv->text_handles[TEXT_HANDLE_SELECTION_BOUND], gtk_widget_unparent);
g_clear_object (&priv->extra_menu);
G_OBJECT_CLASS (gtk_text_parent_class)->dispose (object);
@ -1869,7 +1897,6 @@ gtk_text_finalize (GObject *object)
g_clear_object (&priv->cached_layout);
g_clear_object (&priv->im_context);
g_clear_pointer (&priv->magnifier_popover, gtk_widget_destroy);
g_clear_object (&priv->text_handle);
g_free (priv->im_module);
g_clear_pointer (&priv->placeholder, gtk_widget_unparent);
@ -1904,23 +1931,6 @@ gtk_text_ensure_magnifier (GtkText *self)
gtk_widget_show (priv->magnifier);
}
static void
gtk_text_ensure_text_handles (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
if (priv->text_handle)
return;
priv->text_handle = _gtk_text_handle_new (GTK_WIDGET (self));
g_signal_connect (priv->text_handle, "drag-started",
G_CALLBACK (gtk_text_handle_drag_started), self);
g_signal_connect (priv->text_handle, "handle-dragged",
G_CALLBACK (gtk_text_handle_dragged), self);
g_signal_connect (priv->text_handle, "drag-finished",
G_CALLBACK (gtk_text_handle_drag_finished), self);
}
static void
begin_change (GtkText *self)
{
@ -2051,10 +2061,8 @@ gtk_text_unmap (GtkWidget *widget)
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
priv->text_handles_enabled = FALSE;
gtk_text_update_handles (self);
priv->cursor_alpha = 1.0;
GTK_WIDGET_CLASS (gtk_text_parent_class)->unmap (widget);
@ -2119,20 +2127,20 @@ update_im_cursor_location (GtkText *self)
static void
gtk_text_move_handle (GtkText *self,
GtkTextHandlePosition pos,
GtkTextHandle *handle,
int x,
int y,
int height)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
if (!_gtk_text_handle_get_is_dragged (priv->text_handle, pos) &&
if (!gtk_text_handle_get_is_dragged (handle) &&
(x < 0 || x > gtk_widget_get_width (GTK_WIDGET (self))))
{
/* Hide the handle if it's not being manipulated
* and fell outside of the visible text area.
*/
_gtk_text_handle_set_visible (priv->text_handle, pos, FALSE);
gtk_widget_hide (GTK_WIDGET (handle));
}
else
{
@ -2143,9 +2151,9 @@ gtk_text_move_handle (GtkText *self,
rect.width = 1;
rect.height = height;
_gtk_text_handle_set_visible (priv->text_handle, pos, TRUE);
_gtk_text_handle_set_position (priv->text_handle, pos, &rect);
_gtk_text_handle_set_direction (priv->text_handle, pos, priv->resolved_dir);
gtk_text_handle_set_position (handle, &rect);
gtk_widget_set_direction (GTK_WIDGET (handle), priv->resolved_dir);
gtk_widget_show (GTK_WIDGET (handle));
}
}
@ -2173,20 +2181,27 @@ gtk_text_get_selection_bound_location (GtkText *self)
}
static void
gtk_text_update_handles (GtkText *self,
GtkTextHandleMode mode)
gtk_text_update_handles (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
const int text_height = gtk_widget_get_height (GTK_WIDGET (self));
int strong_x;
int cursor, bound;
_gtk_text_handle_set_mode (priv->text_handle, mode);
if (!priv->text_handles_enabled)
{
if (priv->text_handles[TEXT_HANDLE_CURSOR])
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
else
{
gtk_text_ensure_text_handles (self);
gtk_text_get_cursor_locations (self, &strong_x, NULL);
cursor = strong_x - priv->scroll_offset;
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
if (priv->selection_bound != priv->current_pos)
{
int start, end;
@ -2204,14 +2219,27 @@ gtk_text_update_handles (GtkText *self,
}
/* Update start selection bound */
gtk_text_move_handle (self, GTK_TEXT_HANDLE_POSITION_SELECTION_START,
start, 0, text_height);
gtk_text_move_handle (self, GTK_TEXT_HANDLE_POSITION_SELECTION_END,
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
GTK_TEXT_HANDLE_ROLE_SELECTION_END);
gtk_text_move_handle (self,
priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
end, 0, text_height);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_SELECTION_START);
gtk_text_move_handle (self,
priv->text_handles[TEXT_HANDLE_CURSOR],
start, 0, text_height);
}
else
gtk_text_move_handle (self, GTK_TEXT_HANDLE_POSITION_CURSOR,
{
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_CURSOR);
gtk_text_move_handle (self,
priv->text_handles[TEXT_HANDLE_CURSOR],
cursor, 0, text_height);
}
}
}
static void
@ -2342,13 +2370,7 @@ gtk_text_size_allocate (GtkWidget *widget,
if (chooser)
gtk_native_check_resize (GTK_NATIVE (chooser));
if (priv->text_handle)
{
GtkTextHandleMode handle_mode = _gtk_text_handle_get_mode (priv->text_handle);
if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_update_handles (self, handle_mode);
}
gtk_text_update_handles (self);
if (priv->emoji_completion)
gtk_native_check_resize (GTK_NATIVE (priv->emoji_completion));
@ -2361,6 +2383,12 @@ gtk_text_size_allocate (GtkWidget *widget,
if (priv->selection_bubble)
gtk_native_check_resize (GTK_NATIVE (priv->selection_bubble));
if (priv->text_handles[TEXT_HANDLE_CURSOR])
gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR]));
if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
static void
@ -2599,7 +2627,6 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
else if (button == GDK_BUTTON_PRIMARY)
{
gboolean have_selection;
GtkTextHandleMode mode;
gboolean is_touchscreen, extend_selection;
GdkDevice *source;
guint state;
@ -2612,15 +2639,7 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
is_touchscreen = gtk_simulate_touchscreen () ||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
if (!is_touchscreen)
mode = GTK_TEXT_HANDLE_MODE_NONE;
else if (have_selection)
mode = GTK_TEXT_HANDLE_MODE_SELECTION;
else
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
if (is_touchscreen)
gtk_text_ensure_text_handles (self);
priv->text_handles_enabled = is_touchscreen;
priv->in_drag = FALSE;
priv->select_words = FALSE;
@ -2693,15 +2712,11 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
case 2:
priv->select_words = TRUE;
gtk_text_select_word (self);
if (is_touchscreen)
mode = GTK_TEXT_HANDLE_MODE_SELECTION;
break;
case 3:
priv->select_lines = TRUE;
gtk_text_select_line (self);
if (is_touchscreen)
mode = GTK_TEXT_HANDLE_MODE_SELECTION;
break;
default:
@ -2733,8 +2748,7 @@ gtk_text_click_gesture_pressed (GtkGestureClick *gesture,
gtk_gesture_set_state (priv->drag_gesture,
GTK_EVENT_SEQUENCE_CLAIMED);
if (priv->text_handle)
gtk_text_update_handles (self, mode);
gtk_text_update_handles (self);
}
if (n_press >= 3)
@ -2950,11 +2964,8 @@ gtk_text_drag_gesture_update (GtkGestureDrag *gesture,
if (gtk_simulate_touchscreen () ||
input_source == GDK_SOURCE_TOUCHSCREEN)
{
gtk_text_ensure_text_handles (self);
gtk_text_update_handles (self,
(priv->current_pos == priv->selection_bound) ?
GTK_TEXT_HANDLE_MODE_CURSOR :
GTK_TEXT_HANDLE_MODE_SELECTION);
priv->text_handles_enabled = TRUE;
gtk_text_update_handles (self);
gtk_text_show_magnifier (self, x - priv->scroll_offset, y);
}
}
@ -2967,10 +2978,8 @@ gtk_text_drag_gesture_end (GtkGestureDrag *gesture,
GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
gboolean in_drag, is_touchscreen;
gboolean in_drag;
GdkEventSequence *sequence;
GdkEvent *event;
GdkDevice *source;
sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
in_drag = priv->in_drag;
@ -2983,11 +2992,6 @@ gtk_text_drag_gesture_end (GtkGestureDrag *gesture,
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 = gtk_simulate_touchscreen () ||
gdk_device_get_source (source) == GDK_SOURCE_TOUCHSCREEN;
if (in_drag)
{
int tmp_pos = gtk_text_find_position (self, priv->drag_start_x);
@ -2995,8 +2999,7 @@ gtk_text_drag_gesture_end (GtkGestureDrag *gesture,
gtk_text_set_selection_bounds (self, tmp_pos, tmp_pos);
}
if (is_touchscreen && priv->selection_bound != priv->current_pos)
gtk_text_update_handles (self, GTK_TEXT_HANDLE_MODE_CURSOR);
gtk_text_update_handles (self);
gtk_text_update_primary_selection (self);
}
@ -3029,9 +3032,8 @@ gtk_text_key_controller_key_pressed (GtkEventControllerKey *controller,
gtk_text_selection_bubble_popup_unset (self);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
priv->text_handles_enabled = FALSE;
gtk_text_update_handles (self);
if (keyval == GDK_KEY_Return ||
keyval == GDK_KEY_KP_Enter ||
@ -3082,9 +3084,8 @@ gtk_text_focus_out (GtkWidget *widget)
gtk_text_selection_bubble_popup_unset (self);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
priv->text_handles_enabled = FALSE;
gtk_text_update_handles (self);
gtk_widget_queue_draw (widget);
@ -3957,15 +3958,7 @@ gtk_text_cut_clipboard (GtkText *self)
gtk_text_selection_bubble_popup_unset (self);
if (priv->text_handle)
{
GtkTextHandleMode handle_mode;
handle_mode = _gtk_text_handle_get_mode (priv->text_handle);
if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_update_handles (self, GTK_TEXT_HANDLE_MODE_CURSOR);
}
gtk_text_update_handles (self);
}
static void
@ -3978,15 +3971,7 @@ gtk_text_paste_clipboard (GtkText *self)
else
gtk_widget_error_bell (GTK_WIDGET (self));
if (priv->text_handle)
{
GtkTextHandleMode handle_mode;
handle_mode = _gtk_text_handle_get_mode (priv->text_handle);
if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_update_handles (self, GTK_TEXT_HANDLE_MODE_CURSOR);
}
gtk_text_update_handles (self);
}
static void
@ -4243,9 +4228,6 @@ gtk_text_reset_layout (GtkText *self)
static void
gtk_text_recompute (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkTextHandleMode handle_mode;
gtk_text_reset_layout (self);
gtk_text_check_cursor_blink (self);
@ -4253,13 +4235,7 @@ gtk_text_recompute (GtkText *self)
update_im_cursor_location (self);
if (priv->text_handle)
{
handle_mode = _gtk_text_handle_get_mode (priv->text_handle);
if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_update_handles (self, handle_mode);
}
gtk_text_update_handles (self);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@ -4543,74 +4519,58 @@ gtk_text_draw_cursor (GtkText *self,
static void
gtk_text_handle_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos,
int x,
int y,
GtkText *self)
{
int cursor_pos, selection_bound_pos, tmp_pos;
int cursor_pos, selection_bound_pos, tmp_pos, *old_pos;
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkTextHandleMode mode;
int *min, *max;
gtk_text_selection_bubble_popup_unset (self);
cursor_pos = priv->current_pos;
selection_bound_pos = priv->selection_bound;
mode = _gtk_text_handle_get_mode (handle);
tmp_pos = gtk_text_find_position (self, x + priv->scroll_offset);
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR ||
cursor_pos >= selection_bound_pos)
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR])
{
max = &cursor_pos;
min = &selection_bound_pos;
/* Avoid running past the other handle in selection mode */
if (tmp_pos >= selection_bound_pos &&
gtk_widget_is_visible (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])))
{
tmp_pos = selection_bound_pos - 1;
}
old_pos = &cursor_pos;
}
else if (handle == priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
{
/* Avoid running past the other handle */
if (tmp_pos <= cursor_pos)
tmp_pos = cursor_pos + 1;
old_pos = &selection_bound_pos;
}
else
{
max = &selection_bound_pos;
min = &cursor_pos;
}
g_assert_not_reached ();
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
if (tmp_pos != *old_pos)
{
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
{
int min_pos;
*old_pos = tmp_pos;
min_pos = MAX (*min + 1, 0);
tmp_pos = MAX (tmp_pos, min_pos);
}
*max = tmp_pos;
}
else
{
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
{
int max_pos;
max_pos = *max - 1;
*min = MIN (tmp_pos, max_pos);
}
}
if (cursor_pos != priv->current_pos ||
selection_bound_pos != priv->selection_bound)
{
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR)
{
priv->cursor_handle_dragged = TRUE;
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR] &&
!gtk_widget_is_visible (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])))
gtk_text_set_positions (self, cursor_pos, cursor_pos);
}
else
{
priv->selection_handle_dragged = TRUE;
gtk_text_set_positions (self, cursor_pos, selection_bound_pos);
}
gtk_text_update_handles (self, mode);
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR])
priv->cursor_handle_dragged = TRUE;
else if (handle == priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
priv->selection_handle_dragged = TRUE;
gtk_text_update_handles (self);
}
gtk_text_show_magnifier (self, x, y);
@ -4618,7 +4578,6 @@ gtk_text_handle_dragged (GtkTextHandle *handle,
static void
gtk_text_handle_drag_started (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
@ -4629,7 +4588,6 @@ gtk_text_handle_drag_started (GtkTextHandle *handle,
static void
gtk_text_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
@ -4644,7 +4602,7 @@ gtk_text_handle_drag_finished (GtkTextHandle *handle,
if (g_get_monotonic_time() - priv->handle_place_time < double_click_time * 1000)
{
gtk_text_select_word (self);
gtk_text_update_handles (self, GTK_TEXT_HANDLE_MODE_SELECTION);
gtk_text_update_handles (self);
}
else
gtk_text_selection_bubble_popup_set (self);
@ -4755,20 +4713,14 @@ static gboolean
gtk_text_get_is_selection_handle_dragged (GtkText *self)
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GtkTextHandlePosition pos;
if (!priv->text_handle)
return FALSE;
if (_gtk_text_handle_get_mode (priv->text_handle) != GTK_TEXT_HANDLE_MODE_SELECTION)
return FALSE;
GtkTextHandle *handle;
if (priv->current_pos >= priv->selection_bound)
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
handle = priv->text_handles[TEXT_HANDLE_CURSOR];
else
pos = GTK_TEXT_HANDLE_POSITION_SELECTION_END;
handle = priv->text_handles[TEXT_HANDLE_SELECTION_BOUND];
return _gtk_text_handle_get_is_dragged (priv->text_handle, pos);
return handle && gtk_text_handle_get_is_dragged (handle);
}
static void
@ -4818,7 +4770,6 @@ gtk_text_adjust_scroll (GtkText *self)
int min_offset, max_offset;
int strong_x, weak_x;
int strong_xoffset, weak_xoffset;
GtkTextHandleMode handle_mode;
if (!gtk_widget_get_realized (GTK_WIDGET (self)))
return;
@ -4881,13 +4832,7 @@ gtk_text_adjust_scroll (GtkText *self)
g_object_notify_by_pspec (G_OBJECT (self), text_props[PROP_SCROLL_OFFSET]);
if (priv->text_handle)
{
handle_mode = _gtk_text_handle_get_mode (priv->text_handle);
if (handle_mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_update_handles (self, handle_mode);
}
gtk_text_update_handles (self);
}
static int
@ -5926,23 +5871,10 @@ show_or_hide_handles (GtkWidget *popover,
{
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
gboolean visible;
GtkTextHandle *handle;
GtkTextHandleMode mode;
visible = gtk_widget_get_visible (popover);
handle = priv->text_handle;
mode = _gtk_text_handle_get_mode (handle);
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR)
{
_gtk_text_handle_set_visible (handle, GTK_TEXT_HANDLE_POSITION_CURSOR, !visible);
}
else if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
{
_gtk_text_handle_set_visible (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, !visible);
_gtk_text_handle_set_visible (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, !visible);
}
priv->text_handles_enabled = !visible;
gtk_text_update_handles (self);
}
static void

File diff suppressed because it is too large Load Diff

View File

@ -22,68 +22,27 @@
G_BEGIN_DECLS
#define GTK_TYPE_TEXT_HANDLE (_gtk_text_handle_get_type ())
#define GTK_TEXT_HANDLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_TEXT_HANDLE, GtkTextHandle))
#define GTK_TEXT_HANDLE_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), GTK_TYPE_TEXT_HANDLE, GtkTextHandleClass))
#define GTK_IS_TEXT_HANDLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_TEXT_HANDLE))
#define GTK_IS_TEXT_HANDLE_CLASS(o) (G_TYPE_CHECK_CLASS_TYPE ((o), GTK_TYPE_TEXT_HANDLE))
#define GTK_TEXT_HANDLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_TEXT_HANDLE, GtkTextHandleClass))
typedef struct _GtkTextHandle GtkTextHandle;
typedef struct _GtkTextHandleClass GtkTextHandleClass;
#define GTK_TYPE_TEXT_HANDLE (gtk_text_handle_get_type ())
G_DECLARE_FINAL_TYPE (GtkTextHandle, gtk_text_handle,
GTK, TEXT_HANDLE, GtkWidget)
typedef enum
{
GTK_TEXT_HANDLE_POSITION_CURSOR,
GTK_TEXT_HANDLE_POSITION_SELECTION_START,
GTK_TEXT_HANDLE_POSITION_SELECTION_END = GTK_TEXT_HANDLE_POSITION_CURSOR
} GtkTextHandlePosition;
GTK_TEXT_HANDLE_ROLE_CURSOR,
GTK_TEXT_HANDLE_ROLE_SELECTION_START,
GTK_TEXT_HANDLE_ROLE_SELECTION_END,
} GtkTextHandleRole;
typedef enum
{
GTK_TEXT_HANDLE_MODE_NONE,
GTK_TEXT_HANDLE_MODE_CURSOR,
GTK_TEXT_HANDLE_MODE_SELECTION
} GtkTextHandleMode;
GtkTextHandle * gtk_text_handle_new (GtkWidget *parent);
struct _GtkTextHandle
{
GObject parent_instance;
gpointer priv;
};
void gtk_text_handle_set_role (GtkTextHandle *handle,
GtkTextHandleRole role);
GtkTextHandleRole gtk_text_handle_get_role (GtkTextHandle *handle);
struct _GtkTextHandleClass
{
GObjectClass parent_class;
void gtk_text_handle_set_position (GtkTextHandle *handle,
const GdkRectangle *rect);
void (* handle_dragged) (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gint x,
gint y);
void (* drag_finished) (GtkTextHandle *handle,
GtkTextHandlePosition pos);
};
GType _gtk_text_handle_get_type (void) G_GNUC_CONST;
GtkTextHandle * _gtk_text_handle_new (GtkWidget *parent);
void _gtk_text_handle_set_mode (GtkTextHandle *handle,
GtkTextHandleMode mode);
GtkTextHandleMode
_gtk_text_handle_get_mode (GtkTextHandle *handle);
void _gtk_text_handle_set_position (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GdkRectangle *rect);
void _gtk_text_handle_set_visible (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gboolean visible);
gboolean _gtk_text_handle_get_is_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos);
void _gtk_text_handle_set_direction (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextDirection dir);
gboolean gtk_text_handle_get_is_dragged (GtkTextHandle *handle);
G_END_DECLS

View File

@ -149,6 +149,13 @@
typedef struct _GtkTextWindow GtkTextWindow;
typedef struct _GtkTextPendingScroll GtkTextPendingScroll;
enum
{
TEXT_HANDLE_CURSOR,
TEXT_HANDLE_SELECTION_BOUND,
TEXT_HANDLE_N_HANDLES
};
struct _GtkTextViewPrivate
{
GtkTextLayout *layout;
@ -161,7 +168,7 @@ struct _GtkTextViewPrivate
gint dnd_x;
gint dnd_y;
GtkTextHandle *text_handle;
GtkTextHandle *text_handles[TEXT_HANDLE_N_HANDLES];
GtkWidget *selection_bubble;
guint selection_bubble_timeout_id;
@ -273,6 +280,8 @@ struct _GtkTextViewPrivate
guint scroll_after_paste : 1;
guint text_handles_enabled : 1;
/* GtkScrollablePolicy needs to be checked when
* driving the scrollable adjustment values */
guint hscroll_policy : 1;
@ -565,18 +574,14 @@ static void update_node_ordering (GtkWidget *widget);
/* GtkTextHandle handlers */
static void gtk_text_view_handle_drag_started (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view);
static void gtk_text_view_handle_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gint x,
gint y,
GtkTextView *text_view);
static void gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view);
static void gtk_text_view_update_handles (GtkTextView *text_view,
GtkTextHandleMode mode);
static void gtk_text_view_update_handles (GtkTextView *text_view);
static void gtk_text_view_selection_bubble_popup_unset (GtkTextView *text_view);
static void gtk_text_view_selection_bubble_popup_set (GtkTextView *text_view);
@ -1719,6 +1724,26 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
gtk_text_view_activate_misc_insert_emoji);
}
static void
_gtk_text_view_ensure_text_handles (GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
int i;
for (i = 0; i < TEXT_HANDLE_N_HANDLES; i++)
{
if (priv->text_handles[i])
continue;
priv->text_handles[i] = gtk_text_handle_new (GTK_WIDGET (text_view));
g_signal_connect (priv->text_handles[i], "drag-started",
G_CALLBACK (gtk_text_view_handle_drag_started), text_view);
g_signal_connect (priv->text_handles[i], "handle-dragged",
G_CALLBACK (gtk_text_view_handle_dragged), text_view);
g_signal_connect (priv->text_handles[i], "drag-finished",
G_CALLBACK (gtk_text_view_handle_drag_finished), text_view);
}
}
static void
gtk_text_view_init (GtkTextView *text_view)
{
@ -1848,23 +1873,6 @@ gtk_text_view_get_selection_node (GtkTextView *text_view)
return text_view->priv->selection_node;
}
static void
_gtk_text_view_ensure_text_handles (GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
if (priv->text_handle)
return;
priv->text_handle = _gtk_text_handle_new (GTK_WIDGET (text_view));
g_signal_connect (priv->text_handle, "drag-started",
G_CALLBACK (gtk_text_view_handle_drag_started), text_view);
g_signal_connect (priv->text_handle, "handle-dragged",
G_CALLBACK (gtk_text_view_handle_dragged), text_view);
g_signal_connect (priv->text_handle, "drag-finished",
G_CALLBACK (gtk_text_view_handle_drag_finished), text_view);
}
static void
_gtk_text_view_ensure_magnifier (GtkTextView *text_view)
{
@ -2043,8 +2051,7 @@ gtk_text_view_set_buffer (GtkTextView *text_view,
gtk_text_buffer_add_selection_clipboard (priv->buffer, clipboard);
}
if (priv->text_handle)
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_NONE);
gtk_text_view_update_handles (text_view);
gtk_widget_action_set_enabled (GTK_WIDGET (text_view), "text.undo", can_undo);
gtk_widget_action_set_enabled (GTK_WIDGET (text_view), "text.redo", can_redo);
@ -2655,9 +2662,7 @@ gtk_text_view_flush_scroll (GtkTextView *text_view)
scroll->yalign,
TRUE);
if (text_view->priv->text_handle)
gtk_text_view_update_handles (text_view,
_gtk_text_handle_get_mode (text_view->priv->text_handle));
gtk_text_view_update_handles (text_view);
free_pending_scroll (scroll);
@ -3695,6 +3700,9 @@ gtk_text_view_destroy (GtkWidget *widget)
if (priv->magnifier)
_gtk_magnifier_set_inspected (GTK_MAGNIFIER (priv->magnifier), NULL);
g_clear_pointer ((GtkWidget **) &priv->text_handles[TEXT_HANDLE_CURSOR], gtk_widget_unparent);
g_clear_pointer ((GtkWidget **) &priv->text_handles[TEXT_HANDLE_SELECTION_BOUND], gtk_widget_unparent);
GTK_WIDGET_CLASS (gtk_text_view_parent_class)->destroy (widget);
}
@ -3737,8 +3745,6 @@ gtk_text_view_finalize (GObject *object)
if (priv->magnifier_popover)
gtk_widget_destroy (priv->magnifier_popover);
if (priv->text_handle)
g_object_unref (priv->text_handle);
g_object_unref (priv->im_context);
g_free (priv->im_module);
@ -4428,6 +4434,12 @@ gtk_text_view_size_allocate (GtkWidget *widget,
if (priv->popup_menu)
gtk_native_check_resize (GTK_NATIVE (priv->popup_menu));
if (priv->text_handles[TEXT_HANDLE_CURSOR])
gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_CURSOR]));
if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
gtk_native_check_resize (GTK_NATIVE (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
static void
@ -4861,8 +4873,8 @@ _widget_to_text_surface_coords (GtkTextView *text_view,
static void
gtk_text_view_set_handle_position (GtkTextView *text_view,
GtkTextIter *iter,
GtkTextHandlePosition pos)
GtkTextHandle *handle,
GtkTextIter *iter)
{
GtkTextViewPrivate *priv;
GdkRectangle rect;
@ -4874,32 +4886,32 @@ gtk_text_view_set_handle_position (GtkTextView *text_view,
x = rect.x - priv->xoffset;
y = rect.y - priv->yoffset;
if (!_gtk_text_handle_get_is_dragged (priv->text_handle, pos) &&
if (!gtk_text_handle_get_is_dragged (handle) &&
(x < 0 || x > SCREEN_WIDTH (text_view) ||
y < 0 || y > SCREEN_HEIGHT (text_view)))
{
/* Hide the handle if it's not being manipulated
* and fell outside of the visible text area.
*/
_gtk_text_handle_set_visible (priv->text_handle, pos, FALSE);
gtk_widget_hide (GTK_WIDGET (handle));
}
else
{
GtkTextDirection dir = GTK_TEXT_DIR_LTR;
GtkTextAttributes attributes = { 0 };
_gtk_text_handle_set_visible (priv->text_handle, pos, TRUE);
gtk_widget_show (GTK_WIDGET (handle));
rect.x = CLAMP (x, 0, SCREEN_WIDTH (text_view));
rect.y = CLAMP (y, 0, SCREEN_HEIGHT (text_view));
_text_window_to_widget_coords (text_view, &rect.x, &rect.y);
_gtk_text_handle_set_position (priv->text_handle, pos, &rect);
gtk_text_handle_set_position (handle, &rect);
if (gtk_text_iter_get_attributes (iter, &attributes))
dir = attributes.direction;
_gtk_text_handle_set_direction (priv->text_handle, pos, dir);
gtk_widget_set_direction (GTK_WIDGET (handle), dir);
}
}
@ -4949,22 +4961,16 @@ gtk_text_view_show_magnifier (GtkTextView *text_view,
static void
gtk_text_view_handle_dragged (GtkTextHandle *handle,
GtkTextHandlePosition pos,
gint x,
gint y,
GtkTextView *text_view)
{
GtkTextViewPrivate *priv;
GtkTextIter old_cursor, old_bound;
GtkTextIter cursor, bound, iter;
GtkTextIter *min, *max;
GtkTextHandleMode mode;
GtkTextIter cursor, bound, iter, *old_iter;
GtkTextBuffer *buffer;
GtkTextHandlePosition cursor_pos;
priv = text_view->priv;
buffer = get_buffer (text_view);
mode = _gtk_text_handle_get_mode (handle);
_widget_to_text_surface_coords (text_view, &x, &y);
@ -4972,83 +4978,72 @@ gtk_text_view_handle_dragged (GtkTextHandle *handle,
gtk_text_layout_get_iter_at_pixel (priv->layout, &iter,
x + priv->xoffset,
y + priv->yoffset);
gtk_text_buffer_get_iter_at_mark (buffer, &old_cursor,
gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
gtk_text_buffer_get_insert (buffer));
gtk_text_buffer_get_iter_at_mark (buffer, &old_bound,
gtk_text_buffer_get_iter_at_mark (buffer, &bound,
gtk_text_buffer_get_selection_bound (buffer));
cursor = old_cursor;
bound = old_bound;
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR ||
gtk_text_iter_compare (&cursor, &bound) >= 0)
{
cursor_pos = GTK_TEXT_HANDLE_POSITION_CURSOR;
max = &cursor;
min = &bound;
}
else
{
cursor_pos = GTK_TEXT_HANDLE_POSITION_SELECTION_START;
max = &bound;
min = &cursor;
}
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR])
{
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
gtk_text_iter_compare (&iter, min) <= 0)
/* Avoid running past the other handle in selection mode */
if (gtk_text_iter_compare (&iter, &bound) >= 0 &&
gtk_widget_is_visible (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])))
{
iter = *min;
gtk_text_iter_forward_char (&iter);
}
*max = iter;
gtk_text_view_set_handle_position (text_view, &iter, pos);
}
else
{
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
gtk_text_iter_compare (&iter, max) >= 0)
{
iter = *max;
iter = bound;
gtk_text_iter_backward_char (&iter);
}
*min = iter;
gtk_text_view_set_handle_position (text_view, &iter, pos);
old_iter = &cursor;
gtk_text_view_set_handle_position (text_view, handle, &iter);
}
else if (handle == priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
{
/* Avoid running past the other handle */
if (gtk_text_iter_compare (&iter, &cursor) <= 0)
{
iter = cursor;
gtk_text_iter_forward_char (&iter);
}
if (gtk_text_iter_compare (&old_cursor, &cursor) != 0 ||
gtk_text_iter_compare (&old_bound, &bound) != 0)
old_iter = &bound;
gtk_text_view_set_handle_position (text_view, handle, &iter);
}
else
g_assert_not_reached ();
if (gtk_text_iter_compare (&iter, old_iter) != 0)
{
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR)
*old_iter = iter;
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR] &&
!gtk_widget_is_visible (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])))
gtk_text_buffer_place_cursor (buffer, &cursor);
else
gtk_text_buffer_select_range (buffer, &cursor, &bound);
if (_gtk_text_handle_get_is_dragged (priv->text_handle, cursor_pos))
if (handle == priv->text_handles[TEXT_HANDLE_CURSOR])
{
text_view->priv->cursor_handle_dragged = TRUE;
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_insert (buffer));
}
else
else if (handle == priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
{
text_view->priv->selection_handle_dragged = TRUE;
gtk_text_view_scroll_mark_onscreen (text_view,
gtk_text_buffer_get_selection_bound (buffer));
}
gtk_text_view_update_handles (text_view);
}
if (_gtk_text_handle_get_is_dragged (priv->text_handle, cursor_pos))
gtk_text_view_show_magnifier (text_view, &cursor, x, y);
else
gtk_text_view_show_magnifier (text_view, &bound, x, y);
gtk_text_view_show_magnifier (text_view, &iter, x, y);
}
static void
gtk_text_view_handle_drag_started (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view)
{
text_view->priv->cursor_handle_dragged = FALSE;
@ -5057,7 +5052,6 @@ gtk_text_view_handle_drag_started (GtkTextHandle *handle,
static void
gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
GtkTextHandlePosition pos,
GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
@ -5079,7 +5073,7 @@ gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
extend_selection (text_view, SELECT_WORDS, &cursor, &start, &end);
gtk_text_buffer_select_range (buffer, &start, &end);
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
gtk_text_view_update_handles (text_view);
}
else
gtk_text_view_selection_bubble_popup_set (text_view);
@ -5092,13 +5086,22 @@ gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
static gboolean cursor_visible (GtkTextView *text_view);
static void
gtk_text_view_update_handles (GtkTextView *text_view,
GtkTextHandleMode mode)
gtk_text_view_update_handles (GtkTextView *text_view)
{
GtkTextViewPrivate *priv = text_view->priv;
GtkTextIter cursor, bound, min, max;
GtkTextIter cursor, bound;
GtkTextBuffer *buffer;
if (!priv->text_handles_enabled)
{
if (priv->text_handles[TEXT_HANDLE_CURSOR])
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
if (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
else
{
_gtk_text_view_ensure_text_handles (text_view);
buffer = get_buffer (text_view);
gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
@ -5106,38 +5109,41 @@ gtk_text_view_update_handles (GtkTextView *text_view,
gtk_text_buffer_get_iter_at_mark (buffer, &bound,
gtk_text_buffer_get_selection_bound (buffer));
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION &&
gtk_text_iter_compare (&cursor, &bound) == 0)
if (gtk_text_iter_compare (&cursor, &bound) == 0 && priv->editable)
{
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
/* Cursor mode */
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
gtk_text_view_set_handle_position (text_view,
priv->text_handles[TEXT_HANDLE_CURSOR],
&cursor);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_CURSOR);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
}
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
(!gtk_widget_is_sensitive (GTK_WIDGET (text_view)) || !cursor_visible (text_view)))
else if (gtk_text_iter_compare (&cursor, &bound) != 0)
{
mode = GTK_TEXT_HANDLE_MODE_NONE;
}
/* Selection mode */
gtk_text_view_set_handle_position (text_view,
priv->text_handles[TEXT_HANDLE_CURSOR],
&cursor);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_CURSOR],
GTK_TEXT_HANDLE_ROLE_SELECTION_START);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
_gtk_text_handle_set_mode (priv->text_handle, mode);
if (gtk_text_iter_compare (&cursor, &bound) >= 0)
{
min = bound;
max = cursor;
gtk_text_view_set_handle_position (text_view,
priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
&bound);
gtk_text_handle_set_role (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND],
GTK_TEXT_HANDLE_ROLE_SELECTION_END);
gtk_widget_show (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
else
{
min = cursor;
max = bound;
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_CURSOR]));
gtk_widget_hide (GTK_WIDGET (priv->text_handles[TEXT_HANDLE_SELECTION_BOUND]));
}
}
if (mode != GTK_TEXT_HANDLE_MODE_NONE)
gtk_text_view_set_handle_position (text_view, &max,
GTK_TEXT_HANDLE_POSITION_SELECTION_END);
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
gtk_text_view_set_handle_position (text_view, &min,
GTK_TEXT_HANDLE_POSITION_SELECTION_START);
}
static gboolean
@ -5199,9 +5205,8 @@ gtk_text_view_key_controller_key_pressed (GtkEventControllerKey *controller,
gtk_text_view_reset_blink_time (text_view);
gtk_text_view_pend_cursor_blink (text_view);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
text_view->priv->text_handles_enabled = FALSE;
gtk_text_view_update_handles (text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
@ -5312,7 +5317,6 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
}
else if (button == GDK_BUTTON_PRIMARY)
{
GtkTextHandleMode handle_mode = GTK_TEXT_HANDLE_MODE_NONE;
gboolean extends = FALSE;
GdkModifierType state;
@ -5332,8 +5336,7 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
*/
GtkTextIter start, end;
if (is_touchscreen)
handle_mode = GTK_TEXT_HANDLE_MODE_CURSOR;
priv->text_handles_enabled = is_touchscreen;
get_iter_from_gesture (text_view, GTK_GESTURE (gesture),
&iter, NULL, NULL);
@ -5348,12 +5351,11 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
!gtk_widget_get_visible (priv->selection_bubble))
{
gtk_text_view_selection_bubble_popup_set (text_view);
handle_mode = GTK_TEXT_HANDLE_MODE_NONE;
priv->text_handles_enabled = FALSE;
}
else
{
gtk_text_view_selection_bubble_popup_unset (text_view);
handle_mode = GTK_TEXT_HANDLE_MODE_SELECTION;
}
}
else
@ -5383,11 +5385,6 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
}
case 2:
case 3:
if (is_touchscreen)
{
handle_mode = GTK_TEXT_HANDLE_MODE_SELECTION;
break;
}
gtk_text_view_end_selection_drag (text_view);
get_iter_from_gesture (text_view, GTK_GESTURE (gesture),
@ -5400,8 +5397,7 @@ gtk_text_view_click_gesture_pressed (GtkGestureClick *gesture,
break;
}
_gtk_text_view_ensure_text_handles (text_view);
gtk_text_view_update_handles (text_view, handle_mode);
gtk_text_view_update_handles (text_view);
}
if (n_press >= 3)
@ -5468,9 +5464,8 @@ gtk_text_view_focus_out (GtkWidget *widget)
text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
text_view->priv->text_handles_enabled = FALSE;
gtk_text_view_update_handles (text_view);
if (priv->editable)
{
@ -6840,11 +6835,8 @@ gtk_text_view_buffer_changed_handler (GtkTextBuffer *buffer,
gpointer data)
{
GtkTextView *text_view = data;
GtkTextViewPrivate *priv = text_view->priv;
if (priv->text_handle)
gtk_text_view_update_handles (text_view,
_gtk_text_handle_get_mode (priv->text_handle));
gtk_text_view_update_handles (text_view);
}
static void
@ -7288,8 +7280,8 @@ gtk_text_view_drag_gesture_update (GtkGestureDrag *gesture,
if (is_touchscreen)
{
_gtk_text_view_ensure_text_handles (text_view);
gtk_text_view_update_handles (text_view, GTK_TEXT_HANDLE_MODE_SELECTION);
text_view->priv->text_handles_enabled = TRUE;
gtk_text_view_update_handles (text_view);
gtk_text_view_show_magnifier (text_view, &cursor, x, y);
}
}
@ -7338,7 +7330,6 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
if (!is_touchscreen && clicked_in_selection &&
!gtk_drag_check_threshold (GTK_WIDGET (text_view), start_x, start_y, x, y))
{
GtkTextHandleMode mode = GTK_TEXT_HANDLE_MODE_NONE;
GtkTextIter iter;
/* Unselect everything; we clicked inside selection, but
@ -7351,13 +7342,7 @@ gtk_text_view_drag_gesture_end (GtkGestureDrag *gesture,
gtk_text_buffer_place_cursor (get_buffer (text_view), &iter);
gtk_text_view_check_cursor_blink (text_view);
if (priv->text_handle)
{
if (is_touchscreen)
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
gtk_text_view_update_handles (text_view, mode);
}
gtk_text_view_update_handles (text_view);
}
}
@ -8094,9 +8079,7 @@ gtk_text_view_value_changed (GtkAdjustment *adjustment,
*/
gtk_text_view_update_im_spot_location (text_view);
if (priv->text_handle)
gtk_text_view_update_handles (text_view,
_gtk_text_handle_get_mode (priv->text_handle));
gtk_text_view_update_handles (text_view);
if (priv->anchored_children.length > 0)
gtk_widget_queue_allocate (GTK_WIDGET (text_view));
@ -8285,9 +8268,7 @@ gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
if (need_reset)
{
gtk_text_view_reset_im_context (text_view);
if (text_view->priv->text_handle)
gtk_text_view_update_handles (text_view,
_gtk_text_handle_get_mode (text_view->priv->text_handle));
gtk_text_view_update_handles (text_view);
has_selection = gtk_text_buffer_get_selection_bounds (get_buffer (text_view), NULL, NULL);
gtk_css_node_set_visible (text_view->priv->selection_node, has_selection);
@ -8697,21 +8678,10 @@ show_or_hide_handles (GtkWidget *popover,
GtkTextView *text_view)
{
gboolean visible;
GtkTextHandle *handle;
GtkTextHandleMode mode;
visible = gtk_widget_get_visible (popover);
handle = text_view->priv->text_handle;
mode = _gtk_text_handle_get_mode (handle);
if (!visible)
gtk_text_view_update_handles (text_view, mode);
else
{
_gtk_text_handle_set_visible (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_START, FALSE);
_gtk_text_handle_set_visible (handle, GTK_TEXT_HANDLE_POSITION_SELECTION_END, FALSE);
}
text_view->priv->text_handles_enabled = !visible;
gtk_text_view_update_handles (text_view);
}
static void