Merge branch 'explicit-focus-handling'

This commit is contained in:
Florian Bruhin 2023-12-08 15:14:54 +01:00
commit bfe2878ca8
5 changed files with 50 additions and 18 deletions

View File

@ -49,6 +49,8 @@ Changed
Fixed
~~~~~
- Some web pages jumping to the top when the statusbar is hidden or (with
v3.0.x) when a prompt is hidden.
- Compatibility with PDF.js v4
- Added an elaborate workaround for a bug in QtWebEngine 6.6.0 causing crashes
on Google Mail/Meet/Chat, and a bug in QtWebEngine 6.5.0/.1/.2 causing crashes

View File

@ -483,6 +483,8 @@ class MainWindow(QWidget):
mode_manager = modeman.instance(self.win_id)
# misc
self._prompt_container.release_focus.connect(
self.tabbed_browser.on_release_focus)
self.tabbed_browser.close_window.connect(self.close)
mode_manager.entered.connect(hints.on_mode_entered)
@ -559,6 +561,7 @@ class MainWindow(QWidget):
self._completion.on_clear_completion_selection)
self.status.cmd.hide_completion.connect(
self._completion.hide)
self.status.cmd.hide_cmd.connect(self.tabbed_browser.on_release_focus)
def _set_decoration(self, hidden):
"""Set the visibility of the window decoration via Qt."""

View File

@ -202,6 +202,7 @@ class PromptQueue(QObject):
log.prompt.debug("Left mode {}, hiding {}".format(
mode, self._question))
self.show_prompts.emit(None)
if self._question.answer is None and not self._question.is_aborted:
log.prompt.debug("Cancelling {} because {} was left".format(
self._question, mode))
@ -261,6 +262,7 @@ class PromptContainer(QWidget):
}
"""
update_geometry = pyqtSignal()
release_focus = pyqtSignal()
def __init__(self, win_id, parent=None):
super().__init__(parent)
@ -287,19 +289,26 @@ class PromptContainer(QWidget):
Args:
question: A Question object or None.
"""
item = self._layout.takeAt(0)
if item is not None:
item = qtutils.add_optional(self._layout.takeAt(0))
if item is None:
widget = None
else:
widget = item.widget()
assert widget is not None
log.prompt.debug("Deleting old prompt {}".format(widget))
widget.hide()
log.prompt.debug(f"Deleting old prompt {widget!r}")
widget.deleteLater()
if question is None:
log.prompt.debug("No prompts left, hiding prompt container.")
self._prompt = None
self.release_focus.emit()
self.hide()
return
elif widget is not None:
# We have more prompts to show, just hide the old one.
# This needs to happen *after* we possibly hid the entire prompt container,
# so that keyboard focus can be reassigned properly via release_focus.
widget.hide()
classes = {
usertypes.PromptMode.yesno: YesNoPrompt,

View File

@ -377,9 +377,11 @@ class StatusBar(QWidget):
@pyqtSlot(usertypes.KeyMode)
def on_mode_entered(self, mode):
"""Mark certain modes in the commandline."""
mode_manager = modeman.instance(self._win_id)
if config.val.statusbar.show == 'in-mode':
if config.val.statusbar.show == 'in-mode' and mode != usertypes.KeyMode.command:
# Showing in command mode is handled via _show_cmd_widget()
self.show()
mode_manager = modeman.instance(self._win_id)
if mode_manager.parsers[mode].passthrough:
self._set_mode_text(mode.name)
if mode in [usertypes.KeyMode.insert,
@ -393,9 +395,11 @@ class StatusBar(QWidget):
@pyqtSlot(usertypes.KeyMode, usertypes.KeyMode)
def on_mode_left(self, old_mode, new_mode):
"""Clear marked mode."""
mode_manager = modeman.instance(self._win_id)
if config.val.statusbar.show == 'in-mode':
if config.val.statusbar.show == 'in-mode' and old_mode != usertypes.KeyMode.command:
# Hiding in command mode is handled via _hide_cmd_widget()
self.hide()
mode_manager = modeman.instance(self._win_id)
if mode_manager.parsers[old_mode].passthrough:
if mode_manager.parsers[new_mode].passthrough:
self._set_mode_text(new_mode.name)

View File

@ -858,20 +858,34 @@ class TabbedBrowser(QWidget):
assert isinstance(tab, browsertab.AbstractTab), tab
tab.data.input_mode = mode
@pyqtSlot(usertypes.KeyMode)
def on_mode_left(self, mode):
"""Give focus to current tab if command mode was left."""
@pyqtSlot()
def on_release_focus(self):
"""Give keyboard focus to the current tab when requested by statusbar/prompt.
This gets emitted by the statusbar and prompt container before they call .hide()
on themselves, with the idea that we can explicitly reassign the focus,
instead of Qt implicitly calling its QWidget::focusNextPrevChild() method,
finding a new widget to give keyboard focus to.
"""
widget = qtutils.add_optional(self.widget.currentWidget())
if widget is None:
return
if mode in [usertypes.KeyMode.command] + modeman.PROMPT_MODES:
log.modes.debug("Left status-input mode, focusing {!r}".format(
widget))
widget.setFocus()
if config.val.tabs.mode_on_change == 'restore':
assert isinstance(widget, browsertab.AbstractTab), widget
widget.data.input_mode = usertypes.KeyMode.normal
log.modes.debug(f"Focus released, focusing {widget!r}")
widget.setFocus()
@pyqtSlot()
def on_mode_left(self):
"""Save input mode for restoring if needed."""
if config.val.tabs.mode_on_change != 'restore':
return
widget = qtutils.add_optional(self.widget.currentWidget())
if widget is None:
return
assert isinstance(widget, browsertab.AbstractTab), widget
widget.data.input_mode = usertypes.KeyMode.normal
@pyqtSlot(int)
def _on_current_changed(self, idx):