Github Issue #8878 - New Global Config app not closing if disposable in which doc link was opened is still running

Github Issue #8878 - New Global Config app not closing if disposable in which doc link was opened is still running

On Jan 20, UndeadDevel writes:

When clicking on doc links in the new Global Config app, e.g. the link to “online documentation” on the “URL Handling” page, a new DVM will open with firefox to display the linked doc page. However, this will block finishing interactions with the app, as it will not close on “OK” or “Cancel” button presses until that DVM has shut down again.

Diagnosis

Issue is reproducible. Happens to Cancel button, OK button and X Closing button of the main Window if user has clicked on any online help links. The help browser VMs are opened via two functions of _open_url_in_dvm & open_url_in_disposable, using subprocess and threading. Gtk refuses to quit while the opened threads are active.

Solution 1 (Ugly):

Let the subprocess timeout after qrexec_timeout seconds. The aim of the subprocess was to start disposable & open the help URL in Firefox within the new disposable via qubes.OpenURL RPC call. It should be open by qrexec_timeout seconds. And we do not want to parse Firefox system messages via subprocess. So something like this:

Ugly patch
index 5b569f9..ad75928 100644
--- a/qubes_config/widgets/utils.py
+++ b/qubes_config/widgets/utils.py
@@ -112,7 +112,7 @@ def _open_url_in_dvm(url, default_dvm: qubesadmin.vm.QubesVM):
     subprocess.run(
         ['qvm-run', '-p', '--service', f'--dispvm={default_dvm}',
          'qubes.OpenURL'], input=url.encode(), check=False,
-        stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
+        stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL, timeout=60)
 
 def open_url_in_disposable(url: str, qapp: qubesadmin.Qubes):
     """Open provided url in disposable qube based on default disposable

I simplified a little by not getting the actual qrexec_timeout from the template. But you get my point. Killing the dispossable qrexec subprocesses is also possible and will have the similar effect. But it is complex and reminds me of this sad {turnoff.us} comic. We can do better.

Solution 2 (Proper fix):

Hide the main Gtk Window while the disposable help threads finish gracefully. This will happen after user closes browser help windows and when disposables shutdown. This should be done for two individual _quit and _ask_to_quit functions.

Proper patch
diff --git a/qubes_config/global_config/global_config.py b/qubes_config/global_config/global_config.py
index 078df78..447daa0 100644
--- a/qubes_config/global_config/global_config.py
+++ b/qubes_config/global_config/global_config.py
@@ -469,6 +469,11 @@ class GlobalConfig(Gtk.Application):
             page.reset()
 
     def _quit(self, _widget=None):
+        ''' Hide the main Window '''
+        self.main_window.hide()
+        while Gtk.events_pending():
+            Gtk.main_iteration()
+        ''' Then wait for disposable helper threads to finish '''
         self.quit()
 
     def _ok(self, widget):
@@ -479,6 +484,9 @@ class GlobalConfig(Gtk.Application):
         can_quit = self.verify_changes()
         if not can_quit:
             return True
+        self.main_window.hide()
+        while Gtk.events_pending():
+            Gtk.main_iteration()
         self.quit()
         return False

I will wait for few days to see if anyone would suggest a better solution. Then I will submit the second patch.

1 Like