Merge multimonitor with cursormanager changes
This commit is contained in:
parent
7bd026c9c3
commit
f6869fcaff
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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}));
|
||||
}
|
||||
});
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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}`);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue