mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +00:00
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:
parent
2747dd5c9f
commit
0264a64f29
382
gtk/gtktext.c
382
gtk/gtktext.c
@ -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);
|
||||
@ -2118,21 +2126,21 @@ update_im_cursor_location (GtkText *self)
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_move_handle (GtkText *self,
|
||||
GtkTextHandlePosition pos,
|
||||
int x,
|
||||
int y,
|
||||
int height)
|
||||
gtk_text_move_handle (GtkText *self,
|
||||
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,45 +2181,65 @@ 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);
|
||||
|
||||
gtk_text_get_cursor_locations (self, &strong_x, NULL);
|
||||
cursor = strong_x - priv->scroll_offset;
|
||||
|
||||
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
|
||||
if (!priv->text_handles_enabled)
|
||||
{
|
||||
int start, end;
|
||||
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;
|
||||
|
||||
bound = gtk_text_get_selection_bound_location (self) - priv->scroll_offset;
|
||||
|
||||
if (priv->selection_bound > priv->current_pos)
|
||||
if (priv->selection_bound != priv->current_pos)
|
||||
{
|
||||
start = cursor;
|
||||
end = bound;
|
||||
int start, end;
|
||||
|
||||
bound = gtk_text_get_selection_bound_location (self) - priv->scroll_offset;
|
||||
|
||||
if (priv->selection_bound > priv->current_pos)
|
||||
{
|
||||
start = cursor;
|
||||
end = bound;
|
||||
}
|
||||
else
|
||||
{
|
||||
start = bound;
|
||||
end = cursor;
|
||||
}
|
||||
|
||||
/* Update start selection bound */
|
||||
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
|
||||
{
|
||||
start = bound;
|
||||
end = 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);
|
||||
}
|
||||
|
||||
/* 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,
|
||||
end, 0, text_height);
|
||||
}
|
||||
else
|
||||
gtk_text_move_handle (self, GTK_TEXT_HANDLE_POSITION_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));
|
||||
}
|
||||
@ -4542,84 +4518,67 @@ gtk_text_draw_cursor (GtkText *self,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_handle_dragged (GtkTextHandle *handle,
|
||||
GtkTextHandlePosition pos,
|
||||
int x,
|
||||
int y,
|
||||
GtkText *self)
|
||||
gtk_text_handle_dragged (GtkTextHandle *handle,
|
||||
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
|
||||
g_assert_not_reached ();
|
||||
|
||||
if (tmp_pos != *old_pos)
|
||||
{
|
||||
max = &selection_bound_pos;
|
||||
min = &cursor_pos;
|
||||
}
|
||||
*old_pos = tmp_pos;
|
||||
|
||||
if (pos == GTK_TEXT_HANDLE_POSITION_SELECTION_END)
|
||||
{
|
||||
if (mode == GTK_TEXT_HANDLE_MODE_SELECTION)
|
||||
{
|
||||
int min_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;
|
||||
gtk_text_set_positions (self, cursor_pos, cursor_pos);
|
||||
}
|
||||
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_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);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_handle_drag_started (GtkTextHandle *handle,
|
||||
GtkTextHandlePosition pos,
|
||||
GtkText *self)
|
||||
gtk_text_handle_drag_started (GtkTextHandle *handle,
|
||||
GtkText *self)
|
||||
{
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
|
||||
@ -4628,9 +4587,8 @@ gtk_text_handle_drag_started (GtkTextHandle *handle,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_handle_drag_finished (GtkTextHandle *handle,
|
||||
GtkTextHandlePosition pos,
|
||||
GtkText *self)
|
||||
gtk_text_handle_drag_finished (GtkTextHandle *handle,
|
||||
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
|
||||
|
1027
gtk/gtktexthandle.c
1027
gtk/gtktexthandle.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -4860,9 +4872,9 @@ _widget_to_text_surface_coords (GtkTextView *text_view,
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_set_handle_position (GtkTextView *text_view,
|
||||
GtkTextIter *iter,
|
||||
GtkTextHandlePosition pos)
|
||||
gtk_text_view_set_handle_position (GtkTextView *text_view,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4948,23 +4960,17 @@ 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)
|
||||
gtk_text_view_handle_dragged (GtkTextHandle *handle,
|
||||
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,93 +4978,81 @@ 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);
|
||||
}
|
||||
|
||||
if (gtk_text_iter_compare (&old_cursor, &cursor) != 0 ||
|
||||
gtk_text_iter_compare (&old_bound, &bound) != 0)
|
||||
else if (handle == priv->text_handles[TEXT_HANDLE_SELECTION_BOUND])
|
||||
{
|
||||
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR)
|
||||
/* Avoid running past the other handle */
|
||||
if (gtk_text_iter_compare (&iter, &cursor) <= 0)
|
||||
{
|
||||
iter = cursor;
|
||||
gtk_text_iter_forward_char (&iter);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
*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)
|
||||
gtk_text_view_handle_drag_started (GtkTextHandle *handle,
|
||||
GtkTextView *text_view)
|
||||
{
|
||||
text_view->priv->cursor_handle_dragged = FALSE;
|
||||
text_view->priv->selection_handle_dragged = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
|
||||
GtkTextHandlePosition pos,
|
||||
GtkTextView *text_view)
|
||||
gtk_text_view_handle_drag_finished (GtkTextHandle *handle,
|
||||
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,52 +5086,64 @@ 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;
|
||||
|
||||
buffer = get_buffer (text_view);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
|
||||
gtk_text_buffer_get_insert (buffer));
|
||||
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 (!priv->text_handles_enabled)
|
||||
{
|
||||
mode = GTK_TEXT_HANDLE_MODE_CURSOR;
|
||||
}
|
||||
|
||||
if (mode == GTK_TEXT_HANDLE_MODE_CURSOR &&
|
||||
(!gtk_widget_is_sensitive (GTK_WIDGET (text_view)) || !cursor_visible (text_view)))
|
||||
{
|
||||
mode = GTK_TEXT_HANDLE_MODE_NONE;
|
||||
}
|
||||
|
||||
_gtk_text_handle_set_mode (priv->text_handle, mode);
|
||||
|
||||
if (gtk_text_iter_compare (&cursor, &bound) >= 0)
|
||||
{
|
||||
min = bound;
|
||||
max = cursor;
|
||||
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
|
||||
{
|
||||
min = cursor;
|
||||
max = bound;
|
||||
_gtk_text_view_ensure_text_handles (text_view);
|
||||
buffer = get_buffer (text_view);
|
||||
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &cursor,
|
||||
gtk_text_buffer_get_insert (buffer));
|
||||
gtk_text_buffer_get_iter_at_mark (buffer, &bound,
|
||||
gtk_text_buffer_get_selection_bound (buffer));
|
||||
|
||||
if (gtk_text_iter_compare (&cursor, &bound) == 0 && priv->editable)
|
||||
{
|
||||
/* 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]));
|
||||
}
|
||||
else if (gtk_text_iter_compare (&cursor, &bound) != 0)
|
||||
{
|
||||
/* 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_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
|
||||
{
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user