From aeb19dfedfe14c5ee8d454c831d634e81219bf44 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 15 Feb 2024 14:37:10 +0530 Subject: [PATCH] More Wayland time wasting Wayland is designed so an application cant raise it sub windows without also giving them keyboard focus. So write stupid boilerplate code to ans request focus on wayland when raising a window. Sigh. --- src/calibre/gui2/__init__.py | 20 ++++++++++++++++++- src/calibre/gui2/actions/browse_notes.py | 3 +-- src/calibre/gui2/actions/fts.py | 2 +- src/calibre/gui2/dialogs/template_dialog.py | 2 +- src/calibre/gui2/library/annotations.py | 2 +- src/calibre/gui2/lrf_renderer/main.py | 3 +-- src/calibre/gui2/proceed.py | 2 +- src/calibre/gui2/store/web_store.py | 2 +- src/calibre/gui2/tweak_book/boss.py | 12 +++++------ src/calibre/gui2/tweak_book/char_select.py | 2 +- .../gui2/tweak_book/completion/popup.py | 2 +- .../gui2/tweak_book/function_replace.py | 2 +- src/calibre/gui2/tweak_book/job.py | 2 +- src/calibre/gui2/tweak_book/manage_fonts.py | 2 +- src/calibre/gui2/tweak_book/preview.py | 2 +- src/calibre/gui2/ui.py | 2 +- src/calibre/gui2/viewer/main.py | 2 +- src/calibre/gui2/viewer/ui.py | 4 ++-- src/calibre/gui2/widgets2.py | 2 +- 19 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 34ce7206cf..3ef8d234f3 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -16,7 +16,7 @@ from qt.core import ( QFontDatabase, QFontInfo, QFontMetrics, QGuiApplication, QIcon, QImageReader, QImageWriter, QIODevice, QLocale, QNetworkProxyFactory, QObject, QPalette, QResource, QSettings, QSocketNotifier, QStringListModel, Qt, QThread, QTimer, - QTranslator, QUrl, pyqtSignal, pyqtSlot, + QTranslator, QUrl, QWidget, pyqtSignal, pyqtSlot, ) from threading import Lock, RLock @@ -1706,3 +1706,21 @@ def local_path_for_resource(qurl: QUrl, base_qurl: 'QUrl | None' = None) -> str: if qurl.isRelative(): # this means has no scheme return fix_qt_bodging_windows_paths(qurl.path()) return '' + + +def raise_and_focus(self: QWidget) -> None: + self.raise_() + self.activateWindow() + + +def raise_without_focus(self: QWidget) -> None: + if QApplication.instance().platformName() == 'wayland': + # On fucking Wayland, we cant raise a dialog without also giving it + # keyboard focus. What a joke. + self.raise_and_focus() + else: + self.raise_() + + +QWidget.raise_and_focus = raise_and_focus +QWidget.raise_without_focus = raise_without_focus diff --git a/src/calibre/gui2/actions/browse_notes.py b/src/calibre/gui2/actions/browse_notes.py index 8f7677a7f1..c80808b846 100644 --- a/src/calibre/gui2/actions/browse_notes.py +++ b/src/calibre/gui2/actions/browse_notes.py @@ -19,8 +19,7 @@ class BrowseNotesAction(InterfaceAction): def show_browser(self): if self.d is not None and self.d.isVisible(): - self.d.raise_() - self.d.activateWindow() + self.d.raise_and_focus() else: from calibre.gui2.library.notes import NotesBrowser self.d = NotesBrowser(self.gui) diff --git a/src/calibre/gui2/actions/fts.py b/src/calibre/gui2/actions/fts.py index 6571b3ce9d..c4fdf0f166 100644 --- a/src/calibre/gui2/actions/fts.py +++ b/src/calibre/gui2/actions/fts.py @@ -29,7 +29,7 @@ class FullTextSearchAction(InterfaceAction): if text and ':' not in text: self.dialog.set_search_text(text) self.dialog.show() - self.dialog.raise_() + self.dialog.raise_and_focus() def library_changed(self, db): if self._dialog is not None: diff --git a/src/calibre/gui2/dialogs/template_dialog.py b/src/calibre/gui2/dialogs/template_dialog.py index d88bb664fd..add80773e2 100644 --- a/src/calibre/gui2/dialogs/template_dialog.py +++ b/src/calibre/gui2/dialogs/template_dialog.py @@ -339,7 +339,7 @@ class TemplateDialog(QDialog, Ui_TemplateDialog): QDialog.__init__(self, parent, flags=Qt.WindowType.Dialog) else: QDialog.__init__(self, None, flags=Qt.WindowType.Window) - self.raise_() # Not needed on windows but here just in case + self.raise_and_focus() # Not needed on windows but here just in case Ui_TemplateDialog.__init__(self) self.setupUi(self) self.setWindowIcon(self.windowIcon()) diff --git a/src/calibre/gui2/library/annotations.py b/src/calibre/gui2/library/annotations.py index 58f504e735..0a53a414c9 100644 --- a/src/calibre/gui2/library/annotations.py +++ b/src/calibre/gui2/library/annotations.py @@ -1061,7 +1061,7 @@ class AnnotationsBrowser(Dialog): else: self.reinitialize(restrict_to_book_ids) self.show() - self.raise_() + self.raise_and_focus() QTimer.singleShot(80, self.browse_panel.effective_query_changed) def selection_changed(self): diff --git a/src/calibre/gui2/lrf_renderer/main.py b/src/calibre/gui2/lrf_renderer/main.py index 07dcb2e68f..b3fb4405b2 100644 --- a/src/calibre/gui2/lrf_renderer/main.py +++ b/src/calibre/gui2/lrf_renderer/main.py @@ -314,8 +314,7 @@ def main(args=sys.argv, logger=None): main.set_exception_handler() main.show() main.render() - main.activateWindow() - main.raise_() + main.raise_and_focus() return app.exec() return 0 diff --git a/src/calibre/gui2/proceed.py b/src/calibre/gui2/proceed.py index 57412f1669..96beb32f39 100644 --- a/src/calibre/gui2/proceed.py +++ b/src/calibre/gui2/proceed.py @@ -268,7 +268,7 @@ class ProceedQuestion(QWidget): button = self.action_button if question.focus_action and question.action_callback is not None else \ (self.bb.button(QDialogButtonBox.StandardButton.Ok) if question.show_ok else self.bb.button(QDialogButtonBox.StandardButton.Yes)) button.setDefault(True) - self.raise_() + self.raise_without_focus() self.start_show_animation() if question.auto_hide_after > 0: self.auto_hide_timer = t = QTimer(self) diff --git a/src/calibre/gui2/store/web_store.py b/src/calibre/gui2/store/web_store.py index 4647d40b47..89a1da1309 100644 --- a/src/calibre/gui2/store/web_store.py +++ b/src/calibre/gui2/store/web_store.py @@ -253,7 +253,7 @@ def main(args): override = 'calibre-gui' if islinux else None app = Application(args, override_program_name=override) m = Main(data) - m.show(), m.raise_() + m.show(), m.raise_and_focus() app.exec() del m del app diff --git a/src/calibre/gui2/tweak_book/boss.py b/src/calibre/gui2/tweak_book/boss.py index 340171f566..5845643725 100644 --- a/src/calibre/gui2/tweak_book/boss.py +++ b/src/calibre/gui2/tweak_book/boss.py @@ -874,11 +874,11 @@ class Boss(QObject): editor = editors[name] editor.go_to_line(lnum) editor.setFocus(Qt.FocusReason.OtherFocusReason) - self.gui.raise_() + self.gui.raise_and_focus() d = Diff(revert_button_msg=revert_msg, show_open_in_editor=show_open_in_editor) [x.break_cycles() for x in _diff_dialogs if not x.isVisible()] _diff_dialogs = [x for x in _diff_dialogs if x.isVisible()] + [d] - d.show(), d.raise_(), d.setFocus(Qt.FocusReason.OtherFocusReason), d.setWindowModality(Qt.WindowModality.NonModal) + d.show(), d.raise_and_focus(), d.setFocus(Qt.FocusReason.OtherFocusReason), d.setWindowModality(Qt.WindowModality.NonModal) if show_open_in_editor: d.line_activated.connect(line_activated) return d @@ -1484,7 +1484,7 @@ class Boss(QObject): self.commit_all_editors_to_container() c = self.gui.check_book c.parent().show() - c.parent().raise_() + c.parent().raise_and_focus() c.run_checks(current_container()) def spell_check_requested(self): @@ -1499,7 +1499,7 @@ class Boss(QObject): self.add_savepoint(_('Before: Auto-fix errors')) c = self.gui.check_book c.parent().show() - c.parent().raise_() + c.parent().raise_and_focus() changed = c.fix_errors(current_container(), errors) if changed: self.apply_container_update_to_gui() @@ -1612,14 +1612,14 @@ class Boss(QObject): def browse_images(self): self.gui.image_browser.refresh() self.gui.image_browser.show() - self.gui.image_browser.raise_() + self.gui.image_browser.raise_and_focus() def show_reports(self): if not self.ensure_book(_('You must first open a book in order to see the report.')): return self.gui.reports.refresh() self.gui.reports.show() - self.gui.reports.raise_() + self.gui.reports.raise_and_focus() def reports_edit_requested(self, name): mt = current_container().mime_map.get(name, guess_type(name)) diff --git a/src/calibre/gui2/tweak_book/char_select.py b/src/calibre/gui2/tweak_book/char_select.py index d58ef2e8df..034a04ad21 100644 --- a/src/calibre/gui2/tweak_book/char_select.py +++ b/src/calibre/gui2/tweak_book/char_select.py @@ -810,7 +810,7 @@ class CharSelect(Dialog): def show(self): self.initialize() Dialog.show(self) - self.raise_() + self.raise_and_focus() def char_selected(self, c): if QApplication.keyboardModifiers() & Qt.KeyboardModifier.ControlModifier: diff --git a/src/calibre/gui2/tweak_book/completion/popup.py b/src/calibre/gui2/tweak_book/completion/popup.py index 424fced604..e57eb01c5f 100644 --- a/src/calibre/gui2/tweak_book/completion/popup.py +++ b/src/calibre/gui2/tweak_book/completion/popup.py @@ -164,7 +164,7 @@ class ChoosePopupWidget(QWidget): if self.current_results: self.layout() QWidget.show(self) - self.raise_() + self.raise_without_focus() def hide(self): QWidget.hide(self) diff --git a/src/calibre/gui2/tweak_book/function_replace.py b/src/calibre/gui2/tweak_book/function_replace.py index f8a89f829a..9b34f576ff 100644 --- a/src/calibre/gui2/tweak_book/function_replace.py +++ b/src/calibre/gui2/tweak_book/function_replace.py @@ -133,7 +133,7 @@ class DebugOutput(Dialog): self.text.setPlainText(self.windowTitle() + '\n\n' + text) self.log_text = text self.show() - self.raise_() + self.raise_and_focus() def sizeHint(self): fm = QFontMetrics(self.text.font()) diff --git a/src/calibre/gui2/tweak_book/job.py b/src/calibre/gui2/tweak_book/job.py index e97d596234..dd39b40c7f 100644 --- a/src/calibre/gui2/tweak_book/job.py +++ b/src/calibre/gui2/tweak_book/job.py @@ -63,7 +63,7 @@ class BlockingJob(QWidget): self.setVisible(True) # Prevent any actions from being triggered by key presses self.parent().setEnabled(False) - self.raise_() + self.raise_and_focus() self.setFocus(Qt.FocusReason.OtherFocusReason) self.pi.startAnimation() QApplication.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) diff --git a/src/calibre/gui2/tweak_book/manage_fonts.py b/src/calibre/gui2/tweak_book/manage_fonts.py index 8e28d8b8e6..68b8930a86 100644 --- a/src/calibre/gui2/tweak_book/manage_fonts.py +++ b/src/calibre/gui2/tweak_book/manage_fonts.py @@ -320,7 +320,7 @@ class ManageFonts(Dialog): def display(self): if not self.isVisible(): self.show() - self.raise_() + self.raise_and_focus() QTimer.singleShot(0, self.model.build) def get_selected_data(self): diff --git a/src/calibre/gui2/tweak_book/preview.py b/src/calibre/gui2/tweak_book/preview.py index 805f8e0124..e46b09f279 100644 --- a/src/calibre/gui2/tweak_book/preview.py +++ b/src/calibre/gui2/tweak_book/preview.py @@ -459,7 +459,7 @@ class WebView(RestartingWebEngineView, OpenWithHandler): def inspect(self): self.inspector.parent().show() - self.inspector.parent().raise_() + self.inspector.parent().raise_and_focus() self.pageAction(QWebEnginePage.WebAction.InspectElement).trigger() def contextMenuEvent(self, ev): diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 78af71cc34..12e1291f16 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -857,7 +857,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.handle_cli_args(argv[1:]) self.setWindowState(self.windowState() & ~Qt.WindowState.WindowMinimized|Qt.WindowState.WindowActive) self.show_windows() - self.raise_() + self.raise_and_focus() self.activateWindow() elif msg.startswith('shutdown:'): self.quit(confirm_quit=False) diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py index 4df005c5df..491e67e545 100644 --- a/src/calibre/gui2/viewer/main.py +++ b/src/calibre/gui2/viewer/main.py @@ -162,7 +162,7 @@ def run_gui(app, opts, args, internal_book_data, listener=None): listener.message_received.connect(main.message_from_other_instance, type=Qt.ConnectionType.QueuedConnection) QTimer.singleShot(0, acc.flush) if opts.raise_window: - main.raise_() + main.raise_and_focus() if opts.full_screen: main.set_full_screen(True) diff --git a/src/calibre/gui2/viewer/ui.py b/src/calibre/gui2/viewer/ui.py index 312d21bdcf..a493df7977 100644 --- a/src/calibre/gui2/viewer/ui.py +++ b/src/calibre/gui2/viewer/ui.py @@ -272,7 +272,7 @@ class EbookViewer(MainWindow): print(err, file=sys.stderr) return self.load_ebook(path, open_at=open_at) - self.raise_() + self.raise_and_focus() self.activateWindow() # }}} @@ -321,7 +321,7 @@ class EbookViewer(MainWindow): def show_search(self, text, trigger=False, search_type=None, case_sensitive=None): self.search_dock.setVisible(True) self.search_dock.activateWindow() - self.search_dock.raise_() + self.search_dock.raise_and_focus() self.search_widget.focus_input(text, search_type, case_sensitive) if trigger: self.search_widget.trigger() diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py index e1d7da9253..5e1e589fc7 100644 --- a/src/calibre/gui2/widgets2.py +++ b/src/calibre/gui2/widgets2.py @@ -822,7 +822,7 @@ class MessagePopup(QLabel): self.resize(self.sizeHint()) self.position_in_parent() self.show() - self.raise_() + self.raise_without_focus() self.close_timer.start(timeout) def position_in_parent(self):