Add follow mode support

This commit is contained in:
wheaney 2024-05-09 09:55:58 -07:00
parent 204ae71dd9
commit e50a3f1c2b
10 changed files with 126 additions and 12 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
/build/
__pycache__
*.zip
gschemas.compiled

View File

@ -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;

View File

@ -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

View File

@ -1,5 +1,5 @@
[Desktop Entry]
Name=breezydesktop
Name=Breezy Desktop
Exec=start-breezy-desktop
Icon=com.xronlinux.BreezyDesktop
Terminal=false

View File

@ -28,6 +28,15 @@
Shortcut to change the display distance.
</description>
</key>
<key name="toggle-follow-shortcut" type="as">
<default>
<![CDATA[['<Control><Super>0']]]>
</default>
<summary>Toggle follow mode</summary>
<description>
Shortcut to toggle follow mode.
</description>
</key>
<key name="display-distance" type="d">
<default>
1.05

View File

@ -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"<b>{name}</b>")

View File

@ -65,6 +65,17 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="true">Follow enabled</property>
<property name="subtitle" translatable="true">Keep the virtual display near the center of your view</property>
<child>
<object class="GtkSwitch" id="follow_mode_switch">
<property name="valign">3</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
@ -155,6 +166,35 @@
</child>
</object>
</child>
<child>
<object class="AdwActionRow">
<property name="title" translatable="true">Toggle follow mode shortcut</property>
<property name="subtitle" translatable="true">Quickly toggle follow mode</property>
<property name="valign">2</property>
<child>
<object class="GtkBox">
<property name="spacing">30</property>
<property name="margin-start">30</property>
<child>
<object class="GtkShortcutLabel" id="toggle_follow_shortcut_label">
<property name="valign">3</property>
<property name="accelerator"></property>
</object>
</child>
<child>
<object class="GtkButton" id="reassign_toggle_follow_shortcut_button">
<style>
<class name="row-button"/>
</style>
<property name="name">toggle-follow-shortcut</property>
<property name="valign">3</property>
<property name="label" translatable="true">Change</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>

View File

@ -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

View File

@ -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()

View File

@ -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)