Add follow mode support
This commit is contained in:
parent
204ae71dd9
commit
e50a3f1c2b
|
|
@ -2,3 +2,4 @@
|
||||||
/build/
|
/build/
|
||||||
__pycache__
|
__pycache__
|
||||||
*.zip
|
*.zip
|
||||||
|
gschemas.compiled
|
||||||
|
|
|
||||||
|
|
@ -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('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-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) {
|
} catch (e) {
|
||||||
console.error('Error enabling XR effect', e);
|
console.error('Error enabling XR effect', e);
|
||||||
this._effect_disable();
|
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 file = Gio.file_new_for_path('/dev/shm/xr_driver_control');
|
||||||
const stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
|
const stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
|
||||||
stream.write('recenter_screen=true', null);
|
stream.write(`${key}=${value}`, null);
|
||||||
stream.close(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() {
|
_effect_disable() {
|
||||||
this._is_effect_running = false;
|
this._is_effect_running = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
#!/usr/bin/env bash
|
#!/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"')
|
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
|
# To avoid potentially muddying up $XDG_DATA_DIRS too much, we link the schema paths
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Name=breezydesktop
|
Name=Breezy Desktop
|
||||||
Exec=start-breezy-desktop
|
Exec=start-breezy-desktop
|
||||||
Icon=com.xronlinux.BreezyDesktop
|
Icon=com.xronlinux.BreezyDesktop
|
||||||
Terminal=false
|
Terminal=false
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,15 @@
|
||||||
Shortcut to change the display distance.
|
Shortcut to change the display distance.
|
||||||
</description>
|
</description>
|
||||||
</key>
|
</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">
|
<key name="display-distance" type="d">
|
||||||
<default>
|
<default>
|
||||||
1.05
|
1.05
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
from gi.repository import Gio, Gtk
|
from gi.repository import Gio, Gtk, GObject
|
||||||
from .settingsmanager import SettingsManager
|
from .settingsmanager import SettingsManager
|
||||||
from .shortcutdialog import bind_shortcut_settings
|
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')
|
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/connected-device.ui')
|
||||||
class ConnectedDevice(Gtk.Box):
|
class ConnectedDevice(Gtk.Box):
|
||||||
|
|
@ -8,6 +10,7 @@ class ConnectedDevice(Gtk.Box):
|
||||||
|
|
||||||
effect_enable_switch = Gtk.Template.Child()
|
effect_enable_switch = Gtk.Template.Child()
|
||||||
display_distance_scale = Gtk.Template.Child()
|
display_distance_scale = Gtk.Template.Child()
|
||||||
|
follow_mode_switch = Gtk.Template.Child()
|
||||||
device_label = Gtk.Template.Child()
|
device_label = Gtk.Template.Child()
|
||||||
set_toggle_display_distance_start_button = Gtk.Template.Child()
|
set_toggle_display_distance_start_button = Gtk.Template.Child()
|
||||||
set_toggle_display_distance_end_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()
|
recenter_display_shortcut_label = Gtk.Template.Child()
|
||||||
reassign_toggle_display_distance_shortcut_button = Gtk.Template.Child()
|
reassign_toggle_display_distance_shortcut_button = Gtk.Template.Child()
|
||||||
toggle_display_distance_shortcut_label = 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):
|
def __init__(self):
|
||||||
super(Gtk.Box, self).__init__()
|
super(Gtk.Box, self).__init__()
|
||||||
self.init_template()
|
self.init_template()
|
||||||
self.settings = SettingsManager.get_instance().settings
|
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('display-distance', self.display_distance_scale, 'value', Gio.SettingsBindFlags.DEFAULT)
|
||||||
self.settings.bind('effect-enable', self.effect_enable_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
self.settings.bind('effect-enable', self.effect_enable_switch, 'active', Gio.SettingsBindFlags.DEFAULT)
|
||||||
|
|
||||||
bind_shortcut_settings(self.get_parent(), [
|
bind_shortcut_settings(self.get_parent(), [
|
||||||
[self.reassign_recenter_display_shortcut_button, self.recenter_display_shortcut_label],
|
[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([
|
self.bind_set_distance_toggle([
|
||||||
|
|
@ -34,6 +41,20 @@ class ConnectedDevice(Gtk.Box):
|
||||||
self.set_toggle_display_distance_end_button
|
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):
|
def set_device_name(self, name):
|
||||||
self.device_label.set_markup(f"<b>{name}</b>")
|
self.device_label.set_markup(f"<b>{name}</b>")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,17 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</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>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
|
|
@ -155,6 +166,35 @@
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</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>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@ class Logger:
|
||||||
|
|
||||||
class StateManager(GObject.GObject):
|
class StateManager(GObject.GObject):
|
||||||
__gsignals__ = {
|
__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
|
_instance = None
|
||||||
|
|
@ -32,7 +36,7 @@ class StateManager(GObject.GObject):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
GObject.GObject.__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.connected_device_name = None
|
||||||
|
|
||||||
self.start()
|
self.start()
|
||||||
|
|
@ -49,6 +53,16 @@ class StateManager(GObject.GObject):
|
||||||
new_device_name = StateManager.device_name(self.state)
|
new_device_name = StateManager.device_name(self.state)
|
||||||
if self.connected_device_name != new_device_name:
|
if self.connected_device_name != new_device_name:
|
||||||
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()
|
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
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class BreezydesktopWindow(Gtk.ApplicationWindow):
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
state_manager = StateManager.get_instance()
|
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.connected_device = ConnectedDevice()
|
||||||
self.no_device = NoDevice()
|
self.no_device = NoDevice()
|
||||||
|
|
|
||||||
|
|
@ -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
|
# read-only file that the driver writes (but never reads) to with its current state
|
||||||
DRIVER_STATE_FILE_PATH = '/dev/shm/xr_driver_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']
|
SBS_MODE_VALUES = ['unset', 'enable', 'disable']
|
||||||
MANAGED_EXTERNAL_MODES = ['virtual_display', 'sideview', 'none']
|
MANAGED_EXTERNAL_MODES = ['virtual_display', 'sideview', 'none']
|
||||||
VR_LITE_OUTPUT_MODES = ['mouse', 'joystick']
|
VR_LITE_OUTPUT_MODES = ['mouse', 'joystick']
|
||||||
|
|
@ -58,8 +58,24 @@ CONFIG_ENTRIES = {
|
||||||
'sideview_smooth_follow_enabled': [parse_boolean, False]
|
'sideview_smooth_follow_enabled': [parse_boolean, False]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Logger:
|
||||||
|
def info(self, message):
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
def error(self, message):
|
||||||
|
print(message)
|
||||||
|
|
||||||
class XRDriverIPC:
|
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_installed = False
|
||||||
self.breezy_installing = False
|
self.breezy_installing = False
|
||||||
self.user = user if user else pwd.getpwuid( os.getuid() )[0]
|
self.user = user if user else pwd.getpwuid( os.getuid() )[0]
|
||||||
|
|
@ -218,6 +234,7 @@ class XRDriverIPC:
|
||||||
state['sbs_mode_supported'] = False
|
state['sbs_mode_supported'] = False
|
||||||
state['firmware_update_recommended'] = False
|
state['firmware_update_recommended'] = False
|
||||||
state['device_license'] = {}
|
state['device_license'] = {}
|
||||||
|
state['breezy_desktop_smooth_follow_enabled'] = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with open(DRIVER_STATE_FILE_PATH, 'r') as f:
|
with open(DRIVER_STATE_FILE_PATH, 'r') as f:
|
||||||
|
|
@ -232,7 +249,7 @@ class XRDriverIPC:
|
||||||
state[key] = parse_int(value, 0)
|
state[key] = parse_int(value, 0)
|
||||||
elif key in ['calibration_setup', 'calibration_state', 'connected_device_brand', 'connected_device_model']:
|
elif key in ['calibration_setup', 'calibration_state', 'connected_device_brand', 'connected_device_model']:
|
||||||
state[key] = value
|
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)
|
state[key] = parse_boolean(value, False)
|
||||||
elif key == 'device_license':
|
elif key == 'device_license':
|
||||||
state[key] = json.loads(value)
|
state[key] = json.loads(value)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue