Skip to content

Commit e0a193e

Browse files
committed
Skip confusing buttons from dom0 and disp template
- Dom0: hide shutdown and pause, technically, shutdown can be used by GUIVMs in the future if the action was modified, currently, qubesd logs a failure. - There is no possibility to differentiate between "APPS" and "TEMPLATES" tabs, this means that disposable template "Start qube" is hidden from both tabs, that is not the intended behavior though but would require a redesign to fix. Current behavior though, allows searching for "default-dvm" and not have the "Start qube" button appear. Therefore, to start the disposable template from the app menu, select an application in the "TEMPLATES" tab. Fixes: QubesOS/qubes-issues#10288 For: QubesOS/qubes-issues#1512
1 parent a4c3ac3 commit e0a193e

4 files changed

Lines changed: 120 additions & 43 deletions

File tree

qubes_menu/app_widgets.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
logger = logging.getLogger('qubes-appmenu')
4242

43-
DISP_TEXT = 'new Disposable Qube from '
43+
DISP_TEXT = 'New disposable qube from '
4444

4545

4646
class AppEntry(Gtk.ListBoxRow):

qubes_menu/application_page.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,7 @@ def _selection_changed(self, _widget, row: Optional[VMRow]):
331331
self.selected_vm_entry = row
332332
self._set_right_visibility(True)
333333
self.network_indicator.set_network_state(row.vm_entry.has_network)
334-
self.control_list.update_visibility(row.vm_entry.power_state)
334+
self.control_list.update_visibility(row.vm_entry)
335335
self.control_list.unselect_all()
336336
self.app_list.ephemeral_vm = bool(
337337
self.selected_vm_entry.vm_entry.parent_vm)

qubes_menu/custom_widgets.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,9 @@ def get_appinfo(self) -> ApplicationInfo:
251251
return self.desktop_file_manager.get_app_info_by_name(
252252
vm_entry.settings_desktop_file_name)
253253

254-
def update_state(self, state): # pylint: disable=unused-argument
254+
def update_state(self, vm_entry: VMEntry):
255255
"""Update state: should be always visible."""
256+
# pylint: disable=unused-argument
256257
self.show_all()
257258

258259
def show_menu(self, _widget, event):
@@ -416,7 +417,7 @@ def __init__(self):
416417
self.show_all()
417418
self.command = None
418419

419-
def update_state(self, state):
420+
def update_state(self, vm_entry: VMEntry):
420421
"""
421422
Update own state (visibility/text/sensitivity) based on provided VM
422423
state.
@@ -461,32 +462,46 @@ def show_menu(self, _widget, event):
461462
if event.button == 3:
462463
self.menu.popup_at_pointer(None) # None means current event
463464

464-
def update_state(self, state):
465+
def update_state(self, vm_entry: VMEntry):
465466
"""
466467
Update own state (visibility/text/sensitivity) based on provided VM
467468
state.
468469
"""
469-
self.state = state
470-
if state == 'Running':
470+
vm_name = vm_entry.vm_name
471+
is_dispvm_template = vm_entry.is_dispvm_template
472+
self.state = vm_entry.power_state
473+
474+
if (
475+
vm_name == 'dom0'
476+
or (is_dispvm_template and self.state != "Running")
477+
):
478+
self.row_label.set_label(' ')
479+
self.set_sensitive(False)
480+
self.command = None
481+
self.icon.hide()
482+
return
483+
484+
self.set_sensitive(True)
485+
self.icon.show()
486+
if self.state == 'Running':
471487
self.row_label.set_label('Shutdown qube')
472488
self.command = 'qvm-shutdown'
473489
self.icon.set_from_pixbuf(load_icon("qappmenu-shutdown", size=None,
474490
pixel_size=15))
475491
return
476-
if state == 'Transient':
492+
if self.state == 'Transient':
477493
self.row_label.set_label('Kill qube')
478494
self.command = 'qvm-kill'
479495
self.icon.set_from_pixbuf(load_icon("qappmenu-shutdown", size=None,
480496
pixel_size=15))
481497
return
482-
if state == 'Halted':
498+
if self.state == 'Halted' and not is_dispvm_template:
483499
self.row_label.set_label('Start qube')
484500
self.command = 'qvm-start'
485501
self.icon.set_from_pixbuf(load_icon("qappmenu-start", size=None,
486502
pixel_size=15))
487-
488503
return
489-
if state == 'Paused':
504+
if self.state == 'Paused':
490505
self.row_label.set_label('Unpause qube')
491506
self.command = 'qvm-unpause'
492507
self.icon.set_from_pixbuf(load_icon("qappmenu-start", size=None,
@@ -504,13 +519,15 @@ def __init__(self):
504519
pixel_size=15))
505520
self.state = None
506521

507-
def update_state(self, state):
522+
def update_state(self, vm_entry: VMEntry):
508523
"""
509524
Update own state (visibility/text/sensitivity) based on provided VM
510525
state.
511526
"""
512-
self.state = state
513-
if state == 'Running':
527+
vm_name = vm_entry.vm_name
528+
self.state = vm_entry.power_state
529+
530+
if self.state == 'Running' and vm_name != 'dom0':
514531
self.row_label.set_label('Pause qube')
515532
self.set_sensitive(True)
516533
self.command = 'qvm-pause'
@@ -540,12 +557,12 @@ def __init__(self, app_page):
540557
self.add(self.start_item)
541558
self.add(self.pause_item)
542559

543-
def update_visibility(self, state):
560+
def update_visibility(self, vm_entry: VMEntry):
544561
"""
545562
Update children's state based on provided VM state.
546563
"""
547564
for row in self.get_children():
548-
row.update_state(state)
565+
row.update_state(vm_entry)
549566

550567

551568
class KeynavController:

qubes_menu/tests/test_app_page.py

Lines changed: 87 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,43 +30,101 @@ def test_app_page_vm_state(test_desktop_file_path, test_qapp, test_builder):
3030
dispatcher = MockDispatcher(test_qapp)
3131
vm_manager = VMManager(test_qapp, dispatcher)
3232

33-
with mock.patch.object(DesktopFileManager, 'desktop_dirs',
34-
[test_desktop_file_path]):
33+
with mock.patch.object(
34+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
35+
):
3536
desktop_file_manager = DesktopFileManager(test_qapp)
3637

3738
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
3839

39-
# select a turned off vm
40-
app_page.vm_list.select_row([row for row in app_page.vm_list.get_children()
41-
if row.vm_name == 'test-red'][0])
40+
# select dom0
41+
app_page.vm_list.select_row(
42+
[
43+
row
44+
for row in app_page.vm_list.get_children()
45+
if row.vm_name == "dom0"
46+
][0]
47+
)
48+
assert app_page.control_list.start_item.row_label.get_label() == " "
49+
assert app_page.control_list.pause_item.row_label.get_label() == " "
4250

43-
assert app_page.control_list.start_item.row_label.get_label() == \
44-
"Start qube"
45-
assert app_page.control_list.pause_item.row_label.get_label() == \
46-
" "
51+
# select a turned off vm
52+
app_page.vm_list.select_row(
53+
[
54+
row
55+
for row in app_page.vm_list.get_children()
56+
if row.vm_name == "test-red"
57+
][0]
58+
)
59+
60+
assert (
61+
app_page.control_list.start_item.row_label.get_label() == "Start qube"
62+
)
63+
assert app_page.control_list.pause_item.row_label.get_label() == " "
4764

4865
# select a turned on vm
49-
app_page.vm_list.select_row([row for row in app_page.vm_list.get_children()
50-
if row.vm_name == 'sys-usb'][0])
51-
52-
assert app_page.control_list.start_item.row_label.get_label() == \
53-
"Shutdown qube"
54-
assert app_page.control_list.pause_item.row_label.get_label() == \
55-
"Pause qube"
66+
app_page.vm_list.select_row(
67+
[
68+
row
69+
for row in app_page.vm_list.get_children()
70+
if row.vm_name == "sys-usb"
71+
][0]
72+
)
73+
74+
assert (
75+
app_page.control_list.start_item.row_label.get_label()
76+
== "Shutdown qube"
77+
)
78+
assert (
79+
app_page.control_list.pause_item.row_label.get_label() == "Pause qube"
80+
)
81+
82+
# select a turned off disposable template
83+
app_page.vm_list.select_row(
84+
[
85+
row
86+
for row in app_page.vm_list.get_children()
87+
if row.vm_name == "test-alt-dvm"
88+
][0]
89+
)
90+
assert app_page.control_list.start_item.row_label.get_label() == " "
91+
assert app_page.control_list.pause_item.row_label.get_label() == " "
92+
93+
# select a turned on disposable template
94+
app_page.vm_list.select_row(
95+
[
96+
row
97+
for row in app_page.vm_list.get_children()
98+
if row.vm_name == "test-alt-dvm-running"
99+
][0]
100+
)
101+
assert (
102+
app_page.control_list.start_item.row_label.get_label()
103+
== "Shutdown qube"
104+
)
105+
assert (
106+
app_page.control_list.pause_item.row_label.get_label() == "Pause qube"
107+
)
56108

57109

58110
def test_dispvm_parent_sorting(test_desktop_file_path, test_qapp, test_builder):
59111
# check if dispvm child is sorted after the parent
60-
test_qapp._qubes['disp1233'] = MockQube(
61-
name="disp1233", qapp=test_qapp, klass='DispVM',
62-
template_for_dispvms='True', template='default-dvm', auto_cleanup=True)
112+
test_qapp._qubes["disp1233"] = MockQube(
113+
name="disp1233",
114+
qapp=test_qapp,
115+
klass="DispVM",
116+
template_for_dispvms="True",
117+
template="default-dvm",
118+
auto_cleanup=True,
119+
)
63120
test_qapp.update_vm_calls()
64121

65122
dispatcher = MockDispatcher(test_qapp)
66123
vm_manager = VMManager(test_qapp, dispatcher)
67124

68-
with mock.patch.object(DesktopFileManager, 'desktop_dirs',
69-
[test_desktop_file_path]):
125+
with mock.patch.object(
126+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
127+
):
70128
desktop_file_manager = DesktopFileManager(test_qapp)
71129

72130
app_page = AppPage(vm_manager, test_builder, desktop_file_manager)
@@ -75,11 +133,11 @@ def test_dispvm_parent_sorting(test_desktop_file_path, test_qapp, test_builder):
75133

76134
for row in app_page.vm_list.get_children():
77135
if found_dvm:
78-
if row.vm_name == 'disp1233' and row.vm_entry.parent_vm:
136+
if row.vm_name == "disp1233" and row.vm_entry.parent_vm:
79137
break
80138
found_dvm = False
81139
continue
82-
if row.vm_name == 'default-dvm' and row.vm_entry._is_dispvm_template:
140+
if row.vm_entry.is_dispvm_template:
83141
found_dvm = True
84142
continue
85143
found_dvm = False
@@ -92,12 +150,14 @@ def test_settings_app_page(test_desktop_file_path, test_qapp, test_builder):
92150
dispatcher = MockDispatcher(test_qapp)
93151
vm_manager = VMManager(test_qapp, dispatcher)
94152

95-
with mock.patch.object(DesktopFileManager, 'desktop_dirs',
96-
[test_desktop_file_path]):
153+
with mock.patch.object(
154+
DesktopFileManager, "desktop_dirs", [test_desktop_file_path]
155+
):
97156
desktop_file_manager = DesktopFileManager(test_qapp)
98157

99-
settings_page = SettingsPage(test_qapp, test_builder,
100-
desktop_file_manager, dispatcher)
158+
settings_page = SettingsPage(
159+
test_qapp, test_builder, desktop_file_manager, dispatcher
160+
)
101161

102162
for row in settings_page.app_list.get_children():
103163
assert not row.app_info.vm

0 commit comments

Comments
 (0)