Skip to content

Commit 719c013

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
1 parent 1789756 commit 719c013

File tree

3 files changed

+62
-19
lines changed

3 files changed

+62
-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: 42 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,13 @@ 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(
151+
"domain-pre-delete",
152+
self.remove_domain_item
153+
)
154+
147155
self.dispatcher.add_handler("domain-shutdown", self.vm_shutdown)
148156
self.dispatcher.add_handler("domain-start-failed", self.vm_shutdown)
149157
self.dispatcher.add_handler("domain-start", self.vm_start)
@@ -242,9 +250,12 @@ def initialize_vm_data(self):
242250
self.vms.add(wrapped_vm)
243251
if wrapped_vm.is_dispvm_template:
244252
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()
253+
# Keep track of USBVMs
254+
if wrapped_vm.is_usbvm:
255+
if vm.is_running():
256+
self.active_usbvms.add(wrapped_vm)
257+
else:
258+
self.dormant_usbvms.add(wrapped_vm)
248259
except qubesadmin.exc.QubesException:
249260
# we don't have access to VM state
250261
pass
@@ -360,6 +371,23 @@ def device_unassigned(self, vm, _event, device, **_kwargs):
360371
# assigned. Cheers!
361372
return
362373

374+
def pci_action(self, vm, _event, _device, **_kwargs):
375+
# We assume PCI controllers could be assigned only when qube is shutdown
376+
wrapped_vm = backend.VM(vm)
377+
if wrapped_vm.is_usbvm:
378+
if wrapped_vm not in self.dormant_usbvms:
379+
self.dormant_usbvms.add(wrapped_vm)
380+
elif wrapped_vm in self.dormant_usbvms:
381+
self.dormant_usbvms.discard(wrapped_vm)
382+
383+
def remove_domain_item(self, _submitter, _event, vm, **_kwargs):
384+
# In a perfect world, core should trigger `device-unassign:pci` event
385+
# for PCI devices attached to an HVM before actually removing it and
386+
# this method should not be necessary. But we are not certain :/
387+
wrapped_vm = backend.VM(vm)
388+
if wrapped_vm in self.dormant_usbvms:
389+
self.dormant_usbvms.discard(wrapped_vm)
390+
363391
def update_single_feature(self, _vm, _event, feature, value=None, oldvalue=None):
364392
if not value:
365393
new = set()
@@ -533,8 +561,9 @@ def vm_start(self, vm, _event, **_kwargs):
533561
internal, attachable = False, False
534562
if attachable and not internal:
535563
self.vms.add(wrapped_vm)
536-
if wrapped_vm == self.sysusb:
537-
self.sysusb.is_running = True
564+
if wrapped_vm in self.dormant_usbvms:
565+
self.dormant_usbvms.discard(wrapped_vm)
566+
self.active_usbvms.add(wrapped_vm)
538567

539568
for devclass in DEV_TYPES:
540569
try:
@@ -548,8 +577,9 @@ def vm_start(self, vm, _event, **_kwargs):
548577

549578
def vm_shutdown(self, vm, _event, **_kwargs):
550579
wrapped_vm = backend.VM(vm)
551-
if wrapped_vm == self.sysusb:
552-
self.sysusb.is_running = False
580+
if wrapped_vm in self.active_usbvms:
581+
self.active_usbvms.discard(wrapped_vm)
582+
self.dormant_usbvms.add(wrapped_vm)
553583

554584
self.vms.discard(wrapped_vm)
555585
self.dispvm_templates.discard(wrapped_vm)
@@ -633,13 +663,13 @@ def show_menu(self, _unused, _event):
633663

634664
menu_items.append(device_item)
635665

636-
if not self.sysusb.is_running:
637-
sysusb_item = actionable_widgets.generate_wrapper_widget(
666+
for wrapped_vm in self.dormant_usbvms:
667+
usbvm_item = actionable_widgets.generate_wrapper_widget(
638668
Gtk.MenuItem,
639669
"activate",
640-
actionable_widgets.StartSysUsb(self.sysusb, theme),
670+
actionable_widgets.StartUSBVM(wrapped_vm, theme),
641671
)
642-
menu_items.append(sysusb_item)
672+
menu_items.append(usbvm_item)
643673

644674
for item in menu_items:
645675
tray_menu.add(item)

0 commit comments

Comments
 (0)