Skip to content

Commit 09bb5ab

Browse files
committed
Show "List USB Devices" option if sys-usb exists
Also show individual menu items if user has more than one usbvm resolves: QubesOS/qubes-issues#10131 resolves: QubesOS/qubes-issues#10202 resolves: QubesOS/qubes-issues#10216
1 parent 1789756 commit 09bb5ab

File tree

3 files changed

+60
-19
lines changed

3 files changed

+60
-19
lines changed

qui/devices/actionable_widgets.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -361,20 +361,20 @@ async def widget_action(self, *_args):
361361
)
362362

363363

364-
#### Start sys-usb
364+
#### Start sys-usb (or other custom USBVMs)
365365

366366

367-
class StartSysUsb(ActionableWidget, SimpleActionWidget):
368-
def __init__(self, sysusb: backend.VM, variant: str = "dark"):
367+
class StartUSBVM(ActionableWidget, SimpleActionWidget):
368+
def __init__(self, usbvm: backend.VM, variant: str = "dark"):
369369
super().__init__(
370-
icon_name=sysusb.icon_name,
371-
text="<b>List USB Devices " "(start sys-usb)</b>",
370+
icon_name=usbvm.icon_name,
371+
text="<b>List USB Devices " "(start {})</b>".format(usbvm.name),
372372
variant=variant,
373373
)
374-
self.sysusb = sysusb
374+
self.usbvm = usbvm
375375

376376
async def widget_action(self, *_args):
377-
self.sysusb.vm_object.start()
377+
self.usbvm.vm_object.start()
378378

379379

380380
#### Configuration-related actions

qui/devices/backend.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,19 @@ def is_attachable(self) -> bool:
8787
"""
8888
return self.vm_class != "AdminVM" and self._vm.is_running()
8989

90+
@property
91+
def is_usbvm(self) -> bool:
92+
"""
93+
Does the VM have a PCI USB controller attached to it?
94+
We do not need to cache this since it is checked only at Qui Devices
95+
initialization as well a PCI assignment/un-assignment
96+
"""
97+
for dev in self._vm.devices["pci"].get_assigned_devices():
98+
for interface in dev.device.interfaces:
99+
if interface.category == DeviceCategory.PCI_USB:
100+
return True
101+
return False
102+
90103
@property
91104
def vm_object(self):
92105
"""

qui/devices/device_widget.py

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ def __init__(self, app_name, qapp, dispatcher):
112112
self.vms: Set[backend.VM] = set()
113113
self.dispvm_templates: Set[backend.VM] = set()
114114
self.parent_ports_to_hide = []
115-
self.sysusb: backend.VM | None = None
115+
self.active_usbvms: Set[backend.VM] = set()
116+
self.dormant_usbvms: Set[backend.VM] = set()
116117
self.dev_update_queue: Set = set()
117118
self.vm_update_queue: Set = set()
118119

@@ -144,6 +145,10 @@ def __init__(self, app_name, qapp, dispatcher):
144145
"device-unassign:" + devclass, self.device_unassigned
145146
)
146147

148+
self.dispatcher.add_handler("device-assign:pci", self.pci_action)
149+
self.dispatcher.add_handler("device-unassign:pci", self.pci_action)
150+
self.dispatcher.add_handler("domain-pre-delete", self.remove_domain_item)
151+
147152
self.dispatcher.add_handler("domain-shutdown", self.vm_shutdown)
148153
self.dispatcher.add_handler("domain-start-failed", self.vm_shutdown)
149154
self.dispatcher.add_handler("domain-start", self.vm_start)
@@ -242,9 +247,12 @@ def initialize_vm_data(self):
242247
self.vms.add(wrapped_vm)
243248
if wrapped_vm.is_dispvm_template:
244249
self.dispvm_templates.add(wrapped_vm)
245-
if vm.name == "sys-usb":
246-
self.sysusb = wrapped_vm
247-
self.sysusb.is_running = vm.is_running()
250+
# Keep track of USBVMs
251+
if wrapped_vm.is_usbvm:
252+
if vm.is_running():
253+
self.active_usbvms.add(wrapped_vm)
254+
else:
255+
self.dormant_usbvms.add(wrapped_vm)
248256
except qubesadmin.exc.QubesException:
249257
# we don't have access to VM state
250258
pass
@@ -360,6 +368,24 @@ def device_unassigned(self, vm, _event, device, **_kwargs):
360368
# assigned. Cheers!
361369
return
362370

371+
def pci_action(self, vm, _event, **_kwargs):
372+
# We assume PCI controllers could be assigned only when qube is shutdown
373+
wrapped_vm = backend.VM(vm)
374+
if wrapped_vm.is_usbvm:
375+
if wrapped_vm not in self.dormant_usbvms:
376+
self.dormant_usbvms.add(wrapped_vm)
377+
elif wrapped_vm in self.dormant_usbvms:
378+
self.dormant_usbvms.discard(wrapped_vm)
379+
380+
def remove_domain_item(self, _submitter, _event, vm, **_kwargs):
381+
# In a perfect world, core should trigger `device-unassign:pci` event
382+
# for PCI devices attached to an HVM before actually removing it and
383+
# this method should not be necessary. But we are not certain :/
384+
for wrapped_vm in self.dormant_usbvms:
385+
if wrapped_vm.name == vm:
386+
self.dormant_usbvms.discard(wrapped_vm)
387+
break
388+
363389
def update_single_feature(self, _vm, _event, feature, value=None, oldvalue=None):
364390
if not value:
365391
new = set()
@@ -533,8 +559,9 @@ def vm_start(self, vm, _event, **_kwargs):
533559
internal, attachable = False, False
534560
if attachable and not internal:
535561
self.vms.add(wrapped_vm)
536-
if wrapped_vm == self.sysusb:
537-
self.sysusb.is_running = True
562+
if wrapped_vm in self.dormant_usbvms:
563+
self.dormant_usbvms.discard(wrapped_vm)
564+
self.active_usbvms.add(wrapped_vm)
538565

539566
for devclass in DEV_TYPES:
540567
try:
@@ -548,8 +575,9 @@ def vm_start(self, vm, _event, **_kwargs):
548575

549576
def vm_shutdown(self, vm, _event, **_kwargs):
550577
wrapped_vm = backend.VM(vm)
551-
if wrapped_vm == self.sysusb:
552-
self.sysusb.is_running = False
578+
if wrapped_vm in self.active_usbvms:
579+
self.active_usbvms.discard(wrapped_vm)
580+
self.dormant_usbvms.add(wrapped_vm)
553581

554582
self.vms.discard(wrapped_vm)
555583
self.dispvm_templates.discard(wrapped_vm)
@@ -633,13 +661,13 @@ def show_menu(self, _unused, _event):
633661

634662
menu_items.append(device_item)
635663

636-
if not self.sysusb.is_running:
637-
sysusb_item = actionable_widgets.generate_wrapper_widget(
664+
for wrapped_vm in self.dormant_usbvms:
665+
usbvm_item = actionable_widgets.generate_wrapper_widget(
638666
Gtk.MenuItem,
639667
"activate",
640-
actionable_widgets.StartSysUsb(self.sysusb, theme),
668+
actionable_widgets.StartUSBVM(wrapped_vm, theme),
641669
)
642-
menu_items.append(sysusb_item)
670+
menu_items.append(usbvm_item)
643671

644672
for item in menu_items:
645673
tray_menu.add(item)

0 commit comments

Comments
 (0)