Add virtual display management to the UI
This commit is contained in:
parent
854d74d983
commit
2aa2de6009
|
|
@ -10,6 +10,7 @@
|
|||
<file preprocess="xml-stripblanks">gtk/no-extension.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/no-license.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/shortcut-dialog.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/virtual-display-row.ui</file>
|
||||
<file preprocess="xml-stripblanks">gtk/window.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
from gi.repository import Gio, Gtk, GObject
|
||||
from gi.repository import Gio, GLib, Gtk, GObject
|
||||
from .configmanager import ConfigManager
|
||||
from .extensionsmanager import ExtensionsManager
|
||||
from .license import BREEZY_GNOME_FEATURES
|
||||
|
|
@ -6,6 +6,7 @@ from .settingsmanager import SettingsManager
|
|||
from .shortcutdialog import bind_shortcut_settings
|
||||
from .statemanager import StateManager
|
||||
from .virtualdisplaymanager import VirtualDisplayManager
|
||||
from .virtualdisplayrow import VirtualDisplayRow
|
||||
from .xrdriveripc import XRDriverIPC
|
||||
import gettext
|
||||
import logging
|
||||
|
|
@ -32,8 +33,10 @@ class ConnectedDevice(Gtk.Box):
|
|||
# widescreen_mode_switch = Gtk.Template.Child()
|
||||
# widescreen_mode_row = Gtk.Template.Child()
|
||||
# curved_display_switch = Gtk.Template.Child()
|
||||
add_virtual_display_button_1080p = Gtk.Template.Child()
|
||||
add_virtual_display_button_1440p = Gtk.Template.Child()
|
||||
top_features_group = Gtk.Template.Child()
|
||||
add_virtual_display_menu = Gtk.Template.Child()
|
||||
add_virtual_display_button = Gtk.Template.Child()
|
||||
launch_display_settings_button = Gtk.Template.Child()
|
||||
set_toggle_display_distance_start_button = Gtk.Template.Child()
|
||||
set_toggle_display_distance_end_button = Gtk.Template.Child()
|
||||
reassign_toggle_xr_effect_shortcut_button = Gtk.Template.Child()
|
||||
|
|
@ -70,8 +73,8 @@ class ConnectedDevice(Gtk.Box):
|
|||
# self.follow_mode_switch,
|
||||
# self.follow_threshold_scale,
|
||||
# self.curved_display_switch,
|
||||
self.add_virtual_display_button_1080p,
|
||||
self.add_virtual_display_button_1440p,
|
||||
self.add_virtual_display_menu,
|
||||
self.add_virtual_display_button,
|
||||
self.set_toggle_display_distance_start_button,
|
||||
self.set_toggle_display_distance_end_button,
|
||||
self.movement_look_ahead_scale,
|
||||
|
|
@ -116,8 +119,9 @@ class ConnectedDevice(Gtk.Box):
|
|||
self.set_toggle_display_distance_start_button,
|
||||
self.set_toggle_display_distance_end_button
|
||||
])
|
||||
self.add_virtual_display_button_1080p.connect('clicked', lambda *args: self.on_add_virtual_display(1920, 1080))
|
||||
self.add_virtual_display_button_1440p.connect('clicked', lambda *args: self.on_add_virtual_display(2560, 1440))
|
||||
self.add_virtual_display_menu.set_active_id('1080p')
|
||||
self.add_virtual_display_button.connect('clicked', self.on_add_virtual_display)
|
||||
self.launch_display_settings_button.connect('clicked', self._launch_display_settings)
|
||||
|
||||
self.state_manager = StateManager.get_instance()
|
||||
# self.state_manager.bind_property('follow-mode', self.follow_mode_switch, 'active', GObject.BindingFlags.DEFAULT)
|
||||
|
|
@ -133,6 +137,7 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
self.use_optimal_monitor_config_switch.connect('notify::active', self._refresh_use_optimal_monitor_config)
|
||||
|
||||
self._handle_switch_enabled_state(self.effect_enable_switch, None)
|
||||
self._handle_enabled_features(self.state_manager, None)
|
||||
self._handle_device_supports_sbs(self.state_manager, None)
|
||||
self._handle_enabled_config(None, None)
|
||||
|
|
@ -144,6 +149,16 @@ class ConnectedDevice(Gtk.Box):
|
|||
|
||||
self.connect("destroy", self._on_widget_destroy)
|
||||
|
||||
self.virtual_displays_by_pid = {}
|
||||
|
||||
self._settings_displays_app_info = None
|
||||
|
||||
# use Gio.AppInfo.get_all() and find the one where appinfo.get_id() == 'gnome-display-panel.desktop'
|
||||
for appinfo in Gio.AppInfo.get_all():
|
||||
if appinfo.get_id() == 'gnome-display-panel.desktop':
|
||||
self._settings_displays_app_info = appinfo
|
||||
break
|
||||
|
||||
def _handle_monitor_wrapping_scheme_setting_changed(self, settings, val):
|
||||
self.monitor_wrapping_scheme_menu.set_active_id(val)
|
||||
|
||||
|
|
@ -208,12 +223,41 @@ class ConnectedDevice(Gtk.Box):
|
|||
widget.connect('clicked', lambda *args, widget=widget: on_set_display_distance_toggle(widget))
|
||||
reload_display_distance_toggle_button(widget)
|
||||
|
||||
def on_add_virtual_display(self, width, height):
|
||||
logger.info(f"Adding virtual display {width}x{height}")
|
||||
def on_add_virtual_display(self, *args):
|
||||
resolution = self.add_virtual_display_menu.get_active_id()
|
||||
logger.info(f"Adding virtual display {resolution}")
|
||||
|
||||
width = 1920
|
||||
height = 1080
|
||||
if resolution == '1440p':
|
||||
width = 2560
|
||||
height = 1440
|
||||
|
||||
self.virtual_display_manager.create_virtual_display(width, height, 60)
|
||||
|
||||
def _on_virtual_displays_update(self, virtual_display_manager, val):
|
||||
logger.info(f"Found {len(virtual_display_manager.displays)} virtual displays")
|
||||
GLib.idle_add(self._on_virtual_displays_update_gui, virtual_display_manager)
|
||||
|
||||
def _on_virtual_displays_update_gui(self, virtual_display_manager):
|
||||
self.launch_display_settings_button.set_visible(
|
||||
self._settings_displays_app_info is not None and len(virtual_display_manager.displays) > 0
|
||||
)
|
||||
|
||||
for pid, child in self.virtual_displays_by_pid.items():
|
||||
self.top_features_group.remove(child)
|
||||
|
||||
new_displays_by_pid = {}
|
||||
for display in virtual_display_manager.displays:
|
||||
child = self.virtual_displays_by_pid.get(
|
||||
display['pid'],
|
||||
VirtualDisplayRow(display['pid'], display['width'], display['height'], 60))
|
||||
self.top_features_group.add(child)
|
||||
new_displays_by_pid[display['pid']] = child
|
||||
|
||||
self.virtual_displays_by_pid = new_displays_by_pid
|
||||
|
||||
def _launch_display_settings(self, *args):
|
||||
self._settings_displays_app_info.launch()
|
||||
|
||||
def _on_widget_destroy(self, widget):
|
||||
# self.state_manager.unbind_property('follow-mode', self.follow_mode_switch, 'active')
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
<property name="margin-end">20</property>
|
||||
<property name="spacing">20</property>
|
||||
<child>
|
||||
<object class="AdwPreferencesGroup">
|
||||
<object class="AdwPreferencesGroup" id="top_features_group">
|
||||
<property name="title" translatable="yes"><!-- section heading for switches that enable certain features -->Features</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
|
|
@ -54,28 +54,47 @@
|
|||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes"><!-- adjustment slider -->Virtual monitors</property>
|
||||
<property name="valign">2</property>
|
||||
<property name="valign">2</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="spacing">30</property>
|
||||
<property name="width-request">150</property>
|
||||
<property name="margin-start">30</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_virtual_display_button_1080p">
|
||||
<property name="name">add-virtual-display</property>
|
||||
<object class="GtkButton" id="launch_display_settings_button">
|
||||
<property name="visible">0</property>
|
||||
<property name="name">launch-display-settings</property>
|
||||
<property name="valign">3</property>
|
||||
<property name="label" translatable="yes">Add 1080p</property>
|
||||
<property name="label" translatable="yes">Rearrange displays</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_virtual_display_button_1440p">
|
||||
<property name="name">add-virtual-display</property>
|
||||
<property name="valign">3</property>
|
||||
<property name="label" translatable="yes">Add 1440p</property>
|
||||
<object class="GtkBox">
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="add_virtual_display_menu">
|
||||
<items>
|
||||
<item translatable="yes" id="1080p">1080p</item>
|
||||
<item translatable="yes" id="1440p">1440p</item>
|
||||
</items>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="suffix">
|
||||
<object class="GtkButton" id="add_virtual_display_button">
|
||||
<property name="name">add-virtual-display</property>
|
||||
<property name="icon-name">list-add-symbolic</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
|
|
@ -148,6 +167,10 @@
|
|||
<property name="spacing">30</property>
|
||||
<property name="width-request">150</property>
|
||||
<property name="margin-start">30</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="monitor_wrapping_scheme_menu">
|
||||
<items>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<template class="VirtualDisplayRow" parent="AdwActionRow">
|
||||
<property name="subtitle"></property>
|
||||
<child type="suffix">
|
||||
<object class="GtkButton" id="remove_virtual_display_button">
|
||||
<property name="name">remove-virtual-display</property>
|
||||
<property name="icon-name">user-trash-symbolic</property>
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="flat"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -45,20 +45,20 @@ class VirtualDisplayManager(GObject.GObject):
|
|||
if (os.waitpid(pid, os.WNOHANG) == (pid, 0)):
|
||||
return True
|
||||
except ChildProcessError:
|
||||
return True
|
||||
# process isn't tied to the current process, it's not dead if it's still open
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def _prune_dead_display_processes(self):
|
||||
self.set_property('displays', [disp for disp in self.displays if not self._process_dead(disp['pid'])])
|
||||
self._save_processes()
|
||||
new_displays = [disp for disp in self.displays if not self._process_dead(disp['pid'])]
|
||||
if new_displays != self.displays:
|
||||
self.set_property('displays', new_displays)
|
||||
self._save_processes()
|
||||
|
||||
return GLib.SOURCE_CONTINUE
|
||||
|
||||
def create_virtual_display(self, width, height, framerate) -> int:
|
||||
self._create_virtual_display(width, height, framerate)
|
||||
|
||||
def _create_virtual_display(self, width, height, framerate):
|
||||
def create_virtual_display(self, width, height, framerate):
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
[f"{bindir}/virtualdisplay", "--width", str(width), "--height", str(height), "--framerate", str(framerate)],
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
from gi.repository import Adw, Gtk
|
||||
from .virtualdisplaymanager import VirtualDisplayManager
|
||||
|
||||
import gettext
|
||||
|
||||
_ = gettext.gettext
|
||||
|
||||
@Gtk.Template(resource_path='/com/xronlinux/BreezyDesktop/gtk/virtual-display-row.ui')
|
||||
class VirtualDisplayRow(Adw.ActionRow):
|
||||
__gtype_name__ = "VirtualDisplayRow"
|
||||
|
||||
remove_virtual_display_button = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, pid, width, height, framerate):
|
||||
super(Adw.ActionRow, self).__init__()
|
||||
self.init_template()
|
||||
self.pid = pid
|
||||
|
||||
icon = Gtk.Image.new_from_icon_name("video-display-symbolic")
|
||||
|
||||
# padding around the icon
|
||||
self.add_prefix(Gtk.Label(label=" "))
|
||||
self.add_prefix(icon)
|
||||
self.add_prefix(Gtk.Label(label=" "))
|
||||
|
||||
self.set_subtitle(f"{width} x {height}")
|
||||
|
||||
self.remove_virtual_display_button.connect('clicked', self._remove_virtual_display)
|
||||
|
||||
def _remove_virtual_display(self, widget):
|
||||
VirtualDisplayManager.get_instance().destroy_virtual_display(self.pid)
|
||||
Loading…
Reference in New Issue