@@ -316,6 +316,26 @@ 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+
332+ async def perform_action (self ):
333+ # pylint: disable=consider-using-with
334+ await asyncio .create_subprocess_exec (
335+ "qvm-console-dispvm" , self .vm .name , stderr = subprocess .PIPE
336+ )
337+
338+
319339class OpenFileManagerItem (VMActionMenuItem ):
320340 """Attempts to open a file manager in the VM. If fails, displays an
321341 error message."""
@@ -368,6 +388,11 @@ def __init__(self, vm, app, icon_cache):
368388
369389 self .add (OpenFileManagerItem (self .vm , icon_cache ))
370390 self .add (RunTerminalItem (self .vm , icon_cache ))
391+
392+ # Debug console for developers, troubleshooting, headless qubes
393+ self .debug_console = RunDebugConsoleItem (self .vm , icon_cache )
394+ self .add (self .debug_console )
395+
371396 self .add (PreferencesItem (self .vm , icon_cache ))
372397 self .add (PauseItem (self .vm , icon_cache ))
373398 self .add (ShutdownItem (self .vm , icon_cache ))
@@ -376,6 +401,20 @@ def __init__(self, vm, app, icon_cache):
376401
377402 self .set_reserve_toggle_size (False )
378403 self .show_all ()
404+ self .debug_console_update ()
405+
406+ def debug_console_update (self , * _args , ** _kwargs ):
407+ # Debug console is shown only if debug property is set, no GUIVM is set
408+ # ... or with `wizard-mode` feature per qube or per entire GUIVM.
409+ if (
410+ self .app .wizard_mode
411+ or getattr (self .vm , "debug" )
412+ or not getattr (self .vm , "guivm" )
413+ or bool (self .vm .features .get ("wizard-mode" , False ))
414+ ):
415+ self .debug_console .show ()
416+ else :
417+ self .debug_console .hide ()
379418
380419
381420class PausedMenu (Gtk .Menu ):
@@ -668,6 +707,11 @@ def __init__(self, app_name, qapp, dispatcher, stats_dispatcher):
668707 self .set_application_id (app_name )
669708 self .register () # register Gtk Application
670709
710+ # to display debug console for all qubes
711+ self .wizard_mode = self .qapp .domains [self .qapp .local_name ].features .get (
712+ "wizard-mode" , False
713+ )
714+
671715 def register_events (self ):
672716 self .dispatcher .add_handler ("connection-established" , self .refresh_all )
673717 self .dispatcher .add_handler ("domain-pre-start" , self .update_domain_item )
@@ -717,6 +761,28 @@ def register_events(self):
717761
718762 self .stats_dispatcher .add_handler ("vm-stats" , self .update_stats )
719763
764+ self .dispatcher .add_handler ("property-set:debug" , self .debug_change )
765+ self .dispatcher .add_handler ("property-set:guivm" , self .debug_change )
766+ self .dispatcher .add_handler (
767+ "domain-feature-set:wizard-mode" , self .debug_change
768+ )
769+ self .dispatcher .add_handler (
770+ "domain-feature-delete:wizard-mode" , self .debug_change
771+ )
772+
773+ def debug_change (self , vm , * _args , ** _kwargs ):
774+ if vm == self .qapp .local_name :
775+ self .wizard_mode = self .qapp .domains [
776+ self .qapp .local_name
777+ ].features .get ("wizard-mode" , False )
778+ vms = self .menu_items
779+ else :
780+ vms = {vm }
781+ for menu in vms :
782+ submenu = self .menu_items [menu ].get_submenu ()
783+ if isinstance (submenu , StartedMenu ):
784+ submenu .debug_console_update ()
785+
720786 def show_menu (self , _unused , event ):
721787 self .tray_menu .popup_at_pointer (event ) # None means current event
722788
@@ -1069,6 +1135,15 @@ def _disconnect_signals(self, _event):
10691135
10701136 self .stats_dispatcher .remove_handler ("vm-stats" , self .update_stats )
10711137
1138+ self .dispatcher .remove_handler ("property-set:debug" , self .debug_change )
1139+ self .dispatcher .remove_handler ("property-set:guivm" , self .debug_change )
1140+ self .dispatcher .remove_handler (
1141+ "domain-feature-set:wizard-mode" , self .debug_change
1142+ )
1143+ self .dispatcher .remove_handler (
1144+ "domain-feature-delete:wizard-mode" , self .debug_change
1145+ )
1146+
10721147
10731148def main ():
10741149 """main function"""
0 commit comments