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):