diff --git a/gnome/src/cursormanager.js b/gnome/src/cursormanager.js index 018b942..52d1341 100644 --- a/gnome/src/cursormanager.js +++ b/gnome/src/cursormanager.js @@ -4,10 +4,11 @@ import * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.j import { MouseSpriteContent } from './cursor.js'; import Globals from './globals.js'; + // Taken from https://github.com/jkitching/soft-brightness-plus export class CursorManager { - constructor(mainActor, refreshRate) { - this._mainActor = mainActor; + constructor(overlay, refreshRate) { + this._overlay = overlay; this._refreshRate = refreshRate; // Set/destroyed by _enableCloningMouse/_disableCloningMouse @@ -19,7 +20,7 @@ export class CursorManager { // Set/destroyed by _startCloningMouse / _stopCloningMouse this._cursorWatch = null; this._cursorChangedConnection = null; - this._redraw_timeline = null; + this._systemCursorShown = true; } enable() { @@ -62,10 +63,12 @@ export class CursorManager { } _hideSystemCursor() { - const seat = Clutter.get_default_backend().get_default_seat(); + this._systemCursorShown = false; + + this._cursorRoot.show(); if (!this._cursorUnfocusInhibited) { - seat.inhibit_unfocus(); + Clutter.get_default_backend().get_default_seat().inhibit_unfocus(); this._cursorUnfocusInhibited = true; } @@ -108,17 +111,20 @@ export class CursorManager { // prereqs: setup in _enableCloningMouse _startCloningMouse() { Globals.logger.log_debug('CursorManager _startCloningMouse'); - this._mainActor.add_child(this._cursorRoot); + this._overlay.mainActor().add_child(this._cursorRoot); this._updateMouseSprite(); this._cursorTracker.connectObject('cursor-changed', this._updateMouseSprite.bind(this), this); Meta.disable_unredirect_for_display(global.display); - const interval = 1000.0 / 60; + // cap the refresh rate for performance reasons + const interval = 1000.0 / Math.min(this._refreshRate, 60); + this._cursorWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this._updateMousePosition.bind(this)); this._updateMousePosition(); - this._hideSystemCursor(); + const [xMouse, yMouse] = global.get_pointer(); + if (this._overlay.isWithinBounds(xMouse, yMouse)) this._hideSystemCursor(); } // After this: @@ -134,30 +140,21 @@ export class CursorManager { this._cursorWatch = null; } - this._cursorTracker.disconnectObject(this); - this._mouseSprite.content.texture = null; + if (this._cursorTracker) this._cursorTracker.disconnectObject(this); + if (this._mouseSprite?.content?.texture) this._mouseSprite.content.texture = null; Meta.enable_unredirect_for_display(global.display); - - if (this._cursorChangedConnection) { - this._cursorTracker.disconnect(this._cursorChangedConnection); - this._cursorChangedConnection = null; - } - - if (this._redraw_timeline) { - this._redraw_timeline.stop(); - this._redraw_timeline = null; - } - - if (this._cursorRoot) this._mainActor.remove_child(this._cursorRoot); - - this._showSystemCursor(); + + if (this._cursorRoot) this._overlay.mainActor().remove_child(this._cursorRoot); + if (!this._systemCursorShown) this._showSystemCursor(); } _showSystemCursor() { - const seat = Clutter.get_default_backend().get_default_seat(); + this._systemCursorShown = true; + + if (this._cursorRoot) this._cursorRoot.hide(); if (this._cursorUnfocusInhibited) { - seat.uninhibit_unfocus(); + Clutter.get_default_backend().get_default_seat().uninhibit_unfocus(); this._cursorUnfocusInhibited = false; } @@ -171,20 +168,24 @@ export class CursorManager { _updateMousePosition(...args) { const [xMouse, yMouse] = args.length ? args : global.get_pointer(); + const inBounds = this._overlay.isWithinBounds(xMouse, yMouse); + const [xRel, yRel] = this._overlay.getRelativePosition(xMouse, yMouse); - if (xMouse === this.xMouse && yMouse === this.yMouse) + if (xRel === this.xMouse && yRel === this.yMouse) return; - this.xMouse = xMouse; - this.yMouse = yMouse; + if (inBounds) { + if (this._systemCursorShown) this._hideSystemCursor(); + this._cursorRoot.set_position(xRel, yRel); + } else if (!this._systemCursorShown && !inBounds) { + this._showSystemCursor(); + } - this._cursorRoot.set_position(xMouse, yMouse); - - if (this._mainActor.get_last_child() !== this._cursorRoot) - this._mainActor.set_child_above_sibling(this._cursorRoot, null); + this.xMouse = xRel; + this.yMouse = yRel; const seat = Clutter.get_default_backend().get_default_seat(); - if (!seat.is_unfocus_inhibited() && this._cursorUnfocusInhibited) { + if (this._cursorUnfocusInhibited && !seat.is_unfocus_inhibited()) { Globals.logger.log_debug('reinhibiting'); seat.inhibit_unfocus(); } diff --git a/gnome/src/extension.js b/gnome/src/extension.js index 29a38f1..61ca136 100644 --- a/gnome/src/extension.js +++ b/gnome/src/extension.js @@ -3,13 +3,12 @@ import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; import Meta from 'gi://Meta'; import Shell from 'gi://Shell'; -import St from 'gi://St'; import { CursorManager } from './cursormanager.js'; import Globals from './globals.js'; import { Logger } from './logger.js'; import { MonitorManager } from './monitormanager.js'; -import { SystemBackground } from './systembackground.js'; +import { Overlay } from './overlay.js'; import { isValidKeepAlive } from './time.js'; import { IPC_FILE_PATH, XREffect } from './xrEffect.js'; @@ -248,28 +247,11 @@ export default class BreezyDesktopExtension extends Extension { try { const targetMonitor = this._target_monitor.monitor; const refreshRate = targetMonitor.refreshRate ?? 60; - this._cursor_manager = new CursorManager(Main.layoutManager.uiGroup, refreshRate); + this._overlay = new Overlay(targetMonitor); + + this._cursor_manager = new CursorManager(this._overlay, refreshRate); this._cursor_manager.enable(); - const overlayContent = new Clutter.Actor({clip_to_allocation: true}); - - this._overlay = new St.Bin({ - child: overlayContent - }); - this._overlay.set_position(targetMonitor.x, targetMonitor.y); - this._overlay.set_size(targetMonitor.width, targetMonitor.height); - - global.stage.add_child(this._overlay); - Shell.util_set_hidden_from_pick(this._overlay, true); - - this._background = new SystemBackground(); - overlayContent.add_child(this._background); - - const uiClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup, clip_to_allocation: true }); - uiClone.x = -targetMonitor.x; - uiClone.y = -targetMonitor.y; - overlayContent.add_child(uiClone); - // In GS 45, use of "actor" was renamed to "child". const clutterContainer = Clutter.Container !== undefined; this._actor_added_connection = global.stage.connect( @@ -312,7 +294,7 @@ export default class BreezyDesktopExtension extends Extension { this._look_ahead_override_binding = this.settings.bind('look-ahead-override', this._xr_effect, 'look-ahead-override', Gio.SettingsBindFlags.DEFAULT); this._disable_anti_aliasing_binding = this.settings.bind('disable-anti-aliasing', this._xr_effect, 'disable-anti-aliasing', Gio.SettingsBindFlags.DEFAULT); - this._overlay.add_effect_with_name('xr-desktop', this._xr_effect); + this._overlay.mainActor().add_effect_with_name('xr-desktop', this._xr_effect); Meta.disable_unredirect_for_display(global.display); this._add_settings_keybinding('recenter-display-shortcut', this._recenter_display.bind(this)); @@ -327,7 +309,7 @@ export default class BreezyDesktopExtension extends Extension { _handle_sibling_update() { Globals.logger.log_debug('BreezyDesktopExtension _handle_sibling_update()'); - global.stage.set_child_above_sibling(this._overlay, null); + global.stage.set_child_above_sibling(this._overlay.mainActor(), null); } _add_settings_keybinding(settings_key, bind_to_function) { @@ -522,14 +504,6 @@ export default class BreezyDesktopExtension extends Extension { global.stage.disconnect(this._actor_removed_connection); this._actor_removed_connection = null; } - if (this._overlay) { - if (this._xr_effect) this._xr_effect.cleanup(); - this._overlay.remove_effect_by_name('xr-desktop'); - - global.stage.remove_child(this._overlay); - this._overlay.destroy(); - this._overlay = null; - } if (this._distance_binding) { this.settings.unbind(this._distance_binding); this._distance_binding = null; @@ -579,12 +553,17 @@ export default class BreezyDesktopExtension extends Extension { this._xr_effect.disconnect(this._supported_device_detected_connected); this._supported_device_detected_connected = null; } + this._xr_effect.cleanup(); this._xr_effect = null; } if (this._cursor_manager) { this._cursor_manager.disable(); this._cursor_manager = null; } + if (this._overlay) { + this._overlay.mainActor().remove_effect_by_name('xr-desktop'); + this._overlay.destroy(); + } // this should always be done at the end of this function after the widescreen settings binding is removed, // so it doesn't reset the setting to false diff --git a/gnome/src/overlay.js b/gnome/src/overlay.js new file mode 100644 index 0000000..c42af7c --- /dev/null +++ b/gnome/src/overlay.js @@ -0,0 +1,49 @@ +import Clutter from 'gi://Clutter' +import Shell from 'gi://Shell'; +import St from 'gi://St'; + +import { SystemBackground } from './systembackground.js'; +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; + +export class Overlay { + constructor(targetMonitor) { + this._overlayContent = new Clutter.Actor({clip_to_allocation: true}); + this._overlay = new St.Bin({ + child: this._overlayContent + }); + this._overlay.set_position(targetMonitor.x, targetMonitor.y); + this._overlay.set_size(targetMonitor.width, targetMonitor.height); + + global.stage.add_child(this._overlay); + Shell.util_set_hidden_from_pick(this._overlay, true); + + this._background = new SystemBackground(); + this._overlayContent.add_child(this._background); + + this._uiClone = new Clutter.Clone({ source: Main.layoutManager.uiGroup, clip_to_allocation: true }); + this._uiClone.x = -targetMonitor.x; + this._uiClone.y = -targetMonitor.y; + this._overlayContent.add_child(this._uiClone); + + this._targetMonitor = targetMonitor; + } + + isWithinBounds(x, y) { + return x >= this._targetMonitor.x && x < this._targetMonitor.x + this._targetMonitor.width && + y >= this._targetMonitor.y && y < this._targetMonitor.y + this._targetMonitor.height; + } + + getRelativePosition(x, y) { + return [x - this._targetMonitor.x, y - this._targetMonitor.y]; + } + + mainActor() { + return this._overlayContent; + } + + destroy() { + global.stage.remove_child(this._overlay); + this._overlay.destroy(); + this._overlay = null; + } +} \ No newline at end of file diff --git a/gnome/src/systembackground.js b/gnome/src/systembackground.js index 32b501e..cf7a3bb 100644 --- a/gnome/src/systembackground.js +++ b/gnome/src/systembackground.js @@ -1,9 +1,10 @@ import Clutter from 'gi://Clutter'; +import Cogl from 'gi://Cogl'; import GLib from 'gi://GLib'; import GObject from 'gi://GObject'; import Meta from 'gi://Meta'; -const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff); +const DEFAULT_BACKGROUND_COLOR = Clutter.Color?.from_pixel(0x2e3436ff) || new Cogl.Color({red: 40, green: 40, blue: 40, alpha: 255}); let _systemBackground;