Skip to content

Commit

Permalink
Fix warp pointer if focus window on another monitor (#839)
Browse files Browse the repository at this point in the history
Fixes a related issue partly described in #837.

Note that in Gnome 45+, PaperWM `alt`+`tab` does indeed switch through
all windows across spaces and monitors (by default). However, an issue
does occur that if we switch to (and focus) a window on another monitor
via `alt`+`tab` etc., when we move the mouse focus will be pulled to the
monitor that the mouse is on.

This PR fixes this by warping the mouse pointer to the new monitor if
needed (along with a mouse pointer ripple effect).

This PR also now links the behaviour for showing `all` windows or `only
windows from current space` in PaperWM to the Gnome Multitasking
setting:


![image](https://github.com/paperwm/PaperWM/assets/30424662/b49736a5-a105-4534-a98b-2300f5a399e0)
  • Loading branch information
jtaala authored Apr 26, 2024
2 parents 82535f7 + 9fa5084 commit 8472ed6
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 38 deletions.
34 changes: 18 additions & 16 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
env:
es2021: true
extends: 'eslint:recommended'
#plugins:
# - jsdoc
# plugins:
# - jsdoc
rules:
array-bracket-newline:
- error
Expand Down Expand Up @@ -66,20 +66,21 @@ rules:
- 'CallExpression[callee.object.name=GObject][callee.property.name=registerClass] > ClassExpression:first-child'
# Allow dedenting chained member expressions
MemberExpression: 'off'
jsdoc/check-alignment: error
jsdoc/check-param-names: error
jsdoc/check-tag-names: error
jsdoc/check-types: error
jsdoc/implements-on-classes: error
jsdoc/tag-lines:
- error
- any
- startLines: 1
jsdoc/require-jsdoc: error
jsdoc/require-param: error
jsdoc/require-param-description: error
jsdoc/require-param-name: error
jsdoc/require-param-type: error
# # disabling jsdoc while as plugin jsdoc is disabled (have always had issues with plugin)
# jsdoc/check-alignment: error
# jsdoc/check-param-names: error
# jsdoc/check-tag-names: error
# jsdoc/check-types: error
# jsdoc/implements-on-classes: error
# jsdoc/tag-lines:
# - error
# - any
# - startLines: 1
# jsdoc/require-jsdoc: error
# jsdoc/require-param: error
# jsdoc/require-param-description: error
# jsdoc/require-param-name: error
# jsdoc/require-param-type: error
key-spacing:
- error
- beforeColon: false
Expand Down Expand Up @@ -259,6 +260,7 @@ globals:
ARGV: readonly
Debugger: readonly
GIRepositoryGType: readonly
global: readonly
globalThis: readonly
imports: readonly
Intl: readonly
Expand Down
9 changes: 5 additions & 4 deletions liveAltTab.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,26 @@ import GObject from 'gi://GObject';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as AltTab from 'resource:///org/gnome/shell/ui/altTab.js';

import { Settings, Keybindings, Tiling, Scratch } from './imports.js';
import { Utils, Settings, Keybindings, Tiling, Scratch } from './imports.js';
import { Easer } from './utils.js';

let switcherSettings;
export function enable() {
switcherSettings = new Gio.Settings({
schema_id: 'org.gnome.shell.window-switcher',
schema_id: 'org.gnome.shell.app-switcher',
});
}

export function disable() {
switcherSettings = null;
}

export function liveAltTab(meta_window, space, { display, screen, binding }) {
export function liveAltTab(meta_window, space, { _display, _screen, binding }) {
let tabPopup = new LiveAltTab(binding.is_reversed(), false);
tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask());
}

export function liveAltTabScratch(meta_window, space, { display, screen, binding }) {
export function liveAltTabScratch(meta_window, space, { _display, _screen, binding }) {
let tabPopup = new LiveAltTab(binding.is_reversed(), true);
tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask());
}
Expand Down Expand Up @@ -154,6 +154,7 @@ export const LiveAltTab = GObject.registerClass(
// accepted. This can cause _select to run on the item below the pointer
// ensuring the wrong window.
if (!this.was_accepted) {
// eslint-disable-next-line prefer-rest-params
super._itemEnteredHandler.apply(this, arguments);
}
}
Expand Down
6 changes: 6 additions & 0 deletions tiling.js
Original file line number Diff line number Diff line change
Expand Up @@ -4227,6 +4227,12 @@ export function focus_handler(metaWindow) {
}

let space = spaces.spaceOfWindow(metaWindow);

// if window is on another monitor then warp pointer there
if (Utils.monitorAtCurrentPoint() !== space.monitor) {
Utils.warpPointerToMonitor(space.monitor);
}

if (metaWindow.fullscreen) {
space.enableWindowPositionBar(false);
space.setSpaceTopbarElementsVisible(false);
Expand Down
36 changes: 18 additions & 18 deletions utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,34 +215,40 @@ export function monitorAtPoint(gx, gy) {
* Returns the monitor current pointer coordinates.
*/
export function monitorAtCurrentPoint() {
let [gx, gy, $] = getPointerCoords();
let [gx, gy] = getPointerCoords();
return monitorAtPoint(gx, gy);
}

/**
* Warps pointer to the center of a monitor.
*/
export function warpPointerToMonitor(monitor, center = false) {
export function warpPointerToMonitor(monitor, params = { center: false, ripple: true }) {
const center = params?.center ?? false;
const ripple = params?.ripple ?? true;

// no need to warp if already on this monitor
let currMonitor = monitorAtCurrentPoint();
if (currMonitor === monitor) {
return;
}

let [x, y, _mods] = global.get_pointer();
let [x, y] = global.get_pointer();
if (center) {
x -= monitor.x;
y -= monitor.y;
warpPointer(monitor.x + Math.floor(monitor.width / 2),
monitor.y + Math.floor(monitor.height / 2));
warpPointer(
monitor.x + Math.floor(monitor.width / 2),
monitor.y + Math.floor(monitor.height / 2),
ripple);
return;
}

let proportionalX = (x - currMonitor.x) / currMonitor.width;
let proportionalY = (y - currMonitor.y) / currMonitor.height;
warpPointer(
monitor.x + Math.floor(proportionalX * monitor.width),
monitor.y + Math.floor(proportionalY * monitor.height)
monitor.y + Math.floor(proportionalY * monitor.height),
ripple
);
}

Expand All @@ -262,7 +268,7 @@ export function warpPointer(x, y, ripple = true) {
* Return current modifiers state (or'ed Clutter.ModifierType.*)
*/
export function getModiferState() {
let [x, y, mods] = global.get_pointer();
let [, , mods] = global.get_pointer();
return mods;
}

Expand Down Expand Up @@ -294,6 +300,7 @@ export function mkFmt({ nameOnly } = { nameOnly: false }) {
const extraStr = extra.join(" | ");
let actorId = "";
if (nameOnly) {
// eslint-disable-next-line no-nested-ternary, eqeqeq
actorId = actor.name ? actor.name : prefix.length == 0 ? "" : "#";
} else {
actorId = actor.toString();
Expand Down Expand Up @@ -379,14 +386,7 @@ export function actor_reparent(actor, newParent) {
* Backwards compatible later_add function.
*/
export function later_add(...args) {
// Gnome 44+ uses global.compositor.get_laters()
if (global.compositor?.get_laters) {
global.compositor.get_laters().add(...args);
}
// Gnome 42, 43 used Meta.later_add
else if (Meta.later_add) {
Meta.later_add(...args);
}
global.compositor.get_laters().add(...args);
}

/**
Expand Down Expand Up @@ -563,10 +563,10 @@ export class DisplayConfig {
return;
}

const [serial, monitors, logicalMonitors] = state;
const [, monitors] = state;
for (const monitor of monitors) {
const [specs, modes, props] = monitor;
const [connector, vendor, product, serial] = specs;
const [specs] = monitor;
const [connector] = specs;

// upgrade gnome monitor object to add connector
let gnomeIndex = this.monitorManager.get_monitor_for_connector(connector);
Expand Down

0 comments on commit 8472ed6

Please sign in to comment.