diff options
| author | Victor Kareh <[email protected]> | 2026-08-07 15:28:33 -0400 |
|---|---|---|
| committer | Victor Kareh <[email protected]> | 2026-08-11 18:35:35 +0000 |
| commit | 33a2a3fc73a9b4bb3173f876fec6180d414352ed (patch) | |
| tree | 606d765039e3ec25dd0c5ee69e186d438adcb69e /libview | |
| parent | d6803f25d858bafc0cf4f6cec6dbfd7cc5980381 (diff) | |
| download | atril-33a2a3fc73a9b4bb3173f876fec6180d414352ed.tar.bz2 atril-33a2a3fc73a9b4bb3173f876fec6180d414352ed.tar.xz | |
The previous fix notified every page that currently has a selection, but
that still got the wrong page: removing a selection on one page while
another page's selection stays untouched reported the change on the
untouched page instead of the one it actually happened on.
Now we compare against the previous selection state and only notify
pages that gained, lost, or changed a selection.
Fixes #721
Diffstat (limited to 'libview')
| -rw-r--r-- | libview/ev-view-accessible.c | 76 |
1 files changed, 72 insertions, 4 deletions
diff --git a/libview/ev-view-accessible.c b/libview/ev-view-accessible.c index 5e23ef92..1b21e0f4 100644 --- a/libview/ev-view-accessible.c +++ b/libview/ev-view-accessible.c @@ -65,6 +65,10 @@ struct _EvViewAccessiblePrivate { gint end_page; GPtrArray *children; + + /* Selection state as of the last "text-selection-changed" event, + * for diffing which pages actually changed. */ + GList *previous_selections; }; G_DEFINE_TYPE_WITH_CODE (EvViewAccessible, ev_view_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE, @@ -111,6 +115,9 @@ ev_view_accessible_finalize (GObject *object) for (i = 0; i < LAST_ACTION; i++) g_free (priv->action_descriptions [i]); + g_list_free_full (priv->previous_selections, g_free); + priv->previous_selections = NULL; + clear_children (EV_VIEW_ACCESSIBLE (object)); G_OBJECT_CLASS (ev_view_accessible_parent_class)->finalize (object); @@ -338,15 +345,46 @@ ev_view_accessible_cursor_moved (EvView *view, g_signal_emit_by_name (page_accessible, "text-caret-moved", offset); } +typedef struct { + gint page; + EvRectangle rect; +} SelectionSnapshot; + +static SelectionSnapshot * +find_selection_snapshot (GList *snapshots, + gint page) +{ + GList *l; + + for (l = snapshots; l != NULL; l = l->next) { + SelectionSnapshot *snapshot = l->data; + + if (snapshot->page == page) + return snapshot; + } + + return NULL; +} + +static gboolean +selection_rect_equal (EvRectangle *a, + EvRectangle *b) +{ + return a->x1 == b->x1 && a->y1 == b->y1 && + a->x2 == b->x2 && a->y2 == b->y2; +} + static void ev_view_accessible_selection_changed (EvView *view, EvViewAccessible *view_accessible) { + EvViewAccessiblePrivate *priv = view_accessible->priv; AtkObject *page_accessible; GList *l; + GList *current = NULL; - if (view->selection_info.selections == NULL) { - page_accessible = g_ptr_array_index (view_accessible->priv->children, + if (view->selection_info.selections == NULL && priv->previous_selections == NULL) { + page_accessible = g_ptr_array_index (priv->children, get_relevant_page (view)); g_signal_emit_by_name (page_accessible, "text-selection-changed"); return; @@ -358,11 +396,41 @@ ev_view_accessible_selection_changed (EvView *view, * currently considers "current" (e.g. via AT-SPI). */ for (l = view->selection_info.selections; l != NULL; l = l->next) { EvViewSelection *selection = (EvViewSelection *) l->data; + SelectionSnapshot *snapshot = g_new (SelectionSnapshot, 1); + + snapshot->page = selection->page; + snapshot->rect = selection->rect; + current = g_list_prepend (current, snapshot); + } + current = g_list_reverse (current); + + /* Only notify pages that their selection differs from last time. + * A page untouched by this change shouldn't get random events. */ + for (l = current; l != NULL; l = l->next) { + SelectionSnapshot *new_snapshot = l->data; + SelectionSnapshot *old_snapshot = + find_selection_snapshot (priv->previous_selections, new_snapshot->page); + + if (old_snapshot != NULL && selection_rect_equal (&old_snapshot->rect, &new_snapshot->rect)) + continue; - page_accessible = g_ptr_array_index (view_accessible->priv->children, - selection->page); + page_accessible = g_ptr_array_index (priv->children, new_snapshot->page); g_signal_emit_by_name (page_accessible, "text-selection-changed"); } + + /* A page that dropped out of the list lost its selection entirely. */ + for (l = priv->previous_selections; l != NULL; l = l->next) { + SelectionSnapshot *old_snapshot = l->data; + + if (find_selection_snapshot (current, old_snapshot->page) != NULL) + continue; + + page_accessible = g_ptr_array_index (priv->children, old_snapshot->page); + g_signal_emit_by_name (page_accessible, "text-selection-changed"); + } + + g_list_free_full (priv->previous_selections, g_free); + priv->previous_selections = current; } static void |
