summaryrefslogtreecommitdiff
path: root/libview
diff options
context:
space:
mode:
authorVictor Kareh <[email protected]>2026-08-07 15:28:33 -0400
committerVictor Kareh <[email protected]>2026-08-11 18:35:35 +0000
commit33a2a3fc73a9b4bb3173f876fec6180d414352ed (patch)
tree606d765039e3ec25dd0c5ee69e186d438adcb69e /libview
parentd6803f25d858bafc0cf4f6cec6dbfd7cc5980381 (diff)
downloadatril-33a2a3fc73a9b4bb3173f876fec6180d414352ed.tar.bz2
atril-33a2a3fc73a9b4bb3173f876fec6180d414352ed.tar.xz
a11y: report selection changes only on pages that actually changedHEADmaster
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.c76
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