Optimize monitor focus checking, fix toggle XR effect not working when disabled, v2.1.1

This commit is contained in:
wheaney 2025-03-19 12:22:15 -07:00
parent 618dceaf10
commit fb38c89e41
4 changed files with 67 additions and 46 deletions

View File

@ -1 +1 @@
2.1.0 2.1.1

View File

@ -94,6 +94,8 @@ export default class BreezyDesktopExtension extends Extension {
} }
} }
this._add_settings_keybinding('toggle-xr-effect-shortcut', this._toggle_xr_effect.bind(this));
this._setup(); this._setup();
} catch (e) { } catch (e) {
Globals.logger.log(`[ERROR] BreezyDesktopExtension enable ${e.message}\n${e.stack}`); Globals.logger.log(`[ERROR] BreezyDesktopExtension enable ${e.message}\n${e.stack}`);
@ -306,7 +308,6 @@ export default class BreezyDesktopExtension extends Extension {
Meta.disable_unredirect_for_display(global.display); Meta.disable_unredirect_for_display(global.display);
} }
this._add_settings_keybinding('toggle-xr-effect-shortcut', this._toggle_xr_effect.bind(this));
this._add_settings_keybinding('recenter-display-shortcut', this._recenter_display.bind(this)); this._add_settings_keybinding('recenter-display-shortcut', this._recenter_display.bind(this));
this._add_settings_keybinding('toggle-display-distance-shortcut', this._virtual_displays_actor._change_distance.bind(this._virtual_displays_actor)); this._add_settings_keybinding('toggle-display-distance-shortcut', this._virtual_displays_actor._change_distance.bind(this._virtual_displays_actor));
this._add_settings_keybinding('toggle-follow-shortcut', this._toggle_follow_mode.bind(this)); this._add_settings_keybinding('toggle-follow-shortcut', this._toggle_follow_mode.bind(this));
@ -558,7 +559,6 @@ export default class BreezyDesktopExtension extends Extension {
if (Globals.data_stream.smooth_follow_enabled) this._toggle_follow_mode(); if (Globals.data_stream.smooth_follow_enabled) this._toggle_follow_mode();
Main.wm.removeKeybinding('toggle-xr-effect-shortcut');
Main.wm.removeKeybinding('recenter-display-shortcut'); Main.wm.removeKeybinding('recenter-display-shortcut');
Main.wm.removeKeybinding('toggle-display-distance-shortcut'); Main.wm.removeKeybinding('toggle-display-distance-shortcut');
Main.wm.removeKeybinding('toggle-follow-shortcut'); Main.wm.removeKeybinding('toggle-follow-shortcut');
@ -644,6 +644,7 @@ export default class BreezyDesktopExtension extends Extension {
Globals.data_stream.disconnect(this._breezy_desktop_running_connection); Globals.data_stream.disconnect(this._breezy_desktop_running_connection);
this._breezy_desktop_running_connection = null; this._breezy_desktop_running_connection = null;
} }
Main.wm.removeKeybinding('toggle-xr-effect-shortcut');
Gio.Settings.unbind(this.settings, 'debug'); Gio.Settings.unbind(this.settings, 'debug');
Gio.Settings.unbind(this.settings, 'use-optimal-monitor-config'); Gio.Settings.unbind(this.settings, 'use-optimal-monitor-config');
Gio.Settings.unbind(this.settings, 'headset-as-primary'); Gio.Settings.unbind(this.settings, 'headset-as-primary');

View File

@ -329,8 +329,9 @@ export const VirtualDisplayEffect = GObject.registerClass({
if (this._follow_ease_timeline?.is_playing()) this._follow_ease_timeline.stop(); if (this._follow_ease_timeline?.is_playing()) this._follow_ease_timeline.stop();
const ease_to_focus = this.smooth_follow_enabled && this._is_focused();
const from = this._current_follow_ease_progress; const from = this._current_follow_ease_progress;
const to = this.smooth_follow_enabled && this._is_focused() ? 1.0 : 0.0; const to = ease_to_focus ? 1.0 : 0.0;
const toggleTime = this.smooth_follow_toggle_epoch_ms === 0 ? Date.now() : this.smooth_follow_toggle_epoch_ms; const toggleTime = this.smooth_follow_toggle_epoch_ms === 0 ? Date.now() : this.smooth_follow_toggle_epoch_ms;
// would have been a slight delay between request and slerp actually starting // would have been a slight delay between request and slerp actually starting

View File

@ -19,6 +19,34 @@ const FOCUS_THRESHOLD = 0.95 / 2.0;
// if we leave the monitor with some margin, unfocus even if no other monitor is in focus // if we leave the monitor with some margin, unfocus even if no other monitor is in focus
const UNFOCUS_THRESHOLD = 1.1 / 2.0; const UNFOCUS_THRESHOLD = 1.1 / 2.0;
// returns how far the look vector is from the center of the monitor, as a percentage of the monitor's width
function getMonitorDistance(fovDetails, lookUpPixels, lookWestPixels, monitorVector, monitorDetails, upAngleToLength, westAngleToLength) {
const monitorAspectRatio = monitorDetails.width / monitorDetails.height;
// weight the up distance by the aspect ratio
const vectorUpPixels = upAngleToLength(
fovDetails.defaultDistanceVerticalRadians,
fovDetails.heightPixels,
fovDetails.completeScreenDistancePixels,
monitorVector[2],
monitorVector[0]
);
const upDeltaPixels = (lookUpPixels - vectorUpPixels) * monitorAspectRatio;
const vectorWestPixels = westAngleToLength(
fovDetails.defaultDistanceHorizontalRadians,
fovDetails.widthPixels,
fovDetails.completeScreenDistancePixels,
monitorVector[1],
monitorVector[0]
);
const westDeltaPixels = lookWestPixels - vectorWestPixels;
const totalDeltaPixels = Math.sqrt(upDeltaPixels * upDeltaPixels + westDeltaPixels * westDeltaPixels);
// threshold is a percentage of width, and height was already properly weighted
return totalDeltaPixels / monitorDetails.width;
}
/** /**
* Find the vector in the array that's closest to the quaternion rotation * Find the vector in the array that's closest to the quaternion rotation
* *
@ -26,12 +54,11 @@ const UNFOCUS_THRESHOLD = 1.1 / 2.0;
* @param {number[][]} monitorVectors - Array of monitor vectors [x, y, z] to search from * @param {number[][]} monitorVectors - Array of monitor vectors [x, y, z] to search from
* @param {number} currentFocusedIndex - Index of the currently focused monitor * @param {number} currentFocusedIndex - Index of the currently focused monitor
* @param {number} focusedMonitorDistance - Distance to the focused monitor, < 1.0 if zoomed in * @param {number} focusedMonitorDistance - Distance to the focused monitor, < 1.0 if zoomed in
* @param {boolean} smoothFollowEnabled - If true, always keep the current monitor in focus or choose the closest
* @param {Object} fovDetails - Contains reference widthPixels, heightPixels, horizontal and vertical radians, and pixel distance to the center of the screen * @param {Object} fovDetails - Contains reference widthPixels, heightPixels, horizontal and vertical radians, and pixel distance to the center of the screen
* @param {Object[]} monitorsDetails - Contains x, y, width, height (coordinates from top-left) for each monitor * @param {Object[]} monitorsDetails - Contains x, y, width, height (coordinates from top-left) for each monitor
* @returns {number} Index of the closest vector, if it surpasses the previous closest index by a certain margin, otherwise the previous index * @returns {number} Index of the closest vector, if it surpasses the previous closest index by a certain margin, otherwise the previous index
*/ */
function findFocusedMonitor(quaternion, monitorVectors, currentFocusedIndex, focusedMonitorDistance, smoothFollowEnabled, fovDetails, monitorsDetails) { function findFocusedMonitor(quaternion, monitorVectors, currentFocusedIndex, focusedMonitorDistance, fovDetails, monitorsDetails) {
const lookVector = [1.0, 0.0, 0.0]; // NWU vector pointing to the center of the screen const lookVector = [1.0, 0.0, 0.0]; // NWU vector pointing to the center of the screen
const rotatedLookVector = applyQuaternionToVector(lookVector, quaternion); const rotatedLookVector = applyQuaternionToVector(lookVector, quaternion);
@ -56,55 +83,46 @@ function findFocusedMonitor(quaternion, monitorVectors, currentFocusedIndex, foc
let closestIndex = -1; let closestIndex = -1;
let closestDistance = Infinity; let closestDistance = Infinity;
let currentFocusedDistance = Infinity;
// the currently focused monitor is the most likely to be the closest, check it first and exit early if it is
if (currentFocusedIndex !== -1) {
const focusedDistance = getMonitorDistance(
fovDetails,
lookUpPixels,
lookWestPixels,
monitorVectors[currentFocusedIndex],
monitorsDetails[currentFocusedIndex],
upConversionFns.angleToLength,
westConversionFns.angleToLength
) * focusedMonitorDistance;
if (focusedDistance < UNFOCUS_THRESHOLD) return currentFocusedIndex;
}
// find the vector closest to the rotated look vector // find the vector closest to the rotated look vector
monitorVectors.forEach((monitorVector, index) => { monitorVectors.forEach((monitorVector, index) => {
const monitor = monitorsDetails[index]; if (index === currentFocusedIndex) return;
const monitorAspectRatio = monitor.width / monitor.height;
// weight the up distance by the aspect ratio const distance = getMonitorDistance(
const vectorUpPixels = upConversionFns.angleToLength( fovDetails,
fovDetails.defaultDistanceVerticalRadians, lookUpPixels,
fovDetails.heightPixels, lookWestPixels,
fovDetails.completeScreenDistancePixels, monitorVector,
monitorVector[2], monitorsDetails[index],
monitorVector[0] upConversionFns.angleToLength,
westConversionFns.angleToLength
); );
const upDeltaPixels = (lookUpPixels - vectorUpPixels) * monitorAspectRatio;
const vectorWestPixels = westConversionFns.angleToLength( if (distance < closestDistance) {
fovDetails.defaultDistanceHorizontalRadians,
fovDetails.widthPixels,
fovDetails.completeScreenDistancePixels,
monitorVector[1],
monitorVector[0]
);
const westDeltaPixels = lookWestPixels - vectorWestPixels;
const totalDeltaPixels = Math.sqrt(upDeltaPixels * upDeltaPixels + westDeltaPixels * westDeltaPixels);
// threshold is a percentage of width, and height was already properly weighted
const distanceFromCenterSizeRatio = totalDeltaPixels / monitor.width;
if (currentFocusedIndex === index) {
currentFocusedDistance = distanceFromCenterSizeRatio * focusedMonitorDistance;
}
if (distanceFromCenterSizeRatio < closestDistance) {
closestIndex = index; closestIndex = index;
closestDistance = distanceFromCenterSizeRatio; closestDistance = distance;
} }
}); });
const keepCurrent = currentFocusedIndex !== -1 && (smoothFollowEnabled || currentFocusedDistance < UNFOCUS_THRESHOLD); if (closestDistance < FOCUS_THRESHOLD) return closestIndex;
if (!keepCurrent) {
if (smoothFollowEnabled || closestDistance < FOCUS_THRESHOLD) return closestIndex;
// neither the current nor the closest will take focus, unfocus all displays // neither the current nor the closest will take focus, unfocus all displays
return -1; return -1;
}
return currentFocusedIndex;
} }
/*** /***
@ -761,7 +779,9 @@ export const VirtualDisplaysActor = GObject.registerClass({
if (this.show_banner) { if (this.show_banner) {
this.focused_monitor_index = -1; this.focused_monitor_index = -1;
this.focused_monitor_details = null; this.focused_monitor_details = null;
} else if (this.imu_snapshots && (!this._smooth_follow_slerping || this.focused_monitor_index === -1)) { } else if (this.imu_snapshots &&
(!this.smooth_follow_enabled || this.focused_monitor_index === -1) &&
(!this._smooth_follow_slerping || this.focused_monitor_index === -1)) {
// if smooth follow is enabled, use the origin IMU data to inform the initial focused monitor // if smooth follow is enabled, use the origin IMU data to inform the initial focused monitor
// since it reflects where the user is looking in relation to the original monitor positions // since it reflects where the user is looking in relation to the original monitor positions
const currentPoseQuat = this.smooth_follow_enabled ? const currentPoseQuat = this.smooth_follow_enabled ?
@ -773,7 +793,6 @@ export const VirtualDisplaysActor = GObject.registerClass({
this.monitor_placements.map(monitorVectors => monitorVectors.centerLook), this.monitor_placements.map(monitorVectors => monitorVectors.centerLook),
this.focused_monitor_index, this.focused_monitor_index,
this.display_distance / this._display_distance_default(), this.display_distance / this._display_distance_default(),
this.smooth_follow_enabled,
this.fov_details, this.fov_details,
this._all_monitors this._all_monitors
); );