Repository: qutebrowser/qutebrowser

Issue:
RegistryUnavailableError when closing download prompt after closing window
Crash report from some while ago from @edrex, on v1.0.2: https://crashes.qutebrowser.org/view/d658759c

```
13:11:06 DEBUG    modes      tabbedbrowser:on_mode_left:618 Left status-input mode, focusing <qutebrowser.browser.webengine.webenginetab.WebEngineTab tab_id=1 url='https://[...].slack.com/messages/[...]/convo/[...]/'>
13:11:06 DEBUG    modes      modeman:leave:290 Ignoring leave request for KeyMode.prompt (reason aborted) as we're in mode KeyMode.normal
[...]
13:11:06 ERROR    misc       crashsignal:exception_hook:216 Uncaught exception
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/qutebrowser/utils/objreg.py", line 200, in _get_window_registry
    return win.registry
AttributeError: 'NoneType' object has no attribute 'registry'
 
During handling of the above exception, another exception occurred:
 
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/qutebrowser/mainwindow/prompt.py", line 335, in <lambda>
    maybe=True))
  File "/usr/lib/python3.6/site-packages/qutebrowser/keyinput/modeman.py", line 109, in leave
    instance(win_id).leave(mode, reason, maybe=maybe)
  File "/usr/lib/python3.6/site-packages/qutebrowser/keyinput/modeman.py", line 99, in instance
    return objreg.get('mode-manager', scope='window', window=win_id)
  File "/usr/lib/python3.6/site-packages/qutebrowser/utils/objreg.py", line 227, in get
    reg = _get_registry(scope, window, tab)
  File "/usr/lib/python3.6/site-packages/qutebrowser/utils/objreg.py", line 216, in _get_registry
    return _get_window_registry(window)
  File "/usr/lib/python3.6/site-packages/qutebrowser/utils/objreg.py", line 202, in _get_window_registry
    raise RegistryUnavailableError('window')
qutebrowser.utils.objreg.RegistryUnavailableError: window
```

---

> This is repeatable for me on linux/i3. I'm running in "tabs are windows" mode.
>  
>  - Click "print" button for PDF attachment in GMail
>  - It opens in a new window, and "Save to" dialog pops up
>  - Close that window
>  - Hit "escape" to exit the "save to" dialog which is displayed in the original gmail window as well
>  - Crash
>  
> I wonder if it's repeatable for a normal "save as" dialog when closing the originating window and then exiting the dialog from another. Also if it's related to "tabs are windows"



Discussion:
I can still reproduce this from an empty basedir with just

```
c.tabs.tabs_are_windows = True
```

in config.py. I'm not sure how to reproduce without this. Seems likely to be the factor.
(FYI, I removed some earlier comments talking about a GitMate.io bug here)

This also seems to happen when aborting (?) a download in some crash reports (possibly when closing a download tab and then cancelling the prompt?):

- https://crashes.qutebrowser.org/view/ee77a5f6
- https://crashes.qutebrowser.org/view/03c0c155
- https://crashes.qutebrowser.org/view/f36ab86e
- https://crashes.qutebrowser.org/view/f7ed6f72
- https://crashes.qutebrowser.org/view/f287a2b6
- https://crashes.qutebrowser.org/view/75e65467
- https://crashes.qutebrowser.org/view/7252125a
- https://crashes.qutebrowser.org/view/c13f62d9
Pretty sure I hit the same thing (filed a crash report).

1. `qutebrowser` (opens window 1)
2. `qutebrowser ~/downloads/some.pdf` (opens window 2, both windows have a download prompt)
3. Close window 2 via your window manager (without explicitly closing the download prompt)
4. Press `ESC` in window 1 to close the (now orphaned?) download prompt
5. Crash

I don't have `tabs_are_windows` set.

Step 2 presumably opens a download prompt only if you don't have the js pdf viewer.

Resolving patch:
diff --git a/qutebrowser/mainwindow/prompt.py b/qutebrowser/mainwindow/prompt.py
--- a/qutebrowser/mainwindow/prompt.py
+++ b/qutebrowser/mainwindow/prompt.py
@@ -22,6 +22,7 @@
 import os.path
 import html
 import collections
+import functools
 
 import attr
 from PyQt5.QtCore import (pyqtSlot, pyqtSignal, Qt, QTimer, QDir, QModelIndex,
@@ -329,11 +330,10 @@ def _on_show_prompts(self, question):
         log.prompt.debug("Displaying prompt {}".format(prompt))
         self._prompt = prompt
 
+        # If this question was interrupted, we already connected the signal
         if not question.interrupted:
-            # If this question was interrupted, we already connected the signal
             question.aborted.connect(
-                lambda: modeman.leave(self._win_id, prompt.KEY_MODE, 'aborted',
-                                      maybe=True))
+                functools.partial(self._on_aborted, prompt.KEY_MODE))
         modeman.enter(self._win_id, prompt.KEY_MODE, 'question asked')
 
         self.setSizePolicy(prompt.sizePolicy())
@@ -343,6 +343,15 @@ def _on_show_prompts(self, question):
         prompt.setFocus()
         self.update_geometry.emit()
 
+    @pyqtSlot()
+    def _on_aborted(self, key_mode):
+        """Leave KEY_MODE whenever a prompt is aborted."""
+        try:
+            modeman.leave(self._win_id, key_mode, 'aborted', maybe=True)
+        except objreg.RegistryUnavailableError:
+            # window was deleted: ignore
+            pass
+
     @pyqtSlot(usertypes.KeyMode)
     def _on_prompt_done(self, key_mode):
         """Leave the prompt mode in this window if a question was answered."""


Test patch:
diff --git a/tests/end2end/features/downloads.feature b/tests/end2end/features/downloads.feature
--- a/tests/end2end/features/downloads.feature
+++ b/tests/end2end/features/downloads.feature
@@ -92,6 +92,15 @@ Feature: Downloading things from a website.
         And I run :leave-mode
         Then no crash should happen
 
+    Scenario: Aborting a download in a different window (issue 3378)
+        When I set downloads.location.suggestion to filename
+        And I set downloads.location.prompt to true
+        And I open data/downloads/download.bin in a new window without waiting
+        And I wait for "Asking question <qutebrowser.utils.usertypes.Question default='*' mode=<PromptMode.download: 5> *" in the log
+        And I run :window-only
+        And I run :leave-mode
+        Then no crash should happen
+
     # https://github.com/qutebrowser/qutebrowser/issues/4240
     @qt<5.11.2
     Scenario: Downloading with SSL errors (issue 1413)