From e50a3f1c2b2f4f0d599088dc7d641740f042ec42 Mon Sep 17 00:00:00 2001
From: wheaney <42350981+wheaney@users.noreply.github.com>
Date: Thu, 9 May 2024 09:55:58 -0700
Subject: [PATCH] Add follow mode support
---
.gitignore | 1 +
.../breezydesktop@xronlinux.com/extension.js | 13 +++++-
ui/build-aux/start-breezy-desktop.sh | 3 ++
.../com.xronlinux.BreezyDesktop.desktop.in | 2 +-
.../com.xronlinux.BreezyDesktop.gschema.xml | 9 +++++
ui/src/connecteddevice.py | 25 +++++++++++-
ui/src/gtk/connected-device.ui | 40 +++++++++++++++++++
ui/src/statemanager.py | 20 ++++++++--
ui/src/window.py | 2 +-
ui/src/xrdriveripc.py | 23 +++++++++--
10 files changed, 126 insertions(+), 12 deletions(-)
diff --git a/.gitignore b/.gitignore
index 988ea1b..a5ee540 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
/build/
__pycache__
*.zip
+gschemas.compiled
diff --git a/gnome/breezydesktop@xronlinux.com/extension.js b/gnome/breezydesktop@xronlinux.com/extension.js
index a5876d6..cfe2aba 100644
--- a/gnome/breezydesktop@xronlinux.com/extension.js
+++ b/gnome/breezydesktop@xronlinux.com/extension.js
@@ -155,6 +155,7 @@ export default class BreezyDesktopExtension extends Extension {
this._add_settings_keybinding('recenter-display-shortcut', this._recenter_display.bind(this));
this._add_settings_keybinding('toggle-display-distance-shortcut', this._xr_effect._change_distance.bind(this._xr_effect));
+ this._add_settings_keybinding('toggle-follow-shortcut', this._toggle_follow_mode.bind(this));
} catch (e) {
console.error('Error enabling XR effect', e);
this._effect_disable();
@@ -187,13 +188,21 @@ export default class BreezyDesktopExtension extends Extension {
});
}
- _recenter_display() {
+ _write_control(key, value) {
const file = Gio.file_new_for_path('/dev/shm/xr_driver_control');
const stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
- stream.write('recenter_screen=true', null);
+ stream.write(`${key}=${value}`, null);
stream.close(null);
}
+ _recenter_display() {
+ this._write_control('recenter_screen', 'true');
+ }
+
+ _toggle_follow_mode() {
+ this._write_control('toggle_breezy_desktop_smooth_follow', 'true');
+ }
+
_effect_disable() {
this._is_effect_running = false;
diff --git a/ui/build-aux/start-breezy-desktop.sh b/ui/build-aux/start-breezy-desktop.sh
index 33cc604..988ec3f 100644
--- a/ui/build-aux/start-breezy-desktop.sh
+++ b/ui/build-aux/start-breezy-desktop.sh
@@ -1,5 +1,8 @@
#!/usr/bin/env bash
+# stolen from dconf-editor:
+# https://gitlab.gnome.org/GNOME/dconf-editor/-/blob/master/build-aux/start-dconf-editor.sh
+
IFS=: read -ra host_data_dirs < <(flatpak-spawn --host sh -c 'echo "$XDG_DATA_DIRS"')
# To avoid potentially muddying up $XDG_DATA_DIRS too much, we link the schema paths
diff --git a/ui/data/com.xronlinux.BreezyDesktop.desktop.in b/ui/data/com.xronlinux.BreezyDesktop.desktop.in
index f9c4d24..3955dac 100644
--- a/ui/data/com.xronlinux.BreezyDesktop.desktop.in
+++ b/ui/data/com.xronlinux.BreezyDesktop.desktop.in
@@ -1,5 +1,5 @@
[Desktop Entry]
-Name=breezydesktop
+Name=Breezy Desktop
Exec=start-breezy-desktop
Icon=com.xronlinux.BreezyDesktop
Terminal=false
diff --git a/ui/data/com.xronlinux.BreezyDesktop.gschema.xml b/ui/data/com.xronlinux.BreezyDesktop.gschema.xml
index 5061c16..17f5bf7 100644
--- a/ui/data/com.xronlinux.BreezyDesktop.gschema.xml
+++ b/ui/data/com.xronlinux.BreezyDesktop.gschema.xml
@@ -28,6 +28,15 @@
Shortcut to change the display distance.
+
+
+ 0']]]>
+
+ Toggle follow mode
+
+ Shortcut to toggle follow mode.
+
+
1.05
diff --git a/ui/src/connecteddevice.py b/ui/src/connecteddevice.py
index 6fd0ab7..c973905 100644
--- a/ui/src/connecteddevice.py
+++ b/ui/src/connecteddevice.py
@@ -1,6 +1,8 @@
-from gi.repository import Gio, Gtk
+from gi.repository import Gio, Gtk, GObject
from .settingsmanager import SettingsManager
from .shortcutdialog import bind_shortcut_settings
+from .statemanager import StateManager
+from .xrdriveripc import XRDriverIPC
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/connected-device.ui')
class ConnectedDevice(Gtk.Box):
@@ -8,6 +10,7 @@ class ConnectedDevice(Gtk.Box):
effect_enable_switch = Gtk.Template.Child()
display_distance_scale = Gtk.Template.Child()
+ follow_mode_switch = Gtk.Template.Child()
device_label = Gtk.Template.Child()
set_toggle_display_distance_start_button = Gtk.Template.Child()
set_toggle_display_distance_end_button = Gtk.Template.Child()
@@ -15,18 +18,22 @@ class ConnectedDevice(Gtk.Box):
recenter_display_shortcut_label = Gtk.Template.Child()
reassign_toggle_display_distance_shortcut_button = Gtk.Template.Child()
toggle_display_distance_shortcut_label = Gtk.Template.Child()
+ reassign_toggle_follow_shortcut_button = Gtk.Template.Child()
+ toggle_follow_shortcut_label = Gtk.Template.Child()
def __init__(self):
super(Gtk.Box, self).__init__()
self.init_template()
self.settings = SettingsManager.get_instance().settings
+ self.ipc = XRDriverIPC.get_instance()
self.settings.bind('display-distance', self.display_distance_scale, 'value', Gio.SettingsBindFlags.DEFAULT)
self.settings.bind('effect-enable', self.effect_enable_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
bind_shortcut_settings(self.get_parent(), [
[self.reassign_recenter_display_shortcut_button, self.recenter_display_shortcut_label],
- [self.reassign_toggle_display_distance_shortcut_button, self.toggle_display_distance_shortcut_label]
+ [self.reassign_toggle_display_distance_shortcut_button, self.toggle_display_distance_shortcut_label],
+ [self.reassign_toggle_follow_shortcut_button, self.toggle_follow_shortcut_label]
])
self.bind_set_distance_toggle([
@@ -34,6 +41,20 @@ class ConnectedDevice(Gtk.Box):
self.set_toggle_display_distance_end_button
])
+ self.state_manager = StateManager.get_instance()
+ self.state_manager.bind_property('follow-mode', self.follow_mode_switch, 'active', GObject.BindingFlags.DEFAULT)
+
+ self.follow_mode_switch.set_active(self.state_manager.follow_mode)
+ self.follow_mode_switch.connect('notify::active', self._request_follow_mode)
+
+ def _request_follow_mode(self, switch, param):
+ if (self.state_manager.follow_mode == switch.get_active()):
+ return
+
+ self.ipc.write_control_flags({
+ 'enable_breezy_desktop_smooth_follow': switch.get_active()
+ })
+
def set_device_name(self, name):
self.device_label.set_markup(f"{name}")
diff --git a/ui/src/gtk/connected-device.ui b/ui/src/gtk/connected-device.ui
index 6b911dd..ffd8680 100644
--- a/ui/src/gtk/connected-device.ui
+++ b/ui/src/gtk/connected-device.ui
@@ -65,6 +65,17 @@
+
+
+
@@ -155,6 +166,35 @@
+
+
+ Toggle follow mode shortcut
+ Quickly toggle follow mode
+ 2
+
+
+ 30
+ 30
+
+
+ 3
+
+
+
+
+
+
+ toggle-follow-shortcut
+ 3
+ Change
+
+
+
+
+
+
diff --git a/ui/src/statemanager.py b/ui/src/statemanager.py
index a96a893..9c4c79d 100644
--- a/ui/src/statemanager.py
+++ b/ui/src/statemanager.py
@@ -11,7 +11,11 @@ class Logger:
class StateManager(GObject.GObject):
__gsignals__ = {
- 'device_update': (GObject.SIGNAL_RUN_FIRST, None, (str,))
+ 'device-update': (GObject.SIGNAL_RUN_FIRST, None, (str,))
+ }
+
+ __gproperties__ = {
+ 'follow-mode': (bool, 'Follow Mode', 'Whether the follow mode is enabled', False, GObject.ParamFlags.READWRITE)
}
_instance = None
@@ -32,7 +36,7 @@ class StateManager(GObject.GObject):
def __init__(self):
GObject.GObject.__init__(self)
- self.ipc = XRDriverIPC(logger = Logger(), user="wayne", user_home="/home/wayne")
+ self.ipc = XRDriverIPC.get_instance()
self.connected_device_name = None
self.start()
@@ -49,6 +53,16 @@ class StateManager(GObject.GObject):
new_device_name = StateManager.device_name(self.state)
if self.connected_device_name != new_device_name:
self.connected_device_name = new_device_name
- self.emit('device_update', self.connected_device_name)
+ self.emit('device-update', self.connected_device_name)
+
+ self.set_property('follow-mode', self.state.get('breezy_desktop_smooth_follow_enabled'))
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
+
+ def do_get_property(self, prop):
+ if prop.name == 'follow-mode':
+ return self.follow_mode
diff --git a/ui/src/window.py b/ui/src/window.py
index d7e0206..181f3af 100644
--- a/ui/src/window.py
+++ b/ui/src/window.py
@@ -30,7 +30,7 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
super().__init__(**kwargs)
state_manager = StateManager.get_instance()
- state_manager.connect('device_update', self._handle_device_update)
+ state_manager.connect('device-update', self._handle_device_update)
self.connected_device = ConnectedDevice()
self.no_device = NoDevice()
diff --git a/ui/src/xrdriveripc.py b/ui/src/xrdriveripc.py
index 996a13b..58a9d57 100644
--- a/ui/src/xrdriveripc.py
+++ b/ui/src/xrdriveripc.py
@@ -11,7 +11,7 @@ CONTROL_FLAGS_FILE_PATH = '/dev/shm/xr_driver_control'
# read-only file that the driver writes (but never reads) to with its current state
DRIVER_STATE_FILE_PATH = '/dev/shm/xr_driver_state'
-CONTROL_FLAGS = ['recenter_screen', 'recalibrate', 'sbs_mode', 'refresh_device_license']
+CONTROL_FLAGS = ['recenter_screen', 'recalibrate', 'sbs_mode', 'refresh_device_license', 'enable_breezy_desktop_smooth_follow']
SBS_MODE_VALUES = ['unset', 'enable', 'disable']
MANAGED_EXTERNAL_MODES = ['virtual_display', 'sideview', 'none']
VR_LITE_OUTPUT_MODES = ['mouse', 'joystick']
@@ -58,8 +58,24 @@ CONFIG_ENTRIES = {
'sideview_smooth_follow_enabled': [parse_boolean, False]
}
+class Logger:
+ def info(self, message):
+ print(message)
+
+ def error(self, message):
+ print(message)
+
class XRDriverIPC:
- def __init__(self, logger, user=None, user_home=None):
+ _instance = None
+
+ @staticmethod
+ def get_instance():
+ if not XRDriverIPC._instance:
+ XRDriverIPC._instance = XRDriverIPC()
+
+ return XRDriverIPC._instance
+
+ def __init__(self, logger=Logger(), user=None, user_home=None):
self.breezy_installed = False
self.breezy_installing = False
self.user = user if user else pwd.getpwuid( os.getuid() )[0]
@@ -218,6 +234,7 @@ class XRDriverIPC:
state['sbs_mode_supported'] = False
state['firmware_update_recommended'] = False
state['device_license'] = {}
+ state['breezy_desktop_smooth_follow_enabled'] = False
try:
with open(DRIVER_STATE_FILE_PATH, 'r') as f:
@@ -232,7 +249,7 @@ class XRDriverIPC:
state[key] = parse_int(value, 0)
elif key in ['calibration_setup', 'calibration_state', 'connected_device_brand', 'connected_device_model']:
state[key] = value
- elif key in ['sbs_mode_enabled', 'sbs_mode_supported', 'firmware_update_recommended']:
+ elif key in ['sbs_mode_enabled', 'sbs_mode_supported', 'firmware_update_recommended', 'breezy_desktop_smooth_follow_enabled']:
state[key] = parse_boolean(value, False)
elif key == 'device_license':
state[key] = json.loads(value)