Skip to content

Commit 848a630

Browse files
committed
Show a "saving changes" dialog when saving changes in global config
fixes QubesOS/qubes-issues#9926
1 parent 4876fd1 commit 848a630

File tree

1 file changed

+49
-6
lines changed

1 file changed

+49
-6
lines changed

qubes_config/global_config/global_config.py

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@
2121
# pylint: disable=import-error
2222
"""Global Qubes Config tool."""
2323
import sys
24+
import threading
25+
import time
2426
from typing import Dict, Optional, List, Union, Any
2527
from html import escape
2628
import importlib.resources
2729
import logging
2830

2931
import qubesadmin
30-
import qubesadmin.events
3132
import qubesadmin.exc
3233
import qubesadmin.vm
3334
from ..widgets.gtk_utils import (
@@ -36,6 +37,7 @@
3637
load_theme,
3738
is_theme_light,
3839
resize_window_to_reasonable,
40+
show_dialog,
3941
)
4042
from ..widgets.gtk_widgets import ProgressBarDialog, ViewportHandler
4143
from ..widgets.utils import open_url_in_disposable
@@ -267,6 +269,8 @@ def __init__(self, qapp: qubesadmin.Qubes, policy_manager: PolicyManager):
267269
self.progress_bar_dialog = ProgressBarDialog(
268270
self, _("Loading system settings...")
269271
)
272+
self.save_thread: threading.Thread | None = None
273+
self.save_errors: List[str] = []
270274
self.handlers: Dict[str, PageHandler] = {}
271275

272276
def do_command_line(self, command_line):
@@ -555,13 +559,11 @@ def get_current_page(self) -> Optional[PageHandler]:
555559
self.main_notebook.get_nth_page(page_num).get_name(), None
556560
)
557561

558-
def save_page(self, page: PageHandler) -> bool:
559-
"""Save provided page and emit any necessary signals;
560-
return True if successful, False otherwise"""
562+
def perform_save(self, page):
563+
"""Actual saving thread"""
561564
# pylint: disable=protected-access
562565
# need to invalidate cache before and after saving to avoid
563566
# stale cache
564-
565567
self.qapp._invalidate_cache_all()
566568
try:
567569
page.save()
@@ -572,11 +574,52 @@ def save_page(self, page: PageHandler) -> bool:
572574
self.qapp._invalidate_cache_all()
573575
page.reset()
574576
except Exception as ex:
577+
self.save_errors.append(str(ex))
578+
579+
def save_page(self, page: PageHandler) -> bool:
580+
"""Save provided page and emit any necessary signals;
581+
return True if successful, False otherwise"""
582+
self.save_thread = threading.Thread(target=self.perform_save, args=[page])
583+
self.save_thread.start()
584+
585+
spinner = None
586+
dialog = None
587+
time.sleep(0.01)
588+
589+
if self.save_thread.is_alive():
590+
# show waiting dialog
591+
spinner = Gtk.Spinner()
592+
spinner.start()
593+
dialog = show_dialog(
594+
self.main_window,
595+
_("Saving changes"),
596+
_("Saving global configuration changes..."),
597+
{},
598+
spinner,
599+
)
600+
dialog.set_deletable(False)
601+
dialog.show()
602+
603+
# wait for thread and spin spinner
604+
while self.save_thread.is_alive():
605+
while Gtk.events_pending():
606+
Gtk.main_iteration()
607+
time.sleep(0.1)
608+
609+
# cleanup
610+
if spinner:
611+
spinner.stop()
612+
if dialog:
613+
dialog.destroy()
614+
615+
if self.save_errors:
575616
show_error(
576617
self.main_window,
577618
_("Could not save changes"),
578-
_("The following error occurred: ") + escape(str(ex)),
619+
_("The following error occurred: ")
620+
+ escape("\n".join(self.save_errors)),
579621
)
622+
self.save_errors = []
580623
return False
581624
return True
582625

0 commit comments

Comments
 (0)