@@ -244,10 +244,18 @@ def __init__(self, vm):
244244 self .state = {'power' : "" , 'outdated' : "" }
245245 self .updateable = getattr (vm , 'updateable' , False )
246246 self .update (True )
247+ self .CPU_usage = None
248+ self .RAM_usage = None
249+
250+ def update_resource_usage (self , RAM_usage , CPU_usage ):
251+ self .RAM_usage = RAM_usage
252+ self .CPU_usage = CPU_usage
247253
248254 def update_power_state (self ):
249255 try :
250256 self .state ['power' ] = self .vm .get_power_state ()
257+ if self .state ["power" ] in ["Halted" , "Paused" , "Suspended" ]:
258+ self .update_resource_usage (None , None )
251259 if self .state ['power' ] == "Halted" and \
252260 self .vm .klass != "AdminVM" and \
253261 manager_utils .get_feature (
@@ -259,6 +267,7 @@ def update_power_state(self):
259267 except exc .QubesDaemonAccessError :
260268 self .state ['power' ] = ""
261269
270+
262271 self .state ['outdated' ] = ""
263272 try :
264273 if manager_utils .is_running (self .vm , False ):
@@ -422,6 +431,8 @@ def __init__(self, qubes_cache):
422431 "Label" ,
423432 "Name" ,
424433 "State" ,
434+ "CPU" ,
435+ "MEM" ,
425436 "Template" ,
426437 "NetVM" ,
427438 "Disk Usage" ,
@@ -453,6 +464,12 @@ def data(self, index, role):
453464 col_name = self .columns_indices [col ]
454465 vm = self .qubes_cache .get_vm (row )
455466
467+ if role == Qt .ItemDataRole .SizeHintRole :
468+ if col_name in ["CPU" , "MEM" ]:
469+ return QSize (100 , 22 )
470+ if role == Qt .ItemDataRole .TextAlignmentRole :
471+ if col_name in ["CPU" , "MEM" , "Disk Usage" ]:
472+ return Qt .AlignmentFlag .AlignCenter
456473 if role == Qt .ItemDataRole .DisplayRole :
457474 if col_name == "Name" :
458475 return vm .name
@@ -464,6 +481,14 @@ def data(self, index, role):
464481 return vm .template
465482 if col_name == "NetVM" :
466483 return vm .netvm
484+ if col_name == "CPU" :
485+ if not vm .CPU_usage :
486+ return "-"
487+ return vm .CPU_usage + " %"
488+ if col_name == "MEM" :
489+ if not vm .RAM_usage :
490+ return "-"
491+ return str (int (int (vm .RAM_usage ) / 1024 )) + " MiB"
467492 if col_name == "Disk Usage" :
468493 return vm .disk
469494 if col_name == "Internal" :
@@ -508,6 +533,13 @@ def data(self, index, role):
508533 if role == Qt .ItemDataRole .UserRole + 1 :
509534 if vm .klass == 'AdminVM' :
510535 return ""
536+ # Consider allowing dom0 to be sorted for CPU & MEM usage
537+ if col_name == "CPU" :
538+ if vm .CPU_usage :
539+ return int (vm .CPU_usage )
540+ if col_name == "MEM" :
541+ if vm .RAM_usage :
542+ return int (vm .RAM_usage )
511543 if col_name == "Label" :
512544 vmtype , vmcolor = vm .icon .split ("-" , 1 )
513545 try :
@@ -746,7 +778,14 @@ class VmManagerWindow(ui_qubemanager.Ui_VmManagerWindow, QMainWindow):
746778 # suppress saving settings while initializing widgets
747779 settings_loaded = False
748780
749- def __init__ (self , qt_app , qubes_app , dispatcher , _parent = None ):
781+ def __init__ (
782+ self ,
783+ qt_app ,
784+ qubes_app ,
785+ dispatcher ,
786+ stats_dispatcher = None ,
787+ _parent = None
788+ ):
750789 # pylint: disable=too-many-statements
751790 super ().__init__ ()
752791 self .setupUi (self )
@@ -772,6 +811,7 @@ def __init__(self, qt_app, qubes_app, dispatcher, _parent=None):
772811
773812 self .frame_width = 0
774813 self .frame_height = 0
814+ self .foreground = True
775815
776816 self .init_template_menu ()
777817 self .init_network_menu ()
@@ -908,6 +948,9 @@ def __init__(self, qt_app, qubes_app, dispatcher, _parent=None):
908948 dispatcher .add_handler ('domain-feature-delete:skip-update' ,
909949 self .on_domain_updates_available )
910950
951+ if stats_dispatcher :
952+ stats_dispatcher .add_handler ("vm-stats" , self .on_vm_stats )
953+
911954 self .installEventFilter (self )
912955
913956 # It needs to store threads until they finish
@@ -927,8 +970,10 @@ def eventFilter(self, _object, event):
927970 if event .type () == QEvent .Type .WindowActivate :
928971 self .update_running_size ()
929972 self .size_on_disk_timer .setInterval (1000 * 60 )
973+ self .foreground = True
930974 elif event .type () == QEvent .Type .WindowDeactivate :
931975 self .size_on_disk_timer .setInterval (1000 * 60 * 5 )
976+ self .foreground = False
932977 return False
933978
934979 def scroll_to_top (self ):
@@ -1191,6 +1236,16 @@ def update_running_size(self, *_args):
11911236 self .qubes_cache .get_vm (qid = vm .qid ).update (
11921237 update_size_on_disk = True , event = 'disk_size' )
11931238
1239+ def on_vm_stats (self , vm , _event , ** kwargs ):
1240+ if not self .foreground :
1241+ return
1242+ domain = self .qubes_app .domains [vm ]
1243+ self .qubes_cache .get_vm (qid = domain .qid ).update_resource_usage (
1244+ kwargs ["memory_kb" ],
1245+ kwargs ["cpu_usage" ],
1246+ )
1247+ self .proxy .invalidate ()
1248+
11941249 def on_domain_added (self , _submitter , _event , vm , ** _kwargs ):
11951250 try :
11961251 domain = self .qubes_app .domains [vm ]
0 commit comments