Skip to content

Commit fd030cf

Browse files
committed
Add Debug Console to Qui Domains systray widget
fixes: QubesOS/qubes-issues#9788
1 parent 7652c60 commit fd030cf

1 file changed

Lines changed: 96 additions & 0 deletions

File tree

qui/tray/domains.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,34 @@ async def perform_action(self):
316316
)
317317

318318

319+
class RunDebugConsoleItem(VMActionMenuItem):
320+
"""Run Debug Console menu Item. When activated runs a qvm-console-dispvm."""
321+
322+
def __init__(self, vm, icon_cache):
323+
img = Gtk.Image.new_from_file(
324+
"/usr/share/icons/HighContrast/16x16/apps/logviewer.png"
325+
)
326+
super().__init__(
327+
vm,
328+
label=_("Debug Console"),
329+
img=img,
330+
)
331+
self.visible = False
332+
self.connect("show", self.on_show_event)
333+
334+
def on_show_event(self, widget):
335+
if self.visible:
336+
widget.show()
337+
else:
338+
widget.hide()
339+
340+
async def perform_action(self):
341+
# pylint: disable=consider-using-with
342+
await asyncio.create_subprocess_exec(
343+
"qvm-console-dispvm", self.vm.name, stderr=subprocess.PIPE
344+
)
345+
346+
319347
class OpenFileManagerItem(VMActionMenuItem):
320348
"""Attempts to open a file manager in the VM. If fails, displays an
321349
error message."""
@@ -368,15 +396,37 @@ def __init__(self, vm, app, icon_cache):
368396

369397
self.add(OpenFileManagerItem(self.vm, icon_cache))
370398
self.add(RunTerminalItem(self.vm, icon_cache))
399+
400+
# Debug console for developers, troubleshooting, headless qubes
401+
self.debug_console = RunDebugConsoleItem(self.vm, icon_cache)
402+
self.add(self.debug_console)
403+
371404
self.add(PreferencesItem(self.vm, icon_cache))
372405
self.add(PauseItem(self.vm, icon_cache))
373406
self.add(ShutdownItem(self.vm, icon_cache))
374407
if self.vm.klass != "DispVM" or not self.vm.auto_cleanup:
375408
self.add(RestartItem(self.vm, icon_cache))
376409

377410
self.set_reserve_toggle_size(False)
411+
self.debug_console_update()
378412
self.show_all()
379413

414+
def debug_console_update(self, *_args, **_kwargs):
415+
# Debug console is shown only if debug property is set, no GUIVM is set
416+
# ... or with `wizard-mode` feature per qube or per entire GUIVM.
417+
if (
418+
self.app.wizard_mode
419+
or getattr(self.vm, "debug")
420+
or not getattr(self.vm, "guivm")
421+
or not self.vm.features.check_with_template("gui", False)
422+
or self.vm.features.get("wizard-mode", False)
423+
):
424+
self.debug_console.visible = True
425+
self.debug_console.show()
426+
else:
427+
self.debug_console.visible = False
428+
self.debug_console.hide()
429+
380430

381431
class PausedMenu(Gtk.Menu):
382432
"""The sub-menu for a paused domain"""
@@ -668,6 +718,11 @@ def __init__(self, app_name, qapp, dispatcher, stats_dispatcher):
668718
self.set_application_id(app_name)
669719
self.register() # register Gtk Application
670720

721+
# to display debug console for all qubes
722+
self.wizard_mode = self.qapp.domains[self.qapp.local_name].features.get(
723+
"wizard-mode", False
724+
)
725+
671726
def register_events(self):
672727
self.dispatcher.add_handler("connection-established", self.refresh_all)
673728
self.dispatcher.add_handler("domain-pre-start", self.update_domain_item)
@@ -717,6 +772,32 @@ def register_events(self):
717772

718773
self.stats_dispatcher.add_handler("vm-stats", self.update_stats)
719774

775+
self.dispatcher.add_handler("property-set:debug", self.debug_change)
776+
self.dispatcher.add_handler("property-set:guivm", self.debug_change)
777+
self.dispatcher.add_handler("domain-feature-set:gui", self.debug_change)
778+
self.dispatcher.add_handler(
779+
"domain-feature-delete:gui", self.debug_change
780+
)
781+
self.dispatcher.add_handler(
782+
"domain-feature-set:wizard-mode", self.debug_change
783+
)
784+
self.dispatcher.add_handler(
785+
"domain-feature-delete:wizard-mode", self.debug_change
786+
)
787+
788+
def debug_change(self, vm, *_args, **_kwargs):
789+
if vm == self.qapp.local_name:
790+
self.wizard_mode = self.qapp.domains[
791+
self.qapp.local_name
792+
].features.get("wizard-mode", False)
793+
vms = self.menu_items
794+
else:
795+
vms = {vm}
796+
for menu in vms:
797+
submenu = self.menu_items[menu].get_submenu()
798+
if isinstance(submenu, StartedMenu):
799+
submenu.debug_console_update()
800+
720801
def show_menu(self, _unused, event):
721802
self.tray_menu.popup_at_pointer(event) # None means current event
722803

@@ -1069,6 +1150,21 @@ def _disconnect_signals(self, _event):
10691150

10701151
self.stats_dispatcher.remove_handler("vm-stats", self.update_stats)
10711152

1153+
self.dispatcher.remove_handler("property-set:debug", self.debug_change)
1154+
self.dispatcher.remove_handler("property-set:guivm", self.debug_change)
1155+
self.dispatcher.remove_handler(
1156+
"domain-feature-set:gui", self.debug_change
1157+
)
1158+
self.dispatcher.remove_handler(
1159+
"domain-feature-delete:gui", self.debug_change
1160+
)
1161+
self.dispatcher.remove_handler(
1162+
"domain-feature-set:wizard-mode", self.debug_change
1163+
)
1164+
self.dispatcher.remove_handler(
1165+
"domain-feature-delete:wizard-mode", self.debug_change
1166+
)
1167+
10721168

10731169
def main():
10741170
"""main function"""

0 commit comments

Comments
 (0)