From 3dc7a1b7358d9d0926b54794a7c44d73d7c95206 Mon Sep 17 00:00:00 2001 From: Florian Bruhin Date: Mon, 4 Aug 2014 03:14:14 +0200 Subject: [PATCH] Lock mode while prompting. --- qutebrowser/browser/hints.py | 19 +++++++++++++------ qutebrowser/keyinput/modeman.py | 23 +++++++++++++++++++++++ qutebrowser/widgets/statusbar/command.py | 2 +- qutebrowser/widgets/statusbar/prompter.py | 8 +++++++- qutebrowser/widgets/webview.py | 6 +++--- 5 files changed, 47 insertions(+), 11 deletions(-) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 4a9e448b9..7fa29ccdf 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -167,6 +167,14 @@ class HintManager(QObject): modeman.instance().left.connect(self.on_mode_left) modeman.instance().entered.connect(self.on_mode_entered) + def _cleanup(self): + """Clean up after hinting.""" + for elem in self._context.elems.values(): + if not elem.label.isNull(): + elem.label.removeFromDocument() + self._context = None + message.instance().set_text('') + def _hint_strings(self, elems): """Calculate the hint strings for elems. @@ -507,7 +515,10 @@ class HintManager(QObject): self._context = ctx self._connect_frame_signals() self.hint_strings_updated.emit(strings) - modeman.enter(KeyMode.hint, 'HintManager.start') + try: + modeman.enter(KeyMode.hint, 'HintManager.start') + except modeman.ModeLockedError: + self._cleanup() def handle_partial_key(self, keystr): """Handle a new partial keypress.""" @@ -630,8 +641,4 @@ class HintManager(QObject): # self._context might be None, because the current tab is not # hinting. return - for elem in self._context.elems.values(): - if not elem.label.isNull(): - elem.label.removeFromDocument() - self._context = None - message.instance().set_text('') + self._cleanup() diff --git a/qutebrowser/keyinput/modeman.py b/qutebrowser/keyinput/modeman.py index 1df81754b..5feafa8b3 100644 --- a/qutebrowser/keyinput/modeman.py +++ b/qutebrowser/keyinput/modeman.py @@ -34,6 +34,11 @@ from qutebrowser.utils.usertypes import KeyMode from qutebrowser.commands.exceptions import CommandError +class ModeLockedError(Exception): + + """Exception raised when the mode is currently locked.""" + + def instance(): """Get the global modeman instance.""" return QApplication.instance().modeman @@ -49,6 +54,14 @@ def leave(mode, reason=None): instance().leave(mode, reason) +def maybe_enter(mode, reason=None): + """Convenience method to enter 'mode' without exceptions.""" + try: + instance().enter(mode, reason) + except ModeLockedError as e: + pass + + def maybe_leave(mode, reason=None): """Convenience method to leave 'mode' without exceptions.""" try: @@ -65,6 +78,9 @@ class ModeManager(QObject): mode: The current mode (readonly property). passthrough: A list of modes in which to pass through events. mainwindow: The mainwindow object + locked: Whether current mode is locked. This means the current mode can + still be left (then locked will be reset), but no new mode can + be entered while the current mode is active. _handlers: A dictionary of modes and their handlers. _mode_stack: A list of the modes we're currently in, with the active one on the right. @@ -86,6 +102,7 @@ class ModeManager(QObject): def __init__(self, parent=None): super().__init__(parent) self.mainwindow = None + self.locked = False self._handlers = {} self.passthrough = [] self._mode_stack = [] @@ -200,6 +217,11 @@ class ModeManager(QObject): """ if not isinstance(mode, KeyMode): raise TypeError("Mode {} is no KeyMode member!".format(mode)) + if self.locked: + logger.debug("Not entering mode {} because mode is locked to " + "{}.".format(mode, self.mode)) + raise ModeLockedError("Mode is currently locked to {}".format( + self.mode)) logger.debug("Entering mode {}{}".format( mode, '' if reason is None else ' (reason: {})'.format(reason))) if mode not in self._handlers: @@ -238,6 +260,7 @@ class ModeManager(QObject): self._mode_stack.remove(mode) except ValueError: raise ValueError("Mode {} not on mode stack!".format(mode)) + self.locked = False logger.debug("Leaving mode {}{}, new mode stack {}".format( mode, '' if reason is None else ' (reason: {})'.format(reason), self._mode_stack)) diff --git a/qutebrowser/widgets/statusbar/command.py b/qutebrowser/widgets/statusbar/command.py index 9712a8ac0..1fe9a1416 100644 --- a/qutebrowser/widgets/statusbar/command.py +++ b/qutebrowser/widgets/statusbar/command.py @@ -299,7 +299,7 @@ class Command(MinimalLineEdit): def focusInEvent(self, e): """Extend focusInEvent to enter command mode.""" - modeman.enter(KeyMode.command, 'cmd focus') + modeman.maybe_enter(KeyMode.command, 'cmd focus') super().focusInEvent(e) diff --git a/qutebrowser/widgets/statusbar/prompter.py b/qutebrowser/widgets/statusbar/prompter.py index 890a6ab78..526ada3f0 100644 --- a/qutebrowser/widgets/statusbar/prompter.py +++ b/qutebrowser/widgets/statusbar/prompter.py @@ -279,7 +279,13 @@ class Prompter: self.question = question mode = self._display_question() question.aborted.connect(lambda: modeman.maybe_leave(mode, 'aborted')) - modeman.enter(mode, 'question asked') + try: + modeman.enter(mode, 'question asked') + except modeman.ModeLockedError: + if modeman.instance().mode != KeyMode.prompt: + question.abort() + return None + modeman.instance().locked = True if blocking: loop = EventLoop() self._loops.append(loop) diff --git a/qutebrowser/widgets/webview.py b/qutebrowser/widgets/webview.py index 36d286cbb..144b9b5c2 100644 --- a/qutebrowser/widgets/webview.py +++ b/qutebrowser/widgets/webview.py @@ -233,7 +233,7 @@ class WebView(QWebView): elif ((hitresult.isContentEditable() and webelem.is_writable(elem)) or webelem.is_editable(elem)): log.mouse.debug("Clicked editable element!") - modeman.enter(KeyMode.insert, 'click') + modeman.maybe_enter(KeyMode.insert, 'click') else: log.mouse.debug("Clicked non-editable element!") if config.get('input', 'auto-leave-insert-mode'): @@ -247,7 +247,7 @@ class WebView(QWebView): elem = webelem.focus_elem(self.page().currentFrame()) if webelem.is_editable(elem): log.mouse.debug("Clicked editable element (delayed)!") - modeman.enter(KeyMode.insert, 'click-delayed') + modeman.maybe_enter(KeyMode.insert, 'click-delayed') else: log.mouse.debug("Clicked non-editable element (delayed)!") if config.get('input', 'auto-leave-insert-mode'): @@ -402,7 +402,7 @@ class WebView(QWebView): if elem.isNull(): log.webview.debug("Focused element is null!") elif webelem.is_editable(elem): - modeman.enter(KeyMode.insert, 'load finished') + modeman.maybe_enter(KeyMode.insert, 'load finished') @pyqtSlot(str) def set_force_open_target(self, target):