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();
} catch (e) {
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);
}
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('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));
@ -558,7 +559,6 @@ export default class BreezyDesktopExtension extends Extension {
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('toggle-display-distance-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);
this._breezy_desktop_running_connection = null;
}
Main.wm.removeKeybinding('toggle-xr-effect-shortcut');
Gio.Settings.unbind(this.settings, 'debug');
Gio.Settings.unbind(this.settings, 'use-optimal-monitor-config');
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();
const ease_to_focus = this.smooth_follow_enabled && this._is_focused();
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;
// 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
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
*
@ -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} currentFocusedIndex - Index of the currently focused monitor
* @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[]} 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
*/
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 rotatedLookVector = applyQuaternionToVector(lookVector, quaternion);
@ -56,55 +83,46 @@ function findFocusedMonitor(quaternion, monitorVectors, currentFocusedIndex, foc
let closestIndex = -1;
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
monitorVectors.forEach((monitorVector, index) => {
const monitor = monitorsDetails[index];
const monitorAspectRatio = monitor.width / monitor.height;
if (index === currentFocusedIndex) return;
// weight the up distance by the aspect ratio
const vectorUpPixels = upConversionFns.angleToLength(
fovDetails.defaultDistanceVerticalRadians,
fovDetails.heightPixels,
fovDetails.completeScreenDistancePixels,
monitorVector[2],
monitorVector[0]
const distance = getMonitorDistance(
fovDetails,
lookUpPixels,
lookWestPixels,
monitorVector,
monitorsDetails[index],
upConversionFns.angleToLength,
westConversionFns.angleToLength
);
const upDeltaPixels = (lookUpPixels - vectorUpPixels) * monitorAspectRatio;
const vectorWestPixels = westConversionFns.angleToLength(
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) {
if (distance < closestDistance) {
closestIndex = index;
closestDistance = distanceFromCenterSizeRatio;
closestDistance = distance;
}
});
const keepCurrent = currentFocusedIndex !== -1 && (smoothFollowEnabled || currentFocusedDistance < UNFOCUS_THRESHOLD);
if (!keepCurrent) {
if (smoothFollowEnabled || closestDistance < FOCUS_THRESHOLD) return closestIndex;
if (closestDistance < FOCUS_THRESHOLD) return closestIndex;
// neither the current nor the closest will take focus, unfocus all displays
return -1;
}
return currentFocusedIndex;
// neither the current nor the closest will take focus, unfocus all displays
return -1;
}
/***
@ -761,7 +779,9 @@ export const VirtualDisplaysActor = GObject.registerClass({
if (this.show_banner) {
this.focused_monitor_index = -1;
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
// since it reflects where the user is looking in relation to the original monitor positions
const currentPoseQuat = this.smooth_follow_enabled ?
@ -773,7 +793,6 @@ export const VirtualDisplaysActor = GObject.registerClass({
this.monitor_placements.map(monitorVectors => monitorVectors.centerLook),
this.focused_monitor_index,
this.display_distance / this._display_distance_default(),
this.smooth_follow_enabled,
this.fov_details,
this._all_monitors
);