Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add option to enable/disable "multimonitor focus follows mouse" #755

Draft
wants to merge 12 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Settings.ui
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,43 @@
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">False</property>
<property name="focusable">False</property>
<child>
<object class="GtkGrid">
<property name="focusable">False</property>
<property name="tooltip_text" translatable="yes">Monitor focus/activation follows mouse movement</property>
<property name="margin_start">12</property>
<property name="margin_end">12</property>
<property name="margin_top">6</property>
<property name="margin_bottom">6</property>
<property name="column_spacing">32</property>
<child>
<object class="GtkLabel">
<property name="focusable">False</property>
<property name="hexpand">1</property>
<property name="label" translatable="yes">Monitor focus follows mouse</property>
<property name="xalign">0</property>
<layout>
<property name="column">0</property>
<property name="row">0</property>
</layout>
</object>
</child>
<child>
<object class="GtkSwitch" id="monitor-focus-follows-mouse">
<layout>
<property name="column">1</property>
<property name="row">0</property>
</layout>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
Expand Down
56 changes: 20 additions & 36 deletions grab.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,6 @@ import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import { Settings, Utils, Tiling, Navigator, Scratch } from './imports.js';
import { Easer } from './utils.js';

/**
* Returns a virtual pointer (i.e. mouse) device that can be used to
* "clickout" of a drag operation when `grab_end_op` is unavailable
* (i.e. as of Gnome 44 where `grab_end_op` was removed).
* @returns Clutter.VirtualInputDevice
*/
let virtualPointer;
export function getVirtualPointer() {
if (!virtualPointer) {
virtualPointer = Clutter.get_default_backend()
.get_default_seat()
.create_virtual_device(Clutter.InputDeviceType.POINTER_DEVICE);
}

return virtualPointer;
}

export class MoveGrab {
constructor(metaWindow, type, space) {
this.window = metaWindow;
Expand All @@ -38,6 +21,8 @@ export class MoveGrab {
// save whether this was tiled window at start of grab
this.wasTiled = !(this.initialSpace.isFloating(metaWindow) ||
Scratch.isScratchWindow(metaWindow));

this.dndTargets = [];
}

begin({ center } = {}) {
Expand Down Expand Up @@ -286,11 +271,12 @@ export class MoveGrab {
};

if (!sameTarget(target, this.dndTarget)) {
// deactivate only if target exists
// has a new zone target
if (target) {
this.deactivateDndTarget(this.dndTarget);
this.activateDndTarget(target, initial);
this.dndTargets.push(target);
}
this.dndTarget = null;
this.activateDndTarget(target, initial);
}
}

Expand Down Expand Up @@ -369,7 +355,7 @@ export class MoveGrab {

if (dndTarget) {
let space = dndTarget.space;
space.selection.show();
space.showSelection();

if (Scratch.isScratchWindow(metaWindow))
Scratch.unmakeScratch(metaWindow);
Expand Down Expand Up @@ -411,6 +397,7 @@ export class MoveGrab {
metaWindow.move_frame(true, clone.x, clone.y);
Scratch.makeScratch(metaWindow);
this.initialSpace.moveDone();
this.initialSpace.showSelection();

actor.set_scale(clone.scale_x, clone.scale_y);
actor.opacity = clone.opacity;
Expand Down Expand Up @@ -480,21 +467,15 @@ export class MoveGrab {
*/
Utils.later_add(Meta.LaterType.IDLE, () => {
if (!global.display.end_grab_op && this.wasTiled) {
// move to current cursor position
let [x, y, _mods] = global.get_pointer();
getVirtualPointer().notify_absolute_motion(
Clutter.get_current_event_time(),
x, y);

getVirtualPointer().notify_button(Clutter.get_current_event_time(),
Clutter.BUTTON_PRIMARY, Clutter.ButtonState.PRESSED);
getVirtualPointer().notify_button(Clutter.get_current_event_time(),
Clutter.BUTTON_PRIMARY, Clutter.ButtonState.RELEASED);
Utils.clickAtCursorPoint();
}
});
}

activateDndTarget(zone, first) {
if (!zone) {
return;
}
const mkZoneActor = props => {
let actor = new St.Widget({ style_class: "tile-preview" });
actor.x = props.x ?? 0;
Expand All @@ -506,6 +487,10 @@ export class MoveGrab {

zone.actor = mkZoneActor({ ...zone.actorParams });

// deactivate previous target
this.dndTargets.filter(t => t !== zone).forEach(t => this.deactivateDndTarget(t));
this.dndTargets = [zone];

this.dndTarget = zone;
this.zoneActors.add(zone.actor);
const raise = () => Utils.actor_raise(zone.actor);
Expand All @@ -532,26 +517,25 @@ export class MoveGrab {
}

zone.space.cloneContainer.add_child(zone.actor);
zone.space.selection.hide();
zone.space.hideSelection();
zone.actor.show();
raise();
Easer.addEase(zone.actor, params);
}

deactivateDndTarget(zone) {
if (zone) {
zone.space.selection.show();
zone.space.showSelection();
Easer.addEase(zone.actor, {
time: Settings.prefs.animation_time,
[zone.originProp]: zone.center,
[zone.sizeProp]: 0,
onComplete: () => { zone.actor.destroy();
onComplete: () => {
zone.actor.destroy();
this.zoneActors.delete(zone.actor);
},
});
}

this.dndTarget = null;
}
}

Expand Down
12 changes: 6 additions & 6 deletions minimap.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ export class Minimap extends Array {
let container = new St.Widget({ name: 'minimap-container' });
this.container = container;

actor.add_actor(highlight);
actor.add_child(highlight);
actor.add_actor(label);
actor.add_actor(clip);
clip.add_actor(container);
actor.add_child(clip);
clip.add_child(container);
clip.set_position(12 + Settings.prefs.window_gap, 12 + Math.round(1.5 * Settings.prefs.window_gap));
highlight.y = clip.y - 10;
Main.uiGroup.add_actor(this.actor);
Main.uiGroup.add_child(this.actor);
this.actor.opacity = 0;
this.createClones();

Expand Down Expand Up @@ -143,8 +143,8 @@ export class Minimap extends Array {
clone.meta_window = mw;
container.clone = clone;
container.meta_window = mw;
container.add_actor(clone);
this.container.add_actor(container);
container.add_child(clone);
this.container.add_child(container);
return container;
}

Expand Down
54 changes: 40 additions & 14 deletions patches.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,21 +140,47 @@ export function setupOverrides() {
// WorkspaceAnimation.WorkspaceAnimationController.animateSwitch
// Disable the workspace switching animation in Gnome 40+
function (_from, _to, _direction, onComplete) {
// ensure swipeTrackers are disabled after this
const reset = () => {
// gnome windows switch animation time = 250, do that plus a little more
pillSwipeTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 300, () => {
swipeTrackers.forEach(t => {
t.enabled = false;
});
pillSwipeTimer = null;
return false; // on return false destroys timeout
});
};

if (Tiling.inPreview) {
onComplete();
reset();
return;
}

// if using PaperWM workspace switch animation, just do complete here
if (Tiling.inPreview || !Tiling.spaces.space_defaultAnimation) {
if (!Tiling.spaces.space_defaultAnimation) {
onComplete();
reset();
return;
}
else {
const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, 'animateSwitch');
saved.call(this, _from, _to, _direction, onComplete);

// if switching to a paperwm space that is already shown on a monitor
// from / to are workspace indices
const toSpace = Tiling.spaces.spaceOfIndex(_to);

const spaces = Array.from(Tiling.spaces.monitors.values());
const toOnMonitor = spaces.some(space => space === toSpace);
if (toOnMonitor) {
onComplete();
reset();
return;
}

// ensure swipeTrackers are disabled after this
pillSwipeTimer = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
swipeTrackers.forEach(t => t.enabled = false);
pillSwipeTimer = null;
return false; // on return false destroys timeout
});
// standard gnome switch animation
const saved = getSavedPrototype(WorkspaceAnimation.WorkspaceAnimationController, 'animateSwitch');
saved.call(this, _from, _to, _direction, onComplete);
reset();
});

registerOverridePrototype(WorkspaceAnimation.WorkspaceAnimationController, '_prepareWorkspaceSwitch',
Expand Down Expand Up @@ -321,21 +347,21 @@ export function setupOverrides() {
}
switch (mode) {
case AppIconMode.THUMBNAIL_ONLY:
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
this._icon.add_child(_createWindowClone(mutterWindow, size * scaleFactor));
break;

case AppIconMode.BOTH:
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
this._icon.add_child(_createWindowClone(mutterWindow, size * scaleFactor));

if (this.app) {
this._icon.add_actor(
this._icon.add_child(
this._createAppIcon(this.app, APP_ICON_SIZE_SMALL));
}
break;

case AppIconMode.APP_ICON_ONLY:
size = APP_ICON_SIZE;
this._icon.add_actor(this._createAppIcon(this.app, size));
this._icon.add_child(this._createAppIcon(this.app, size));
}

this._icon.set_size(size * scaleFactor, size * scaleFactor);
Expand Down
21 changes: 2 additions & 19 deletions prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,25 +126,6 @@ class SettingsWidget {
});
};

const gestureFingersChanged = key => {
const builder = this.builder.get_object(key);
const setting = this._settings.get_int(key);
const valueToFingers = {
0: 'fingers-disabled',
3: 'three-fingers',
4: 'four-fingers',
};
const fingersToValue = Object.fromEntries(
Object.entries(valueToFingers).map(a => a.reverse())
);

builder.set_active_id(valueToFingers[setting] ?? 'fingers-disable');
builder.connect('changed', obj => {
const value = fingersToValue[obj.get_active_id()] ?? 0;
this._settings.set_int(key, value);
});
};

// General
intValueChanged('window_gap_spin', 'window-gap');
intValueChanged('hmargin_spinner', 'horizontal-margin');
Expand Down Expand Up @@ -299,6 +280,8 @@ class SettingsWidget {
this._settings.set_boolean('show-workspace-indicator', !state);
});

booleanStateChanged('monitor-focus-follows-mouse');

// Workspaces
booleanStateChanged('use-default-background');

Expand Down
Binary file modified schemas/gschemas.compiled
Binary file not shown.
5 changes: 5 additions & 0 deletions schemas/org.gnome.shell.extensions.paperwm.gschema.xml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@
<summary>Show the focus mode icon in the topbar</summary>
</key>

<key type="b" name="monitor-focus-follows-mouse">
<default>true</default>
<summary>Sets whether monitor focus / activation follows mouse movement</summary>
</key>

<key type="d" name="animation-time">
<default>0.25</default>
<summary>Duration of animations in seconds</summary>
Expand Down
3 changes: 2 additions & 1 deletion settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ export function enable(extension) {
'show-window-position-bar', 'show-focus-mode-icon', 'disable-topbar-styling',
'default-focus-mode', 'gesture-enabled', 'gesture-horizontal-fingers',
'gesture-workspace-fingers', 'open-window-position',
'overview-ensure-viewport-animation']
'overview-ensure-viewport-animation', 'monitor-focus-follows-mouse',
]
.forEach(k => setState(null, k));
prefs.__defineGetter__("minimum_margin", () => {
return Math.min(15, prefs.horizontal_margin);
Expand Down
Loading