Skip to content

Commit a7d0b8d

Browse files
cwendlingraveit65
authored andcommitted
EvView: Fix cursor movement when logical and visual line order differs
Make sure not to move the caret in the wrong direction when restoring the visual line X offset, in case the visual and logical order is slightly different. The algorithm used to move the cursor on the next line and restore the X position across lines works as follows: 1. Move `cursor_offset` to the next line by incrementing it until reaching a line break; 2. Find the Y coordinate corresponding to the new cursor_offset; 3. Find the text closest to the new Y coordinate and the previous X coordinate. 4. Move cursor_offset to the text at this new (X, Y) location. The issue lies in step 3, which can find a position on a different line than expected in case several lines have a nearly the same Y position. Evince references: * https://gitlab.gnome.org/GNOME/evince/issues/889 * https://gitlab.gnome.org/GNOME/evince/merge_requests/81 * https://gitlab.gnome.org/GNOME/evince/commit/dddd98b4c7922e2906bba6a31afa07837ae6c39c
1 parent f4a7715 commit a7d0b8d

File tree

1 file changed

+10
-0
lines changed

1 file changed

+10
-0
lines changed

libview/ev-view.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5406,6 +5406,7 @@ ev_view_move_cursor (EvView *view,
54065406
gint prev_page;
54075407
cairo_region_t *damage_region;
54085408
gboolean clear_selections = FALSE;
5409+
const gboolean forward = count >= 0;
54095410

54105411
if (!view->caret_enabled || view->rotation != 0)
54115412
return FALSE;
@@ -5475,9 +5476,18 @@ ev_view_move_cursor (EvView *view,
54755476
return TRUE;
54765477

54775478
if (step == GTK_MOVEMENT_DISPLAY_LINES) {
5479+
const gint prev_cursor_offset = view->cursor_offset;
5480+
54785481
position_caret_cursor_at_location (view,
54795482
MAX (rect.x, view->cursor_line_offset),
54805483
rect.y + (rect.height / 2));
5484+
/* Make sure we didn't move the cursor in the wrong direction
5485+
* in case the visual order isn't the same as the logical one,
5486+
* in order to avoid cursor movement loops */
5487+
if ((forward && prev_cursor_offset > view->cursor_offset) ||
5488+
(!forward && prev_cursor_offset < view->cursor_offset)) {
5489+
view->cursor_offset = prev_cursor_offset;
5490+
}
54815491
if (!clear_selections &&
54825492
prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
54835493
gtk_widget_error_bell (GTK_WIDGET (view));

0 commit comments

Comments
 (0)