From f6869fcaffffc4be8bc282d2c43b61c8e79996f3 Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Tue, 4 Feb 2025 10:16:54 -0800 Subject: [PATCH] Merge multimonitor with cursormanager changes --- gnome/src/cursormanager.js | 33 ++++++++------ gnome/src/customeffect.js | 71 ------------------------------- gnome/src/extension.js | 49 +++++++++++---------- gnome/src/overlay.js | 49 --------------------- gnome/src/virtualmonitorsactor.js | 18 +++----- 5 files changed, 53 insertions(+), 167 deletions(-) delete mode 100644 gnome/src/customeffect.js delete mode 100644 gnome/src/overlay.js diff --git a/gnome/src/cursormanager.js b/gnome/src/cursormanager.js index 52d1341..51965bd 100644 --- a/gnome/src/cursormanager.js +++ b/gnome/src/cursormanager.js @@ -4,11 +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(overlay, refreshRate) { - this._overlay = overlay; + constructor(mainActor, targetMonitors, refreshRate) { + this._mainActor = mainActor; + this._targetMonitors = targetMonitors; this._refreshRate = refreshRate; // Set/destroyed by _enableCloningMouse/_disableCloningMouse @@ -44,6 +44,10 @@ export class CursorManager { this._stopCloningMouse(); } + moveAboveSiblings() { + if (this._cursorRoot) this._mainActor.set_child_above_sibling(this._cursorRoot, null); + } + // After this: // * real cursor is disabled // * cloning is "on" @@ -111,7 +115,7 @@ export class CursorManager { // prereqs: setup in _enableCloningMouse _startCloningMouse() { Globals.logger.log_debug('CursorManager _startCloningMouse'); - this._overlay.mainActor().add_child(this._cursorRoot); + this._mainActor.add_child(this._cursorRoot); this._updateMouseSprite(); this._cursorTracker.connectObject('cursor-changed', this._updateMouseSprite.bind(this), this); @@ -124,7 +128,8 @@ export class CursorManager { this._updateMousePosition(); const [xMouse, yMouse] = global.get_pointer(); - if (this._overlay.isWithinBounds(xMouse, yMouse)) this._hideSystemCursor(); + + if (this._targetMonitors.some(monitor => this._isWithinMonitorBounds(xMouse, yMouse, monitor))) this._hideSystemCursor(); } // After this: @@ -144,7 +149,7 @@ export class CursorManager { if (this._mouseSprite?.content?.texture) this._mouseSprite.content.texture = null; Meta.enable_unredirect_for_display(global.display); - if (this._cursorRoot) this._overlay.mainActor().remove_child(this._cursorRoot); + if (this._cursorRoot) this._mainActor.remove_child(this._cursorRoot); if (!this._systemCursorShown) this._showSystemCursor(); } @@ -168,21 +173,20 @@ 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); + const inBounds = this._targetMonitors.some(monitor => this._isWithinMonitorBounds(xMouse, yMouse, monitor)); - if (xRel === this.xMouse && yRel === this.yMouse) + if (xMouse === this.xMouse && yMouse === this.yMouse) return; if (inBounds) { if (this._systemCursorShown) this._hideSystemCursor(); - this._cursorRoot.set_position(xRel, yRel); + this._cursorRoot.set_position(xMouse, yMouse); } else if (!this._systemCursorShown && !inBounds) { this._showSystemCursor(); } - this.xMouse = xRel; - this.yMouse = yRel; + this.xMouse = xMouse; + this.yMouse = yMouse; const seat = Clutter.get_default_backend().get_default_seat(); if (this._cursorUnfocusInhibited && !seat.is_unfocus_inhibited()) { @@ -210,4 +214,9 @@ export class CursorManager { this._mouseSprite.hide(); } } + + _isWithinMonitorBounds(x, y, monitor) { + return x >= monitor.x && x < monitor.x + monitor.width && + y >= monitor.y && y < monitor.y + monitor.height; + } } \ No newline at end of file diff --git a/gnome/src/customeffect.js b/gnome/src/customeffect.js deleted file mode 100644 index 0df7fd6..0000000 --- a/gnome/src/customeffect.js +++ /dev/null @@ -1,71 +0,0 @@ -const { Clutter, GLib, GObject } = imports.gi; - -export const CustomEffect = GObject.registerClass({ - Properties: { - 'fov-degrees': GObject.ParamSpec.double( - 'fov-degrees', - 'FOV Degrees', - 'Diagonal field-of-view in degrees', - GObject.ParamFlags.READWRITE, - 1.0, - 179.0, - 60.0 - ) - } -}, class Customffect extends Clutter.ShaderEffect { - _init(params = {}) { - super._init(params); - - this.fov_degrees = params['fov-degrees'] || 60.0; - this.connect('notify::fov-degrees', this._updateMatrices.bind(this)); - - // Set up the vertex shader - this.set_shader_source(Clutter.ShaderType.VERTEX, ` - uniform mat4 viewMatrix; - uniform mat4 projectionMatrix; - uniform vec4 quaternion; - - vec3 applyQuaternionToVector(vec3 v, vec4 q) { - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - - void main() { - // First apply the view matrix to position the vertex in camera space - vec4 viewPosition = viewMatrix * vec4(gl_Vertex.xyz, 1.0); - // Then apply the quaternion rotation - vec3 transformedPosition = applyQuaternionToVector(viewPosition.xyz, quaternion); - // Finally apply the projection matrix - gl_Position = projectionMatrix * vec4(transformedPosition, 1.0); - gl_TexCoord[0] = gl_MultiTexCoord0; - } - `); - - // Initialize with the current matrices - this._updateMatrices(); - } - - _updateMatrices() { - let aspect = this.get_parent().width / this.get_parent().height; - let fov = this.fov_degrees * Math.PI / 180.0; - let near = 0.1; - let far = 100.0; - let top = Math.tan(fov / 2.0) * near; - let bottom = -top; - let right = top * aspect; - let left = -right; - - let projectionMatrix = GLib.Matrix.init_frustum(left, right, bottom, top, near, far); - let viewMatrix = GLib.Matrix.init_identity(); - - // Calculate the appropriate Z-distance based on FOV - let distance = -1.0 / Math.tan(fov / 2.0); - viewMatrix = viewMatrix.translate(0, 0, distance); - - this.set_shader_uniform_value('projectionMatrix', new Clutter.ShaderValue({matrix: projectionMatrix})); - this.set_shader_uniform_value('viewMatrix', new Clutter.ShaderValue({matrix: viewMatrix})); - } - - set_quaternion(quat) { - this.set_shader_uniform_value('quaternion', new Clutter.ShaderValue({vector4: quat})); - } -}); diff --git a/gnome/src/extension.js b/gnome/src/extension.js index 3c5e368..14f211c 100644 --- a/gnome/src/extension.js +++ b/gnome/src/extension.js @@ -1,16 +1,15 @@ import Clutter from 'gi://Clutter' import Gio from 'gi://Gio'; import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; import Meta from 'gi://Meta'; import Shell from 'gi://Shell'; +import St from 'gi://St'; import { CursorManager } from './cursormanager.js'; import { DeviceDataStream } from './devicedatastream.js'; import Globals from './globals.js'; import { Logger } from './logger.js'; import { MonitorManager } from './monitormanager.js'; -import { Overlay } from './overlay.js'; import { VirtualMonitorsActor } from './virtualmonitorsactor.js'; import {Extension} from 'resource:///org/gnome/shell/extensions/extension.js'; @@ -278,12 +277,34 @@ export default class BreezyDesktopExtension extends Extension { try { const targetMonitor = this._target_monitor.monitor; + const virtualMonitors = this._find_virtual_monitors(); const refreshRate = targetMonitor.refreshRate ?? 60; - this._overlay = new Overlay(targetMonitor); - this._cursor_manager = new CursorManager(this._overlay, refreshRate); + this._cursor_manager = new CursorManager(Main.layoutManager.uiGroup, [targetMonitor, ...virtualMonitors], refreshRate); this._cursor_manager.enable(); + this._overlay = new St.Bin({ style: 'background-color: rgba(0, 0, 0, 1);', reactive: false, clip_to_allocation: true }); + this._overlay.opacity = 255; + this._overlay.set_position(targetMonitor.x, targetMonitor.y); + this._overlay.set_size(targetMonitor.width, targetMonitor.height); + + // const textureSourceActor = Main.layoutManager.uiGroup; + Globals.data_stream.refresh_data(); + this._overlay_content = new VirtualMonitorsActor({ + monitors: virtualMonitors, + fov_degrees: 46.0, + target_monitor: targetMonitor, + display_distance: this.settings.get_double('display-distance'), + toggle_display_distance_start: this.settings.get_double('toggle-display-distance-start'), + toggle_display_distance_end: this.settings.get_double('toggle-display-distance-end'), + imu_snapshots: Globals.data_stream.imu_snapshots + }); + + this._overlay.set_child(this._overlay_content); + + Shell.util_set_hidden_from_pick(this._overlay, true); + global.stage.add_child(this._overlay); + // In GS 45, use of "actor" was renamed to "child". const clutterContainer = Clutter.Container !== undefined; this._actor_added_connection = global.stage.connect( @@ -318,7 +339,6 @@ 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.mainActor().add_effect_with_name('xr-desktop', this._xr_effect); Meta.disable_unredirect_for_display(global.display); this._add_settings_keybinding('toggle-xr-effect-shortcut', this._toggle_xr_effect.bind(this)); @@ -335,7 +355,8 @@ 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.mainActor(), null); + this._cursor_manager.moveAboveSiblings(); + global.stage.set_child_above_sibling(this._overlay, null); } _add_settings_keybinding(settings_key, bind_to_function) { @@ -628,26 +649,10 @@ export default class BreezyDesktopExtension extends Extension { this._overlay = null; } - if (this._xr_effect) { - if (this._widescreen_mode_effect_state_connection) { - this._xr_effect.disconnect(this._widescreen_mode_effect_state_connection); - this._widescreen_mode_effect_state_connection = null; - } - if (this._supported_device_detected_connected) { - 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 deleted file mode 100644 index c42af7c..0000000 --- a/gnome/src/overlay.js +++ /dev/null @@ -1,49 +0,0 @@ -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/virtualmonitorsactor.js b/gnome/src/virtualmonitorsactor.js index f66bdf9..d45a2ba 100644 --- a/gnome/src/virtualmonitorsactor.js +++ b/gnome/src/virtualmonitorsactor.js @@ -657,30 +657,22 @@ export const VirtualMonitorsActor = GObject.registerClass({ const length = Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]); return [vector[0] / length, vector[1] / length, vector[2] / length]; }); - const monitors = this._all_monitors; - const minMonitorX = Math.min(...monitors.map(monitor => monitor.x)); - const maxMonitorX = Math.max(...monitors.map(monitor => monitor.x + monitor.width)); - const minMonitorY = Math.min(...monitors.map(monitor => monitor.y)); - const maxMonitorY = Math.max(...monitors.map(monitor => monitor.y + monitor.height)); - - const displayWidth = global.stage.width; - const displayHeight = global.stage.height; const actorToDisplayRatios = [ - displayWidth / this.width, - displayHeight / this.height + global.stage.width / this.width, + global.stage.height / this.height ]; // how far this viewport actor's center is from the center of the whole stage const actorMidX = this.target_monitor.x + this.width / 2; const actorMidY = this.target_monitor.y + this.height / 2; const actorToDisplayOffsets = [ - (displayWidth / 2 - (actorMidX - global.stage.x)) * 2 / this.width, - (displayHeight / 2 - (actorMidY - global.stage.y)) * 2 / this.height + (global.stage.width / 2 - (actorMidX - global.stage.x)) * 2 / this.width, + (global.stage.height / 2 - (actorMidY - global.stage.y)) * 2 / this.height ]; Globals.logger.log_debug(`\t\t\tActor to display ratios: ${actorToDisplayRatios}, offsets: ${actorToDisplayOffsets}`); - monitors.forEach(((monitor, index) => { + this._all_monitors.forEach(((monitor, index) => { // if (index === 0) return; Globals.logger.log(`\t\t\tMonitor ${index}: ${monitor.x}, ${monitor.y}, ${monitor.width}, ${monitor.height}`);