summaryrefslogtreecommitdiff
path: root/0001-magnifier-Request-window-relative-coordinates-for-fo.patch
diff options
context:
space:
mode:
Diffstat (limited to '0001-magnifier-Request-window-relative-coordinates-for-fo.patch')
-rw-r--r--0001-magnifier-Request-window-relative-coordinates-for-fo.patch148
1 files changed, 148 insertions, 0 deletions
diff --git a/0001-magnifier-Request-window-relative-coordinates-for-fo.patch b/0001-magnifier-Request-window-relative-coordinates-for-fo.patch
new file mode 100644
index 0000000..0ebffe9
--- /dev/null
+++ b/0001-magnifier-Request-window-relative-coordinates-for-fo.patch
@@ -0,0 +1,148 @@
+From ea7e7acd45e428cc17306de2bf65730c90d7e118 Mon Sep 17 00:00:00 2001
+From: Sebastian Keller <skeller@gnome.org>
+Date: Mon, 23 May 2022 23:01:23 +0200
+Subject: [PATCH] magnifier: Request window-relative coordinates for
+ focus/caret events
+
+Absolute screen coordinates are impossible for Wayland clients to
+provide, because the clients don't know where the window is positioned.
+Some clients, such as the ones using GTK 3 were providing window
+relative coordinates even when screen coordinates were requested,
+while others, such as GTK 4 clients, were just returning an error for
+caret events or also window-relative coordinates for focus events.
+
+So for this to work on Wayland we have to request window-relative
+coordinates and translate them to the current focus window.
+
+To ensure the correct coordinates, we have to only consider events
+coming from the current focus window. All other events are filtered out
+now. As a side effect this also fixes the magnifier always jumping
+to a terminal cursor whenever there was some output, even if the window
+was not focused.
+
+This also needs some special handling for events coming from the shell
+itself, which should not be translated to the focus window either. As
+another side effect this fixes another bug that was caused by these
+events already including scaling and getting scaled again.
+
+Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/5509
+Part-of:
+<https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2301>
+---
+ js/ui/magnifier.js | 77 +++++++++++++++++++++++++++++++++++++++++-----
+ 1 file changed, 70 insertions(+), 7 deletions(-)
+
+diff --git a/js/ui/magnifier.js b/js/ui/magnifier.js
+index 4c2e88f1a..9813664be 100644
+--- a/js/ui/magnifier.js
++++ b/js/ui/magnifier.js
+@@ -789,21 +789,81 @@ var ZoomRegion = class ZoomRegion {
+ }
+ }
+
++ _convertExtentsToScreenSpace(accessible, extents) {
++ const toplevelWindowTypes = new Set([
++ Atspi.Role.FRAME,
++ Atspi.Role.DIALOG,
++ Atspi.Role.WINDOW,
++ ]);
++
++ try {
++ let app = null;
++ let parentWindow = null;
++ let iter = accessible;
++ while (iter) {
++ if (iter.get_role() === Atspi.Role.APPLICATION) {
++ app = iter;
++ /* This is the last Accessible we are interested in */
++ break;
++ } else if (toplevelWindowTypes.has(iter.get_role())) {
++ parentWindow = iter;
++ }
++ iter = iter.get_parent();
++ }
++
++ /* We don't want to translate our own events to the focus window.
++ * They are also already scaled by clutter before being sent, so
++ * we don't need to do that here either. */
++ if (app && app.get_name() === 'gnome-shell')
++ return extents;
++
++ /* Only events from the focused widget of the focused window. Some
++ * widgets seem to claim to have focus when the window does not so
++ * check both. */
++ const windowActive = parentWindow &&
++ parentWindow.get_state_set().contains(Atspi.StateType.ACTIVE);
++ const accessibleFocused =
++ accessible.get_state_set().contains(Atspi.StateType.FOCUSED);
++ if (!windowActive || !accessibleFocused)
++ return null;
++ } catch (e) {
++ throw new Error(`Failed to validate parent window: ${e}`);
++ }
++
++ const focusWindowRect = global.display.focus_window?.get_frame_rect();
++ if (!focusWindowRect)
++ return null;
++
++ const scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
++ const screenSpaceExtents = new Atspi.Rect({
++ x: focusWindowRect.x + (scaleFactor * extents.x),
++ y: focusWindowRect.y + (scaleFactor * extents.y),
++ width: scaleFactor * extents.width,
++ height: scaleFactor * extents.height,
++ });
++
++ return screenSpaceExtents;
++ }
++
+ _updateFocus(caller, event) {
+ let component = event.source.get_component_iface();
+ if (!component || event.detail1 != 1)
+ return;
+ let extents;
+ try {
+- extents = component.get_extents(Atspi.CoordType.SCREEN);
++ extents = component.get_extents(Atspi.CoordType.WINDOW);
++ extents = this._convertExtentsToScreenSpace(event.source, extents);
++ if (!extents)
++ return;
+ } catch (e) {
+ log(`Failed to read extents of focused component: ${e.message}`);
+ return;
+ }
+
+- let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
+- let [xFocus, yFocus] = [(extents.x + (extents.width / 2)) * scaleFactor,
+- (extents.y + (extents.height / 2)) * scaleFactor];
++ const [xFocus, yFocus] = [
++ extents.x + (extents.width / 2),
++ extents.y + (extents.height / 2),
++ ];
+
+ if (this._xFocus !== xFocus || this._yFocus !== yFocus) {
+ [this._xFocus, this._yFocus] = [xFocus, yFocus];
+@@ -817,14 +877,17 @@ var ZoomRegion = class ZoomRegion {
+ return;
+ let extents;
+ try {
+- extents = text.get_character_extents(text.get_caret_offset(), 0);
++ extents = text.get_character_extents(text.get_caret_offset(),
++ Atspi.CoordType.WINDOW);
++ extents = this._convertExtentsToScreenSpace(text, extents);
++ if (!extents)
++ return;
+ } catch (e) {
+ log(`Failed to read extents of text caret: ${e.message}`);
+ return;
+ }
+
+- let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
+- let [xCaret, yCaret] = [extents.x * scaleFactor, extents.y * scaleFactor];
++ const [xCaret, yCaret] = [extents.x, extents.y];
+
+ // Ignore event(s) if the caret size is none (0x0). This happens a lot if
+ // the cursor offset can't be translated into a location. This is a work
+--
+2.38.1
+