diff --git a/VERSION b/VERSION index 50aea0e..7c32728 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.0 \ No newline at end of file +2.1.1 \ No newline at end of file diff --git a/gnome/src/extension.js b/gnome/src/extension.js index 852e23e..6e5fb88 100644 --- a/gnome/src/extension.js +++ b/gnome/src/extension.js @@ -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'); diff --git a/gnome/src/virtualdisplayeffect.js b/gnome/src/virtualdisplayeffect.js index eac98f2..0cb8a16 100644 --- a/gnome/src/virtualdisplayeffect.js +++ b/gnome/src/virtualdisplayeffect.js @@ -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 diff --git a/gnome/src/virtualdisplaysactor.js b/gnome/src/virtualdisplaysactor.js index b4eecbc..c695d4b 100644 --- a/gnome/src/virtualdisplaysactor.js +++ b/gnome/src/virtualdisplaysactor.js @@ -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 );