From dffcc2db69eb4e38c31d9efde6b02a2ab51ad6ba Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:18:29 -0700 Subject: [PATCH] Add SBS controls --- gnome/src/extension.js | 25 ++++++ gnome/src/xrEffect.js | 24 +++-- .../com.xronlinux.BreezyDesktop.gschema.xml | 27 ++++++ ui/src/connecteddevice.py | 32 ++++++- ui/src/gtk/connected-device.ui | 89 ++++++++++++++++++- ui/src/statemanager.py | 6 ++ 6 files changed, 195 insertions(+), 8 deletions(-) diff --git a/gnome/src/extension.js b/gnome/src/extension.js index 4f56a51..d33caa7 100644 --- a/gnome/src/extension.js +++ b/gnome/src/extension.js @@ -40,8 +40,11 @@ export default class BreezyDesktopExtension extends Extension { this._distance_binding = null; this._distance_connection = null; this._follow_threshold_connection = null; + this._widescreen_mode_connection = null; this._start_binding = null; this._end_binding = null; + this._curved_display_binding = null; + this._display_size_binding = null; if (!Globals.logger) { Globals.logger = new Logger({ @@ -186,12 +189,16 @@ export default class BreezyDesktopExtension extends Extension { this._update_display_distance(this.settings); this._update_follow_threshold(this.settings); + this._update_widescreen_mode(this.settings); this._distance_binding = this.settings.bind('display-distance', this._xr_effect, 'display-distance', Gio.SettingsBindFlags.DEFAULT) this._distance_connection = this.settings.connect('changed::display-distance', this._update_display_distance.bind(this)) this._follow_threshold_connection = this.settings.connect('changed::follow-threshold', this._update_follow_threshold.bind(this)) + this._widescreen_mode_connection = this.settings.connect('changed::widescreen-mode', this._update_widescreen_mode.bind(this)) this._start_binding = this.settings.bind('toggle-display-distance-start', this._xr_effect, 'toggle-display-distance-start', Gio.SettingsBindFlags.DEFAULT) this._end_binding = this.settings.bind('toggle-display-distance-end', this._xr_effect, 'toggle-display-distance-end', Gio.SettingsBindFlags.DEFAULT) + this._curved_display_binding = this.settings.bind('curved-display', this._xr_effect, 'curved-display', Gio.SettingsBindFlags.DEFAULT) + this._display_size_binding = this.settings.bind('widescreen-display-size', this._xr_effect, 'widescreen-display-size', Gio.SettingsBindFlags.DEFAULT) this._overlay.add_effect_with_name('xr-desktop', this._xr_effect); Meta.disable_unredirect_for_display(global.display); @@ -258,6 +265,12 @@ export default class BreezyDesktopExtension extends Extension { if (value !== undefined) this._write_control('breezy_desktop_follow_threshold', value); } + _update_widescreen_mode(settings, event) { + const value = settings.get_boolean('widescreen-mode'); + Globals.logger.log_debug(`BreezyDesktopExtension _update_widescreen_mode ${value}`); + if (value !== undefined) this._write_control('sbs_mode', value ? 'enable' : 'disable'); + } + _recenter_display() { Globals.logger.log_debug('BreezyDesktopExtension _recenter_display'); this._write_control('recenter_screen', 'true'); @@ -299,6 +312,10 @@ export default class BreezyDesktopExtension extends Extension { this.settings.disconnect(this._follow_threshold_connection); this._follow_threshold_connection = null; } + if (this._widescreen_mode_connection) { + this.settings.disconnect(this._widescreen_mode_connection); + this._widescreen_mode_connection = null; + } if (this._start_binding) { this.settings.unbind(this._start_binding); this._start_binding = null; @@ -307,6 +324,14 @@ export default class BreezyDesktopExtension extends Extension { this.settings.unbind(this._end_binding); this._end_binding = null; } + if (this._curved_display_binding) { + this.settings.unbind(this._curved_display_binding); + this._curved_display_binding = null; + } + if (this._display_size_binding) { + this.settings.unbind(this._display_size_binding); + this._display_size_binding = null; + } if (this._xr_effect) { this._xr_effect.cleanup(); this._xr_effect = null; diff --git a/gnome/src/xrEffect.js b/gnome/src/xrEffect.js index a9cceec..41f9ea3 100644 --- a/gnome/src/xrEffect.js +++ b/gnome/src/xrEffect.js @@ -63,7 +63,7 @@ const shaderUniformLocations = { 'half_fov_y_rads': null, 'source_resolution': null, 'display_resolution': null, - 'curved': null + 'curved_display': null }; function setUniformFloat(effect, locationName, dataViewInfo, value) { @@ -144,9 +144,7 @@ function setIntermittentUniformVariables() { setSingleFloat(this, 'trim_height_percent', trimHeightPercent); setSingleFloat(this, 'half_fov_z_rads', halfFovZRads); setSingleFloat(this, 'half_fov_y_rads', halfFovYRads); - - // TODO - drive from settings - setSingleFloat(this, 'display_size', 1.0); + setSingleFloat(this, 'curved_display', this.curved_display ? 1.0 : 0.0); } // these variables are always in play, even if enabled is false @@ -156,7 +154,6 @@ function setIntermittentUniformVariables() { setSingleFloat(this, 'sbs_mode_stretched', 1.0); // content always fills the whole display setSingleFloat(this, 'sbs_enabled', dataViewUint8(dataView, SBS_ENABLED) !== 0 ? 1.0 : 0.0); setSingleFloat(this, 'custom_banner_enabled', dataViewUint8(dataView, CUSTOM_BANNER_ENABLED) !== 0 ? 1.0 : 0.0); - setSingleFloat(this, 'curved', 1.0); // TODO - drive from settings this.set_uniform_float(shaderUniformLocations['display_resolution'], 2, displayRes); this.set_uniform_float(shaderUniformLocations['source_resolution'], 2, [this.target_monitor.width, this.target_monitor.height]); @@ -205,6 +202,22 @@ export const XREffect = GObject.registerClass({ 0.2, 2.5, 1.05 + ), + 'curved-display': GObject.ParamSpec.boolean( + 'curved-display', + 'Curved Display', + 'Whether the display is curved', + GObject.ParamFlags.READWRITE, + false + ), + 'widescreen-display-size': GObject.ParamSpec.double( + 'widescreen-display-size', + 'Widescreen display size', + 'Size of the display when in widescreen/SBS mode', + GObject.ParamFlags.READWRITE, + 0.2, + 2.5, + 1.0 ) } }, class XREffect extends Shell.GLSLEffect { @@ -292,6 +305,7 @@ export const XREffect = GObject.registerClass({ setSingleFloat(this, 'display_north_offset', this.display_distance); setSingleFloat(this, 'look_ahead_ms', lookAheadMS(this._dataView)); setUniformMatrix(this, 'imu_quat_data', 4, this._dataView, IMU_QUAT_DATA); + setSingleFloat(this, 'display_size', this.widescreen_display_size); } else if (this._dataView.byteLength !== 0) { Globals.logger.log(`ERROR: Invalid dataView.byteLength: ${this._dataView.byteLength} !== ${DATA_VIEW_LENGTH}`) } diff --git a/ui/data/com.xronlinux.BreezyDesktop.gschema.xml b/ui/data/com.xronlinux.BreezyDesktop.gschema.xml index a1babc3..ae031f1 100644 --- a/ui/data/com.xronlinux.BreezyDesktop.gschema.xml +++ b/ui/data/com.xronlinux.BreezyDesktop.gschema.xml @@ -64,6 +64,33 @@ End distance when using the "toggle display distance" shortcut. + + + false + + Widescreen mode + + Enable widescreen/SBS mode + + + + + 1.0 + + Widescreen display size + + The size of the display when in widescreen/SBS mode + + + + + false + + Curved display + + Enable curved display mode + + false diff --git a/ui/src/connecteddevice.py b/ui/src/connecteddevice.py index 16f9ad4..69ae5f3 100644 --- a/ui/src/connecteddevice.py +++ b/ui/src/connecteddevice.py @@ -10,13 +10,21 @@ from .xrdriveripc import XRDriverIPC class ConnectedDevice(Gtk.Box): __gtype_name__ = "ConnectedDevice" + device_label = Gtk.Template.Child() effect_enable_switch = Gtk.Template.Child() + display_distance_row = Gtk.Template.Child() display_distance_scale = Gtk.Template.Child() display_distance_adjustment = Gtk.Template.Child() follow_threshold_scale = Gtk.Template.Child() follow_threshold_adjustment = Gtk.Template.Child() follow_mode_switch = Gtk.Template.Child() - device_label = Gtk.Template.Child() + widescreen_mode_switch = Gtk.Template.Child() + widescreen_display_distance_row = Gtk.Template.Child() + widescreen_display_distance_scale = Gtk.Template.Child() + widescreen_display_distance_adjustment = Gtk.Template.Child() + widescreen_display_size_scale = Gtk.Template.Child() + widescreen_display_size_adjustment = Gtk.Template.Child() + curved_display_switch = Gtk.Template.Child() set_toggle_display_distance_start_button = Gtk.Template.Child() set_toggle_display_distance_end_button = Gtk.Template.Child() reassign_recenter_display_shortcut_button = Gtk.Template.Child() @@ -33,6 +41,10 @@ class ConnectedDevice(Gtk.Box): self.display_distance_scale, self.follow_mode_switch, self.follow_threshold_scale, + self.widescreen_mode_switch, + self.widescreen_display_distance_scale, + self.widescreen_display_size_scale, + self.curved_display_switch, self.set_toggle_display_distance_start_button, self.set_toggle_display_distance_end_button, self.reassign_recenter_display_shortcut_button, @@ -45,7 +57,11 @@ class ConnectedDevice(Gtk.Box): self.extensions_manager = ExtensionsManager.get_instance() self.settings.bind('display-distance', self.display_distance_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT) + self.settings.bind('display-distance', self.widescreen_display_distance_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT) self.settings.bind('follow-threshold', self.follow_threshold_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT) + self.settings.bind('widescreen-mode', self.widescreen_mode_switch, 'active', Gio.SettingsBindFlags.DEFAULT) + self.settings.bind('widescreen-display-size', self.widescreen_display_size_adjustment, 'value', Gio.SettingsBindFlags.DEFAULT) + self.settings.bind('curved-display', self.curved_display_switch, 'active', Gio.SettingsBindFlags.DEFAULT) bind_shortcut_settings(self.get_parent(), [ [self.reassign_recenter_display_shortcut_button, self.recenter_display_shortcut_label], @@ -65,6 +81,8 @@ class ConnectedDevice(Gtk.Box): self.follow_mode_switch.set_active(self.state_manager.follow_mode) self.follow_mode_switch.connect('notify::active', self._refresh_follow_mode) + self.widescreen_mode_switch.connect('notify::active', self._refresh_widescreen_mode) + self.effect_enable_switch.set_active(self._is_config_enabled(self.ipc.retrieve_config()) and self.extensions_manager.is_enabled()) self.effect_enable_switch.connect('notify::active', self._refresh_inputs_for_enabled_state) @@ -83,6 +101,13 @@ class ConnectedDevice(Gtk.Box): def _is_config_enabled(self, config): return config.get('disabled') == False and 'breezy_desktop' in config.get('external_mode', []) + + def _refresh_widescreen_mode(self, switch, param): + widescreen_mode_enabled = switch.get_active() + self.widescreen_display_distance_row.set_visible(widescreen_mode_enabled) + self.display_distance_row.set_visible(not widescreen_mode_enabled) + for widget in [self.widescreen_display_distance_scale, self.widescreen_display_size_scale]: + widget.set_sensitive(widescreen_mode_enabled) def _refresh_inputs_for_enabled_state(self, switch, param): requesting_enabled = switch.get_active() @@ -98,7 +123,9 @@ class ConnectedDevice(Gtk.Box): for widget in self.all_enabled_state_inputs: widget.set_sensitive(requesting_enabled) - if requesting_enabled: self._refresh_follow_mode(self.follow_mode_switch, None) + if requesting_enabled: + self._refresh_follow_mode(self.follow_mode_switch, None) + self._refresh_widescreen_mode(self.widescreen_mode_switch, None) def _refresh_follow_mode(self, switch, param): self.follow_threshold_scale.set_sensitive(switch.get_active()) @@ -121,6 +148,7 @@ class ConnectedDevice(Gtk.Box): self.state_manager.unbind_property('follow-mode', self.follow_mode_switch, 'active') self.settings.unbind('display-distance', self.display_distance_adjustment, 'value') self.settings.unbind('follow-threshold', self.follow_threshold_adjustment, 'value') + self.settings.unbind('widescreen-mode', self.widescreen_mode_switch, 'active') self.extensions_manager.unbind_property('breezy-enabled', self.effect_enable_switch, 'active') def reload_display_distance_toggle_button(widget): diff --git a/ui/src/gtk/connected-device.ui b/ui/src/gtk/connected-device.ui index 5617700..29ab274 100644 --- a/ui/src/gtk/connected-device.ui +++ b/ui/src/gtk/connected-device.ui @@ -38,7 +38,7 @@ - + Display distance @@ -100,6 +100,93 @@ + + + Curved display + Switch between flat and curved displays + 2 + + + 3 + + + + + + + + Widescreen + Widescreen mode switches your glasses into side-by-side mode and doubles the width of the display + + + Enable widescreen + Switches your glasses into side-by-side mode + 2 + + + 3 + + + + + + + Display distance + Move the screen closer or further using SBS depth + + + 3 + true + 0 + 2 + 350 + false + + + 0.2 + 2.5 + 0.01 + 1.05 + + + + + + + + + + + + + + Display size + Combine with display distance to achieve a comfortable level of depth and size + + + 3 + true + 0 + 2 + 350 + false + + + 0.2 + 2.5 + 0.01 + 1.0 + + + + + + + + + + + diff --git a/ui/src/statemanager.py b/ui/src/statemanager.py index a8aa977..8e43fa7 100644 --- a/ui/src/statemanager.py +++ b/ui/src/statemanager.py @@ -22,6 +22,7 @@ class StateManager(GObject.GObject): __gproperties__ = { 'follow-mode': (bool, 'Follow Mode', 'Whether the follow mode is enabled', False, GObject.ParamFlags.READWRITE), 'follow-threshold': (float, 'Follow Threshold', 'The follow threshold', 1.0, 45.0, 15.0, GObject.ParamFlags.READWRITE), + 'widescreen-mode': (bool, 'Widescreen Mode', 'Whether widescreen mode is enabled', False, GObject.ParamFlags.READWRITE), 'license-action-needed': (bool, 'License Action Needed', 'Whether the license needs attention', False, GObject.ParamFlags.READWRITE), 'license-present': (bool, 'License Present', 'Whether a license is present', False, GObject.ParamFlags.READWRITE), 'enabled-features-list': (object, 'Enabled Features List', 'A list of the enabled features', GObject.ParamFlags.READWRITE), @@ -94,12 +95,15 @@ class StateManager(GObject.GObject): self.set_property('license-present', False) self.set_property('follow-mode', self.state.get('breezy_desktop_smooth_follow_enabled')) + self.set_property('widescreen-mode', self.state.get('sbs_mode_enabled') == 'true') if self.running: threading.Timer(1.0, self._refresh_state).start() def do_set_property(self, prop, value): if prop.name == 'follow-mode': self.follow_mode = value + if prop.name == 'widescreen-mode': + self.widescreen_mode = value if prop.name == 'license-action-needed': self.license_action_needed = value if prop.name == 'license-present': @@ -110,6 +114,8 @@ class StateManager(GObject.GObject): def do_get_property(self, prop): if prop.name == 'follow-mode': return self.follow_mode + if prop.name == 'widescreen-mode': + return self.widescreen_mode if prop.name == 'license-action-needed': return self.license_action_needed if prop.name == 'license-present':