From f7d53a5c302a4bb5b7bd0a52b3b088a719519fbf Mon Sep 17 00:00:00 2001 From: toofar Date: Sun, 26 Jun 2022 13:37:08 +1200 Subject: Re-write PyQt references to always include the module Still some manual fixes to make, see #995 and linked PRs. This was done like: date ; for mod in core dbus gui network printsupport qml sql webengine webenginecore webenginewidgets webkit webkitwidgets widgets test opengl; do echo "renaming $mod" python3 -m libcst.tool codemod rename_pyqt.RenameCommand qutebrowser/ tests --old_name=qutebrowser.qt.$mod.* --new_name=qutebrowser.qt:$mod.* --no-format done ; date Where the list of modules was obtained from the current pyqt5/pqyt6/pyside2 import wrapper machinery. That list of modules to include can also be obtained using semgrep like so (it might miss out the QtTest module for some reason): semgrep --lang=py -e 'from qutebrowser.qt.$SUBMODULE import ($IMPORTEES)' -o findings.json --json qutebrowser scripts/ tests/ and then with open("findings.json") as f: data=json.load(f) results = data['results'] submodules = sorted(set(r['extra']['metavars']['$SUBMODULE']['abstract_content'] for r in results)) for m in submodules: print(m --- qutebrowser/api/config.py | 4 +- qutebrowser/api/downloads.py | 11 +- qutebrowser/app.py | 35 +-- qutebrowser/browser/browsertab.py | 170 ++++++----- qutebrowser/browser/commands.py | 70 +++-- qutebrowser/browser/downloads.py | 103 ++++--- qutebrowser/browser/downloadview.py | 34 +-- qutebrowser/browser/eventfilter.py | 33 +-- qutebrowser/browser/greasemonkey.py | 13 +- qutebrowser/browser/hints.py | 46 +-- qutebrowser/browser/history.py | 44 ++- qutebrowser/browser/inspector.py | 26 +- qutebrowser/browser/navigate.py | 28 +- qutebrowser/browser/network/pac.py | 53 ++-- qutebrowser/browser/network/proxy.py | 20 +- qutebrowser/browser/pdfjs.py | 19 +- qutebrowser/browser/qtnetworkdownloads.py | 64 ++-- qutebrowser/browser/qutescheme.py | 80 +++-- qutebrowser/browser/shared.py | 23 +- qutebrowser/browser/signalfilter.py | 4 +- qutebrowser/browser/urlmarks.py | 13 +- qutebrowser/browser/webelem.py | 51 ++-- qutebrowser/browser/webengine/certificateerror.py | 12 +- qutebrowser/browser/webengine/interceptor.py | 63 ++-- qutebrowser/browser/webengine/notification.py | 188 ++++++------ qutebrowser/browser/webengine/tabhistory.py | 11 +- .../browser/webengine/webenginedownloads.py | 51 ++-- qutebrowser/browser/webengine/webengineelem.py | 27 +- .../browser/webengine/webengineinspector.py | 17 +- .../browser/webengine/webenginequtescheme.py | 44 ++- qutebrowser/browser/webengine/webenginesettings.py | 121 ++++---- qutebrowser/browser/webengine/webenginetab.py | 207 +++++++------ qutebrowser/browser/webengine/webview.py | 62 ++-- qutebrowser/browser/webkit/cache.py | 4 +- qutebrowser/browser/webkit/certificateerror.py | 7 +- qutebrowser/browser/webkit/cookies.py | 14 +- qutebrowser/browser/webkit/http.py | 4 +- qutebrowser/browser/webkit/mhtml.py | 14 +- .../browser/webkit/network/networkmanager.py | 41 ++- qutebrowser/browser/webkit/network/networkreply.py | 40 ++- .../browser/webkit/network/webkitqutescheme.py | 21 +- qutebrowser/browser/webkit/tabhistory.py | 11 +- qutebrowser/browser/webkit/webkitelem.py | 46 ++- qutebrowser/browser/webkit/webkithistory.py | 6 +- qutebrowser/browser/webkit/webkitinspector.py | 14 +- qutebrowser/browser/webkit/webkitsettings.py | 111 ++++--- qutebrowser/browser/webkit/webkittab.py | 228 +++++++------- qutebrowser/browser/webkit/webpage.py | 100 +++---- qutebrowser/browser/webkit/webview.py | 40 ++- qutebrowser/commands/argparser.py | 4 +- qutebrowser/commands/runners.py | 13 +- qutebrowser/commands/userscripts.py | 32 +- qutebrowser/completion/completer.py | 14 +- qutebrowser/completion/completiondelegate.py | 111 ++++--- qutebrowser/completion/completionwidget.py | 29 +- qutebrowser/completion/models/completionmodel.py | 41 ++- qutebrowser/completion/models/filepathcategory.py | 17 +- qutebrowser/completion/models/histcategory.py | 7 +- qutebrowser/completion/models/listcategory.py | 16 +- qutebrowser/completion/models/urlmodel.py | 4 +- qutebrowser/components/braveadblock.py | 6 +- qutebrowser/components/hostblock.py | 4 +- qutebrowser/components/misccommands.py | 11 +- qutebrowser/components/readlinecommands.py | 13 +- qutebrowser/components/utils/blockutils.py | 15 +- qutebrowser/config/config.py | 13 +- qutebrowser/config/configcommands.py | 11 +- qutebrowser/config/configfiles.py | 26 +- qutebrowser/config/configinit.py | 4 +- qutebrowser/config/configtypes.py | 60 ++-- qutebrowser/config/configutils.py | 14 +- qutebrowser/config/qtargs.py | 4 +- qutebrowser/config/stylesheet.py | 13 +- qutebrowser/config/websettings.py | 17 +- qutebrowser/extensions/interceptors.py | 8 +- qutebrowser/extensions/loader.py | 4 +- qutebrowser/keyinput/basekeyparser.py | 52 ++-- qutebrowser/keyinput/eventfilter.py | 24 +- qutebrowser/keyinput/keyutils.py | 301 ++++++++++--------- qutebrowser/keyinput/modeman.py | 42 ++- qutebrowser/keyinput/modeparsers.py | 65 ++-- qutebrowser/mainwindow/mainwindow.py | 64 ++-- qutebrowser/mainwindow/messageview.py | 34 +-- qutebrowser/mainwindow/prompt.py | 99 +++---- qutebrowser/mainwindow/statusbar/bar.py | 40 ++- qutebrowser/mainwindow/statusbar/clock.py | 7 +- qutebrowser/mainwindow/statusbar/command.py | 38 ++- qutebrowser/mainwindow/statusbar/keystring.py | 4 +- qutebrowser/mainwindow/statusbar/percentage.py | 7 +- qutebrowser/mainwindow/statusbar/progress.py | 14 +- qutebrowser/mainwindow/statusbar/searchmatch.py | 4 +- qutebrowser/mainwindow/statusbar/tabindex.py | 4 +- qutebrowser/mainwindow/statusbar/textbase.py | 18 +- qutebrowser/mainwindow/statusbar/url.py | 13 +- qutebrowser/mainwindow/tabbedbrowser.py | 98 +++--- qutebrowser/mainwindow/tabwidget.py | 166 +++++------ qutebrowser/mainwindow/windowundo.py | 8 +- qutebrowser/misc/autoupdate.py | 13 +- qutebrowser/misc/backendproblem.py | 51 ++-- qutebrowser/misc/cmdhistory.py | 9 +- qutebrowser/misc/consolewidget.py | 30 +- qutebrowser/misc/crashdialog.py | 88 +++--- qutebrowser/misc/crashsignal.py | 31 +- qutebrowser/misc/earlyinit.py | 36 +-- qutebrowser/misc/editor.py | 21 +- qutebrowser/misc/guiprocess.py | 64 ++-- qutebrowser/misc/httpclient.py | 27 +- qutebrowser/misc/ipc.py | 65 ++-- qutebrowser/misc/keyhintwidget.py | 18 +- qutebrowser/misc/lineparser.py | 9 +- qutebrowser/misc/miscwidgets.py | 86 +++--- qutebrowser/misc/msgbox.py | 15 +- qutebrowser/misc/pastebin.py | 13 +- qutebrowser/misc/quitter.py | 13 +- qutebrowser/misc/savemanager.py | 11 +- qutebrowser/misc/sessions.py | 22 +- qutebrowser/misc/sql.py | 31 +- qutebrowser/misc/throttle.py | 6 +- qutebrowser/misc/utilcmds.py | 9 +- qutebrowser/utils/debug.py | 28 +- qutebrowser/utils/error.py | 4 +- qutebrowser/utils/jinja.py | 6 +- qutebrowser/utils/log.py | 26 +- qutebrowser/utils/message.py | 19 +- qutebrowser/utils/objreg.py | 15 +- qutebrowser/utils/qtutils.py | 119 ++++---- qutebrowser/utils/standarddir.py | 57 ++-- qutebrowser/utils/urlmatch.py | 6 +- qutebrowser/utils/urlutils.py | 81 +++-- qutebrowser/utils/usertypes.py | 32 +- qutebrowser/utils/utils.py | 32 +- qutebrowser/utils/version.py | 50 ++-- tests/conftest.py | 8 +- tests/end2end/conftest.py | 12 +- tests/end2end/features/test_downloads_bdd.py | 4 +- tests/end2end/features/test_editor_bdd.py | 10 +- tests/end2end/fixtures/notificationserver.py | 44 ++- tests/end2end/fixtures/quteprocess.py | 17 +- tests/end2end/fixtures/test_testprocess.py | 4 +- tests/end2end/fixtures/testprocess.py | 25 +- tests/end2end/fixtures/webserver.py | 6 +- tests/end2end/test_dirbrowser.py | 6 +- tests/end2end/test_invocations.py | 16 +- tests/helpers/fixtures.py | 32 +- tests/helpers/messagemock.py | 12 +- tests/helpers/stubs.py | 88 +++--- tests/helpers/test_helper_utils.py | 10 +- tests/helpers/testutils.py | 6 +- tests/unit/browser/test_browsertab.py | 6 +- tests/unit/browser/test_caret.py | 4 +- tests/unit/browser/test_downloadview.py | 6 +- tests/unit/browser/test_hints.py | 8 +- tests/unit/browser/test_history.py | 139 +++++---- tests/unit/browser/test_inspector.py | 6 +- tests/unit/browser/test_navigate.py | 48 +-- tests/unit/browser/test_notification.py | 31 +- tests/unit/browser/test_pdfjs.py | 14 +- tests/unit/browser/test_qutescheme.py | 48 +-- tests/unit/browser/test_signalfilter.py | 14 +- tests/unit/browser/test_urlmarks.py | 26 +- .../browser/webengine/test_webengine_cookies.py | 11 +- .../browser/webengine/test_webenginedownloads.py | 4 +- .../browser/webengine/test_webengineinterceptor.py | 6 +- tests/unit/browser/webengine/test_webview.py | 8 +- tests/unit/browser/webkit/http/test_http.py | 4 +- .../unit/browser/webkit/network/test_filescheme.py | 15 +- .../browser/webkit/network/test_networkreply.py | 24 +- tests/unit/browser/webkit/network/test_pac.py | 34 +-- tests/unit/browser/webkit/test_cache.py | 43 ++- tests/unit/browser/webkit/test_certificateerror.py | 11 +- tests/unit/browser/webkit/test_cookies.py | 10 +- tests/unit/browser/webkit/test_tabhistory.py | 32 +- tests/unit/browser/webkit/test_webkitelem.py | 95 +++--- tests/unit/commands/test_argparser.py | 4 +- tests/unit/commands/test_userscripts.py | 4 +- tests/unit/completion/test_completer.py | 4 +- tests/unit/completion/test_completiondelegate.py | 24 +- tests/unit/completion/test_completionmodel.py | 4 +- tests/unit/completion/test_completionwidget.py | 4 +- tests/unit/completion/test_models.py | 110 ++++--- tests/unit/components/test_blockutils.py | 6 +- tests/unit/components/test_braveadblock.py | 24 +- tests/unit/components/test_hostblock.py | 24 +- tests/unit/components/test_readlinecommands.py | 9 +- tests/unit/config/test_config.py | 11 +- tests/unit/config/test_configcommands.py | 12 +- tests/unit/config/test_configfiles.py | 6 +- tests/unit/config/test_configtypes.py | 94 +++--- tests/unit/config/test_configutils.py | 37 ++- tests/unit/config/test_qtargs_locale_workaround.py | 4 +- tests/unit/config/test_stylesheet.py | 4 +- tests/unit/javascript/conftest.py | 8 +- tests/unit/javascript/test_greasemonkey.py | 10 +- tests/unit/javascript/test_js_execution.py | 22 +- tests/unit/javascript/test_js_quirks.py | 12 +- tests/unit/keyinput/key_data.py | 6 +- tests/unit/keyinput/test_basekeyparser.py | 90 +++--- tests/unit/keyinput/test_bindingtrie.py | 30 +- tests/unit/keyinput/test_keyutils.py | 327 ++++++++++----------- tests/unit/keyinput/test_modeman.py | 24 +- tests/unit/keyinput/test_modeparsers.py | 25 +- tests/unit/mainwindow/statusbar/test_textbase.py | 10 +- tests/unit/mainwindow/statusbar/test_url.py | 30 +- tests/unit/mainwindow/test_messageview.py | 18 +- tests/unit/mainwindow/test_prompt.py | 10 +- tests/unit/mainwindow/test_tabwidget.py | 6 +- tests/unit/misc/test_autoupdate.py | 4 +- tests/unit/misc/test_editor.py | 24 +- tests/unit/misc/test_guiprocess.py | 15 +- tests/unit/misc/test_ipc.py | 85 +++--- tests/unit/misc/test_miscwidgets.py | 33 +-- tests/unit/misc/test_msgbox.py | 21 +- tests/unit/misc/test_pastebin.py | 8 +- tests/unit/misc/test_sessions.py | 16 +- tests/unit/misc/test_sql.py | 12 +- tests/unit/misc/test_throttle.py | 5 +- tests/unit/misc/test_utilcmds.py | 4 +- tests/unit/test_app.py | 4 +- tests/unit/utils/test_debug.py | 65 ++-- tests/unit/utils/test_error.py | 9 +- tests/unit/utils/test_jinja.py | 6 +- tests/unit/utils/test_log.py | 4 +- tests/unit/utils/test_qtutils.py | 185 ++++++------ tests/unit/utils/test_standarddir.py | 10 +- tests/unit/utils/test_urlmatch.py | 42 +-- tests/unit/utils/test_urlutils.py | 157 +++++----- tests/unit/utils/test_utils.py | 23 +- tests/unit/utils/test_version.py | 11 +- tests/unit/utils/usertypes/test_timer.py | 4 +- 229 files changed, 3810 insertions(+), 4101 deletions(-) diff --git a/qutebrowser/api/config.py b/qutebrowser/api/config.py index fd0890602..1b5045bed 100644 --- a/qutebrowser/api/config.py +++ b/qutebrowser/api/config.py @@ -21,7 +21,7 @@ from typing import cast, Any -from qutebrowser.qt.core import QUrl +from qutebrowser.qt import core from qutebrowser.config import config @@ -38,6 +38,6 @@ from qutebrowser.config import config val = cast('config.ConfigContainer', None) -def get(name: str, url: QUrl = None) -> Any: +def get(name: str, url: core.QUrl = None) -> Any: """Get a value from the config based on a string name.""" return config.instance.get(name, url) diff --git a/qutebrowser/api/downloads.py b/qutebrowser/api/downloads.py index 85f5b8b91..a27319833 100644 --- a/qutebrowser/api/downloads.py +++ b/qutebrowser/api/downloads.py @@ -23,20 +23,19 @@ import io -from qutebrowser.qt.core import QObject, pyqtSignal, pyqtSlot, QUrl - from qutebrowser.browser import downloads, qtnetworkdownloads from qutebrowser.utils import objreg +from qutebrowser.qt import core UnsupportedAttribute = downloads.UnsupportedAttribute -class TempDownload(QObject): +class TempDownload(core.QObject): """A download of some data into a file object.""" - finished = pyqtSignal() + finished = core.pyqtSignal() def __init__(self, item: qtnetworkdownloads.DownloadItem) -> None: super().__init__() @@ -45,13 +44,13 @@ class TempDownload(QObject): self.successful = False self.fileobj = item.fileobj - @pyqtSlot() + @core.pyqtSlot() def _on_download_finished(self) -> None: self.successful = self._item.successful self.finished.emit() -def download_temp(url: QUrl) -> TempDownload: +def download_temp(url: core.QUrl) -> TempDownload: """Download the given URL into a file object. The download is not saved to disk. diff --git a/qutebrowser/app.py b/qutebrowser/app.py index 6b5c35914..d5a65ba87 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -46,10 +46,7 @@ import datetime import argparse from typing import Iterable, Optional -from qutebrowser.qt import machinery -from qutebrowser.qt.widgets import QApplication, QWidget -from qutebrowser.qt.gui import QDesktopServices, QPixmap, QIcon -from qutebrowser.qt.core import pyqtSlot, QUrl, QObject, QEvent, pyqtSignal, Qt +from qutebrowser.qt import widgets, gui, core, machinery import qutebrowser from qutebrowser.commands import runners @@ -147,7 +144,7 @@ def init(*, args: argparse.Namespace) -> None: crashsignal.crash_handler.init_faulthandler() objects.qapp.setQuitOnLastWindowClosed(False) - quitter.instance.shutting_down.connect(QApplication.closeAllWindows) + quitter.instance.shutting_down.connect(widgets.QApplication.closeAllWindows) _init_icon() @@ -170,7 +167,7 @@ def init(*, args: argparse.Namespace) -> None: _process_args(args) for scheme in ['http', 'https', 'qute']: - QDesktopServices.setUrlHandler( + gui.QDesktopServices.setUrlHandler( scheme, open_desktopservices_url) log.init.debug("Init done!") @@ -179,16 +176,16 @@ def init(*, args: argparse.Namespace) -> None: def _init_icon(): """Initialize the icon of qutebrowser.""" - fallback_icon = QIcon() + fallback_icon = gui.QIcon() for size in [16, 24, 32, 48, 64, 96, 128, 256, 512]: filename = 'icons/qutebrowser-{size}x{size}.png'.format(size=size) - pixmap = QPixmap() + pixmap = gui.QPixmap() pixmap.loadFromData(resources.read_file_binary(filename)) if pixmap.isNull(): log.init.warning("Failed to load {}".format(filename)) else: fallback_icon.addPixmap(pixmap) - icon = QIcon.fromTheme('qutebrowser', fallback_icon) + icon = gui.QIcon.fromTheme('qutebrowser', fallback_icon) if icon.isNull(): log.init.warning("Failed to load icon") else: @@ -374,7 +371,7 @@ def _open_special_pages(args): for state, condition, url in pages: if general_sect.get(state) != '1' and condition: - tabbed_browser.tabopen(QUrl(url), background=False) + tabbed_browser.tabopen(core.QUrl(url), background=False) general_sect[state] = '1' # Show changelog on new releases @@ -401,7 +398,7 @@ def _open_special_pages(args): message.info(f"Showing changelog after upgrade to qutebrowser v{qbversion}.") changelog_url = f'qute://help/changelog.html#v{qbversion}' - tabbed_browser.tabopen(QUrl(changelog_url), background=False) + tabbed_browser.tabopen(core.QUrl(changelog_url), background=False) def on_focus_changed(_old, new): @@ -409,7 +406,7 @@ def on_focus_changed(_old, new): if new is None: return - if not isinstance(new, QWidget): + if not isinstance(new, widgets.QWidget): log.misc.debug("on_focus_changed called with non-QWidget {!r}".format( new)) return @@ -520,7 +517,7 @@ def _init_modules(*, args): windowundo.init() -class Application(QApplication): +class Application(widgets.QApplication): """Main application instance. @@ -533,8 +530,8 @@ class Application(QApplication): window_closing: A window is being closed. """ - new_window = pyqtSignal(mainwindow.MainWindow) - window_closing = pyqtSignal(mainwindow.MainWindow) + new_window = core.pyqtSignal(mainwindow.MainWindow) + window_closing = core.pyqtSignal(mainwindow.MainWindow) def __init__(self, args): """Constructor. @@ -558,19 +555,19 @@ class Application(QApplication): self.focusObjectChanged.connect(self.on_focus_object_changed) try: - self.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps, True) + self.setAttribute(core.Qt.ApplicationAttribute.AA_UseHighDpiPixmaps, True) except AttributeError: # default and removed in Qt 6 pass self.new_window.connect(self._on_new_window) - @pyqtSlot(mainwindow.MainWindow) + @core.pyqtSlot(mainwindow.MainWindow) def _on_new_window(self, window): window.tabbed_browser.shutting_down.connect(functools.partial( self.window_closing.emit, window)) - @pyqtSlot(QObject) + @core.pyqtSlot(core.QObject) def on_focus_object_changed(self, obj): """Log when the focus object changed.""" output = repr(obj) @@ -580,7 +577,7 @@ class Application(QApplication): def event(self, e): """Handle macOS FileOpen events.""" - if e.type() != QEvent.Type.FileOpen: + if e.type() != core.QEvent.Type.FileOpen: return super().event(e) url = e.url() diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 811a530a7..0b5e79573 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -25,13 +25,7 @@ import functools import dataclasses from typing import (cast, TYPE_CHECKING, Any, Callable, Iterable, List, Optional, Sequence, Set, Type, Union, Tuple) - -from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt, - QEvent, QPoint, QRect) -from qutebrowser.qt.gui import QKeyEvent, QIcon, QPixmap -from qutebrowser.qt.widgets import QApplication, QWidget -from qutebrowser.qt.printsupport import QPrintDialog, QPrinter -from qutebrowser.qt.network import QNetworkAccessManager +from qutebrowser.qt import widgets, printsupport, network if TYPE_CHECKING: from qutebrowser.qt.webkit import QWebHistory, QWebHistoryItem @@ -45,7 +39,7 @@ from qutebrowser.utils import (utils, objreg, usertypes, log, qtutils, urlutils, message, jinja) from qutebrowser.misc import miscwidgets, objects, sessions from qutebrowser.browser import eventfilter, inspector -from qutebrowser.qt import sip +from qutebrowser.qt import gui, core, sip if TYPE_CHECKING: from qutebrowser.browser import webelem @@ -58,7 +52,7 @@ _WidgetType = Union["QWebView", "QWebEngineView"] def create(win_id: int, private: bool, - parent: QWidget = None) -> 'AbstractTab': + parent: widgets.QWidget = None) -> 'AbstractTab': """Get a QtWebKit/QtWebEngine tab object. Args: @@ -225,22 +219,22 @@ class AbstractAction: self._tab.dump_async(show_source_cb) -class AbstractPrinting(QObject): +class AbstractPrinting(core.QObject): """Attribute ``printing`` of AbstractTab for printing the page.""" - printing_finished = pyqtSignal(bool) - pdf_printing_finished = pyqtSignal(str, bool) # filename, ok + printing_finished = core.pyqtSignal(bool) + pdf_printing_finished = core.pyqtSignal(str, bool) # filename, ok - def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None: + def __init__(self, tab: 'AbstractTab', parent: widgets.QWidget = None) -> None: super().__init__(parent) self._widget = cast(_WidgetType, None) self._tab = tab - self._dialog: QPrintDialog = None + self._dialog: printsupport.QPrintDialog = None self.printing_finished.connect(self._on_printing_finished) self.pdf_printing_finished.connect(self._on_pdf_printing_finished) - @pyqtSlot(bool) + @core.pyqtSlot(bool) def _on_printing_finished(self, ok): # Only reporting error here, as the user has feedback from the dialog # (and probably their printer) already. @@ -250,7 +244,7 @@ class AbstractPrinting(QObject): self._dialog.deleteLater() self._dialog = None - @pyqtSlot(str, bool) + @core.pyqtSlot(str, bool) def _on_pdf_printing_finished(self, path, ok): if ok: message.info(f"Printed to {path}") @@ -277,7 +271,7 @@ class AbstractPrinting(QObject): """Print the tab to a PDF with the given filename.""" raise NotImplementedError - def to_printer(self, printer: QPrinter): + def to_printer(self, printer: printsupport.QPrinter): """Print the tab. Args: @@ -287,7 +281,7 @@ class AbstractPrinting(QObject): def show_dialog(self) -> None: """Print with a QPrintDialog.""" - self._dialog = QPrintDialog(self._tab) + self._dialog = printsupport.QPrintDialog(self._tab) self._dialog.open(lambda: self.to_printer(self._dialog.printer())) # Gets cleaned up in on_printing_finished @@ -347,7 +341,7 @@ class SearchNavigationResult(enum.Enum): wrap_prevented_top = enum.auto() -class AbstractSearch(QObject): +class AbstractSearch(core.QObject): """Attribute ``search`` of AbstractTab for doing searches. @@ -367,14 +361,14 @@ class AbstractSearch(QObject): cleared: An existing search was cleared. """ - finished = pyqtSignal(bool) - match_changed = pyqtSignal(SearchMatch) - cleared = pyqtSignal() + finished = core.pyqtSignal(bool) + match_changed = core.pyqtSignal(SearchMatch) + cleared = core.pyqtSignal() _Callback = Callable[[bool], None] _NavCallback = Callable[[SearchNavigationResult], None] - def __init__(self, tab: 'AbstractTab', parent: QWidget = None): + def __init__(self, tab: 'AbstractTab', parent: widgets.QWidget = None): super().__init__(parent) self._tab = tab self._widget = cast(_WidgetType, None) @@ -435,11 +429,11 @@ class AbstractSearch(QObject): raise NotImplementedError -class AbstractZoom(QObject): +class AbstractZoom(core.QObject): """Attribute ``zoom`` of AbstractTab for controlling zoom.""" - def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None: + def __init__(self, tab: 'AbstractTab', parent: widgets.QWidget = None) -> None: super().__init__(parent) self._tab = tab self._widget = cast(_WidgetType, None) @@ -449,7 +443,7 @@ class AbstractZoom(QObject): config.instance.changed.connect(self._on_config_changed) self._zoom_factor = float(config.val.zoom.default) / 100 - @pyqtSlot(str) + @core.pyqtSlot(str) def _on_config_changed(self, option: str) -> None: if option in ['zoom.levels', 'zoom.default']: if not self._default_zoom_changed: @@ -522,19 +516,19 @@ class SelectionState(enum.Enum): line = enum.auto() -class AbstractCaret(QObject): +class AbstractCaret(core.QObject): """Attribute ``caret`` of AbstractTab for caret browsing.""" #: Signal emitted when the selection was toggled. - selection_toggled = pyqtSignal(SelectionState) + selection_toggled = core.pyqtSignal(SelectionState) #: Emitted when a ``follow_selection`` action is done. - follow_selected_done = pyqtSignal() + follow_selected_done = core.pyqtSignal() def __init__(self, tab: 'AbstractTab', mode_manager: modeman.ModeManager, - parent: QWidget = None) -> None: + parent: widgets.QWidget = None) -> None: super().__init__(parent) self._widget = cast(_WidgetType, None) self._mode_manager = mode_manager @@ -608,32 +602,32 @@ class AbstractCaret(QObject): def _follow_enter(self, tab: bool) -> None: """Follow a link by faking an enter press.""" if tab: - self._tab.fake_key_press(Qt.Key.Key_Enter, modifier=Qt.KeyboardModifier.ControlModifier) + self._tab.fake_key_press(core.Qt.Key.Key_Enter, modifier=core.Qt.KeyboardModifier.ControlModifier) else: - self._tab.fake_key_press(Qt.Key.Key_Enter) + self._tab.fake_key_press(core.Qt.Key.Key_Enter) def follow_selected(self, *, tab: bool = False) -> None: raise NotImplementedError -class AbstractScroller(QObject): +class AbstractScroller(core.QObject): """Attribute ``scroller`` of AbstractTab to manage scroll position.""" #: Signal emitted when the scroll position changed (int, int) - perc_changed = pyqtSignal(int, int) + perc_changed = core.pyqtSignal(int, int) #: Signal emitted before the user requested a jump. #: Used to set the special ' mark so the user can return. - before_jump_requested = pyqtSignal() + before_jump_requested = core.pyqtSignal() - def __init__(self, tab: 'AbstractTab', parent: QWidget = None): + def __init__(self, tab: 'AbstractTab', parent: widgets.QWidget = None): super().__init__(parent) self._tab = tab self._widget = cast(_WidgetType, None) if 'log-scroll-pos' in objects.debug_flags: self.perc_changed.connect(self._log_scroll_pos_change) - @pyqtSlot() + @core.pyqtSlot() def _log_scroll_pos_change(self) -> None: log.webview.vdebug( # type: ignore[attr-defined] "Scroll position changed to {}".format(self.pos_px())) @@ -641,7 +635,7 @@ class AbstractScroller(QObject): def _init_widget(self, widget: _WidgetType) -> None: self._widget = widget - def pos_px(self) -> QPoint: + def pos_px(self) -> core.QPoint: raise NotImplementedError def pos_perc(self) -> Tuple[int, int]: @@ -650,7 +644,7 @@ class AbstractScroller(QObject): def to_perc(self, x: float = None, y: float = None) -> None: raise NotImplementedError - def to_point(self, point: QPoint) -> None: + def to_point(self, point: core.QPoint) -> None: raise NotImplementedError def to_anchor(self, name: str) -> None: @@ -825,7 +819,7 @@ class AbstractElements: """ raise NotImplementedError - def find_at_pos(self, pos: QPoint, callback: _SingleCallback) -> None: + def find_at_pos(self, pos: core.QPoint, callback: _SingleCallback) -> None: """Find the element at the given position async. This is also called "hit test" elsewhere. @@ -838,14 +832,14 @@ class AbstractElements: raise NotImplementedError -class AbstractAudio(QObject): +class AbstractAudio(core.QObject): """Handling of audio/muting for this tab.""" - muted_changed = pyqtSignal(bool) - recently_audible_changed = pyqtSignal(bool) + muted_changed = core.pyqtSignal(bool) + recently_audible_changed = core.pyqtSignal(bool) - def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None: + def __init__(self, tab: 'AbstractTab', parent: widgets.QWidget = None) -> None: super().__init__(parent) self._widget = cast(_WidgetType, None) self._tab = tab @@ -883,7 +877,7 @@ class AbstractTabPrivate: self._tab = tab self._mode_manager = mode_manager - def event_target(self) -> Optional[QWidget]: + def event_target(self) -> Optional[widgets.QWidget]: """Return the widget events should be sent to.""" raise NotImplementedError @@ -912,7 +906,7 @@ class AbstractTabPrivate: def clear_ssl_errors(self) -> None: raise NotImplementedError - def networkaccessmanager(self) -> Optional[QNetworkAccessManager]: + def networkaccessmanager(self) -> Optional[network.QNetworkAccessManager]: """Get the QNetworkAccessManager for this tab. This is only implemented for QtWebKit. @@ -957,7 +951,7 @@ class AbstractTabPrivate: def _init_inspector(self, splitter: 'miscwidgets.InspectorSplitter', win_id: int, - parent: QWidget = None) -> 'AbstractWebInspector': + parent: widgets.QWidget = None) -> 'AbstractWebInspector': """Get a WebKitInspector/WebEngineInspector. Args: @@ -968,49 +962,49 @@ class AbstractTabPrivate: raise NotImplementedError -class AbstractTab(QWidget): +class AbstractTab(widgets.QWidget): """An adapter for QWebView/QWebEngineView representing a single tab.""" #: Signal emitted when a website requests to close this tab. - window_close_requested = pyqtSignal() + window_close_requested = core.pyqtSignal() #: Signal emitted when a link is hovered (the hover text) - link_hovered = pyqtSignal(str) + link_hovered = core.pyqtSignal(str) #: Signal emitted when a page started loading - load_started = pyqtSignal() + load_started = core.pyqtSignal() #: Signal emitted when a page is loading (progress percentage) - load_progress = pyqtSignal(int) + load_progress = core.pyqtSignal(int) #: Signal emitted when a page finished loading (success as bool) - load_finished = pyqtSignal(bool) + load_finished = core.pyqtSignal(bool) #: Signal emitted when a page's favicon changed (icon as QIcon) - icon_changed = pyqtSignal(QIcon) + icon_changed = core.pyqtSignal(gui.QIcon) #: Signal emitted when a page's title changed (new title as str) - title_changed = pyqtSignal(str) + title_changed = core.pyqtSignal(str) #: Signal emitted when this tab was pinned/unpinned (new pinned state as bool) - pinned_changed = pyqtSignal(bool) + pinned_changed = core.pyqtSignal(bool) #: Signal emitted when a new tab should be opened (url as QUrl) - new_tab_requested = pyqtSignal(QUrl) + new_tab_requested = core.pyqtSignal(core.QUrl) #: Signal emitted when a page's URL changed (url as QUrl) - url_changed = pyqtSignal(QUrl) + url_changed = core.pyqtSignal(core.QUrl) #: Signal emitted when a tab's content size changed #: (new size as QSizeF) - contents_size_changed = pyqtSignal(QSizeF) + contents_size_changed = core.pyqtSignal(core.QSizeF) #: Signal emitted when a page requested full-screen (bool) - fullscreen_requested = pyqtSignal(bool) + fullscreen_requested = core.pyqtSignal(bool) #: Signal emitted before load starts (URL as QUrl) - before_load_started = pyqtSignal(QUrl) + before_load_started = core.pyqtSignal(core.QUrl) # Signal emitted when a page's load status changed # (argument: usertypes.LoadStatus) - load_status_changed = pyqtSignal(usertypes.LoadStatus) + load_status_changed = core.pyqtSignal(usertypes.LoadStatus) # Signal emitted before shutting down - shutting_down = pyqtSignal() + shutting_down = core.pyqtSignal() # Signal emitted when a history item should be added - history_item_triggered = pyqtSignal(QUrl, QUrl, str) + history_item_triggered = core.pyqtSignal(core.QUrl, core.QUrl, str) # Signal emitted when the underlying renderer process terminated. # arg 0: A TerminationStatus member. # arg 1: The exit code. - renderer_process_terminated = pyqtSignal(TerminationStatus, int) + renderer_process_terminated = core.pyqtSignal(TerminationStatus, int) # Hosts for which a certificate error happened. Shared between all tabs. # @@ -1035,7 +1029,7 @@ class AbstractTab(QWidget): def __init__(self, *, win_id: int, mode_manager: 'modeman.ModeManager', private: bool, - parent: QWidget = None) -> None: + parent: widgets.QWidget = None) -> None: utils.unused(mode_manager) # needed for mypy self.is_private = private self.win_id = win_id @@ -1097,7 +1091,7 @@ class AbstractTab(QWidget): self._load_status = val self.load_status_changed.emit(val) - def send_event(self, evt: QEvent) -> None: + def send_event(self, evt: core.QEvent) -> None: """Send the given event to the underlying widget. The event will be sent via QApplication.postEvent. @@ -1116,35 +1110,35 @@ class AbstractTab(QWidget): return evt.posted = True # type: ignore[attr-defined] - QApplication.postEvent(recipient, evt) + widgets.QApplication.postEvent(recipient, evt) def navigation_blocked(self) -> bool: """Test if navigation is allowed on the current tab.""" return self.data.pinned and config.val.tabs.pinned.frozen - @pyqtSlot(QUrl) - def _on_before_load_started(self, url: QUrl) -> None: + @core.pyqtSlot(core.QUrl) + def _on_before_load_started(self, url: core.QUrl) -> None: """Adjust the title if we are going to visit a URL soon.""" qtutils.ensure_valid(url) url_string = url.toDisplayString() log.webview.debug("Going to start loading: {}".format(url_string)) self.title_changed.emit(url_string) - @pyqtSlot(QUrl) - def _on_url_changed(self, url: QUrl) -> None: + @core.pyqtSlot(core.QUrl) + def _on_url_changed(self, url: core.QUrl) -> None: """Update title when URL has changed and no title is available.""" if url.isValid() and not self.title(): self.title_changed.emit(url.toDisplayString()) self.url_changed.emit(url) - @pyqtSlot() + @core.pyqtSlot() def _on_load_started(self) -> None: self._progress = 0 self.data.viewing_source = False self._set_load_status(usertypes.LoadStatus.loading) self.load_started.emit() - @pyqtSlot(usertypes.NavigationRequest) + @core.pyqtSlot(usertypes.NavigationRequest) def _on_navigation_request( self, navigation: usertypes.NavigationRequest @@ -1172,7 +1166,7 @@ class AbstractTab(QWidget): navigation.url.errorString())) navigation.accepted = False - @pyqtSlot(bool) + @core.pyqtSlot(bool) def _on_load_finished(self, ok: bool) -> None: assert self._widget is not None if sip.isdeleted(self._widget): @@ -1209,17 +1203,17 @@ class AbstractTab(QWidget): self._set_load_status(loadstatus) - @pyqtSlot() + @core.pyqtSlot() def _on_history_trigger(self) -> None: """Emit history_item_triggered based on backend-specific signal.""" raise NotImplementedError - @pyqtSlot(int) + @core.pyqtSlot(int) def _on_load_progress(self, perc: int) -> None: self._progress = perc self.load_progress.emit(perc) - def url(self, *, requested: bool = False) -> QUrl: + def url(self, *, requested: bool = False) -> core.QUrl: raise NotImplementedError def progress(self) -> int: @@ -1228,11 +1222,11 @@ class AbstractTab(QWidget): def load_status(self) -> usertypes.LoadStatus: return self._load_status - def _load_url_prepare(self, url: QUrl) -> None: + def _load_url_prepare(self, url: core.QUrl) -> None: qtutils.ensure_valid(url) self.before_load_started.emit(url) - def load_url(self, url: QUrl) -> None: + def load_url(self, url: core.QUrl) -> None: raise NotImplementedError def reload(self, *, force: bool = False) -> None: @@ -1242,11 +1236,11 @@ class AbstractTab(QWidget): raise NotImplementedError def fake_key_press(self, - key: Qt.Key, - modifier: Qt.KeyboardModifier = Qt.KeyboardModifier.NoModifier) -> None: + key: core.Qt.Key, + modifier: core.Qt.KeyboardModifier = core.Qt.KeyboardModifier.NoModifier) -> None: """Send a fake key event to this tab.""" - press_evt = QKeyEvent(QEvent.Type.KeyPress, key, modifier, 0, 0, 0) - release_evt = QKeyEvent(QEvent.Type.KeyRelease, key, modifier, + press_evt = gui.QKeyEvent(core.QEvent.Type.KeyPress, key, modifier, 0, 0, 0) + release_evt = gui.QKeyEvent(core.QEvent.Type.KeyRelease, key, modifier, 0, 0, 0) self.send_event(press_evt) self.send_event(release_evt) @@ -1283,10 +1277,10 @@ class AbstractTab(QWidget): def title(self) -> str: raise NotImplementedError - def icon(self) -> QIcon: + def icon(self) -> gui.QIcon: raise NotImplementedError - def set_html(self, html: str, base_url: QUrl = QUrl()) -> None: + def set_html(self, html: str, base_url: core.QUrl = core.QUrl()) -> None: raise NotImplementedError def set_pinned(self, pinned: bool) -> None: @@ -1301,7 +1295,7 @@ class AbstractTab(QWidget): """ raise NotImplementedError - def grab_pixmap(self, rect: QRect = None) -> Optional[QPixmap]: + def grab_pixmap(self, rect: core.QRect = None) -> Optional[gui.QPixmap]: """Grab a QPixmap of the displayed page. Returns None if we got a null pixmap from Qt. @@ -1320,7 +1314,7 @@ class AbstractTab(QWidget): def __repr__(self) -> str: try: qurl = self.url() - url = qurl.toDisplayString(QUrl.ComponentFormattingOption.EncodeUnicode) + url = qurl.toDisplayString(core.QUrl.ComponentFormattingOption.EncodeUnicode) except (AttributeError, RuntimeError) as exc: url = '<{}>'.format(exc.__class__.__name__) else: diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 97aa21a3e..7ddb77146 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -24,9 +24,6 @@ import shlex import functools from typing import cast, Callable, Dict, Union -from qutebrowser.qt.widgets import QApplication, QTabBar -from qutebrowser.qt.core import Qt, QUrl, QEvent, QUrlQuery - from qutebrowser.commands import userscripts, runners from qutebrowser.api import cmdutils from qutebrowser.config import config, configdata @@ -39,6 +36,7 @@ from qutebrowser.utils.usertypes import KeyMode from qutebrowser.misc import editor, guiprocess, objects from qutebrowser.completion.models import urlmodel, miscmodels from qutebrowser.mainwindow import mainwindow, windowundo +from qutebrowser.qt import widgets, core class CommandDispatcher: @@ -197,16 +195,16 @@ class CommandDispatcher: """ cmdutils.check_exclusive((prev, next_, opposite), 'pno') if prev: - return QTabBar.SelectionBehavior.SelectLeftTab + return widgets.QTabBar.SelectionBehavior.SelectLeftTab elif next_: - return QTabBar.SelectionBehavior.SelectRightTab + return widgets.QTabBar.SelectionBehavior.SelectRightTab elif opposite: conf_selection = config.val.tabs.select_on_remove - if conf_selection == QTabBar.SelectionBehavior.SelectLeftTab: - return QTabBar.SelectionBehavior.SelectRightTab - elif conf_selection == QTabBar.SelectionBehavior.SelectRightTab: - return QTabBar.SelectionBehavior.SelectLeftTab - elif conf_selection == QTabBar.SelectionBehavior.SelectPreviousTab: + if conf_selection == widgets.QTabBar.SelectionBehavior.SelectLeftTab: + return widgets.QTabBar.SelectionBehavior.SelectRightTab + elif conf_selection == widgets.QTabBar.SelectionBehavior.SelectRightTab: + return widgets.QTabBar.SelectionBehavior.SelectLeftTab + elif conf_selection == widgets.QTabBar.SelectionBehavior.SelectPreviousTab: raise cmdutils.CommandError( "-o is not supported with 'tabs.select_on_remove' set to " "'last-used'!") @@ -366,7 +364,7 @@ class CommandDispatcher: Return: A list of URLs that can be opened. """ - if isinstance(url, QUrl): + if isinstance(url, core.QUrl): yield url return @@ -604,7 +602,7 @@ class CommandDispatcher: widget = self._current_widget() url = self._current_url() - handlers: Dict[str, Callable[..., QUrl]] = { + handlers: Dict[str, Callable[..., core.QUrl]] = { 'prev': functools.partial(navigate.prevnext, prev=True), 'next': functools.partial(navigate.prevnext, prev=False), 'up': navigate.path_up, @@ -671,12 +669,12 @@ class CommandDispatcher: assert what in ['url', 'pretty-url'], what if what == 'pretty-url': - flags = QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.DecodeReserved + flags = core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.DecodeReserved else: - flags = QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded + flags = core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded - url = QUrl(self._current_url()) - url_query = QUrlQuery() + url = core.QUrl(self._current_url()) + url_query = core.QUrlQuery() url_query_str = url.query() if '&' not in url_query_str and ';' in url_query_str: url_query.setQueryDelimiters('=', ';') @@ -908,7 +906,7 @@ class CommandDispatcher: idx = int(index_parts[1]) elif len(index_parts) == 1: idx = int(index_parts[0]) - active_win = QApplication.activeWindow() + active_win = widgets.QApplication.activeWindow() if active_win is None: # Not sure how you enter a command without an active window... raise cmdutils.CommandError( @@ -1100,7 +1098,7 @@ class CommandDispatcher: if output: tb = objreg.get('tabbed-browser', scope='window', window='last-focused') - tb.load_url(QUrl(f'qute://process/{proc.pid}'), newtab=True) + tb.load_url(core.QUrl(f'qute://process/{proc.pid}'), newtab=True) if userscript: def _selection_callback(s): @@ -1164,7 +1162,7 @@ class CommandDispatcher: except qtutils.QtValueError: pass else: - env['QUTE_URL'] = url.toString(QUrl.ComponentFormattingOption.FullyEncoded) + env['QUTE_URL'] = url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded) try: runner = userscripts.run_async( @@ -1295,8 +1293,8 @@ class CommandDispatcher: current page's url. """ if url is None: - url = self._current_url().toString(QUrl.UrlFormattingOption.RemovePassword | - QUrl.ComponentFormattingOption.FullyEncoded) + url = self._current_url().toString(core.QUrl.UrlFormattingOption.RemovePassword | + core.QUrl.ComponentFormattingOption.FullyEncoded) try: objreg.get('bookmark-manager').delete(url) except KeyError: @@ -1313,7 +1311,7 @@ class CommandDispatcher: window: Open in a new window. jump: Jump to the "bookmarks" header. """ - url = QUrl('qute://bookmarks/') + url = core.QUrl('qute://bookmarks/') if jump: url.setFragment('bookmarks') self._open(url, tab, bg, window) @@ -1342,7 +1340,7 @@ class CommandDispatcher: if mhtml_: raise cmdutils.CommandError("Can only download the current " "page as mhtml.") - url = QUrl.fromUserInput(url) + url = core.QUrl.fromUserInput(url) urlutils.raise_cmdexc_if_invalid(url) download_manager.get(url, target=target) elif mhtml_: @@ -1407,7 +1405,7 @@ class CommandDispatcher: bg: Open in a background tab. window: Open in a new window. """ - url = QUrl('qute://history/') + url = core.QUrl('qute://history/') self._open(url, tab, bg, window) @cmdutils.register(instance='command-dispatcher', name='help', @@ -1443,7 +1441,7 @@ class CommandDispatcher: path = 'settings.html#{}'.format(topic) else: raise cmdutils.CommandError("Invalid help topic {}!".format(topic)) - url = QUrl('qute://help/{}'.format(path)) + url = core.QUrl('qute://help/{}'.format(path)) self._open(url, tab, bg, window) @cmdutils.register(instance='command-dispatcher', scope='window') @@ -1466,7 +1464,7 @@ class CommandDispatcher: if level.upper() not in log.LOG_LEVELS: raise cmdutils.CommandError("Invalid log level {}!".format(level)) - query = QUrlQuery() + query = core.QUrlQuery() query.addQueryItem('level', level) if plain: query.addQueryItem('plain', cast(str, None)) @@ -1478,7 +1476,7 @@ class CommandDispatcher: raise cmdutils.CommandError(e) query.addQueryItem('logfilter', logfilter) - url = QUrl('qute://log') + url = core.QUrl('qute://log') url.setQuery(query) self._open(url, tab, bg, window) @@ -1711,7 +1709,7 @@ class CommandDispatcher: raise cmdutils.CommandError(str(e)) elif url: try: - js_code = urlutils.parse_javascript_url(QUrl(js_code)) + js_code = urlutils.parse_javascript_url(core.QUrl(js_code)) except urlutils.Error as e: raise cmdutils.CommandError(str(e)) @@ -1739,15 +1737,15 @@ class CommandDispatcher: raise cmdutils.CommandError(str(e)) for keyinfo in sequence: - press_event = keyinfo.to_event(QEvent.Type.KeyPress) - release_event = keyinfo.to_event(QEvent.Type.KeyRelease) + press_event = keyinfo.to_event(core.QEvent.Type.KeyPress) + release_event = keyinfo.to_event(core.QEvent.Type.KeyRelease) if global_: - window = QApplication.focusWindow() + window = widgets.QApplication.focusWindow() if window is None: raise cmdutils.CommandError("No focused window!") - QApplication.postEvent(window, press_event) - QApplication.postEvent(window, release_event) + widgets.QApplication.postEvent(window, press_event) + widgets.QApplication.postEvent(window, release_event) else: tab = self._current_widget() tab.send_event(press_event) @@ -1847,9 +1845,9 @@ class CommandDispatcher: if not window.isFullScreen(): window.state_before_fullscreen = window.windowState() if enter: - window.setWindowState(window.windowState() | Qt.WindowState.WindowFullScreen) + window.setWindowState(window.windowState() | core.Qt.WindowState.WindowFullScreen) else: - window.setWindowState(window.windowState() ^ Qt.WindowState.WindowFullScreen) + window.setWindowState(window.windowState() ^ core.Qt.WindowState.WindowFullScreen) log.misc.debug('state before fullscreen: {}'.format( - debug.qflags_key(Qt, window.state_before_fullscreen))) + debug.qflags_key(core.Qt, window.state_before_fullscreen))) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 8ce0ca1b2..c518c3b57 100644 --- a/qutebrowser/browser/downloads.py +++ b/qutebrowser/browser/downloads.py @@ -30,22 +30,19 @@ import tempfile import enum from typing import Any, Dict, IO, List, MutableSequence, Optional, Union -from qutebrowser.qt.core import (pyqtSlot, pyqtSignal, Qt, QObject, QModelIndex, - QTimer, QAbstractListModel, QUrl) - from qutebrowser.browser import pdfjs from qutebrowser.api import cmdutils from qutebrowser.config import config from qutebrowser.utils import (usertypes, standarddir, utils, message, log, qtutils, objreg) -from qutebrowser.qt import sip +from qutebrowser.qt import core, sip class ModelRole(enum.IntEnum): """Custom download model roles.""" - item = Qt.ItemDataRole.UserRole + item = core.Qt.ItemDataRole.UserRole # Remember the last used directory @@ -78,7 +75,7 @@ def init(): config.instance.changed.connect(_clear_last_used) -@pyqtSlot() +@core.pyqtSlot() def shutdown(): temp_download_manager.cleanup() @@ -188,7 +185,7 @@ def get_filename_question(*, suggested_filename, url, parent=None): q.title = "Save file to:" q.text = "Please enter a location for {}".format( html.escape(url.toDisplayString())) - q.url = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + q.url = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) q.mode = usertypes.PromptMode.download q.completed.connect(q.deleteLater) q.default = _path_suggestion(suggested_filename) @@ -329,7 +326,7 @@ class PDFJSDownloadTarget(_DownloadTarget): return 'temporary PDF.js file' -class DownloadItemStats(QObject): +class DownloadItemStats(core.QObject): """Statistics (bytes done, total bytes, time, etc.) about a download. @@ -398,7 +395,7 @@ class DownloadItemStats(QObject): else: return remaining_bytes / avg - @pyqtSlot('qint64', 'qint64') + @core.pyqtSlot('qint64', 'qint64') def on_download_progress(self, bytes_done, bytes_total): """Update local variables when the download progress changed. @@ -412,7 +409,7 @@ class DownloadItemStats(QObject): self.total = bytes_total -class AbstractDownloadItem(QObject): +class AbstractDownloadItem(core.QObject): """Shared QtNetwork/QtWebEngine part of a download item. @@ -441,12 +438,12 @@ class AbstractDownloadItem(QObject): arg 2: The original download URL. """ - data_changed = pyqtSignal() - finished = pyqtSignal() - error = pyqtSignal(str) - cancelled = pyqtSignal() - remove_requested = pyqtSignal() - pdfjs_requested = pyqtSignal(str, QUrl) + data_changed = core.pyqtSignal() + finished = core.pyqtSignal() + error = core.pyqtSignal(str) + cancelled = core.pyqtSignal() + remove_requested = core.pyqtSignal() + pdfjs_requested = core.pyqtSignal(str, core.QUrl) def __init__(self, manager, parent=None): super().__init__(parent) @@ -565,7 +562,7 @@ class AbstractDownloadItem(QObject): """Actual cancel implementation.""" raise NotImplementedError - @pyqtSlot() + @core.pyqtSlot() def cancel(self, *, remove_data=True): """Cancel the download. @@ -581,7 +578,7 @@ class AbstractDownloadItem(QObject): self.finished.emit() self.data_changed.emit() - @pyqtSlot() + @core.pyqtSlot() def remove(self): """Remove the download from the model.""" self.remove_requested.emit() @@ -597,12 +594,12 @@ class AbstractDownloadItem(QObject): except OSError: log.downloads.exception("Failed to remove partial file") - @pyqtSlot() + @core.pyqtSlot() def retry(self): """Retry a failed download.""" raise NotImplementedError - @pyqtSlot() + @core.pyqtSlot() def try_retry(self): """Try to retry a download and show an error if it's unsupported.""" try: @@ -610,11 +607,11 @@ class AbstractDownloadItem(QObject): except UnsupportedOperationError as e: message.error(str(e)) - def url(self) -> QUrl: + def url(self) -> core.QUrl: """Get the download's URL (i.e. where the file is downloaded from).""" raise NotImplementedError - def origin(self) -> QUrl: + def origin(self) -> core.QUrl: """Get the download's origin URL (i.e. the page starting the download).""" raise NotImplementedError @@ -625,7 +622,7 @@ class AbstractDownloadItem(QObject): """ raise NotImplementedError - @pyqtSlot() + @core.pyqtSlot() def open_file(self, cmdline=None, open_dir=False): """Open the downloaded file. @@ -647,7 +644,7 @@ class AbstractDownloadItem(QObject): # is important on systems where process creation takes long, as # otherwise the prompt might hang around and cause bugs # (see issue #2296) - QTimer.singleShot(0, lambda: utils.open_file(filename, cmdline)) + core.QTimer.singleShot(0, lambda: utils.open_file(filename, cmdline)) def _ensure_can_set_filename(self, filename): """Make sure we can still set a filename.""" @@ -884,7 +881,7 @@ class AbstractDownloadItem(QObject): raise ValueError("Unsupported download target: {}".format(target)) -class AbstractDownloadManager(QObject): +class AbstractDownloadManager(core.QObject): """Backend-independent download manager code. @@ -901,11 +898,11 @@ class AbstractDownloadManager(QObject): The argument is the index of the changed download """ - begin_remove_row = pyqtSignal(int) - end_remove_row = pyqtSignal() - begin_insert_row = pyqtSignal(int) - end_insert_row = pyqtSignal() - data_changed = pyqtSignal(int) + begin_remove_row = core.pyqtSignal(int) + end_remove_row = core.pyqtSignal() + begin_insert_row = core.pyqtSignal(int) + end_insert_row = core.pyqtSignal() + data_changed = core.pyqtSignal(int) def __init__(self, parent=None): super().__init__(parent) @@ -917,7 +914,7 @@ class AbstractDownloadManager(QObject): def __repr__(self): return utils.get_repr(self, downloads=len(self.downloads)) - @pyqtSlot() + @core.pyqtSlot() def _update_gui(self): """Periodical GUI update of all items.""" assert self.downloads @@ -925,8 +922,8 @@ class AbstractDownloadManager(QObject): dl.stats.update_speed() self.data_changed.emit(-1) - @pyqtSlot(str, QUrl) - def _on_pdfjs_requested(self, filename: str, original_url: QUrl) -> None: + @core.pyqtSlot(str, core.QUrl) + def _on_pdfjs_requested(self, filename: str, original_url: core.QUrl) -> None: """Open PDF.js when a download requests it.""" tabbed_browser = objreg.get('tabbed-browser', scope='window', window='last-focused') @@ -942,7 +939,7 @@ class AbstractDownloadManager(QObject): delay = config.val.downloads.remove_finished if delay > -1: download.finished.connect( - lambda: QTimer.singleShot(delay, download.remove)) + lambda: core.QTimer.singleShot(delay, download.remove)) elif auto_remove: download.finished.connect(download.remove) @@ -961,7 +958,7 @@ class AbstractDownloadManager(QObject): if not self._update_timer.isActive(): self._update_timer.start() - @pyqtSlot(AbstractDownloadItem) + @core.pyqtSlot(AbstractDownloadItem) def _on_data_changed(self, download): """Emit data_changed signal when download data changed.""" try: @@ -971,12 +968,12 @@ class AbstractDownloadManager(QObject): return self.data_changed.emit(idx) - @pyqtSlot(str) + @core.pyqtSlot(str) def _on_error(self, msg): """Display error message on download errors.""" message.error("Download error: {}".format(msg)) - @pyqtSlot(AbstractDownloadItem) + @core.pyqtSlot(AbstractDownloadItem) def _remove_item(self, download): """Remove a given download.""" if sip.isdeleted(self): @@ -1009,7 +1006,7 @@ class AbstractDownloadManager(QObject): download.cancelled.connect(question.abort) download.error.connect(question.abort) - @pyqtSlot() + @core.pyqtSlot() def shutdown(self): """Cancel all downloads when shutting down.""" for download in self.downloads: @@ -1017,7 +1014,7 @@ class AbstractDownloadManager(QObject): download.cancel(remove_data=False) -class DownloadModel(QAbstractListModel): +class DownloadModel(core.QAbstractListModel): """A list model showing downloads.""" @@ -1066,25 +1063,25 @@ class DownloadModel(QAbstractListModel): log.downloads.debug("_on_begin_insert_row with idx {}, " "webengine {}".format(idx, webengine)) if idx == -1: - self.beginInsertRows(QModelIndex(), 0, -1) + self.beginInsertRows(core.QModelIndex(), 0, -1) return assert idx >= 0, idx if webengine: idx += len(self._qtnetwork_manager.downloads) - self.beginInsertRows(QModelIndex(), idx, idx) + self.beginInsertRows(core.QModelIndex(), idx, idx) def _on_begin_remove_row(self, idx, webengine=False): log.downloads.debug("_on_begin_remove_row with idx {}, " "webengine {}".format(idx, webengine)) if idx == -1: - self.beginRemoveRows(QModelIndex(), 0, -1) + self.beginRemoveRows(core.QModelIndex(), 0, -1) return assert idx >= 0, idx if webengine: idx += len(self._qtnetwork_manager.downloads) - self.beginRemoveRows(QModelIndex(), idx, idx) + self.beginRemoveRows(core.QModelIndex(), idx, idx) def _on_data_changed(self, idx, *, webengine): """Called when a downloader's data changed. @@ -1266,10 +1263,10 @@ class DownloadModel(QAbstractListModel): idx = self.index(self.rowCount() - 1) return idx - def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole): + def headerData(self, section, orientation, role=core.Qt.ItemDataRole.DisplayRole): """Simple constant header.""" - if (section == 0 and orientation == Qt.Orientation.Horizontal and - role == Qt.ItemDataRole.DisplayRole): + if (section == 0 and orientation == core.Qt.Orientation.Horizontal and + role == core.Qt.ItemDataRole.DisplayRole): return "Downloads" else: return "" @@ -1283,15 +1280,15 @@ class DownloadModel(QAbstractListModel): return None item = self[index.row()] - if role == Qt.ItemDataRole.DisplayRole: + if role == core.Qt.ItemDataRole.DisplayRole: data: Any = str(item) - elif role == Qt.ItemDataRole.ForegroundRole: + elif role == core.Qt.ItemDataRole.ForegroundRole: data = item.get_status_color('fg') - elif role == Qt.ItemDataRole.BackgroundRole: + elif role == core.Qt.ItemDataRole.BackgroundRole: data = item.get_status_color('bg') elif role == ModelRole.item: data = item - elif role == Qt.ItemDataRole.ToolTipRole: + elif role == core.Qt.ItemDataRole.ToolTipRole: if item.error_msg is None: data = None else: @@ -1306,10 +1303,10 @@ class DownloadModel(QAbstractListModel): The default would be Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable. """ if not index.isValid(): - return Qt.ItemFlag.NoItemFlags - return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemNeverHasChildren + return core.Qt.ItemFlag.NoItemFlags + return core.Qt.ItemFlag.ItemIsEnabled | core.Qt.ItemFlag.ItemNeverHasChildren - def rowCount(self, parent=QModelIndex()): + def rowCount(self, parent=core.QModelIndex()): """Get count of active downloads.""" if parent.isValid(): # We don't have children diff --git a/qutebrowser/browser/downloadview.py b/qutebrowser/browser/downloadview.py index da0763b76..2811368ac 100644 --- a/qutebrowser/browser/downloadview.py +++ b/qutebrowser/browser/downloadview.py @@ -22,12 +22,10 @@ import functools from typing import Callable, MutableSequence, Tuple, Union -from qutebrowser.qt.core import pyqtSlot, QSize, Qt -from qutebrowser.qt.widgets import QListView, QSizePolicy, QMenu, QStyleFactory - from qutebrowser.browser import downloads from qutebrowser.config import stylesheet from qutebrowser.utils import qtutils, utils +from qutebrowser.qt import widgets, core _ActionListType = MutableSequence[ @@ -38,7 +36,7 @@ _ActionListType = MutableSequence[ ] -class DownloadView(QListView): +class DownloadView(widgets.QListView): """QListView which shows currently running downloads as a bar. @@ -60,13 +58,13 @@ class DownloadView(QListView): def __init__(self, model, parent=None): super().__init__(parent) if not utils.is_mac: - self.setStyle(QStyleFactory.create('Fusion')) + self.setStyle(widgets.QStyleFactory.create('Fusion')) stylesheet.set_register(self) - self.setResizeMode(QListView.ResizeMode.Adjust) - self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) - self.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Fixed) - self.setFocusPolicy(Qt.FocusPolicy.NoFocus) - self.setFlow(QListView.Flow.LeftToRight) + self.setResizeMode(widgets.QListView.ResizeMode.Adjust) + self.setVerticalScrollBarPolicy(core.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.setSizePolicy(widgets.QSizePolicy.Policy.MinimumExpanding, widgets.QSizePolicy.Policy.Fixed) + self.setFocusPolicy(core.Qt.FocusPolicy.NoFocus) + self.setFlow(widgets.QListView.Flow.LeftToRight) self.setSpacing(1) self._menu = None model.rowsInserted.connect(self._update_geometry) @@ -74,7 +72,7 @@ class DownloadView(QListView): model.dataChanged.connect(self._update_geometry) self.setModel(model) self.setWrapping(True) - self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) + self.setContextMenuPolicy(core.Qt.ContextMenuPolicy.CustomContextMenu) self.customContextMenuRequested.connect(self.show_context_menu) self.clicked.connect(self.on_clicked) @@ -95,7 +93,7 @@ class DownloadView(QListView): assert isinstance(model, downloads.DownloadModel), model return model - @pyqtSlot() + @core.pyqtSlot() def _update_geometry(self): """Wrapper to call updateGeometry. @@ -104,7 +102,7 @@ class DownloadView(QListView): """ self.updateGeometry() - @pyqtSlot(bool) + @core.pyqtSlot(bool) def on_fullscreen_requested(self, on): """Hide/show the downloadview when entering/leaving fullscreen.""" if on: @@ -112,7 +110,7 @@ class DownloadView(QListView): else: self.show() - @pyqtSlot('QModelIndex') + @core.pyqtSlot('QModelIndex') def on_clicked(self, index): """Handle clicking of an item. @@ -158,7 +156,7 @@ class DownloadView(QListView): actions.append(("Remove all finished", model.download_clear)) return actions - @pyqtSlot('QPoint') + @core.pyqtSlot('QPoint') def show_context_menu(self, point): """Show the context menu.""" index = self.indexAt(point) @@ -166,7 +164,7 @@ class DownloadView(QListView): item = self._model().data(index, downloads.ModelRole.item) else: item = None - self._menu = QMenu(self) + self._menu = widgets.QMenu(self) actions = self._get_menu_actions(item) for (name, handler) in actions: if name is None and handler is None: @@ -191,8 +189,8 @@ class DownloadView(QListView): margins = self.contentsMargins() height = (bottom + margins.top() + margins.bottom() + 2 * self.spacing()) - size = QSize(0, height) + size = core.QSize(0, height) else: - size = QSize(0, 0) + size = core.QSize(0, 0) qtutils.ensure_valid(size) return size diff --git a/qutebrowser/browser/eventfilter.py b/qutebrowser/browser/eventfilter.py index 616798f9b..8d8d351b2 100644 --- a/qutebrowser/browser/eventfilter.py +++ b/qutebrowser/browser/eventfilter.py @@ -19,15 +19,14 @@ """Event handling for a browser tab.""" -from qutebrowser.qt import machinery -from qutebrowser.qt.core import QObject, QEvent, Qt, QTimer +from qutebrowser.qt import core, machinery from qutebrowser.config import config from qutebrowser.utils import log, message, usertypes from qutebrowser.keyinput import modeman -class ChildEventFilter(QObject): +class ChildEventFilter(core.QObject): """An event filter re-adding TabEventFilter on ChildEvent. @@ -48,7 +47,7 @@ class ChildEventFilter(QObject): def eventFilter(self, obj, event): """Act on ChildAdded events.""" - if event.type() == QEvent.Type.ChildAdded: + if event.type() == core.QEvent.Type.ChildAdded: child = event.child() log.misc.debug("{} got new child {}, installing filter" .format(obj, child)) @@ -58,14 +57,14 @@ class ChildEventFilter(QObject): assert obj is self._widget child.installEventFilter(self._filter) - elif event.type() == QEvent.Type.ChildRemoved: + elif event.type() == core.QEvent.Type.ChildRemoved: child = event.child() log.misc.debug("{}: removed child {}".format(obj, child)) return False -class TabEventFilter(QObject): +class TabEventFilter(core.QObject): """Handle mouse/keyboard events on a tab. @@ -81,9 +80,9 @@ class TabEventFilter(QObject): super().__init__(parent) self._tab = tab self._handlers = { - QEvent.Type.MouseButtonPress: self._handle_mouse_press, - QEvent.Type.MouseButtonRelease: self._handle_mouse_release, - QEvent.Type.Wheel: self._handle_wheel, + core.QEvent.Type.MouseButtonPress: self._handle_mouse_press, + core.QEvent.Type.MouseButtonRelease: self._handle_mouse_release, + core.QEvent.Type.Wheel: self._handle_wheel, } self._ignore_wheel_event = False self._check_insertmode_on_release = False @@ -98,9 +97,9 @@ class TabEventFilter(QObject): True if the event should be filtered, False otherwise. """ is_rocker_gesture = (config.val.input.mouse.rocker_gestures and - e.buttons() == Qt.MouseButton.LeftButton | Qt.MouseButton.RightButton) + e.buttons() == core.Qt.MouseButton.LeftButton | core.Qt.MouseButton.RightButton) - if e.button() in [Qt.MouseButton.XButton1, Qt.MouseButton.XButton2] or is_rocker_gesture: + if e.button() in [core.Qt.MouseButton.XButton1, core.Qt.MouseButton.XButton2] or is_rocker_gesture: if not machinery.IS_QT6: self._mousepress_backforward(e) # FIXME:qt6 For some reason, this doesn't filter the action on @@ -114,7 +113,7 @@ class TabEventFilter(QObject): log.mouse.warning("Ignoring invalid click at {}".format(pos)) return False - if e.button() != Qt.MouseButton.NoButton: + if e.button() != core.Qt.MouseButton.NoButton: self._tab.elements.find_at_pos(pos, self._mousepress_insertmode_cb) return False @@ -130,7 +129,7 @@ class TabEventFilter(QObject): """ # We want to make sure we check the focus element after the WebView is # updated completely. - QTimer.singleShot(0, self._mouserelease_insertmode) + core.QTimer.singleShot(0, self._mouserelease_insertmode) return False def _handle_wheel(self, e): @@ -152,7 +151,7 @@ class TabEventFilter(QObject): if mode == usertypes.KeyMode.hint: return True - elif e.modifiers() & Qt.KeyboardModifier.ControlModifier: + elif e.modifiers() & core.Qt.KeyboardModifier.ControlModifier: if mode == usertypes.KeyMode.passthrough: return False @@ -227,17 +226,17 @@ class TabEventFilter(QObject): True if the event should be filtered, False otherwise. """ if (not config.val.input.mouse.back_forward_buttons and - e.button() in [Qt.MouseButton.XButton1, Qt.MouseButton.XButton2]): + e.button() in [core.Qt.MouseButton.XButton1, core.Qt.MouseButton.XButton2]): # Back and forward on mice are disabled return - if e.button() in [Qt.MouseButton.XButton1, Qt.MouseButton.LeftButton]: + if e.button() in [core.Qt.MouseButton.XButton1, core.Qt.MouseButton.LeftButton]: # Back button on mice which have it, or rocker gesture if self._tab.history.can_go_back(): self._tab.history.back() else: message.error("At beginning of history.") - elif e.button() in [Qt.MouseButton.XButton2, Qt.MouseButton.RightButton]: + elif e.button() in [core.Qt.MouseButton.XButton2, core.Qt.MouseButton.RightButton]: # Forward button on mice which have it, or rocker gesture if self._tab.history.can_go_forward(): self._tab.history.forward() diff --git a/qutebrowser/browser/greasemonkey.py b/qutebrowser/browser/greasemonkey.py index a0cdf0fcc..88a3dd15c 100644 --- a/qutebrowser/browser/greasemonkey.py +++ b/qutebrowser/browser/greasemonkey.py @@ -29,13 +29,12 @@ import textwrap import dataclasses from typing import cast, List, Sequence, Tuple, Optional -from qutebrowser.qt.core import pyqtSignal, QObject, QUrl - from qutebrowser.utils import (log, standarddir, jinja, objreg, utils, javascript, urlmatch, version, usertypes, message) from qutebrowser.api import cmdutils from qutebrowser.browser import downloads from qutebrowser.misc import objects +from qutebrowser.qt import core gm_manager = cast('GreasemonkeyManager', None) @@ -221,7 +220,7 @@ class MatchingScripts: """All userscripts registered to run on a particular url.""" - url: QUrl + url: core.QUrl start: List[GreasemonkeyScript] = dataclasses.field(default_factory=list) end: List[GreasemonkeyScript] = dataclasses.field(default_factory=list) idle: List[GreasemonkeyScript] = dataclasses.field(default_factory=list) @@ -270,7 +269,7 @@ class GreasemonkeyMatcher: def __init__(self, url): self._url = url - self._url_string = url.toString(QUrl.ComponentFormattingOption.FullyEncoded) + self._url_string = url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded) self.is_greaseable = url.scheme() in self.GREASEABLE_SCHEMES def _match_pattern(self, pattern): @@ -295,7 +294,7 @@ class GreasemonkeyMatcher: return (matching_includes or matching_match) and not matching_excludes -class GreasemonkeyManager(QObject): +class GreasemonkeyManager(core.QObject): """Manager of userscripts and a Greasemonkey compatible environment. @@ -305,7 +304,7 @@ class GreasemonkeyManager(QObject): considered obsolete. """ - scripts_reloaded = pyqtSignal() + scripts_reloaded = core.pyqtSignal() def __init__(self, parent=None): super().__init__(parent) @@ -444,7 +443,7 @@ class GreasemonkeyManager(QObject): for url, target_path in required_dls: target = downloads.FileDownloadTarget(target_path, force_overwrite=True) - download = download_manager.get(QUrl(url), target=target, + download = download_manager.get(core.QUrl(url), target=target, auto_remove=True) # FIXME:mypy Build this into downloads instead of patching here? download.requested_url = url diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 91534a58b..ceefa7c78 100644 --- a/qutebrowser/browser/hints.py +++ b/qutebrowser/browser/hints.py @@ -29,9 +29,7 @@ import dataclasses from string import ascii_lowercase from typing import (TYPE_CHECKING, Callable, Dict, Iterable, Iterator, List, Mapping, MutableSequence, Optional, Sequence, Set) - -from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, Qt, QUrl -from qutebrowser.qt.widgets import QLabel +from qutebrowser.qt import widgets from qutebrowser.config import config, configexc from qutebrowser.keyinput import modeman, modeparsers, basekeyparser @@ -39,6 +37,8 @@ from qutebrowser.browser import webelem, history from qutebrowser.commands import runners from qutebrowser.api import cmdutils from qutebrowser.utils import usertypes, log, qtutils, message, objreg, utils +from qutebrowser.qt import core + if TYPE_CHECKING: from qutebrowser.browser import browsertab @@ -77,7 +77,7 @@ def on_mode_entered(mode: usertypes.KeyMode, win_id: int) -> None: maybe=True) -class HintLabel(QLabel): +class HintLabel(widgets.QLabel): """A label for a link. @@ -92,12 +92,12 @@ class HintLabel(QLabel): self._context = context self.elem = elem - self.setTextFormat(Qt.TextFormat.RichText) + self.setTextFormat(core.Qt.TextFormat.RichText) # Make sure we can style the background via a style sheet, and we don't # get any extra text indent from Qt. # The real stylesheet lives in mainwindow.py for performance reasons.. - self.setAttribute(Qt.WidgetAttribute.WA_StyledBackground, True) + self.setAttribute(core.Qt.WidgetAttribute.WA_StyledBackground, True) self.setIndent(0) self._context.tab.contents_size_changed.connect(self._move_to_elem) @@ -134,7 +134,7 @@ class HintLabel(QLabel): self.setText(unmatched) self.adjustSize() - @pyqtSlot() + @core.pyqtSlot() def _move_to_elem(self) -> None: """Reposition the label to its element.""" if not self.elem.has_frame(): @@ -189,7 +189,7 @@ class HintContext: hint_mode: str add_history: bool first: bool - baseurl: QUrl + baseurl: core.QUrl args: List[str] group: str @@ -247,14 +247,14 @@ class HintActions: except webelem.Error as e: raise HintingError(str(e)) - def yank(self, url: QUrl, context: HintContext) -> None: + def yank(self, url: core.QUrl, context: HintContext) -> None: """Yank an element to the clipboard or primary selection.""" sel = (context.target == Target.yank_primary and utils.supports_selection()) - flags = QUrl.ComponentFormattingOption.FullyEncoded | QUrl.UrlFormattingOption.RemovePassword + flags = core.QUrl.ComponentFormattingOption.FullyEncoded | core.QUrl.UrlFormattingOption.RemovePassword if url.scheme() == 'mailto': - flags |= QUrl.UrlFormattingOption.RemoveScheme + flags |= core.QUrl.UrlFormattingOption.RemoveScheme urlstr = url.toString(flags) new_content = urlstr @@ -274,16 +274,16 @@ class HintActions: urlstr) message.info(msg, replace='rapid-hints' if context.rapid else None) - def run_cmd(self, url: QUrl, context: HintContext) -> None: + def run_cmd(self, url: core.QUrl, context: HintContext) -> None: """Run the command based on a hint URL.""" - urlstr = url.toString(QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] + urlstr = url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] args = context.get_args(urlstr) commandrunner = runners.CommandRunner(self._win_id) commandrunner.run_safely(' '.join(args)) - def preset_cmd_text(self, url: QUrl, context: HintContext) -> None: + def preset_cmd_text(self, url: core.QUrl, context: HintContext) -> None: """Preset a commandline text based on a hint URL.""" - flags = QUrl.ComponentFormattingOption.FullyEncoded + flags = core.QUrl.ComponentFormattingOption.FullyEncoded urlstr = url.toDisplayString(flags) # type: ignore[arg-type] args = context.get_args(urlstr) text = ' '.join(args) @@ -325,7 +325,7 @@ class HintActions: cmd = context.args[0] args = context.args[1:] - flags = QUrl.ComponentFormattingOption.FullyEncoded + flags = core.QUrl.ComponentFormattingOption.FullyEncoded env = { 'QUTE_MODE': 'hints', @@ -349,7 +349,7 @@ class HintActions: _context: HintContext) -> None: elem.delete() - def spawn(self, url: QUrl, context: HintContext) -> None: + def spawn(self, url: core.QUrl, context: HintContext) -> None: """Spawn a simple command from a hint. Args: @@ -357,7 +357,7 @@ class HintActions: context: The HintContext to use. """ urlstr = url.toString( - QUrl.ComponentFormattingOption.FullyEncoded | QUrl.UrlFormattingOption.RemovePassword) + core.QUrl.ComponentFormattingOption.FullyEncoded | core.QUrl.UrlFormattingOption.RemovePassword) args = context.get_args(urlstr) commandrunner = runners.CommandRunner(self._win_id) commandrunner.run_safely('spawn ' + ' '.join(args)) @@ -367,7 +367,7 @@ _ElemsType = Sequence[webelem.AbstractWebElement] _HintStringsType = MutableSequence[str] -class HintManager(QObject): +class HintManager(core.QObject): """Manage drawing hints over links or other elements. @@ -402,9 +402,9 @@ class HintManager(QObject): Target.delete: "Delete an element", } - set_text = pyqtSignal(str) + set_text = core.pyqtSignal(str) - def __init__(self, win_id: int, parent: QObject = None) -> None: + def __init__(self, win_id: int, parent: core.QObject = None) -> None: """Constructor.""" super().__init__(parent) self._win_id = win_id @@ -858,7 +858,7 @@ class HintManager(QObject): # unpacking gets us the first (and only) key in the dict. self._fire(*visible) - @pyqtSlot(str) + @core.pyqtSlot(str) def handle_partial_key(self, keystr: str) -> None: """Handle a new partial keypress.""" if self._context is None: @@ -1032,7 +1032,7 @@ class HintManager(QObject): else: self._fire(keystring) - @pyqtSlot(usertypes.KeyMode) + @core.pyqtSlot(usertypes.KeyMode) def on_mode_left(self, mode: usertypes.KeyMode) -> None: """Stop hinting when hinting mode was left.""" if mode != usertypes.KeyMode.hint or self._context is None: diff --git a/qutebrowser/browser/history.py b/qutebrowser/browser/history.py index 312edfc13..bf2277188 100644 --- a/qutebrowser/browser/history.py +++ b/qutebrowser/browser/history.py @@ -25,13 +25,11 @@ import contextlib import pathlib from typing import cast, Mapping, MutableSequence, Optional -from qutebrowser.qt.core import pyqtSlot, QUrl, QObject, pyqtSignal -from qutebrowser.qt.widgets import QProgressDialog, QApplication - from qutebrowser.config import config from qutebrowser.api import cmdutils from qutebrowser.utils import utils, log, usertypes, message, qtutils from qutebrowser.misc import objects, sql +from qutebrowser.qt import widgets, core web_history = cast('WebHistory', None) @@ -52,27 +50,27 @@ class HistoryProgress: def start(self, text): """Start showing a progress dialog.""" - self._progress = QProgressDialog() + self._progress = widgets.QProgressDialog() self._progress.setMaximum(0) # unknown self._progress.setMinimumDuration(0) self._progress.setLabelText(text) self._progress.setCancelButton(None) self._progress.setAutoClose(False) self._progress.show() - QApplication.processEvents() + widgets.QApplication.processEvents() def set_maximum(self, maximum): """Set the progress maximum as soon as we know about it.""" assert self._progress is not None self._progress.setMaximum(maximum) - QApplication.processEvents() + widgets.QApplication.processEvents() def tick(self): """Increase the displayed progress value.""" self._value += 1 if self._progress is not None: self._progress.setValue(self._value) - QApplication.processEvents() + widgets.QApplication.processEvents() def finish(self): """Finish showing the progress dialog. @@ -93,7 +91,7 @@ class CompletionMetaInfo(sql.SqlTable): } def __init__(self, database: sql.Database, - parent: Optional[QObject] = None) -> None: + parent: Optional[core.QObject] = None) -> None: self._fields = ['key', 'value'] self._constraints = {'key': 'PRIMARY KEY'} super().__init__(database, "CompletionMetaInfo", self._fields, @@ -141,7 +139,7 @@ class CompletionHistory(sql.SqlTable): """History which only has the newest entry for each URL.""" def __init__(self, database: sql.Database, - parent: Optional[QObject] = None) -> None: + parent: Optional[core.QObject] = None) -> None: super().__init__(database, "CompletionHistory", ['url', 'title', 'last_atime'], constraints={'url': 'PRIMARY KEY', 'title': 'NOT NULL', @@ -161,12 +159,12 @@ class WebHistory(sql.SqlTable): """ # All web history cleared - history_cleared = pyqtSignal() + history_cleared = core.pyqtSignal() # one url cleared - url_cleared = pyqtSignal(QUrl) + url_cleared = core.pyqtSignal(core.QUrl) def __init__(self, database: sql.Database, progress: HistoryProgress, - parent: Optional[QObject] = None) -> None: + parent: Optional[core.QObject] = None) -> None: super().__init__(database, "History", ['url', 'title', 'atime', 'redirect'], constraints={'url': 'NOT NULL', 'title': 'NOT NULL', @@ -300,14 +298,14 @@ class WebHistory(sql.SqlTable): # Delete old entries self.completion.delete_all() - QApplication.processEvents() + widgets.QApplication.processEvents() # Select the latest entry for each url q = self.database.query('SELECT url, title, max(atime) AS atime FROM History ' 'WHERE NOT redirect ' 'GROUP BY url ORDER BY atime asc') result = q.run() - QApplication.processEvents() + widgets.QApplication.processEvents() entries = list(result) self._progress.set_maximum(len(entries)) @@ -315,7 +313,7 @@ class WebHistory(sql.SqlTable): for entry in entries: self._progress.tick() - url = QUrl(entry.url) + url = core.QUrl(entry.url) if self._is_excluded_from_completion(url): continue data['url'].append(self._format_completion_url(url)) @@ -326,10 +324,10 @@ class WebHistory(sql.SqlTable): # We might have caused fragmentation - let's clean up. self.database.query('VACUUM').run() - QApplication.processEvents() + widgets.QApplication.processEvents() self.completion.insert_batch(data, replace=True) - QApplication.processEvents() + widgets.QApplication.processEvents() self._progress.finish() self.metainfo['force_rebuild'] = False @@ -373,7 +371,7 @@ class WebHistory(sql.SqlTable): Args: url: URL string to delete. """ - qurl = QUrl(url) + qurl = core.QUrl(url) qtutils.ensure_valid(qurl) self.delete('url', self._format_url(qurl)) self.completion.delete('url', self._format_completion_url(qurl)) @@ -381,7 +379,7 @@ class WebHistory(sql.SqlTable): self._last_url = None self.url_cleared.emit(qurl) - @pyqtSlot(QUrl, QUrl, str) + @core.pyqtSlot(core.QUrl, core.QUrl, str) def add_from_tab(self, url, requested_url, title): """Add a new history entry as slot, called from a BrowserTab.""" if self._is_excluded_entirely(url) or self._is_excluded_entirely(requested_url): @@ -390,7 +388,7 @@ class WebHistory(sql.SqlTable): # things set via setHtml return - no_formatting = QUrl.UrlFormattingOption(0) + no_formatting = core.QUrl.UrlFormattingOption(0) if (requested_url.isValid() and not requested_url.matches(url, no_formatting)): # If the url of the page is different than the url of the link @@ -435,10 +433,10 @@ class WebHistory(sql.SqlTable): }, replace=True) def _format_url(self, url): - return url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + return url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) def _format_completion_url(self, url): - return url.toString(QUrl.UrlFormattingOption.RemovePassword) + return url.toString(core.QUrl.UrlFormattingOption.RemovePassword) @cmdutils.register() @@ -479,7 +477,7 @@ def debug_dump_history(dest): raise cmdutils.CommandError(f'Could not write history: {e}') -def init(db_path: pathlib.Path, parent: Optional[QObject] = None) -> None: +def init(db_path: pathlib.Path, parent: Optional[core.QObject] = None) -> None: """Initialize the web history. Args: diff --git a/qutebrowser/browser/inspector.py b/qutebrowser/browser/inspector.py index dcf718552..91082489e 100644 --- a/qutebrowser/browser/inspector.py +++ b/qutebrowser/browser/inspector.py @@ -24,15 +24,15 @@ import binascii import enum from typing import cast, Optional, Any -from qutebrowser.qt.widgets import QWidget -from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QObject, QEvent -from qutebrowser.qt.gui import QCloseEvent +from qutebrowser.qt import widgets +from qutebrowser.qt import gui from qutebrowser.browser import eventfilter from qutebrowser.config import configfiles, config from qutebrowser.utils import log, usertypes from qutebrowser.keyinput import modeman from qutebrowser.misc import miscwidgets +from qutebrowser.qt import core # FIXME:mypy How to annotate this properly without running into Liskov issues? @@ -55,7 +55,7 @@ class Error(Exception): """Raised when the inspector could not be initialized.""" -class _EventFilter(QObject): +class _EventFilter(core.QObject): """Event filter to enter insert mode when inspector was clicked. @@ -70,16 +70,16 @@ class _EventFilter(QObject): the QWebInspector. """ - clicked = pyqtSignal() + clicked = core.pyqtSignal() - def eventFilter(self, _obj: QObject, event: QEvent) -> bool: + def eventFilter(self, _obj: core.QObject, event: core.QEvent) -> bool: """Translate mouse presses to a clicked signal.""" - if event.type() == QEvent.Type.MouseButtonPress: + if event.type() == core.QEvent.Type.MouseButtonPress: self.clicked.emit() return False -class AbstractWebInspector(QWidget): +class AbstractWebInspector(widgets.QWidget): """Base class for QtWebKit/QtWebEngine inspectors. @@ -91,11 +91,11 @@ class AbstractWebInspector(QWidget): recreate: Emitted when the inspector should be recreated. """ - recreate = pyqtSignal() + recreate = core.pyqtSignal() def __init__(self, splitter: 'miscwidgets.InspectorSplitter', win_id: int, - parent: QWidget = None) -> None: + parent: widgets.QWidget = None) -> None: super().__init__(parent) self._widget = cast(_WidgetType, None) self._layout = miscwidgets.WrapperLayout(self) @@ -134,7 +134,7 @@ class AbstractWebInspector(QWidget): """ return False - @pyqtSlot() + @core.pyqtSlot() def _on_clicked(self) -> None: """Enter insert mode if a docked inspector was clicked.""" if (self._position != Position.window and @@ -197,7 +197,7 @@ class AbstractWebInspector(QWidget): if not ok: log.init.warning("Error while loading geometry.") - def closeEvent(self, _e: QCloseEvent) -> None: + def closeEvent(self, _e: gui.QCloseEvent) -> None: """Save the geometry when closed.""" data = self._widget.saveGeometry().data() geom = base64.b64encode(data).decode('ASCII') @@ -208,7 +208,7 @@ class AbstractWebInspector(QWidget): """Inspect the given QWeb(Engine)Page.""" raise NotImplementedError - @pyqtSlot() + @core.pyqtSlot() def shutdown(self) -> None: """Clean up the inspector.""" self.close() diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py index d2783e349..38393ffb4 100644 --- a/qutebrowser/browser/navigate.py +++ b/qutebrowser/browser/navigate.py @@ -23,7 +23,7 @@ import re import posixpath from typing import Optional, Set -from qutebrowser.qt.core import QUrl +from qutebrowser.qt import core from qutebrowser.browser import webelem from qutebrowser.config import config @@ -42,24 +42,24 @@ class Error(Exception): # of information. (host and path use FullyDecoded by default) _URL_SEGMENTS = [ ('host', - lambda url: url.host(QUrl.ComponentFormattingOption.FullyEncoded), - lambda url, host: url.setHost(host, QUrl.ParsingMode.StrictMode)), + lambda url: url.host(core.QUrl.ComponentFormattingOption.FullyEncoded), + lambda url, host: url.setHost(host, core.QUrl.ParsingMode.StrictMode)), ('port', lambda url: str(url.port()) if url.port() > 0 else '', lambda url, x: url.setPort(int(x))), ('path', - lambda url: url.path(QUrl.ComponentFormattingOption.FullyEncoded), - lambda url, path: url.setPath(path, QUrl.ParsingMode.StrictMode)), + lambda url: url.path(core.QUrl.ComponentFormattingOption.FullyEncoded), + lambda url, path: url.setPath(path, core.QUrl.ParsingMode.StrictMode)), ('query', - lambda url: url.query(QUrl.ComponentFormattingOption.FullyEncoded), - lambda url, query: url.setQuery(query, QUrl.ParsingMode.StrictMode)), + lambda url: url.query(core.QUrl.ComponentFormattingOption.FullyEncoded), + lambda url, query: url.setQuery(query, core.QUrl.ParsingMode.StrictMode)), ('anchor', - lambda url: url.fragment(QUrl.ComponentFormattingOption.FullyEncoded), - lambda url, fragment: url.setFragment(fragment, QUrl.ParsingMode.StrictMode)), + lambda url: url.fragment(core.QUrl.ComponentFormattingOption.FullyEncoded), + lambda url, fragment: url.setFragment(fragment, core.QUrl.ParsingMode.StrictMode)), ] @@ -102,7 +102,7 @@ def incdec(url, count, inc_or_dec): segments = {'path', 'query'} # Make a copy of the QUrl so we don't modify the original - url = QUrl(url) + url = core.QUrl(url) # We're searching the last number so we walk the url segments backwards for segment, getter, setter in reversed(_URL_SEGMENTS): if segment not in segments: @@ -130,14 +130,14 @@ def path_up(url, count): count: The number of levels to go up in the url. """ urlutils.ensure_valid(url) - url = url.adjusted(QUrl.UrlFormattingOption.RemoveFragment | QUrl.UrlFormattingOption.RemoveQuery) - path = url.path(QUrl.ComponentFormattingOption.FullyEncoded) + url = url.adjusted(core.QUrl.UrlFormattingOption.RemoveFragment | core.QUrl.UrlFormattingOption.RemoveQuery) + path = url.path(core.QUrl.ComponentFormattingOption.FullyEncoded) if not path or path == '/': raise Error("Can't go up!") for _i in range(0, min(count, path.count('/'))): path = posixpath.join(path, posixpath.pardir) path = posixpath.normpath(path) - url.setPath(path, QUrl.ParsingMode.StrictMode) + url.setPath(path, core.QUrl.ParsingMode.StrictMode) return url @@ -146,7 +146,7 @@ def strip(url, count): if count != 1: raise Error("Count is not supported when stripping URL components") urlutils.ensure_valid(url) - return url.adjusted(QUrl.UrlFormattingOption.RemoveFragment | QUrl.UrlFormattingOption.RemoveQuery) + return url.adjusted(core.QUrl.UrlFormattingOption.RemoveFragment | core.QUrl.UrlFormattingOption.RemoveQuery) def _find_prevnext(prev, elems): diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py index be25a2a41..df3bd1466 100644 --- a/qutebrowser/browser/network/pac.py +++ b/qutebrowser/browser/network/pac.py @@ -23,13 +23,8 @@ import sys import functools from typing import Optional -from qutebrowser.qt.core import QObject, pyqtSignal, pyqtSlot, QUrl -from qutebrowser.qt.network import (QNetworkProxy, QNetworkRequest, QHostInfo, - QNetworkReply, QNetworkAccessManager, - QHostAddress) -from qutebrowser.qt.qml import QJSEngine, QJSValue - from qutebrowser.utils import log, utils, qtutils, resources +from qutebrowser.qt import qml, network, core class ParseProxyError(Exception): @@ -66,12 +61,12 @@ def _js_slot(*args): return self._error_con.callAsConstructor([e]) # pylint: enable=protected-access - deco = pyqtSlot(*args, result=QJSValue) + deco = core.pyqtSlot(*args, result=qml.QJSValue) return deco(new_method) return _decorator -class _PACContext(QObject): +class _PACContext(core.QObject): """Implementation of PAC API functions that require native calls. @@ -108,11 +103,11 @@ class _PACContext(QObject): Args: host: hostname to resolve. """ - ips = QHostInfo.fromName(host) - if ips.error() != QHostInfo.HostInfoError.NoError or not ips.addresses(): + ips = network.QHostInfo.fromName(host) + if ips.error() != network.QHostInfo.HostInfoError.NoError or not ips.addresses(): err_f = "Failed to resolve host during PAC evaluation: {}" log.network.info(err_f.format(host)) - return QJSValue(QJSValue.SpecialValue.NullValue) + return qml.QJSValue(qml.QJSValue.SpecialValue.NullValue) else: return ips.addresses()[0].toString() @@ -123,7 +118,7 @@ class _PACContext(QObject): Return the server IP address of the current machine, as a string in the dot-separated integer format. """ - return QHostAddress(QHostAddress.SpecialAddress.LocalHost).toString() + return network.QHostAddress(network.QHostAddress.SpecialAddress.LocalHost).toString() class PACResolver: @@ -150,17 +145,17 @@ class PACResolver: if len(config) != 1: raise ParseProxyError("Invalid number of parameters for " + "DIRECT") - return QNetworkProxy(QNetworkProxy.ProxyType.NoProxy) + return network.QNetworkProxy(network.QNetworkProxy.ProxyType.NoProxy) elif config[0] == "PROXY": if len(config) != 2: raise ParseProxyError("Invalid number of parameters for PROXY") host, port = PACResolver._parse_proxy_host(config[1]) - return QNetworkProxy(QNetworkProxy.ProxyType.HttpProxy, host, port) + return network.QNetworkProxy(network.QNetworkProxy.ProxyType.HttpProxy, host, port) elif config[0] in ["SOCKS", "SOCKS5"]: if len(config) != 2: raise ParseProxyError("Invalid number of parameters for SOCKS") host, port = PACResolver._parse_proxy_host(config[1]) - return QNetworkProxy(QNetworkProxy.ProxyType.Socks5Proxy, host, port) + return network.QNetworkProxy(network.QNetworkProxy.ProxyType.Socks5Proxy, host, port) else: err = "Unknown proxy type: {}" raise ParseProxyError(err.format(config[0])) @@ -182,9 +177,9 @@ class PACResolver: Args: pac_str: JavaScript code containing PAC resolver. """ - self._engine = QJSEngine() + self._engine = qml.QJSEngine() - self._engine.installExtensions(QJSEngine.Extension.ConsoleExtension) + self._engine.installExtensions(qml.QJSEngine.Extension.ConsoleExtension) self._ctx = _PACContext(self._engine) self._engine.globalObject().setProperty( @@ -215,12 +210,12 @@ class PACResolver: qtutils.ensure_valid(query.url()) if from_file: - string_flags = QUrl.ComponentFormattingOption.PrettyDecoded + string_flags = core.QUrl.ComponentFormattingOption.PrettyDecoded else: - string_flags = QUrl.UrlFormattingOption.RemoveUserInfo # type: ignore[assignment] + string_flags = core.QUrl.UrlFormattingOption.RemoveUserInfo # type: ignore[assignment] if query.url().scheme() == 'https': - string_flags |= QUrl.UrlFormattingOption.RemovePath # type: ignore[assignment] - string_flags |= QUrl.UrlFormattingOption.RemoveQuery # type: ignore[assignment] + string_flags |= core.QUrl.UrlFormattingOption.RemovePath # type: ignore[assignment] + string_flags |= core.QUrl.UrlFormattingOption.RemoveQuery # type: ignore[assignment] result = self._resolver.call([query.url().toString(string_flags), query.peerHostName()]) @@ -231,11 +226,11 @@ class PACResolver: return self._parse_proxy_string(result_str) -class PACFetcher(QObject): +class PACFetcher(core.QObject): """Asynchronous fetcher of PAC files.""" - finished = pyqtSignal() + finished = core.pyqtSignal() def __init__(self, url, parent=None): """Resolve a PAC proxy from URL. @@ -254,8 +249,8 @@ class PACFetcher(QObject): with log.disable_qt_msghandler(): # WORKAROUND for a hang when messages are printed, see our # NetworkAccessManager subclass for details. - self._manager: Optional[QNetworkAccessManager] = QNetworkAccessManager() - self._manager.setProxy(QNetworkProxy(QNetworkProxy.ProxyType.NoProxy)) + self._manager: Optional[network.QNetworkAccessManager] = network.QNetworkAccessManager() + self._manager.setProxy(network.QNetworkProxy(network.QNetworkProxy.ProxyType.NoProxy)) self._pac = None self._error_message = None self._reply = None @@ -269,13 +264,13 @@ class PACFetcher(QObject): def fetch(self): """Fetch the proxy from the remote URL.""" assert self._manager is not None - self._reply = self._manager.get(QNetworkRequest(self._pac_url)) + self._reply = self._manager.get(network.QNetworkRequest(self._pac_url)) self._reply.finished.connect(self._finish) - @pyqtSlot() + @core.pyqtSlot() def _finish(self): assert self._reply is not None - if self._reply.error() != QNetworkReply.NetworkError.NoError: + if self._reply.error() != network.QNetworkReply.NetworkError.NoError: error = "Can't fetch PAC file from URL, error code {}: {}" self._error_message = error.format( self._reply.error(), self._reply.errorString()) @@ -334,4 +329,4 @@ class PACFetcher(QObject): # Later NetworkManager.createRequest will detect this and display # an error message. error_host = "pac-resolve-error.qutebrowser.invalid" - return [QNetworkProxy(QNetworkProxy.ProxyType.HttpProxy, error_host, 9)] + return [network.QNetworkProxy(network.QNetworkProxy.ProxyType.HttpProxy, error_host, 9)] diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py index 4022337c4..ed3c94983 100644 --- a/qutebrowser/browser/network/proxy.py +++ b/qutebrowser/browser/network/proxy.py @@ -19,13 +19,11 @@ """Handling of proxies.""" -from qutebrowser.qt.core import QUrl, pyqtSlot -from qutebrowser.qt.network import QNetworkProxy, QNetworkProxyFactory - from qutebrowser.config import config, configtypes from qutebrowser.utils import message, usertypes, urlutils, utils from qutebrowser.misc import objects from qutebrowser.browser.network import pac +from qutebrowser.qt import network, core application_factory = None @@ -35,7 +33,7 @@ def init(): """Set the application wide proxy factory.""" global application_factory application_factory = ProxyFactory() - QNetworkProxyFactory.setApplicationProxyFactory(application_factory) + network.QNetworkProxyFactory.setApplicationProxyFactory(application_factory) config.instance.changed.connect(_warn_for_pac) _warn_for_pac() @@ -50,13 +48,13 @@ def _warn_for_pac(): message.error("PAC support isn't implemented for QtWebEngine yet!") -@pyqtSlot() +@core.pyqtSlot() def shutdown(): - QNetworkProxyFactory.setApplicationProxyFactory( + network.QNetworkProxyFactory.setApplicationProxyFactory( None) # type: ignore[arg-type] -class ProxyFactory(QNetworkProxyFactory): +class ProxyFactory(network.QNetworkProxyFactory): """Factory for proxies to be used by qutebrowser.""" @@ -73,11 +71,11 @@ class ProxyFactory(QNetworkProxyFactory): return None def _set_capabilities(self, proxy): - if proxy.type() == QNetworkProxy.ProxyType.NoProxy: + if proxy.type() == network.QNetworkProxy.ProxyType.NoProxy: return capabilities = proxy.capabilities() - lookup_cap = QNetworkProxy.Capability.HostNameLookupCapability + lookup_cap = network.QNetworkProxy.Capability.HostNameLookupCapability if config.val.content.proxy_dns_requests: capabilities |= lookup_cap else: @@ -98,11 +96,11 @@ class ProxyFactory(QNetworkProxyFactory): # On Linux, use "export http_proxy=socks5://host:port" to manually # set system proxy. # ref. https://doc.qt.io/qt-5/qnetworkproxyfactory.html#systemProxyForQuery - proxies = QNetworkProxyFactory.systemProxyForQuery(query) + proxies = network.QNetworkProxyFactory.systemProxyForQuery(query) elif isinstance(proxy, pac.PACFetcher): if objects.backend == usertypes.Backend.QtWebEngine: # Looks like query.url() is always invalid on QtWebEngine... - proxy = urlutils.proxy_from_url(QUrl('direct://')) + proxy = urlutils.proxy_from_url(core.QUrl('direct://')) assert not isinstance(proxy, pac.PACFetcher) proxies = [proxy] elif objects.backend == usertypes.Backend.QtWebKit: diff --git a/qutebrowser/browser/pdfjs.py b/qutebrowser/browser/pdfjs.py index 4b86b4c27..9c3ed97b8 100644 --- a/qutebrowser/browser/pdfjs.py +++ b/qutebrowser/browser/pdfjs.py @@ -22,10 +22,9 @@ import os -from qutebrowser.qt.core import QUrl, QUrlQuery - from qutebrowser.utils import resources, javascript, jinja, standarddir, log from qutebrowser.config import config +from qutebrowser.qt import core _SYSTEM_PATHS = [ @@ -90,13 +89,13 @@ def _generate_pdfjs_script(filename): Args: filename: The name of the file to open. """ - url = QUrl('qute://pdfjs/file') - url_query = QUrlQuery() + url = core.QUrl('qute://pdfjs/file') + url_query = core.QUrlQuery() url_query.addQueryItem('filename', filename) url.setQuery(url_query) js_url = javascript.to_js( - url.toString(QUrl.ComponentFormattingOption.FullyEncoded)) # type: ignore[arg-type] + url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded)) # type: ignore[arg-type] return jinja.js_environment.from_string(""" document.addEventListener("DOMContentLoaded", function() { @@ -225,19 +224,19 @@ def should_use_pdfjs(mimetype, url): """Check whether PDF.js should be used.""" # e.g. 'blob:qute%3A///b45250b3-787e-44d1-a8d8-c2c90f81f981' is_download_url = (url.scheme() == 'blob' and - QUrl(url.path()).scheme() == 'qute') + core.QUrl(url.path()).scheme() == 'qute') is_pdf = mimetype in ['application/pdf', 'application/x-pdf'] config_enabled = config.instance.get('content.pdfjs', url=url) return is_pdf and not is_download_url and config_enabled -def get_main_url(filename: str, original_url: QUrl) -> QUrl: +def get_main_url(filename: str, original_url: core.QUrl) -> core.QUrl: """Get the URL to be opened to view a local PDF.""" - url = QUrl('qute://pdfjs/web/viewer.html') - query = QUrlQuery() + url = core.QUrl('qute://pdfjs/web/viewer.html') + query = core.QUrlQuery() query.addQueryItem('filename', filename) # read from our JS query.addQueryItem('file', '') # to avoid pdfjs opening the default PDF - urlstr = original_url.toString(QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] + urlstr = original_url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] query.addQueryItem('source', urlstr) url.setQuery(query) return url diff --git a/qutebrowser/browser/qtnetworkdownloads.py b/qutebrowser/browser/qtnetworkdownloads.py index 586570390..3c782db84 100644 --- a/qutebrowser/browser/qtnetworkdownloads.py +++ b/qutebrowser/browser/qtnetworkdownloads.py @@ -25,10 +25,7 @@ import shutil import functools import dataclasses from typing import Dict, IO, Optional - -from qutebrowser.qt.core import pyqtSlot, pyqtSignal, QTimer, QUrl -from qutebrowser.qt.widgets import QApplication -from qutebrowser.qt.network import QNetworkRequest, QNetworkReply, QNetworkAccessManager +from qutebrowser.qt import widgets from qutebrowser.config import config, websettings from qutebrowser.utils import message, usertypes, log, urlutils, utils, debug, objreg @@ -36,13 +33,14 @@ from qutebrowser.misc import quitter from qutebrowser.browser import downloads from qutebrowser.browser.webkit import http from qutebrowser.browser.webkit.network import networkmanager +from qutebrowser.qt import network, core @dataclasses.dataclass class _RetryInfo: - request: QNetworkRequest - manager: QNetworkAccessManager + request: network.QNetworkRequest + manager: network.QNetworkAccessManager class DownloadItem(downloads.AbstractDownloadItem): @@ -78,7 +76,7 @@ class DownloadItem(downloads.AbstractDownloadItem): arg 0: The new DownloadItem """ - adopt_download = pyqtSignal(object) # DownloadItem + adopt_download = core.pyqtSignal(object) # DownloadItem def __init__(self, reply, manager): """Constructor. @@ -172,10 +170,10 @@ class DownloadItem(downloads.AbstractDownloadItem): # We could have got signals before we connected slots to them. # Here no signals are connected to the DownloadItem yet, so we use a # singleShot QTimer to emit them after they are connected. - if reply.error() != QNetworkReply.NetworkError.NoError: - QTimer.singleShot(0, lambda: self._die(reply.errorString())) + if reply.error() != network.QNetworkReply.NetworkError.NoError: + core.QTimer.singleShot(0, lambda: self._die(reply.errorString())) - @pyqtSlot(QUrl) + @core.pyqtSlot(core.QUrl) def _on_redirected(self, url): log.downloads.debug(f"redirected: {self._reply.url()} -> {url}") @@ -190,7 +188,7 @@ class DownloadItem(downloads.AbstractDownloadItem): self.fileobj.close() self.cancelled.emit() - @pyqtSlot() + @core.pyqtSlot() def retry(self): """Retry a failed download.""" assert self.done @@ -213,20 +211,20 @@ class DownloadItem(downloads.AbstractDownloadItem): filename = getattr(self.fileobj, 'name', None) return filename - def url(self) -> QUrl: + def url(self) -> core.QUrl: # Note: self._reply is deleted when the download finishes return self._url - def origin(self) -> QUrl: + def origin(self) -> core.QUrl: if self._reply is None: - return QUrl() + return core.QUrl() origin = self._reply.request().originatingObject() try: return origin.url() except AttributeError: # Raised either if origin is None or some object that doesn't # have its own url. - return QUrl() + return core.QUrl() def _ensure_can_set_filename(self, filename): if self.fileobj is not None: # pragma: no cover @@ -300,7 +298,7 @@ class DownloadItem(downloads.AbstractDownloadItem): self.fileobj.write(self._reply.readAll()) if self._autoclose: self.fileobj.close() - self.successful = self._reply.error() == QNetworkReply.NetworkError.NoError + self.successful = self._reply.error() == network.QNetworkReply.NetworkError.NoError self._reply.close() self._reply.deleteLater() self._reply = None @@ -309,7 +307,7 @@ class DownloadItem(downloads.AbstractDownloadItem): log.downloads.debug("Download {} finished".format(self.basename)) self.data_changed.emit() - @pyqtSlot() + @core.pyqtSlot() def _on_reply_finished(self): """Clean up when the download was finished. @@ -327,7 +325,7 @@ class DownloadItem(downloads.AbstractDownloadItem): # clean up. self._finish_download() - @pyqtSlot() + @core.pyqtSlot() def _on_ready_read(self): """Read available data and save file when ready to read.""" if self.fileobj is None or self._reply is None: @@ -342,21 +340,21 @@ class DownloadItem(downloads.AbstractDownloadItem): except OSError as e: self._die(e.strerror) - @pyqtSlot('QNetworkReply::NetworkError') + @core.pyqtSlot('QNetworkReply::NetworkError') def _on_reply_error(self, code): """Handle QNetworkReply errors.""" - if code == QNetworkReply.NetworkError.OperationCanceledError: + if code == network.QNetworkReply.NetworkError.OperationCanceledError: return if self._reply is None: error = "Unknown error: {}".format( - debug.qenum_key(QNetworkReply, code)) + debug.qenum_key(network.QNetworkReply, code)) else: error = self._reply.errorString() self._die(error) - @pyqtSlot() + @core.pyqtSlot() def _on_read_timer_timeout(self): """Read some bytes from the QNetworkReply periodically.""" assert self._reply is not None @@ -366,7 +364,7 @@ class DownloadItem(downloads.AbstractDownloadItem): if data is not None: self._buffer.write(data) - @pyqtSlot() + @core.pyqtSlot() def _on_meta_data_changed(self): """Update the download's metadata.""" if self._reply is None: @@ -408,7 +406,7 @@ class DownloadManager(downloads.AbstractDownloadManager): win_id=None, tab_id=None, private=config.val.content.private_browsing, parent=self) - @pyqtSlot('QUrl') + @core.pyqtSlot('QUrl') def get(self, url, cache=True, **kwargs): """Start a download with a link URL. @@ -424,18 +422,18 @@ class DownloadManager(downloads.AbstractDownloadManager): urlutils.invalid_url_error(url, "start download") return None - req = QNetworkRequest(url) + req = network.QNetworkRequest(url) user_agent = websettings.user_agent(url) - req.setHeader(QNetworkRequest.KnownHeaders.UserAgentHeader, user_agent) + req.setHeader(network.QNetworkRequest.KnownHeaders.UserAgentHeader, user_agent) if not cache: - req.setAttribute(QNetworkRequest.Attribute.CacheSaveControlAttribute, False) + req.setAttribute(network.QNetworkRequest.Attribute.CacheSaveControlAttribute, False) # Needed for Qt 5, default on Qt 6 # We don't set this on the QNAM because QtWebKit handles redirects manually. req.setAttribute( - QNetworkRequest.Attribute.RedirectPolicyAttribute, - QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy, + network.QNetworkRequest.Attribute.RedirectPolicyAttribute, + network.QNetworkRequest.RedirectPolicy.NoLessSafeRedirectPolicy, ) req.setMaximumRedirectsAllowed(self._MAX_REDIRECTS) @@ -497,8 +495,8 @@ class DownloadManager(downloads.AbstractDownloadManager): """ # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 - request.setAttribute(QNetworkRequest.Attribute.CacheLoadControlAttribute, - QNetworkRequest.CacheLoadControl.AlwaysNetwork) + request.setAttribute(network.QNetworkRequest.Attribute.CacheLoadControlAttribute, + network.QNetworkRequest.CacheLoadControl.AlwaysNetwork) if suggested_fn is None: suggested_fn = self._get_suggested_filename(request) @@ -524,7 +522,7 @@ class DownloadManager(downloads.AbstractDownloadManager): reply = qnam.get(request) return self.fetch(reply, **kwargs) - @pyqtSlot('QNetworkReply') + @core.pyqtSlot('QNetworkReply') def fetch(self, reply, *, target=None, auto_remove=False, suggested_filename=None, prompt_download_directory=None): """Download a QNetworkReply to disk. @@ -595,6 +593,6 @@ class DownloadManager(downloads.AbstractDownloadManager): def init(): """Initialize the global QtNetwork download manager.""" - download_manager = DownloadManager(parent=QApplication.instance()) + download_manager = DownloadManager(parent=widgets.QApplication.instance()) objreg.register('qtnetwork-download-manager', download_manager) quitter.instance.shutting_down.connect(download_manager.shutdown) diff --git a/qutebrowser/browser/qutescheme.py b/qutebrowser/browser/qutescheme.py index 322066c3f..0cf0aaa27 100644 --- a/qutebrowser/browser/qutescheme.py +++ b/qutebrowser/browser/qutescheme.py @@ -34,15 +34,13 @@ import collections import secrets from typing import TypeVar, Callable, Dict, List, Optional, Union, Sequence, Tuple -from qutebrowser.qt.core import QUrlQuery, QUrl - import qutebrowser from qutebrowser.browser import pdfjs, downloads, history from qutebrowser.config import config, configdata, configexc from qutebrowser.utils import (version, utils, jinja, log, message, docutils, resources, objreg, standarddir) from qutebrowser.misc import guiprocess, quitter -from qutebrowser.qt import sip +from qutebrowser.qt import core, sip pyeval_output = ":pyeval was never called" @@ -85,14 +83,14 @@ class Redirect(Exception): url: The URL to redirect to, as a QUrl. """ - def __init__(self, url: QUrl): + def __init__(self, url: core.QUrl): super().__init__(url.toDisplayString()) self.url = url # Return value: (mimetype, data) (encoded as utf-8 if a str is returned) _HandlerRet = Tuple[str, Union[str, bytes]] -_HandlerCallable = Callable[[QUrl], _HandlerRet] +_HandlerCallable = Callable[[core.QUrl], _HandlerRet] _Handler = TypeVar('_Handler', bound=_HandlerCallable) @@ -113,13 +111,13 @@ class add_handler: # noqa: N801,N806 pylint: disable=invalid-name _HANDLERS[self._name] = self.wrapper return function - def wrapper(self, url: QUrl) -> _HandlerRet: + def wrapper(self, url: core.QUrl) -> _HandlerRet: """Call the underlying function.""" assert self._function is not None return self._function(url) -def data_for_url(url: QUrl) -> Tuple[str, bytes]: +def data_for_url(url: core.QUrl) -> Tuple[str, bytes]: """Get the data to show for the given URL. Args: @@ -129,8 +127,8 @@ def data_for_url(url: QUrl) -> Tuple[str, bytes]: A (mimetype, data) tuple. """ norm_url = url.adjusted( - QUrl.UrlFormattingOption.NormalizePathSegments | - QUrl.UrlFormattingOption.StripTrailingSlash) + core.QUrl.UrlFormattingOption.NormalizePathSegments | + core.QUrl.UrlFormattingOption.StripTrailingSlash) if norm_url != url: raise Redirect(norm_url) @@ -141,7 +139,7 @@ def data_for_url(url: QUrl) -> Tuple[str, bytes]: log.misc.debug("url: {}, path: {}, host {}".format( url.toDisplayString(), path, host)) if not path or not host: - new_url = QUrl() + new_url = core.QUrl() new_url.setScheme('qute') # When path is absent, e.g. qute://help (with no trailing slash) if host: @@ -177,7 +175,7 @@ def data_for_url(url: QUrl) -> Tuple[str, bytes]: @add_handler('bookmarks') -def qute_bookmarks(_url: QUrl) -> _HandlerRet: +def qute_bookmarks(_url: core.QUrl) -> _HandlerRet: """Handler for qute://bookmarks. Display all quickmarks / bookmarks.""" bookmarks = sorted(objreg.get('bookmark-manager').marks.items(), key=lambda x: x[1]) # Sort by title @@ -192,7 +190,7 @@ def qute_bookmarks(_url: QUrl) -> _HandlerRet: @add_handler('tabs') -def qute_tabs(_url: QUrl) -> _HandlerRet: +def qute_tabs(_url: core.QUrl) -> _HandlerRet: """Handler for qute://tabs. Display information about all open tabs.""" tabs: Dict[str, List[Tuple[str, str]]] = collections.defaultdict(list) for win_id, window in objreg.window_registry.items(): @@ -202,7 +200,7 @@ def qute_tabs(_url: QUrl) -> _HandlerRet: scope='window', window=win_id) for tab in tabbed_browser.widgets(): - if tab.url() not in [QUrl("qute://tabs/"), QUrl("qute://tabs")]: + if tab.url() not in [core.QUrl("qute://tabs/"), core.QUrl("qute://tabs")]: urlstr = tab.url().toDisplayString() tabs[str(win_id)].append((tab.title(), urlstr)) @@ -238,17 +236,17 @@ def history_data( @add_handler('history') -def qute_history(url: QUrl) -> _HandlerRet: +def qute_history(url: core.QUrl) -> _HandlerRet: """Handler for qute://history. Display and serve history.""" if url.path() == '/data': - q_offset = QUrlQuery(url).queryItemValue("offset") + q_offset = core.QUrlQuery(url).queryItemValue("offset") try: offset = int(q_offset) if q_offset else None except ValueError: raise UrlInvalidError("Query parameter offset is invalid") # Use start_time in query or current time. - q_start_time = QUrlQuery(url).queryItemValue("start_time") + q_start_time = core.QUrlQuery(url).queryItemValue("start_time") try: start_time = float(q_start_time) if q_start_time else time.time() except ValueError: @@ -264,7 +262,7 @@ def qute_history(url: QUrl) -> _HandlerRet: @add_handler('javascript') -def qute_javascript(url: QUrl) -> _HandlerRet: +def qute_javascript(url: core.QUrl) -> _HandlerRet: """Handler for qute://javascript. Return content of file given as query parameter. @@ -278,14 +276,14 @@ def qute_javascript(url: QUrl) -> _HandlerRet: @add_handler('pyeval') -def qute_pyeval(_url: QUrl) -> _HandlerRet: +def qute_pyeval(_url: core.QUrl) -> _HandlerRet: """Handler for qute://pyeval.""" src = jinja.render('pre.html', title='pyeval', content=pyeval_output) return 'text/html', src @add_handler('process') -def qute_process(url: QUrl) -> _HandlerRet: +def qute_process(url: core.QUrl) -> _HandlerRet: """Handler for qute://process.""" path = url.path()[1:] try: @@ -307,7 +305,7 @@ def qute_process(url: QUrl) -> _HandlerRet: @add_handler('version') @add_handler('verizon') -def qute_version(_url: QUrl) -> _HandlerRet: +def qute_version(_url: core.QUrl) -> _HandlerRet: """Handler for qute://version.""" src = jinja.render('version.html', title='Version info', version=version.version_info(), @@ -316,7 +314,7 @@ def qute_version(_url: QUrl) -> _HandlerRet: @add_handler('log') -def qute_log(url: QUrl) -> _HandlerRet: +def qute_log(url: core.QUrl) -> _HandlerRet: """Handler for qute://log. There are three query parameters: @@ -330,7 +328,7 @@ def qute_log(url: QUrl) -> _HandlerRet: - logfilter: A filter string like the --logfilter commandline argument accepts. """ - query = QUrlQuery(url) + query = core.QUrlQuery(url) plain = (query.hasQueryItem('plain') and query.queryItemValue('plain').lower() != 'false') @@ -358,7 +356,7 @@ def qute_log(url: QUrl) -> _HandlerRet: @add_handler('gpl') -def qute_gpl(_url: QUrl) -> _HandlerRet: +def qute_gpl(_url: core.QUrl) -> _HandlerRet: """Handler for qute://gpl. Return HTML content as string.""" return 'text/html', resources.read_file('html/license.html') @@ -373,7 +371,7 @@ def _asciidoc_fallback_path(html_path: str) -> Optional[str]: @add_handler('help') -def qute_help(url: QUrl) -> _HandlerRet: +def qute_help(url: core.QUrl) -> _HandlerRet: """Handler for qute://help.""" urlpath = url.path() if not urlpath or urlpath == '/': @@ -422,11 +420,11 @@ def qute_help(url: QUrl) -> _HandlerRet: return 'text/html', data -def _qute_settings_set(url: QUrl) -> _HandlerRet: +def _qute_settings_set(url: core.QUrl) -> _HandlerRet: """Handler for qute://settings/set.""" - query = QUrlQuery(url) - option = query.queryItemValue('option', QUrl.ComponentFormattingOption.FullyDecoded) - value = query.queryItemValue('value', QUrl.ComponentFormattingOption.FullyDecoded) + query = core.QUrlQuery(url) + option = query.queryItemValue('option', core.QUrl.ComponentFormattingOption.FullyDecoded) + value = query.queryItemValue('value', core.QUrl.ComponentFormattingOption.FullyDecoded) # https://github.com/qutebrowser/qutebrowser/issues/727 if option == 'content.javascript.enabled' and value == 'false': @@ -444,7 +442,7 @@ def _qute_settings_set(url: QUrl) -> _HandlerRet: @add_handler('settings') -def qute_settings(url: QUrl) -> _HandlerRet: +def qute_settings(url: core.QUrl) -> _HandlerRet: """Handler for qute://settings. View/change qute configuration.""" global csrf_token @@ -470,7 +468,7 @@ def qute_settings(url: QUrl) -> _HandlerRet: @add_handler('bindings') -def qute_bindings(_url: QUrl) -> _HandlerRet: +def qute_bindings(_url: core.QUrl) -> _HandlerRet: """Handler for qute://bindings. View keybindings.""" bindings = {} defaults = config.val.bindings.default @@ -488,7 +486,7 @@ def qute_bindings(_url: QUrl) -> _HandlerRet: @add_handler('back') -def qute_back(url: QUrl) -> _HandlerRet: +def qute_back(url: core.QUrl) -> _HandlerRet: """Handler for qute://back. Simple page to free ram / lazy load a site, goes back on focusing the tab. @@ -500,15 +498,15 @@ def qute_back(url: QUrl) -> _HandlerRet: @add_handler('configdiff') -def qute_configdiff(url: QUrl) -> _HandlerRet: +def qute_configdiff(url: core.QUrl) -> _HandlerRet: """Handler for qute://configdiff.""" - include_hidden = QUrlQuery(url).queryItemValue('include_hidden') == 'true' + include_hidden = core.QUrlQuery(url).queryItemValue('include_hidden') == 'true' dump = config.instance.dump_userconfig(include_hidden=include_hidden) return 'text/plain', dump.encode('utf-8') @add_handler('pastebin-version') -def qute_pastebin_version(_url: QUrl) -> _HandlerRet: +def qute_pastebin_version(_url: core.QUrl) -> _HandlerRet: """Handler that pastebins the version string.""" version.pastebin_version() return 'text/plain', b'Paste called.' @@ -521,14 +519,14 @@ def _pdf_path(filename: str) -> str: @add_handler('pdfjs') -def qute_pdfjs(url: QUrl) -> _HandlerRet: +def qute_pdfjs(url: core.QUrl) -> _HandlerRet: """Handler for qute://pdfjs. Return the pdf.js viewer or redirect to original URL if the file does not exist. """ if url.path() == '/file': - filename = QUrlQuery(url).queryItemValue('filename') + filename = core.QUrlQuery(url).queryItemValue('filename') if not filename: raise UrlInvalidError("Missing filename") if '/' in filename or os.sep in filename: @@ -542,7 +540,7 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet: return mimetype, data if url.path() == '/web/viewer.html': - query = QUrlQuery(url) + query = core.QUrlQuery(url) filename = query.queryItemValue("filename") if not filename: raise UrlInvalidError("Missing filename") @@ -552,7 +550,7 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet: source = query.queryItemValue('source') if not source: # This may happen with old URLs stored in history raise UrlInvalidError("Missing source") - raise Redirect(QUrl(source)) + raise Redirect(core.QUrl(source)) data = pdfjs.generate_pdfjs_page(filename, url) return 'text/html', data @@ -572,7 +570,7 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet: @add_handler('warning') -def qute_warning(url: QUrl) -> _HandlerRet: +def qute_warning(url: core.QUrl) -> _HandlerRet: """Handler for qute://warning.""" path = url.path() if path == '/webkit': @@ -592,7 +590,7 @@ def qute_warning(url: QUrl) -> _HandlerRet: @add_handler('resource') -def qute_resource(url: QUrl) -> _HandlerRet: +def qute_resource(url: core.QUrl) -> _HandlerRet: """Handler for qute://resource.""" path = url.path().lstrip('/') mimetype = utils.guess_mimetype(path, fallback=True) @@ -604,7 +602,7 @@ def qute_resource(url: QUrl) -> _HandlerRet: @add_handler('start') -def qute_start(_url: QUrl) -> _HandlerRet: +def qute_start(_url: core.QUrl) -> _HandlerRet: """Handler for qute://start.""" bookmarks = sorted(objreg.get('bookmark-manager').marks.items(), key=lambda x: x[1]) # Sort by title diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index 779eb8197..b752eab4f 100644 --- a/qutebrowser/browser/shared.py +++ b/qutebrowser/browser/shared.py @@ -27,13 +27,12 @@ import netrc import tempfile from typing import Callable, Mapping, List, Optional, Iterable, Iterator -from qutebrowser.qt.core import QUrl, pyqtBoundSignal - from qutebrowser.config import config from qutebrowser.utils import (usertypes, message, log, objreg, jinja, utils, qtutils, version) from qutebrowser.mainwindow import mainwindow from qutebrowser.misc import guiprocess, objects +from qutebrowser.qt import core class CallSuper(Exception): @@ -72,7 +71,7 @@ def authentication_required(url, authenticator, abort_on): else: msg = '{} needs authentication'.format( html.escape(url.toDisplayString())) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) answer = message.ask(title="Authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, abort_on=abort_on, url=urlstr) @@ -95,7 +94,7 @@ def javascript_confirm(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), _format_msg(js_msg)) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) ans = message.ask('Javascript confirm', msg, mode=usertypes.PromptMode.yesno, abort_on=abort_on, url=urlstr) @@ -112,7 +111,7 @@ def javascript_prompt(url, js_msg, default, abort_on): msg = '{} asks:
{}'.format(html.escape(url.toDisplayString()), _format_msg(js_msg)) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) answer = message.ask('Javascript prompt', msg, mode=usertypes.PromptMode.text, default=default, @@ -135,7 +134,7 @@ def javascript_alert(url, js_msg, abort_on): msg = 'From {}:
{}'.format(html.escape(url.toDisplayString()), _format_msg(js_msg)) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) message.ask('Javascript alert', msg, mode=usertypes.PromptMode.alert, abort_on=abort_on, url=urlstr) @@ -160,10 +159,10 @@ def javascript_log_message(level, source, line, msg): def handle_certificate_error( *, - request_url: QUrl, - first_party_url: QUrl, + request_url: core.QUrl, + first_party_url: core.QUrl, error: usertypes.AbstractCertificateErrorWrapper, - abort_on: Iterable[pyqtBoundSignal], + abort_on: Iterable[core.pyqtBoundSignal], ) -> None: """Display a certificate error question. @@ -184,7 +183,7 @@ def handle_certificate_error( first_party_url.isValid() and not request_url.matches( first_party_url, - QUrl.UrlFormattingOption.RemoveScheme)) # type: ignore[arg-type] + core.QUrl.UrlFormattingOption.RemoveScheme)) # type: ignore[arg-type] if conf == 'ask' or conf == 'ask-block-thirdparty' and not is_resource: err_template = jinja.environment.from_string(""" @@ -214,7 +213,7 @@ def handle_certificate_error( error=error, ) urlstr = request_url.toString( - QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] + core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] title = "Certificate error" try: @@ -275,7 +274,7 @@ def feature_permission(url, option, msg, yes_action, no_action, abort_on, config_val = config.instance.get(option, url=url) if config_val == 'ask': if url.isValid(): - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) text = "Allow the website at {} to {}?".format( html.escape(url.toDisplayString()), msg) else: diff --git a/qutebrowser/browser/signalfilter.py b/qutebrowser/browser/signalfilter.py index beb91e70a..c673faa4a 100644 --- a/qutebrowser/browser/signalfilter.py +++ b/qutebrowser/browser/signalfilter.py @@ -21,12 +21,12 @@ import functools -from qutebrowser.qt.core import QObject +from qutebrowser.qt import core from qutebrowser.utils import debug, log, objreg -class SignalFilter(QObject): +class SignalFilter(core.QObject): """A filter for signals. diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py index 0d30f7973..42883fbd2 100644 --- a/qutebrowser/browser/urlmarks.py +++ b/qutebrowser/browser/urlmarks.py @@ -32,12 +32,11 @@ import functools import collections from typing import MutableMapping -from qutebrowser.qt.core import pyqtSignal, QUrl, QObject - from qutebrowser.utils import (message, usertypes, qtutils, urlutils, standarddir, objreg, log) from qutebrowser.api import cmdutils from qutebrowser.misc import lineparser +from qutebrowser.qt import core class Error(Exception): @@ -60,7 +59,7 @@ class AlreadyExistsError(Error): """Exception emitted when a given URL does already exist.""" -class UrlMarkManager(QObject): +class UrlMarkManager(core.QObject): """Base class for BookmarkManager and QuickmarkManager. @@ -72,7 +71,7 @@ class UrlMarkManager(QObject): changed: Emitted when anything changed. """ - changed = pyqtSignal() + changed = core.pyqtSignal() _lineparser: lineparser.LineParser @@ -151,7 +150,7 @@ class QuickmarkManager(UrlMarkManager): if not url.isValid(): urlutils.invalid_url_error(url, "save quickmark") return - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) message.ask_async( "Add quickmark:", usertypes.PromptMode.text, functools.partial(self.quickmark_add, urlstr), @@ -198,7 +197,7 @@ class QuickmarkManager(UrlMarkManager): Use a name instead where possible. """ qtutils.ensure_valid(url) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) try: index = list(self.marks.values()).index(urlstr) @@ -270,7 +269,7 @@ class BookmarkManager(UrlMarkManager): errstr = urlutils.get_errstring(url) raise InvalidUrlError(errstr) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) if urlstr in self.marks: if toggle: diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index a734f15b8..7192b758e 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -21,13 +21,12 @@ from typing import Iterator, Optional, Set, TYPE_CHECKING, Union, Dict import collections.abc - -from qutebrowser.qt.core import QUrl, Qt, QEvent, QTimer, QRect, QPointF -from qutebrowser.qt.gui import QMouseEvent +from qutebrowser.qt import gui from qutebrowser.config import config from qutebrowser.keyinput import modeman from qutebrowser.utils import log, usertypes, utils, qtutils, objreg +from qutebrowser.qt import core if TYPE_CHECKING: from qutebrowser.browser import browsertab @@ -46,7 +45,7 @@ class OrphanedError(Error): """Raised when a webelement's parent has vanished.""" -def css_selector(group: str, url: QUrl) -> str: +def css_selector(group: str, url: core.QUrl) -> str: """Get a CSS selector for the given group/URL.""" selectors = config.instance.get('hints.selectors', url) if group not in selectors: @@ -98,7 +97,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a """Check if this element has a valid frame attached.""" raise NotImplementedError - def geometry(self) -> QRect: + def geometry(self) -> core.QRect: """Get the geometry for this element.""" raise NotImplementedError @@ -144,8 +143,8 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a """Insert the given text into the element.""" raise NotImplementedError - def rect_on_view(self, *, elem_geometry: QRect = None, - no_js: bool = False) -> QRect: + def rect_on_view(self, *, elem_geometry: core.QRect = None, + no_js: bool = False) -> core.QRect: """Get the geometry of the element relative to the webview. Args: @@ -281,7 +280,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a """Remove target from link.""" raise NotImplementedError - def resolve_url(self, baseurl: QUrl) -> Optional[QUrl]: + def resolve_url(self, baseurl: core.QUrl) -> Optional[core.QUrl]: """Resolve the URL in the element's src/href attribute. Args: @@ -300,7 +299,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a else: return None - url = QUrl(text) + url = core.QUrl(text) if not url.isValid(): return None if url.isRelative(): @@ -317,7 +316,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a """Return True if clicking this element needs user interaction.""" raise NotImplementedError - def _mouse_pos(self) -> QPointF: + def _mouse_pos(self) -> core.QPointF: """Get the position to click/hover.""" # Click the center of the largest square fitting into the top/left # corner of the rectangle, this will help if part of the element @@ -331,43 +330,43 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a pos = rect.center() if pos.x() < 0 or pos.y() < 0: raise Error("Element position is out of view!") - return QPointF(pos) + return core.QPointF(pos) def _move_text_cursor(self) -> None: """Move cursor to end after clicking.""" raise NotImplementedError def _click_fake_event(self, click_target: usertypes.ClickTarget, - button: Qt.MouseButton = Qt.MouseButton.LeftButton) -> None: + button: core.Qt.MouseButton = core.Qt.MouseButton.LeftButton) -> None: """Send a fake click event to the element.""" pos = self._mouse_pos() log.webelem.debug("Sending fake click to {!r} at position {} with " "target {}".format(self, pos, click_target)) - target_modifiers: Dict[usertypes.ClickTarget, Qt.KeyboardModifier] = { - usertypes.ClickTarget.normal: Qt.KeyboardModifier.NoModifier, - usertypes.ClickTarget.window: Qt.KeyboardModifier.AltModifier | Qt.KeyboardModifier.ShiftModifier, - usertypes.ClickTarget.tab: Qt.KeyboardModifier.ControlModifier, - usertypes.ClickTarget.tab_bg: Qt.KeyboardModifier.ControlModifier, + target_modifiers: Dict[usertypes.ClickTarget, core.Qt.KeyboardModifier] = { + usertypes.ClickTarget.normal: core.Qt.KeyboardModifier.NoModifier, + usertypes.ClickTarget.window: core.Qt.KeyboardModifier.AltModifier | core.Qt.KeyboardModifier.ShiftModifier, + usertypes.ClickTarget.tab: core.Qt.KeyboardModifier.ControlModifier, + usertypes.ClickTarget.tab_bg: core.Qt.KeyboardModifier.ControlModifier, } if config.val.tabs.background: - target_modifiers[usertypes.ClickTarget.tab] |= Qt.KeyboardModifier.ShiftModifier + target_modifiers[usertypes.ClickTarget.tab] |= core.Qt.KeyboardModifier.ShiftModifier else: - target_modifiers[usertypes.ClickTarget.tab_bg] |= Qt.KeyboardModifier.ShiftModifier + target_modifiers[usertypes.ClickTarget.tab_bg] |= core.Qt.KeyboardModifier.ShiftModifier modifiers = target_modifiers[click_target] events = [ - QMouseEvent(QEvent.Type.MouseMove, pos, Qt.MouseButton.NoButton, Qt.MouseButton.NoButton, Qt.KeyboardModifier.NoModifier), - QMouseEvent(QEvent.Type.MouseButtonPress, pos, button, button, modifiers), - QMouseEvent(QEvent.Type.MouseButtonRelease, pos, button, Qt.MouseButton.NoButton, modifiers), + gui.QMouseEvent(core.QEvent.Type.MouseMove, pos, core.Qt.MouseButton.NoButton, core.Qt.MouseButton.NoButton, core.Qt.KeyboardModifier.NoModifier), + gui.QMouseEvent(core.QEvent.Type.MouseButtonPress, pos, button, button, modifiers), + gui.QMouseEvent(core.QEvent.Type.MouseButtonRelease, pos, button, core.Qt.MouseButton.NoButton, modifiers), ] for evt in events: self._tab.send_event(evt) - QTimer.singleShot(0, self._move_text_cursor) + core.QTimer.singleShot(0, self._move_text_cursor) def _click_editable(self, click_target: usertypes.ClickTarget) -> None: """Fake a click on an editable input field.""" @@ -445,11 +444,11 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a def hover(self) -> None: """Simulate a mouse hover over the element.""" pos = self._mouse_pos() - event = QMouseEvent(QEvent.Type.MouseMove, pos, Qt.MouseButton.NoButton, Qt.MouseButton.NoButton, - Qt.KeyboardModifier.NoModifier) + event = gui.QMouseEvent(core.QEvent.Type.MouseMove, pos, core.Qt.MouseButton.NoButton, core.Qt.MouseButton.NoButton, + core.Qt.KeyboardModifier.NoModifier) self._tab.send_event(event) def right_click(self) -> None: """Simulate a right-click on the element.""" self._click_fake_event(usertypes.ClickTarget.normal, - button=Qt.MouseButton.RightButton) + button=core.Qt.MouseButton.RightButton) diff --git a/qutebrowser/browser/webengine/certificateerror.py b/qutebrowser/browser/webengine/certificateerror.py index 7ee69640f..45fab52a9 100644 --- a/qutebrowser/browser/webengine/certificateerror.py +++ b/qutebrowser/browser/webengine/certificateerror.py @@ -21,9 +21,7 @@ from typing import Any -from qutebrowser.qt import machinery -from qutebrowser.qt.core import QUrl -from qutebrowser.qt.webenginecore import QWebEngineCertificateError +from qutebrowser.qt import webenginecore, core, machinery from qutebrowser.utils import usertypes, utils, debug @@ -35,7 +33,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): Base code shared between Qt 5 and 6 implementations. """ - def __init__(self, error: QWebEngineCertificateError) -> None: + def __init__(self, error: webenginecore.QWebEngineCertificateError) -> None: super().__init__() self._error = error self.ignore = False @@ -53,10 +51,10 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): def __repr__(self) -> str: return utils.get_repr( self, - error=debug.qenum_key(QWebEngineCertificateError, self._type()), + error=debug.qenum_key(webenginecore.QWebEngineCertificateError, self._type()), string=str(self)) - def url(self) -> QUrl: + def url(self) -> core.QUrl: return self._error.url() def is_overridable(self) -> bool: @@ -112,7 +110,7 @@ class CertificateErrorWrapperQt6(CertificateErrorWrapper): self._error.acceptCertificate() -def create(error: QWebEngineCertificateError) -> CertificateErrorWrapper: +def create(error: webenginecore.QWebEngineCertificateError) -> CertificateErrorWrapper: """Factory function picking the right class based on Qt version.""" if machinery.IS_QT5: return CertificateErrorWrapperQt5(error) diff --git a/qutebrowser/browser/webengine/interceptor.py b/qutebrowser/browser/webengine/interceptor.py index a3370a599..419026fbb 100644 --- a/qutebrowser/browser/webengine/interceptor.py +++ b/qutebrowser/browser/webengine/interceptor.py @@ -19,29 +19,26 @@ """A request interceptor taking care of adblocking and custom headers.""" -from qutebrowser.qt.core import QUrl, QByteArray -from qutebrowser.qt.webenginecore import (QWebEngineUrlRequestInterceptor, - QWebEngineUrlRequestInfo) - from qutebrowser.config import websettings, config from qutebrowser.browser import shared from qutebrowser.utils import debug, log from qutebrowser.extensions import interceptors from qutebrowser.misc import objects +from qutebrowser.qt import webenginecore, core class WebEngineRequest(interceptors.Request): """QtWebEngine-specific request interceptor functionality.""" - _WHITELISTED_REQUEST_METHODS = {QByteArray(b'GET'), QByteArray(b'HEAD')} + _WHITELISTED_REQUEST_METHODS = {core.QByteArray(b'GET'), core.QByteArray(b'HEAD')} def __init__(self, *args, webengine_info, **kwargs): super().__init__(*args, **kwargs) self._webengine_info = webengine_info self._redirected = False - def redirect(self, url: QUrl, *, ignore_unsupported: bool = False) -> None: + def redirect(self, url: core.QUrl, *, ignore_unsupported: bool = False) -> None: if self._redirected: raise interceptors.RedirectException("Request already redirected.") if self._webengine_info is None: @@ -62,7 +59,7 @@ class WebEngineRequest(interceptors.Request): self._redirected = True -class RequestInterceptor(QWebEngineUrlRequestInterceptor): +class RequestInterceptor(webenginecore.QWebEngineUrlRequestInterceptor): """Handle ad blocking and custom headers.""" def __init__(self, parent=None): @@ -71,47 +68,47 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor): # extension ResourceTypes. If a ResourceType is added to Qt, this table # should be updated too. self._resource_types = { - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeMainFrame: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeMainFrame: interceptors.ResourceType.main_frame, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSubFrame: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSubFrame: interceptors.ResourceType.sub_frame, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeStylesheet: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeStylesheet: interceptors.ResourceType.stylesheet, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeScript: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeScript: interceptors.ResourceType.script, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeImage: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeImage: interceptors.ResourceType.image, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeFontResource: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeFontResource: interceptors.ResourceType.font_resource, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSubResource: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSubResource: interceptors.ResourceType.sub_resource, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeObject: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeObject: interceptors.ResourceType.object, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeMedia: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeMedia: interceptors.ResourceType.media, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeWorker: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeWorker: interceptors.ResourceType.worker, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSharedWorker: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeSharedWorker: interceptors.ResourceType.shared_worker, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypePrefetch: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypePrefetch: interceptors.ResourceType.prefetch, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeFavicon: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeFavicon: interceptors.ResourceType.favicon, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeXhr: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeXhr: interceptors.ResourceType.xhr, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypePing: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypePing: interceptors.ResourceType.ping, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeServiceWorker: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeServiceWorker: interceptors.ResourceType.service_worker, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeCspReport: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeCspReport: interceptors.ResourceType.csp_report, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypePluginResource: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypePluginResource: interceptors.ResourceType.plugin_resource, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeUnknown: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeUnknown: interceptors.ResourceType.unknown, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeNavigationPreloadMainFrame: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeNavigationPreloadMainFrame: interceptors.ResourceType.preload_main_frame, - QWebEngineUrlRequestInfo.ResourceType.ResourceTypeNavigationPreloadSubFrame: + webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeNavigationPreloadSubFrame: interceptors.ResourceType.preload_sub_frame, } @@ -132,9 +129,9 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor): info: QWebEngineUrlRequestInfo &info """ if 'log-requests' in objects.debug_flags: - resource_type_str = debug.qenum_key(QWebEngineUrlRequestInfo, + resource_type_str = debug.qenum_key(webenginecore.QWebEngineUrlRequestInfo, info.resourceType()) - navigation_type_str = debug.qenum_key(QWebEngineUrlRequestInfo, + navigation_type_str = debug.qenum_key(webenginecore.QWebEngineUrlRequestInfo, info.navigationType()) log.network.debug("{} {}, first-party {}, resource {}, " "navigation {}".format( @@ -157,15 +154,15 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor): except KeyError: log.network.warning( "Resource type {} not found in RequestInterceptor dict." - .format(debug.qenum_key(QWebEngineUrlRequestInfo, + .format(debug.qenum_key(webenginecore.QWebEngineUrlRequestInfo, info.resourceType()))) resource_type = interceptors.ResourceType.unknown - is_xhr = info.resourceType() == QWebEngineUrlRequestInfo.ResourceType.ResourceTypeXhr + is_xhr = info.resourceType() == webenginecore.QWebEngineUrlRequestInfo.ResourceType.ResourceTypeXhr if ((url.scheme(), url.host(), url.path()) == ('qute', 'settings', '/set')): - if first_party != QUrl('qute://settings/') or not is_xhr: + if first_party != core.QUrl('qute://settings/') or not is_xhr: log.network.warning("Blocking malicious request from {} to {}" .format(first_party.toDisplayString(), url.toDisplayString())) diff --git a/qutebrowser/browser/webengine/notification.py b/qutebrowser/browser/webengine/notification.py index 88f889da3..55dcbff37 100644 --- a/qutebrowser/browser/webengine/notification.py +++ b/qutebrowser/browser/webengine/notification.py @@ -49,26 +49,20 @@ import itertools import functools import subprocess from typing import Any, List, Dict, Optional, Iterator, Type, TYPE_CHECKING - -from qutebrowser.qt.core import (Qt, QObject, QVariant, QMetaType, QByteArray, pyqtSlot, - pyqtSignal, QTimer, QProcess, QUrl) -from qutebrowser.qt.gui import QImage, QIcon, QPixmap -from qutebrowser.qt.dbus import (QDBusConnection, QDBusInterface, QDBus, QDBusServiceWatcher, - QDBusArgument, QDBusMessage, QDBusError) -from qutebrowser.qt.widgets import QSystemTrayIcon +from qutebrowser.qt import widgets if TYPE_CHECKING: # putting these behind TYPE_CHECKING also means this module is importable # on installs that don't have these - from qutebrowser.qt.webenginecore import QWebEngineNotification - from qutebrowser.qt.webenginewidgets import QWebEngineProfile + from qutebrowser.qt import webenginewidgets, webenginecore, QWebEngineNotification + from qutebrowser.qt import QWebEngineProfile from qutebrowser.config import config from qutebrowser.misc import objects from qutebrowser.utils import ( qtutils, log, utils, debug, message, objreg, resources, ) -from qutebrowser.qt import sip +from qutebrowser.qt import gui, dbus, core, sip bridge: Optional['NotificationBridgePresenter'] = None @@ -126,8 +120,8 @@ class DBusError(Error): "org.freedesktop.DBus.Error.NameHasNoOwner", } - def __init__(self, msg: QDBusMessage) -> None: - assert msg.type() == QDBusMessage.MessageType.ErrorMessage + def __init__(self, msg: dbus.QDBusMessage) -> None: + assert msg.type() == dbus.QDBusMessage.MessageType.ErrorMessage self.error = msg.errorName() self.error_message = msg.errorMessage() self.is_fatal = self.error not in self._NON_FATAL_ERRORS @@ -135,7 +129,7 @@ class DBusError(Error): super().__init__(text) -class AbstractNotificationAdapter(QObject): +class AbstractNotificationAdapter(core.QObject): """An adapter taking notifications and displaying them. @@ -148,14 +142,14 @@ class AbstractNotificationAdapter(QObject): # Emitted by the adapter when the notification with the given ID was closed or # clicked by the user. - close_id = pyqtSignal(int) - click_id = pyqtSignal(int) + close_id = core.pyqtSignal(int) + click_id = core.pyqtSignal(int) # Emitted by the adapter when an error occurred, which should result in the adapter # getting swapped out (potentially initializing the same adapter again, or using a # different one if that fails). - error = pyqtSignal(str) - clear_all = pyqtSignal() + error = core.pyqtSignal(str) + clear_all = core.pyqtSignal() def present( self, @@ -173,7 +167,7 @@ class AbstractNotificationAdapter(QObject): """ raise NotImplementedError - def _should_include_origin(self, origin: QUrl) -> bool: + def _should_include_origin(self, origin: core.QUrl) -> bool: """Check if the origin is useful to include. If we open the page via a file scheme, the origin is QUrl('file:///') which @@ -184,13 +178,13 @@ class AbstractNotificationAdapter(QObject): config.instance.get('content.notifications.show_origin', url=origin), ) - @pyqtSlot(int) + @core.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: """Called when a notification was closed by the website.""" raise NotImplementedError -class NotificationBridgePresenter(QObject): +class NotificationBridgePresenter(core.QObject): """Notification presenter which bridges notifications to an adapter. @@ -200,7 +194,7 @@ class NotificationBridgePresenter(QObject): - Switching out adapters if the current one emitted its error signal. """ - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: core.QObject = None) -> None: super().__init__(parent) self._active_notifications: Dict[int, 'QWebEngineNotification'] = {} @@ -326,7 +320,7 @@ class NotificationBridgePresenter(QObject): log.misc.debug("Did not find match") return None - @pyqtSlot(int) + @core.pyqtSlot(int) def _on_adapter_closed(self, notification_id: int) -> None: """A notification was closed by the adapter (usually due to the user). @@ -344,7 +338,7 @@ class NotificationBridgePresenter(QObject): notification.close() - @pyqtSlot(int) + @core.pyqtSlot(int) def _on_adapter_clicked(self, notification_id: int) -> None: """A notification was clicked by the adapter (usually due to the user). @@ -367,7 +361,7 @@ class NotificationBridgePresenter(QObject): for win_id in objreg.window_registry: tabbedbrowser = objreg.get("tabbed-browser", window=win_id, scope="window") for idx, tab in enumerate(tabbedbrowser.widgets()): - if tab.url().matches(notification.origin(), QUrl.UrlFormattingOption.RemovePath): + if tab.url().matches(notification.origin(), core.QUrl.UrlFormattingOption.RemovePath): tabbedbrowser.widget.setCurrentIndex(idx) return log.misc.debug(f"No matching tab found for {notification.origin()}") @@ -385,7 +379,7 @@ class NotificationBridgePresenter(QObject): self._adapter = None self._on_adapter_clear_all() - @pyqtSlot() + @core.pyqtSlot() def _on_adapter_clear_all(self) -> None: """Called when the adapter requests clearing all notifications. @@ -399,7 +393,7 @@ class NotificationBridgePresenter(QObject): for notification_id in list(self._active_notifications): self._on_adapter_closed(notification_id) - @pyqtSlot(str) + @core.pyqtSlot(str) def _on_adapter_error(self, error: str) -> None: """A fatal error happened in the adapter. @@ -430,14 +424,14 @@ class SystrayNotificationAdapter(AbstractNotificationAdapter): NAME = "systray" NOTIFICATION_ID = 1 # only one concurrent notification supported - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: core.QObject = None) -> None: super().__init__(parent) - if not QSystemTrayIcon.isSystemTrayAvailable(): + if not widgets.QSystemTrayIcon.isSystemTrayAvailable(): raise Error("No system tray available") - if not QSystemTrayIcon.supportsMessages(): + if not widgets.QSystemTrayIcon.supportsMessages(): raise Error("System tray does not support messages") - self._systray = QSystemTrayIcon(self) + self._systray = widgets.QSystemTrayIcon(self) self._systray.setIcon(objects.qapp.windowIcon()) self._systray.messageClicked.connect(self._on_systray_clicked) @@ -458,27 +452,27 @@ class SystrayNotificationAdapter(AbstractNotificationAdapter): return self.NOTIFICATION_ID - def _convert_icon(self, image: QImage) -> QIcon: + def _convert_icon(self, image: gui.QImage) -> gui.QIcon: """Convert a QImage to a QIcon.""" if image.isNull(): - return QIcon() - pixmap = QPixmap.fromImage(image, Qt.ImageConversionFlag.NoFormatConversion) + return gui.QIcon() + pixmap = gui.QPixmap.fromImage(image, core.Qt.ImageConversionFlag.NoFormatConversion) assert not pixmap.isNull() - icon = QIcon(pixmap) + icon = gui.QIcon(pixmap) assert not icon.isNull() return icon - def _format_message(self, text: str, origin: QUrl) -> str: + def _format_message(self, text: str, origin: core.QUrl) -> str: """Format the message to display.""" if not self._should_include_origin(origin): return text return origin.toDisplayString() + '\n\n' + text - @pyqtSlot() + @core.pyqtSlot() def _on_systray_clicked(self) -> None: self.click_id.emit(self.NOTIFICATION_ID) - @pyqtSlot(int) + @core.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: assert notification_id == self.NOTIFICATION_ID, notification_id if not sip.isdeleted(self._systray): @@ -499,7 +493,7 @@ class MessagesNotificationAdapter(AbstractNotificationAdapter): NAME = "messages" - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: core.QObject = None) -> None: super().__init__(parent) self._id_gen = itertools.count(1) @@ -515,12 +509,12 @@ class MessagesNotificationAdapter(AbstractNotificationAdapter): message.info(markup, replace=f'notifications-{new_id}', rich=True) # Faking closing, timing might not be 100% accurate - QTimer.singleShot( + core.QTimer.singleShot( config.val.messages.timeout, lambda: self.close_id.emit(new_id)) return new_id - @pyqtSlot(int) + @core.pyqtSlot(int) def on_web_closed(self, _notification_id: int) -> None: """We can't close messages.""" @@ -551,7 +545,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): NAME = "herbe" - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: core.QObject = None) -> None: super().__init__(parent) # Also cleans up potentially hanging semaphores from herbe. # https://github.com/dudik/herbe#notifications-dont-show-up @@ -572,7 +566,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): if replaces_id is not None: self.on_web_closed(replaces_id) - proc = QProcess(self) + proc = core.QProcess(self) proc.errorOccurred.connect(self._on_error) lines = list(self._message_lines(qt_notification)) @@ -600,7 +594,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): if not qt_notification.icon().isNull(): yield "(icon not shown)" - def _on_finished(self, pid: int, code: int, status: QProcess.ExitStatus) -> None: + def _on_finished(self, pid: int, code: int, status: core.QProcess.ExitStatus) -> None: """Handle a closing herbe process. From the GitHub page: @@ -613,7 +607,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): signals, we can't do much - emitting self.error would just go use herbe again, so there's no point. """ - if status == QProcess.ExitStatus.CrashExit: + if status == core.QProcess.ExitStatus.CrashExit: pass elif code == 0: self.click_id.emit(pid) @@ -621,20 +615,20 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): pass else: proc = self.sender() - assert isinstance(proc, QProcess), proc + assert isinstance(proc, core.QProcess), proc stderr = proc.readAllStandardError() raise Error(f'herbe exited with status {code}: {stderr}') self.close_id.emit(pid) - @pyqtSlot(QProcess.ProcessError) - def _on_error(self, error: QProcess.ProcessError) -> None: - if error == QProcess.ProcessError.Crashed: + @core.pyqtSlot(core.QProcess.ProcessError) + def _on_error(self, error: core.QProcess.ProcessError) -> None: + if error == core.QProcess.ProcessError.Crashed: return - name = debug.qenum_key(QProcess.ProcessError, error) + name = debug.qenum_key(core.QProcess.ProcessError, error) raise Error(f'herbe process error: {name}') - @pyqtSlot(int) + @core.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: """Handle closing the notification from JS. @@ -682,16 +676,16 @@ class _ServerCapabilities: ) -def _as_uint32(x: int) -> QVariant: +def _as_uint32(x: int) -> core.QVariant: """Convert the given int to an uint32 for DBus.""" - variant = QVariant(x) + variant = core.QVariant(x) try: # Qt 5 - target_type = QVariant.Type.UInt + target_type = core.QVariant.Type.UInt except AttributeError: # Qt 6 - target_type = QMetaType(QMetaType.Type.UInt.value) + target_type = core.QMetaType(core.QMetaType.Type.UInt.value) successful = variant.convert(target_type) assert successful @@ -717,7 +711,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): SPEC_VERSION = "1.2" # Released in January 2011, still current in March 2021. NAME = "libnotify" - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: core.QObject = None) -> None: super().__init__(parent) if utils.is_windows: @@ -727,16 +721,16 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): # possible to run DBus there. raise Error("libnotify is not supported on Windows") - bus = QDBusConnection.sessionBus() + bus = dbus.QDBusConnection.sessionBus() if not bus.isConnected(): raise Error( "Failed to connect to DBus session bus: " + self._dbus_error_str(bus.lastError())) - self._watcher = QDBusServiceWatcher( + self._watcher = dbus.QDBusServiceWatcher( self.SERVICE, bus, - QDBusServiceWatcher.WatchModeFlag.WatchForUnregistration, + dbus.QDBusServiceWatcher.WatchModeFlag.WatchForUnregistration, self, ) self._watcher.serviceUnregistered.connect(self._on_service_unregistered) @@ -744,7 +738,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): test_service = 'test-notification-service' in objects.debug_flags service = f"{self.TEST_SERVICE}{os.getpid()}" if test_service else self.SERVICE - self.interface = QDBusInterface(service, self.PATH, self.INTERFACE, bus) + self.interface = dbus.QDBusInterface(service, self.PATH, self.INTERFACE, bus) if not self.interface.isValid(): raise Error( "Could not construct a DBus interface: " + @@ -771,7 +765,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): else: self._fetch_capabilities() - @pyqtSlot(str) + @core.pyqtSlot(str) def _on_service_unregistered(self) -> None: """Make sure we know when the notification daemon exits. @@ -858,8 +852,8 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _get_server_info(self) -> None: """Query notification server information and set quirks.""" - reply = self.interface.call(QDBus.CallMode.BlockWithGui, "GetServerInformation") - self._verify_message(reply, "ssss", QDBusMessage.MessageType.ReplyMessage) + reply = self.interface.call(dbus.QDBus.CallMode.BlockWithGui, "GetServerInformation") + self._verify_message(reply, "ssss", dbus.QDBusMessage.MessageType.ReplyMessage) name, vendor, ver, spec_version = reply.arguments() log.misc.debug( @@ -886,7 +880,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): if spec_version in icon_key_overrides: self._quirks.icon_key = icon_key_overrides[spec_version] - def _dbus_error_str(self, error: QDBusError) -> str: + def _dbus_error_str(self, error: dbus.QDBusError) -> str: """Get a string for a DBus error.""" if not error.isValid(): return "Unknown error" @@ -894,20 +888,20 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _verify_message( self, - msg: QDBusMessage, + msg: dbus.QDBusMessage, expected_signature: str, - expected_type: QDBusMessage.MessageType, + expected_type: dbus.QDBusMessage.MessageType, ) -> None: """Check the signature/type of a received message. Raises DBusError if the signature doesn't match. """ assert expected_type not in [ - QDBusMessage.MessageType.ErrorMessage, - QDBusMessage.MessageType.InvalidMessage, + dbus.QDBusMessage.MessageType.ErrorMessage, + dbus.QDBusMessage.MessageType.InvalidMessage, ], expected_type - if msg.type() == QDBusMessage.MessageType.ErrorMessage: + if msg.type() == dbus.QDBusMessage.MessageType.ErrorMessage: raise DBusError(msg) signature = msg.signature() @@ -918,8 +912,8 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): typ = msg.type() if typ != expected_type: - type_str = debug.qenum_key(QDBusMessage.MessageType, typ) - expected_type_str = debug.qenum_key(QDBusMessage.MessageType, expected_type) + type_str = debug.qenum_key(dbus.QDBusMessage.MessageType, typ) + expected_type_str = debug.qenum_key(dbus.QDBusMessage.MessageType, expected_type) raise Error( f"Got a message of type {type_str} but expected {expected_type_str}" f"(args: {msg.arguments()})") @@ -950,17 +944,17 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): return html.escape(title, quote=False) return title - def _get_actions_arg(self) -> QDBusArgument: + def _get_actions_arg(self) -> dbus.QDBusArgument: """Get the actions argument for present().""" actions = [] if self._capabilities.actions: actions = ['default', 'Activate'] # key, name - return QDBusArgument( + return dbus.QDBusArgument( actions, - qtutils.extract_enum_val(QMetaType.Type.QStringList), + qtutils.extract_enum_val(core.QMetaType.Type.QStringList), ) - def _get_hints_arg(self, *, origin_url: QUrl, icon: QImage) -> Dict[str, Any]: + def _get_hints_arg(self, *, origin_url: core.QUrl, icon: gui.QImage) -> Dict[str, Any]: """Get the hints argument for present().""" origin_url_str = origin_url.toDisplayString() hints: Dict[str, Any] = { @@ -976,7 +970,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): if icon.isNull(): filename = 'icons/qutebrowser-64x64.png' - icon = QImage.fromData(resources.read_file_binary(filename)) + icon = gui.QImage.fromData(resources.read_file_binary(filename)) key = self._quirks.icon_key or "image-data" data = self._convert_image(icon) @@ -988,17 +982,17 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _call_notify_wrapper( self, *, appname: str, - replaces_id: QVariant, + replaces_id: core.QVariant, icon: str, title: str, body: str, - actions: QDBusArgument, + actions: dbus.QDBusArgument, hints: Dict[str, Any], timeout: int, ) -> Any: """Wrapper around DBus call to use keyword args.""" return self.interface.call( - QDBus.CallMode.BlockWithGui, + dbus.QDBus.CallMode.BlockWithGui, "Notify", appname, replaces_id, @@ -1038,7 +1032,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): ) try: - self._verify_message(reply, "u", QDBusMessage.MessageType.ReplyMessage) + self._verify_message(reply, "u", dbus.QDBusMessage.MessageType.ReplyMessage) except DBusError as e: if e.is_fatal: raise @@ -1050,7 +1044,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): self._verify_notification_id(notification_id, replaces_id=replaces_id) return notification_id - def _convert_image(self, qimage: QImage) -> Optional[QDBusArgument]: + def _convert_image(self, qimage: gui.QImage) -> Optional[dbus.QDBusArgument]: """Convert a QImage to the structure DBus expects. https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html#icons-and-images-formats @@ -1058,10 +1052,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): bits_per_color = 8 has_alpha = qimage.hasAlphaChannel() if has_alpha: - image_format = QImage.Format.Format_RGBA8888 + image_format = gui.QImage.Format.Format_RGBA8888 channel_count = 4 else: - image_format = QImage.Format.Format_RGB888 + image_format = gui.QImage.Format.Format_RGB888 channel_count = 3 qimage.convertTo(image_format) @@ -1069,7 +1063,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): width = qimage.width() height = qimage.height() - image_data = QDBusArgument() + image_data = dbus.QDBusArgument() image_data.beginStructure() image_data.add(width) image_data.add(height) @@ -1111,37 +1105,37 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): return None bits = qimage.constBits().asstring(size) - image_data.add(QByteArray(bits)) + image_data.add(core.QByteArray(bits)) image_data.endStructure() return image_data - @pyqtSlot(QDBusMessage) - def _handle_close(self, msg: QDBusMessage) -> None: + @core.pyqtSlot(dbus.QDBusMessage) + def _handle_close(self, msg: dbus.QDBusMessage) -> None: """Handle NotificationClosed from DBus.""" try: - self._verify_message(msg, "uu", QDBusMessage.MessageType.SignalMessage) + self._verify_message(msg, "uu", dbus.QDBusMessage.MessageType.SignalMessage) except Error: if not self._quirks.wrong_closes_type: raise - self._verify_message(msg, "ui", QDBusMessage.MessageType.SignalMessage) + self._verify_message(msg, "ui", dbus.QDBusMessage.MessageType.SignalMessage) notification_id, _close_reason = msg.arguments() self.close_id.emit(notification_id) - @pyqtSlot(QDBusMessage) - def _handle_action(self, msg: QDBusMessage) -> None: + @core.pyqtSlot(dbus.QDBusMessage) + def _handle_action(self, msg: dbus.QDBusMessage) -> None: """Handle ActionInvoked from DBus.""" - self._verify_message(msg, "us", QDBusMessage.MessageType.SignalMessage) + self._verify_message(msg, "us", dbus.QDBusMessage.MessageType.SignalMessage) notification_id, action_key = msg.arguments() if action_key == "default": self.click_id.emit(notification_id) - @pyqtSlot(int) + @core.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: """Send CloseNotification if a notification was closed from JS.""" self.interface.call( - QDBus.CallMode.NoBlock, + dbus.QDBus.CallMode.NoBlock, "CloseNotification", _as_uint32(notification_id), ) @@ -1149,10 +1143,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _fetch_capabilities(self) -> None: """Fetch capabilities from the notification server.""" reply = self.interface.call( - QDBus.CallMode.BlockWithGui, + dbus.QDBus.CallMode.BlockWithGui, "GetCapabilities", ) - self._verify_message(reply, "as", QDBusMessage.MessageType.ReplyMessage) + self._verify_message(reply, "as", dbus.QDBusMessage.MessageType.ReplyMessage) caplist = reply.arguments()[0] self._capabilities = _ServerCapabilities.from_list(caplist) @@ -1163,7 +1157,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): log.misc.debug(f"Notification server capabilities: {self._capabilities}") - def _format_body(self, body: str, origin_url: QUrl) -> str: + def _format_body(self, body: str, origin_url: core.QUrl) -> str: """Format the body according to the server capabilities. If the server doesn't support x-kde-origin-name, we include the origin URL as a @@ -1179,7 +1173,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): prefix = None elif self._capabilities.body_markup and self._capabilities.body_hyperlinks: href = html.escape( - origin_url.toString(QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] + origin_url.toString(core.QUrl.ComponentFormattingOption.FullyEncoded) # type: ignore[arg-type] ) text = html.escape(urlstr, quote=False) prefix = f'{text}' diff --git a/qutebrowser/browser/webengine/tabhistory.py b/qutebrowser/browser/webengine/tabhistory.py index 6efc6a2aa..1c73e557e 100644 --- a/qutebrowser/browser/webengine/tabhistory.py +++ b/qutebrowser/browser/webengine/tabhistory.py @@ -19,9 +19,8 @@ """QWebHistory serializer for QtWebEngine.""" -from qutebrowser.qt.core import QByteArray, QDataStream, QIODevice, QUrl - from qutebrowser.utils import qtutils +from qutebrowser.qt import core # kHistoryStreamVersion = 3 was originally set when history serializing was @@ -64,7 +63,7 @@ def _serialize_item(item, stream): ## QByteArray(encodedPageState.data(), encodedPageState.size()); # \xff\xff\xff\xff - qtutils.serialize_stream(stream, QByteArray()) + qtutils.serialize_stream(stream, core.QByteArray()) ## static_cast(entry->GetTransitionType()); # chromium/ui/base/page_transition_types.h @@ -77,7 +76,7 @@ def _serialize_item(item, stream): ## toQt(entry->GetReferrer().url); # \xff\xff\xff\xff - qtutils.serialize_stream(stream, QUrl()) + qtutils.serialize_stream(stream, core.QUrl()) ## static_cast(entry->GetReferrer().policy); # chromium/third_party/WebKit/public/platform/WebReferrerPolicy.h @@ -123,8 +122,8 @@ def serialize(items): If 'data' goes out of scope, reading from 'stream' will result in a segfault! """ - data = QByteArray() - stream = QDataStream(data, QIODevice.OpenModeFlag.ReadWrite) + data = core.QByteArray() + stream = core.QDataStream(data, core.QIODevice.OpenModeFlag.ReadWrite) cur_user_data = None current_idx = None diff --git a/qutebrowser/browser/webengine/webenginedownloads.py b/qutebrowser/browser/webengine/webenginedownloads.py index 363feeb57..c29842ac4 100644 --- a/qutebrowser/browser/webengine/webenginedownloads.py +++ b/qutebrowser/browser/webengine/webenginedownloads.py @@ -22,13 +22,12 @@ import re import os.path import functools - -from qutebrowser.qt.core import pyqtSlot, Qt, QUrl, QObject -from qutebrowser.qt.webenginecore import QWebEngineDownloadRequest +from qutebrowser.qt import webenginecore from qutebrowser.browser import downloads, pdfjs from qutebrowser.utils import (debug, usertypes, message, log, objreg, urlutils, utils, version) +from qutebrowser.qt import core class DownloadItem(downloads.AbstractDownloadItem): @@ -39,9 +38,9 @@ class DownloadItem(downloads.AbstractDownloadItem): _qt_item: The wrapped item. """ - def __init__(self, qt_item: QWebEngineDownloadRequest, + def __init__(self, qt_item: webenginecore.QWebEngineDownloadRequest, manager: downloads.AbstractDownloadManager, - parent: QObject = None) -> None: + parent: core.QObject = None) -> None: super().__init__(manager=manager, parent=manager) self._qt_item = qt_item try: @@ -71,19 +70,19 @@ class DownloadItem(downloads.AbstractDownloadItem): def _is_page_download(self): """Check if this item is a page (i.e. mhtml) download.""" return (self._qt_item.savePageFormat() != - QWebEngineDownloadRequest.SavePageFormat.UnknownSaveFormat) + webenginecore.QWebEngineDownloadRequest.SavePageFormat.UnknownSaveFormat) - @pyqtSlot(QWebEngineDownloadRequest.DownloadState) + @core.pyqtSlot(webenginecore.QWebEngineDownloadRequest.DownloadState) def _on_state_changed(self, state): - state_name = debug.qenum_key(QWebEngineDownloadRequest, state) + state_name = debug.qenum_key(webenginecore.QWebEngineDownloadRequest, state) log.downloads.debug("State for {!r} changed to {}".format( self, state_name)) - if state == QWebEngineDownloadRequest.DownloadState.DownloadRequested: + if state == webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadRequested: pass - elif state == QWebEngineDownloadRequest.DownloadState.DownloadInProgress: + elif state == webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadInProgress: pass - elif state == QWebEngineDownloadRequest.DownloadState.DownloadCompleted: + elif state == webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadCompleted: log.downloads.debug("Download {} finished".format(self.basename)) if self._is_page_download(): # Same logging as QtWebKit mhtml downloads. @@ -92,12 +91,12 @@ class DownloadItem(downloads.AbstractDownloadItem): self.done = True self.finished.emit() self.stats.finish() - elif state == QWebEngineDownloadRequest.DownloadState.DownloadCancelled: + elif state == webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadCancelled: self.successful = False self.done = True self.cancelled.emit() self.stats.finish() - elif state == QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: + elif state == webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: self.successful = False reason = self._qt_item.interruptReasonString() self._die(reason) @@ -113,22 +112,22 @@ class DownloadItem(downloads.AbstractDownloadItem): # Qt 6 self._qt_item.receivedBytesChanged.disconnect() self._qt_item.totalBytesChanged.disconnect() - if self._qt_item.state() != QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: + if self._qt_item.state() != webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: self._qt_item.cancel() def _do_cancel(self): state = self._qt_item.state() - state_name = debug.qenum_key(QWebEngineDownloadRequest, state) - assert state not in [QWebEngineDownloadRequest.DownloadState.DownloadCompleted, - QWebEngineDownloadRequest.DownloadState.DownloadCancelled], state_name + state_name = debug.qenum_key(webenginecore.QWebEngineDownloadRequest, state) + assert state not in [webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadCompleted, + webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadCancelled], state_name self._qt_item.cancel() def retry(self): state = self._qt_item.state() - if state != QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: + if state != webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadInterrupted: log.downloads.warning( "Refusing to retry download in state {}".format( - debug.qenum_key(QWebEngineDownloadRequest, state))) + debug.qenum_key(webenginecore.QWebEngineDownloadRequest, state))) return self._qt_item.resume() @@ -136,12 +135,12 @@ class DownloadItem(downloads.AbstractDownloadItem): def _get_open_filename(self): return self._filename - def url(self) -> QUrl: + def url(self) -> core.QUrl: return self._qt_item.url() - def origin(self) -> QUrl: + def origin(self) -> core.QUrl: page = self._qt_item.page() - return page.url() if page else QUrl() + return page.url() if page else core.QUrl() def _set_fileobj(self, fileobj, *, autoclose=True): raise downloads.UnsupportedOperationError @@ -153,8 +152,8 @@ class DownloadItem(downloads.AbstractDownloadItem): def _ensure_can_set_filename(self, filename): state = self._qt_item.state() - if state != QWebEngineDownloadRequest.DownloadState.DownloadRequested: - state_name = debug.qenum_key(QWebEngineDownloadRequest, state) + if state != webenginecore.QWebEngineDownloadRequest.DownloadState.DownloadRequested: + state_name = debug.qenum_key(webenginecore.QWebEngineDownloadRequest, state) raise ValueError("Trying to set filename {} on {!r} which is " "state {} (not in requested state)!".format( filename, self, state_name)) @@ -263,9 +262,9 @@ class DownloadManager(downloads.AbstractDownloadManager): def install(self, profile): """Set up the download manager on a QWebEngineProfile.""" profile.downloadRequested.connect(self.handle_download, - Qt.ConnectionType.DirectConnection) + core.Qt.ConnectionType.DirectConnection) - @pyqtSlot(QWebEngineDownloadRequest) + @core.pyqtSlot(webenginecore.QWebEngineDownloadRequest) def handle_download(self, qt_item): """Start a download coming from a QWebEngineProfile.""" qt_filename = qt_item.downloadFileName() diff --git a/qutebrowser/browser/webengine/webengineelem.py b/qutebrowser/browser/webengine/webengineelem.py index 2e348055c..34a7672eb 100644 --- a/qutebrowser/browser/webengine/webengineelem.py +++ b/qutebrowser/browser/webengine/webengineelem.py @@ -21,13 +21,12 @@ from typing import ( TYPE_CHECKING, Any, Callable, Dict, Iterator, Optional, Set, Tuple, Union) - -from qutebrowser.qt.core import QRect, QEventLoop -from qutebrowser.qt.widgets import QApplication -from qutebrowser.qt.webenginecore import QWebEngineSettings +from qutebrowser.qt import widgets +from qutebrowser.qt import webenginecore from qutebrowser.utils import log, javascript, urlutils, usertypes, utils from qutebrowser.browser import webelem +from qutebrowser.qt import core if TYPE_CHECKING: from qutebrowser.browser.webengine import webenginetab @@ -116,9 +115,9 @@ class WebEngineElement(webelem.AbstractWebElement): def has_frame(self) -> bool: return True - def geometry(self) -> QRect: + def geometry(self) -> core.QRect: log.stub() - return QRect() + return core.QRect() def classes(self) -> Set[str]: """Get a list of classes assigned to this element.""" @@ -165,8 +164,8 @@ class WebEngineElement(webelem.AbstractWebElement): log.webelem.debug("Inserting text into element {!r}".format(self)) self._js_call('insert_text', text) - def rect_on_view(self, *, elem_geometry: QRect = None, - no_js: bool = False) -> QRect: + def rect_on_view(self, *, elem_geometry: core.QRect = None, + no_js: bool = False) -> core.QRect: """Get the geometry of the element relative to the webview. Skipping of small rectangles is due to elements containing other @@ -195,7 +194,7 @@ class WebEngineElement(webelem.AbstractWebElement): # We're not checking for zoom.text_only here as that doesn't # exist for QtWebEngine. zoom = self._tab.zoom.factor() - rect = QRect(int(left * zoom), int(top * zoom), + rect = core.QRect(int(left * zoom), int(top * zoom), int(width * zoom), int(height * zoom)) # FIXME:qtwebengine # frame = self._elem.webFrame() @@ -207,7 +206,7 @@ class WebEngineElement(webelem.AbstractWebElement): return rect log.webelem.debug("Couldn't find rectangle for {!r} ({})".format( self, rects)) - return QRect() + return core.QRect() def remove_blank_target(self) -> None: if self._js_dict['attributes'].get('target') == '_blank': @@ -241,7 +240,7 @@ class WebEngineElement(webelem.AbstractWebElement): view = self._tab._widget assert view is not None # pylint: enable=protected-access - attribute = QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows + attribute = webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows could_open_windows = view.settings().testAttribute(attribute) view.settings().setAttribute(attribute, True) @@ -249,9 +248,9 @@ class WebEngineElement(webelem.AbstractWebElement): # (it does so with a 0ms QTimer...) # This is also used in Qt's tests: # https://github.com/qt/qtwebengine/commit/5e572e88efa7ba7c2b9138ec19e606d3e345ac90 - QApplication.processEvents( - QEventLoop.ProcessEventsFlag.ExcludeSocketNotifiers | - QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) + widgets.QApplication.processEvents( + core.QEventLoop.ProcessEventsFlag.ExcludeSocketNotifiers | + core.QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) def reset_setting(_arg: Any) -> None: """Set the JavascriptCanOpenWindows setting to its old value.""" diff --git a/qutebrowser/browser/webengine/webengineinspector.py b/qutebrowser/browser/webengine/webengineinspector.py index 3ba72a7d1..be2eee41d 100644 --- a/qutebrowser/browser/webengine/webengineinspector.py +++ b/qutebrowser/browser/webengine/webengineinspector.py @@ -19,9 +19,8 @@ """Customized QWebInspector for QtWebEngine.""" -from qutebrowser.qt.webenginewidgets import QWebEngineView -from qutebrowser.qt.webenginecore import QWebEnginePage -from qutebrowser.qt.widgets import QWidget +from qutebrowser.qt import widgets, webenginewidgets +from qutebrowser.qt import webenginecore from qutebrowser.browser import inspector from qutebrowser.browser.webengine import webenginesettings, webview @@ -30,7 +29,7 @@ from qutebrowser.utils import version, usertypes, qtutils from qutebrowser.keyinput import modeman -class WebEngineInspectorView(QWebEngineView): +class WebEngineInspectorView(webenginewidgets.QWebEngineView): """The QWebEngineView used for the inspector. @@ -39,7 +38,7 @@ class WebEngineInspectorView(QWebEngineView): """ def createWindow(self, - wintype: QWebEnginePage.WebWindowType) -> QWebEngineView: + wintype: webenginecore.QWebEnginePage.WebWindowType) -> webenginewidgets.QWebEngineView: """Called by Qt when a page wants to create a new tab or window. In case the user wants to open a resource in a new tab, we use the @@ -51,7 +50,7 @@ class WebEngineInspectorView(QWebEngineView): try: # Qt 5 view = inspected_page.view() - assert isinstance(view, QWebEngineView), view + assert isinstance(view, webenginewidgets.QWebEngineView), view return view.createWindow(wintype) except AttributeError: # Qt 6 @@ -67,7 +66,7 @@ class WebEngineInspector(inspector.AbstractWebInspector): def __init__(self, splitter: miscwidgets.InspectorSplitter, win_id: int, - parent: QWidget = None) -> None: + parent: widgets.QWidget = None) -> None: super().__init__(splitter, win_id, parent) self._check_devtools_resources() self._settings = None @@ -99,10 +98,10 @@ class WebEngineInspector(inspector.AbstractWebInspector): "please install the qt5-qtwebengine-devtools " "Fedora package.") - def inspect(self, page: QWebEnginePage) -> None: + def inspect(self, page: webenginecore.QWebEnginePage) -> None: if not self._widget: view = WebEngineInspectorView() - inspector_page = QWebEnginePage( + inspector_page = webenginecore.QWebEnginePage( page.profile(), self ) diff --git a/qutebrowser/browser/webengine/webenginequtescheme.py b/qutebrowser/browser/webengine/webenginequtescheme.py index 6fb809f6d..1b17d6859 100644 --- a/qutebrowser/browser/webengine/webenginequtescheme.py +++ b/qutebrowser/browser/webengine/webenginequtescheme.py @@ -19,23 +19,19 @@ """QtWebEngine specific qute://* handlers and glue code.""" -from qutebrowser.qt.core import QBuffer, QIODevice, QUrl -from qutebrowser.qt.webenginecore import (QWebEngineUrlSchemeHandler, - QWebEngineUrlRequestJob, - QWebEngineUrlScheme) - from qutebrowser.browser import qutescheme from qutebrowser.utils import log, qtutils +from qutebrowser.qt import webenginecore, core -class QuteSchemeHandler(QWebEngineUrlSchemeHandler): +class QuteSchemeHandler(webenginecore.QWebEngineUrlSchemeHandler): """Handle qute://* requests on QtWebEngine.""" def install(self, profile): """Install the handler for qute:// URLs on the given profile.""" - if QWebEngineUrlScheme is not None: - assert QWebEngineUrlScheme.schemeByName(b'qute') is not None + if webenginecore.QWebEngineUrlScheme is not None: + assert webenginecore.QWebEngineUrlScheme.schemeByName(b'qute') is not None profile.installUrlSchemeHandler(b'qute', self) @@ -55,7 +51,7 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): request_url = job.requestUrl() # https://codereview.qt-project.org/#/c/234849/ - is_opaque = initiator == QUrl('null') + is_opaque = initiator == core.QUrl('null') target = request_url.scheme(), request_url.host() if target == ('qute', 'testdata') and is_opaque: @@ -67,7 +63,7 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): log.network.warning("Blocking malicious request from {} to {}" .format(initiator.toDisplayString(), request_url.toDisplayString())) - job.fail(QWebEngineUrlRequestJob.Error.RequestDenied) + job.fail(webenginecore.QWebEngineUrlRequestJob.Error.RequestDenied) return False return True @@ -87,7 +83,7 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): return if job.requestMethod() != b'GET': - job.fail(QWebEngineUrlRequestJob.Error.RequestDenied) + job.fail(webenginecore.QWebEngineUrlRequestJob.Error.RequestDenied) return assert url.scheme() == 'qute' @@ -98,15 +94,15 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): except qutescheme.Error as e: errors = { qutescheme.NotFoundError: - QWebEngineUrlRequestJob.Error.UrlNotFound, + webenginecore.QWebEngineUrlRequestJob.Error.UrlNotFound, qutescheme.UrlInvalidError: - QWebEngineUrlRequestJob.Error.UrlInvalid, + webenginecore.QWebEngineUrlRequestJob.Error.UrlInvalid, qutescheme.RequestDeniedError: - QWebEngineUrlRequestJob.Error.RequestDenied, + webenginecore.QWebEngineUrlRequestJob.Error.RequestDenied, qutescheme.SchemeOSError: - QWebEngineUrlRequestJob.Error.UrlNotFound, + webenginecore.QWebEngineUrlRequestJob.Error.UrlNotFound, qutescheme.Error: - QWebEngineUrlRequestJob.Error.RequestFailed, + webenginecore.QWebEngineUrlRequestJob.Error.RequestFailed, } exctype = type(e) log.network.error(f"{exctype.__name__} while handling qute://* URL: {e}") @@ -120,8 +116,8 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): # We can't just use the QBuffer constructor taking a QByteArray, # because that somehow segfaults... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html - buf = QBuffer(parent=self) - buf.open(QIODevice.OpenModeFlag.WriteOnly) + buf = core.QBuffer(parent=self) + buf.open(core.QIODevice.OpenModeFlag.WriteOnly) buf.write(data) buf.seek(0) buf.close() @@ -134,10 +130,10 @@ def init(): Note this needs to be called early, before constructing any QtWebEngine classes. """ - if QWebEngineUrlScheme is not None: - assert not QWebEngineUrlScheme.schemeByName(b'qute').name() - scheme = QWebEngineUrlScheme(b'qute') + if webenginecore.QWebEngineUrlScheme is not None: + assert not webenginecore.QWebEngineUrlScheme.schemeByName(b'qute').name() + scheme = webenginecore.QWebEngineUrlScheme(b'qute') scheme.setFlags( - QWebEngineUrlScheme.Flag.LocalScheme | - QWebEngineUrlScheme.Flag.LocalAccessAllowed) - QWebEngineUrlScheme.registerScheme(scheme) + webenginecore.QWebEngineUrlScheme.Flag.LocalScheme | + webenginecore.QWebEngineUrlScheme.Flag.LocalAccessAllowed) + webenginecore.QWebEngineUrlScheme.registerScheme(scheme) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 8a8c4766f..b24dcd55c 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -29,10 +29,7 @@ import operator import pathlib from typing import cast, Any, List, Optional, Tuple, Union, TYPE_CHECKING -from qutebrowser.qt import machinery -from qutebrowser.qt.gui import QFont -from qutebrowser.qt.widgets import QApplication -from qutebrowser.qt.webenginecore import QWebEngineSettings, QWebEngineProfile +from qutebrowser.qt import widgets, webenginecore, gui, machinery from qutebrowser.browser import history from qutebrowser.browser.webengine import (spell, webenginequtescheme, cookies, @@ -45,9 +42,9 @@ if TYPE_CHECKING: from qutebrowser.browser.webengine import interceptor # The default QWebEngineProfile -default_profile = cast(QWebEngineProfile, None) +default_profile = cast(webenginecore.QWebEngineProfile, None) # The QWebEngineProfile used for private (off-the-record) windows -private_profile: Optional[QWebEngineProfile] = None +private_profile: Optional[webenginecore.QWebEngineProfile] = None # The global WebEngineSettings object _global_settings = cast('WebEngineSettings', None) @@ -112,105 +109,105 @@ class WebEngineSettings(websettings.AbstractSettings): _ATTRIBUTES = { 'content.xss_auditing': - Attr(QWebEngineSettings.WebAttribute.XSSAuditingEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.XSSAuditingEnabled), 'content.images': - Attr(QWebEngineSettings.WebAttribute.AutoLoadImages), + Attr(webenginecore.QWebEngineSettings.WebAttribute.AutoLoadImages), 'content.javascript.enabled': - Attr(QWebEngineSettings.WebAttribute.JavascriptEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.JavascriptEnabled), 'content.javascript.can_open_tabs_automatically': - Attr(QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows), + Attr(webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanOpenWindows), 'content.plugins': - Attr(QWebEngineSettings.WebAttribute.PluginsEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.PluginsEnabled), 'content.hyperlink_auditing': - Attr(QWebEngineSettings.WebAttribute.HyperlinkAuditingEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.HyperlinkAuditingEnabled), 'content.local_content_can_access_remote_urls': - Attr(QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls), + Attr(webenginecore.QWebEngineSettings.WebAttribute.LocalContentCanAccessRemoteUrls), 'content.local_content_can_access_file_urls': - Attr(QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls), + Attr(webenginecore.QWebEngineSettings.WebAttribute.LocalContentCanAccessFileUrls), 'content.webgl': - Attr(QWebEngineSettings.WebAttribute.WebGLEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.WebGLEnabled), 'content.local_storage': - Attr(QWebEngineSettings.WebAttribute.LocalStorageEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.LocalStorageEnabled), 'content.desktop_capture': - Attr(QWebEngineSettings.WebAttribute.ScreenCaptureEnabled, + Attr(webenginecore.QWebEngineSettings.WebAttribute.ScreenCaptureEnabled, converter=lambda val: True if val == 'ask' else val), # 'ask' is handled via the permission system 'input.spatial_navigation': - Attr(QWebEngineSettings.WebAttribute.SpatialNavigationEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.SpatialNavigationEnabled), 'input.links_included_in_focus_chain': - Attr(QWebEngineSettings.WebAttribute.LinksIncludedInFocusChain), + Attr(webenginecore.QWebEngineSettings.WebAttribute.LinksIncludedInFocusChain), 'scrolling.smooth': - Attr(QWebEngineSettings.WebAttribute.ScrollAnimatorEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.ScrollAnimatorEnabled), 'content.print_element_backgrounds': - Attr(QWebEngineSettings.WebAttribute.PrintElementBackgrounds), + Attr(webenginecore.QWebEngineSettings.WebAttribute.PrintElementBackgrounds), 'content.autoplay': - Attr(QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture, + Attr(webenginecore.QWebEngineSettings.WebAttribute.PlaybackRequiresUserGesture, converter=operator.not_), 'content.dns_prefetch': - Attr(QWebEngineSettings.WebAttribute.DnsPrefetchEnabled), + Attr(webenginecore.QWebEngineSettings.WebAttribute.DnsPrefetchEnabled), 'tabs.favicons.show': - Attr(QWebEngineSettings.WebAttribute.AutoLoadIconsForPage, + Attr(webenginecore.QWebEngineSettings.WebAttribute.AutoLoadIconsForPage, converter=lambda val: val != 'never'), } _FONT_SIZES = { 'fonts.web.size.minimum': - QWebEngineSettings.FontSize.MinimumFontSize, + webenginecore.QWebEngineSettings.FontSize.MinimumFontSize, 'fonts.web.size.minimum_logical': - QWebEngineSettings.FontSize.MinimumLogicalFontSize, + webenginecore.QWebEngineSettings.FontSize.MinimumLogicalFontSize, 'fonts.web.size.default': - QWebEngineSettings.FontSize.DefaultFontSize, + webenginecore.QWebEngineSettings.FontSize.DefaultFontSize, 'fonts.web.size.default_fixed': - QWebEngineSettings.FontSize.DefaultFixedFontSize, + webenginecore.QWebEngineSettings.FontSize.DefaultFixedFontSize, } _FONT_FAMILIES = { - 'fonts.web.family.standard': QWebEngineSettings.FontFamily.StandardFont, - 'fonts.web.family.fixed': QWebEngineSettings.FontFamily.FixedFont, - 'fonts.web.family.serif': QWebEngineSettings.FontFamily.SerifFont, - 'fonts.web.family.sans_serif': QWebEngineSettings.FontFamily.SansSerifFont, - 'fonts.web.family.cursive': QWebEngineSettings.FontFamily.CursiveFont, - 'fonts.web.family.fantasy': QWebEngineSettings.FontFamily.FantasyFont, + 'fonts.web.family.standard': webenginecore.QWebEngineSettings.FontFamily.StandardFont, + 'fonts.web.family.fixed': webenginecore.QWebEngineSettings.FontFamily.FixedFont, + 'fonts.web.family.serif': webenginecore.QWebEngineSettings.FontFamily.SerifFont, + 'fonts.web.family.sans_serif': webenginecore.QWebEngineSettings.FontFamily.SansSerifFont, + 'fonts.web.family.cursive': webenginecore.QWebEngineSettings.FontFamily.CursiveFont, + 'fonts.web.family.fantasy': webenginecore.QWebEngineSettings.FontFamily.FantasyFont, } _UNKNOWN_URL_SCHEME_POLICY = { 'disallow': - QWebEngineSettings.UnknownUrlSchemePolicy.DisallowUnknownUrlSchemes, + webenginecore.QWebEngineSettings.UnknownUrlSchemePolicy.DisallowUnknownUrlSchemes, 'allow-from-user-interaction': - QWebEngineSettings.UnknownUrlSchemePolicy.AllowUnknownUrlSchemesFromUserInteraction, + webenginecore.QWebEngineSettings.UnknownUrlSchemePolicy.AllowUnknownUrlSchemesFromUserInteraction, 'allow-all': - QWebEngineSettings.UnknownUrlSchemePolicy.AllowAllUnknownUrlSchemes, + webenginecore.QWebEngineSettings.UnknownUrlSchemePolicy.AllowAllUnknownUrlSchemes, } # Mapping from WebEngineSettings::initDefaults in # qtwebengine/src/core/web_engine_settings.cpp _FONT_TO_QFONT = { - QWebEngineSettings.FontFamily.StandardFont: QFont.StyleHint.Serif, - QWebEngineSettings.FontFamily.FixedFont: QFont.StyleHint.Monospace, - QWebEngineSettings.FontFamily.SerifFont: QFont.StyleHint.Serif, - QWebEngineSettings.FontFamily.SansSerifFont: QFont.StyleHint.SansSerif, - QWebEngineSettings.FontFamily.CursiveFont: QFont.StyleHint.Cursive, - QWebEngineSettings.FontFamily.FantasyFont: QFont.StyleHint.Fantasy, + webenginecore.QWebEngineSettings.FontFamily.StandardFont: gui.QFont.StyleHint.Serif, + webenginecore.QWebEngineSettings.FontFamily.FixedFont: gui.QFont.StyleHint.Monospace, + webenginecore.QWebEngineSettings.FontFamily.SerifFont: gui.QFont.StyleHint.Serif, + webenginecore.QWebEngineSettings.FontFamily.SansSerifFont: gui.QFont.StyleHint.SansSerif, + webenginecore.QWebEngineSettings.FontFamily.CursiveFont: gui.QFont.StyleHint.Cursive, + webenginecore.QWebEngineSettings.FontFamily.FantasyFont: gui.QFont.StyleHint.Fantasy, } _JS_CLIPBOARD_SETTINGS = { 'none': { - QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: False, - QWebEngineSettings.WebAttribute.JavascriptCanPaste: False, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: False, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanPaste: False, }, 'access': { - QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: True, - QWebEngineSettings.WebAttribute.JavascriptCanPaste: False, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: True, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanPaste: False, }, 'access-paste': { - QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: True, - QWebEngineSettings.WebAttribute.JavascriptCanPaste: True, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard: True, + webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanPaste: True, }, } @@ -224,8 +221,8 @@ class WebEngineSettings(websettings.AbstractSettings): self._settings.setUnknownUrlSchemePolicy(new_value) def _set_js_clipboard(self, value: Union[str, usertypes.Unset]) -> None: - attr_access = QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard - attr_paste = QWebEngineSettings.WebAttribute.JavascriptCanPaste + attr_access = webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard + attr_paste = webenginecore.QWebEngineSettings.WebAttribute.JavascriptCanPaste if isinstance(value, usertypes.Unset): self._settings.resetAttribute(attr_access) @@ -283,10 +280,10 @@ class ProfileSetter: settings = self._profile.settings() settings.setAttribute( - QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, True) + webenginecore.QWebEngineSettings.WebAttribute.FullScreenSupportEnabled, True) settings.setAttribute( - QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled, False) - settings.setAttribute(QWebEngineSettings.WebAttribute.PdfViewerEnabled, False) + webenginecore.QWebEngineSettings.WebAttribute.FocusOnNavigationEnabled, False) + settings.setAttribute(webenginecore.QWebEngineSettings.WebAttribute.PdfViewerEnabled, False) def set_http_headers(self): """Set the user agent and accept-language for the given profile. @@ -318,9 +315,9 @@ class ProfileSetter: if self._profile.isOffTheRecord(): return if config.val.content.cookies.store: - value = QWebEngineProfile.PersistentCookiesPolicy.AllowPersistentCookies + value = webenginecore.QWebEngineProfile.PersistentCookiesPolicy.AllowPersistentCookies else: - value = QWebEngineProfile.PersistentCookiesPolicy.NoPersistentCookies + value = webenginecore.QWebEngineProfile.PersistentCookiesPolicy.NoPersistentCookies self._profile.setPersistentCookiesPolicy(value) def set_dictionary_language(self): @@ -356,10 +353,10 @@ def _init_user_agent_str(ua): def init_user_agent(): - _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent()) + _init_user_agent_str(webenginecore.QWebEngineProfile.defaultProfile().httpUserAgent()) -def _init_profile(profile: QWebEngineProfile) -> None: +def _init_profile(profile: webenginecore.QWebEngineProfile) -> None: """Initialize a new QWebEngineProfile. This currently only contains the steps which are shared between a private and a @@ -390,9 +387,9 @@ def _init_default_profile(): global default_profile if machinery.IS_QT6: - default_profile = QWebEngineProfile("Default") + default_profile = webenginecore.QWebEngineProfile("Default") else: - default_profile = QWebEngineProfile.defaultProfile() + default_profile = webenginecore.QWebEngineProfile.defaultProfile() assert not default_profile.isOffTheRecord() assert parsed_user_agent is None # avoid earlier profile initialization @@ -422,7 +419,7 @@ def init_private_profile(): if qtutils.is_single_process(): return - private_profile = QWebEngineProfile() + private_profile = webenginecore.QWebEngineProfile() assert private_profile.isOffTheRecord() _init_profile(private_profile) @@ -527,7 +524,7 @@ def init(): # won't work... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler - app = QApplication.instance() + app = widgets.QApplication.instance() log.init.debug("Initializing qute://* handler...") _qute_scheme_handler = webenginequtescheme.QuteSchemeHandler(parent=app) diff --git a/qutebrowser/browser/webengine/webenginetab.py b/qutebrowser/browser/webengine/webenginetab.py index 37750e343..592a6e2e7 100644 --- a/qutebrowser/browser/webengine/webenginetab.py +++ b/qutebrowser/browser/webengine/webenginetab.py @@ -25,12 +25,7 @@ import dataclasses import re import html as html_utils from typing import cast, Union, Optional - -from qutebrowser.qt.core import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QTimer, QUrl, - QObject) -from qutebrowser.qt.network import QAuthenticator -from qutebrowser.qt.webenginewidgets import QWebEngineView -from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineScript, QWebEngineHistory +from qutebrowser.qt import webenginewidgets, webenginecore, network from qutebrowser.config import config from qutebrowser.browser import browsertab, eventfilter, shared, webelem, greasemonkey @@ -40,16 +35,16 @@ from qutebrowser.browser.webengine import (webview, webengineelem, tabhistory, from qutebrowser.utils import (usertypes, qtutils, log, javascript, utils, resources, message, jinja, debug, version) -from qutebrowser.qt import sip +from qutebrowser.qt import core, sip from qutebrowser.misc import objects, miscwidgets # Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs. _JS_WORLD_MAP = { - usertypes.JsWorld.main: QWebEngineScript.ScriptWorldId.MainWorld, - usertypes.JsWorld.application: QWebEngineScript.ScriptWorldId.ApplicationWorld, - usertypes.JsWorld.user: QWebEngineScript.ScriptWorldId.UserWorld, - usertypes.JsWorld.jseval: QWebEngineScript.ScriptWorldId.UserWorld + 1, + usertypes.JsWorld.main: webenginecore.QWebEngineScript.ScriptWorldId.MainWorld, + usertypes.JsWorld.application: webenginecore.QWebEngineScript.ScriptWorldId.ApplicationWorld, + usertypes.JsWorld.user: webenginecore.QWebEngineScript.ScriptWorldId.UserWorld, + usertypes.JsWorld.jseval: webenginecore.QWebEngineScript.ScriptWorldId.UserWorld + 1, } @@ -58,21 +53,21 @@ class WebEngineAction(browsertab.AbstractAction): """QtWebEngine implementations related to web actions.""" _widget: webview.WebEngineView - action_base = QWebEnginePage.WebAction + action_base = webenginecore.QWebEnginePage.WebAction def exit_fullscreen(self): - self._widget.triggerPageAction(QWebEnginePage.WebAction.ExitFullScreen) + self._widget.triggerPageAction(webenginecore.QWebEnginePage.WebAction.ExitFullScreen) def save_page(self): """Save the current page.""" - self._widget.triggerPageAction(QWebEnginePage.WebAction.SavePage) + self._widget.triggerPageAction(webenginecore.QWebEnginePage.WebAction.SavePage) def show_source(self, pygments=False): if pygments: self._show_source_pygments() return - self._widget.triggerPageAction(QWebEnginePage.WebAction.ViewSource) + self._widget.triggerPageAction(webenginecore.QWebEnginePage.WebAction.ViewSource) class WebEnginePrinting(browsertab.AbstractPrinting): @@ -120,12 +115,12 @@ class _FindFlags: def to_qt(self): """Convert flags into Qt flags.""" # FIXME:mypy Those should be correct, reevaluate with PyQt6-stubs - flags = QWebEnginePage.FindFlag(0) + flags = webenginecore.QWebEnginePage.FindFlag(0) if self.case_sensitive: flags |= ( # type: ignore[assignment] - QWebEnginePage.FindFlag.FindCaseSensitively) + webenginecore.QWebEnginePage.FindFlag.FindCaseSensitively) if self.backward: - flags |= QWebEnginePage.FindFlag.FindBackward # type: ignore[assignment] + flags |= webenginecore.QWebEnginePage.FindFlag.FindBackward # type: ignore[assignment] return flags def __bool__(self): @@ -310,7 +305,7 @@ class WebEngineCaret(browsertab.AbstractCaret): flags.add('windows') return list(flags) - @pyqtSlot(usertypes.KeyMode) + @core.pyqtSlot(usertypes.KeyMode) def _on_mode_entered(self, mode): if mode != usertypes.KeyMode.caret: return @@ -338,7 +333,7 @@ class WebEngineCaret(browsertab.AbstractCaret): else: self.selection_toggled.emit(browsertab.SelectionState.none) - @pyqtSlot(usertypes.KeyMode) + @core.pyqtSlot(usertypes.KeyMode) def _on_mode_left(self, mode): if mode != usertypes.KeyMode.caret: return @@ -502,7 +497,7 @@ class WebEngineScroller(browsertab.AbstractScroller): def __init__(self, tab, parent=None): super().__init__(tab, parent) self._pos_perc = (0, 0) - self._pos_px = QPoint() + self._pos_px = core.QPoint() self._at_bottom = False def _init_widget(self, widget): @@ -510,12 +505,12 @@ class WebEngineScroller(browsertab.AbstractScroller): page = widget.page() page.scrollPositionChanged.connect(self._update_pos) - def _repeated_key_press(self, key, count=1, modifier=Qt.KeyboardModifier.NoModifier): + def _repeated_key_press(self, key, count=1, modifier=core.Qt.KeyboardModifier.NoModifier): """Send count fake key presses to this scroller's WebEngineTab.""" for _ in range(min(count, 1000)): self._tab.fake_key_press(key, modifier) - @pyqtSlot(QPointF) + @core.pyqtSlot(core.QPointF) def _update_pos(self, pos): """Update the scroll position attributes when it changed.""" self._pos_px = pos.toPoint() @@ -589,28 +584,28 @@ class WebEngineScroller(browsertab.AbstractScroller): self._tab.run_js_async(js_code) def up(self, count=1): - self._repeated_key_press(Qt.Key.Key_Up, count) + self._repeated_key_press(core.Qt.Key.Key_Up, count) def down(self, count=1): - self._repeated_key_press(Qt.Key.Key_Down, count) + self._repeated_key_press(core.Qt.Key.Key_Down, count) def left(self, count=1): - self._repeated_key_press(Qt.Key.Key_Left, count) + self._repeated_key_press(core.Qt.Key.Key_Left, count) def right(self, count=1): - self._repeated_key_press(Qt.Key.Key_Right, count) + self._repeated_key_press(core.Qt.Key.Key_Right, count) def top(self): - self._tab.fake_key_press(Qt.Key.Key_Home) + self._tab.fake_key_press(core.Qt.Key.Key_Home) def bottom(self): - self._tab.fake_key_press(Qt.Key.Key_End) + self._tab.fake_key_press(core.Qt.Key.Key_End) def page_up(self, count=1): - self._repeated_key_press(Qt.Key.Key_PageUp, count) + self._repeated_key_press(core.Qt.Key.Key_PageUp, count) def page_down(self, count=1): - self._repeated_key_press(Qt.Key.Key_PageDown, count) + self._repeated_key_press(core.Qt.Key.Key_PageDown, count) def at_top(self): return self.pos_px().y() == 0 @@ -625,7 +620,7 @@ class WebEngineHistoryPrivate(browsertab.AbstractHistoryPrivate): def __init__(self, tab: 'WebEngineTab') -> None: self._tab = tab - self._history = cast(QWebEngineHistory, None) + self._history = cast(webenginecore.QWebEngineHistory, None) def serialize(self): return qtutils.serialize(self._history) @@ -667,7 +662,7 @@ class WebEngineHistoryPrivate(browsertab.AbstractHistoryPrivate): stream, _data, cur_data = tabhistory.serialize(items) qtutils.deserialize_stream(stream, self._history) - @pyqtSlot() + @core.pyqtSlot() def _on_load_finished(): self._tab.scroller.to_point(cur_data['scroll-pos']) self._tab.load_finished.disconnect(_on_load_finished) @@ -676,7 +671,7 @@ class WebEngineHistoryPrivate(browsertab.AbstractHistoryPrivate): if 'zoom' in cur_data: self._tab.zoom.set_factor(cur_data['zoom']) if ('scroll-pos' in cur_data and - self._tab.scroller.pos_px() == QPoint(0, 0)): + self._tab.scroller.pos_px() == core.QPoint(0, 0)): self._tab.load_finished.connect(_on_load_finished) @@ -821,7 +816,7 @@ class WebEngineAudio(browsertab.AbstractAudio): # Implements the intended two-second delay specified at # https://doc.qt.io/qt-5/qwebenginepage.html#recentlyAudibleChanged delay_ms = 2000 - self._silence_timer = QTimer(self) + self._silence_timer = core.QTimer(self) self._silence_timer.setSingleShot(True) self._silence_timer.setInterval(delay_ms) @@ -864,7 +859,7 @@ class WebEngineAudio(browsertab.AbstractAudio): page = self._widget.page() return page.recentlyAudible() - @pyqtSlot(QUrl) + @core.pyqtSlot(core.QUrl) def _on_url_changed(self, url): if self._overridden or not url.isValid(): return @@ -876,32 +871,32 @@ class WebEngineAudio(browsertab.AbstractAudio): self._on_url_changed(self._tab.url()) -class _WebEnginePermissions(QObject): +class _WebEnginePermissions(core.QObject): """Handling of various permission-related signals.""" _widget: webview.WebEngineView _options = { - QWebEnginePage.Feature.Notifications: 'content.notifications.enabled', - QWebEnginePage.Feature.Geolocation: 'content.geolocation', - QWebEnginePage.Feature.MediaAudioCapture: 'content.media.audio_capture', - QWebEnginePage.Feature.MediaVideoCapture: 'content.media.video_capture', - QWebEnginePage.Feature.MediaAudioVideoCapture: 'content.media.audio_video_capture', - QWebEnginePage.Feature.MouseLock: 'content.mouse_lock', - QWebEnginePage.Feature.DesktopVideoCapture: 'content.desktop_capture', - QWebEnginePage.Feature.DesktopAudioVideoCapture: 'content.desktop_capture', + webenginecore.QWebEnginePage.Feature.Notifications: 'content.notifications.enabled', + webenginecore.QWebEnginePage.Feature.Geolocation: 'content.geolocation', + webenginecore.QWebEnginePage.Feature.MediaAudioCapture: 'content.media.audio_capture', + webenginecore.QWebEnginePage.Feature.MediaVideoCapture: 'content.media.video_capture', + webenginecore.QWebEnginePage.Feature.MediaAudioVideoCapture: 'content.media.audio_video_capture', + webenginecore.QWebEnginePage.Feature.MouseLock: 'content.mouse_lock', + webenginecore.QWebEnginePage.Feature.DesktopVideoCapture: 'content.desktop_capture', + webenginecore.QWebEnginePage.Feature.DesktopAudioVideoCapture: 'content.desktop_capture', } _messages = { - QWebEnginePage.Feature.Notifications: 'show notifications', - QWebEnginePage.Feature.Geolocation: 'access your location', - QWebEnginePage.Feature.MediaAudioCapture: 'record audio', - QWebEnginePage.Feature.MediaVideoCapture: 'record video', - QWebEnginePage.Feature.MediaAudioVideoCapture: 'record audio/video', - QWebEnginePage.Feature.MouseLock: 'hide your mouse pointer', - QWebEnginePage.Feature.DesktopVideoCapture: 'capture your desktop', - QWebEnginePage.Feature.DesktopAudioVideoCapture: 'capture your desktop and audio', + webenginecore.QWebEnginePage.Feature.Notifications: 'show notifications', + webenginecore.QWebEnginePage.Feature.Geolocation: 'access your location', + webenginecore.QWebEnginePage.Feature.MediaAudioCapture: 'record audio', + webenginecore.QWebEnginePage.Feature.MediaVideoCapture: 'record video', + webenginecore.QWebEnginePage.Feature.MediaAudioVideoCapture: 'record audio/video', + webenginecore.QWebEnginePage.Feature.MouseLock: 'hide your mouse pointer', + webenginecore.QWebEnginePage.Feature.DesktopVideoCapture: 'capture your desktop', + webenginecore.QWebEnginePage.Feature.DesktopAudioVideoCapture: 'capture your desktop and audio', } def __init__(self, tab, parent=None): @@ -922,7 +917,7 @@ class _WebEnginePermissions(QObject): page.registerProtocolHandlerRequested.connect( self._on_register_protocol_handler_requested) - @pyqtSlot('QWebEngineFullScreenRequest') + @core.pyqtSlot('QWebEngineFullScreenRequest') def _on_fullscreen_requested(self, request): request.accept() on = request.toggleOn() @@ -936,18 +931,18 @@ class _WebEnginePermissions(QObject): notif.set_timeout(timeout) notif.show() - @pyqtSlot(QUrl, 'QWebEnginePage::Feature') + @core.pyqtSlot(core.QUrl, 'QWebEnginePage::Feature') def _on_feature_permission_requested(self, url, feature): """Ask the user for approval for geolocation/media/etc..""" page = self._widget.page() grant_permission = functools.partial( page.setFeaturePermission, url, feature, - QWebEnginePage.PermissionPolicy.PermissionGrantedByUser) + webenginecore.QWebEnginePage.PermissionPolicy.PermissionGrantedByUser) deny_permission = functools.partial( page.setFeaturePermission, url, feature, - QWebEnginePage.PermissionPolicy.PermissionDeniedByUser) + webenginecore.QWebEnginePage.PermissionPolicy.PermissionDeniedByUser) - permission_str = debug.qenum_key(QWebEnginePage, feature) + permission_str = debug.qenum_key(webenginecore.QWebEnginePage, feature) if not url.isValid(): log.webview.warning("Ignoring feature permission {} for invalid URL {}".format( @@ -962,7 +957,7 @@ class _WebEnginePermissions(QObject): return question = shared.feature_permission( - url=url.adjusted(QUrl.UrlFormattingOption.RemovePath), + url=url.adjusted(core.QUrl.UrlFormattingOption.RemovePath), option=self._options[feature], msg=self._messages[feature], yes_action=grant_permission, no_action=deny_permission, abort_on=[self._tab.abort_questions]) @@ -989,7 +984,7 @@ class _WebEnginePermissions(QObject): def _on_quota_requested(self, request): size = utils.format_size(request.requestedSize()) shared.feature_permission( - url=request.origin().adjusted(QUrl.UrlFormattingOption.RemovePath), + url=request.origin().adjusted(core.QUrl.UrlFormattingOption.RemovePath), option='content.persistent_storage', msg='use {} of persistent storage'.format(size), yes_action=request.accept, no_action=request.reject, @@ -998,7 +993,7 @@ class _WebEnginePermissions(QObject): def _on_register_protocol_handler_requested(self, request): shared.feature_permission( - url=request.origin().adjusted(QUrl.UrlFormattingOption.RemovePath), + url=request.origin().adjusted(core.QUrl.UrlFormattingOption.RemovePath), option='content.register_protocol_handler', msg='open all {} links'.format(request.scheme()), yes_action=request.accept, no_action=request.reject, @@ -1010,9 +1005,9 @@ class _WebEnginePermissions(QObject): class _Quirk: filename: str - injection_point: QWebEngineScript.InjectionPoint = ( - QWebEngineScript.InjectionPoint.DocumentCreation) - world: QWebEngineScript.ScriptWorldId = QWebEngineScript.ScriptWorldId.MainWorld + injection_point: webenginecore.QWebEngineScript.InjectionPoint = ( + webenginecore.QWebEngineScript.InjectionPoint.DocumentCreation) + world: webenginecore.QWebEngineScript.ScriptWorldId = webenginecore.QWebEngineScript.ScriptWorldId.MainWorld predicate: bool = True name: Optional[str] = None @@ -1021,7 +1016,7 @@ class _Quirk: self.name = f"js-{self.filename.replace('_', '-')}" -class _WebEngineScripts(QObject): +class _WebEngineScripts(core.QObject): _widget: webview.WebEngineView @@ -1039,13 +1034,13 @@ class _WebEngineScripts(QObject): self._update_stylesheet, searching=False)) self._tab.search.finished.connect(self._update_stylesheet) - @pyqtSlot(str) + @core.pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: self._init_stylesheet() self._update_stylesheet() - @pyqtSlot(bool) + @core.pyqtSlot(bool) def _update_stylesheet(self, searching=False): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(searching=searching) @@ -1053,11 +1048,11 @@ class _WebEngineScripts(QObject): self._tab.run_js_async(code) def _inject_js(self, name, js_code, *, - world=QWebEngineScript.ScriptWorldId.ApplicationWorld, - injection_point=QWebEngineScript.InjectionPoint.DocumentCreation, + world=webenginecore.QWebEngineScript.ScriptWorldId.ApplicationWorld, + injection_point=webenginecore.QWebEngineScript.InjectionPoint.DocumentCreation, subframes=False): """Inject the given script to run early on a page load.""" - script = QWebEngineScript() + script = webenginecore.QWebEngineScript() script.setInjectionPoint(injection_point) script.setSourceCode(js_code) script.setWorldId(world) @@ -1110,7 +1105,7 @@ class _WebEngineScripts(QObject): ) self._inject_js('stylesheet', js_code, subframes=True) - @pyqtSlot() + @core.pyqtSlot() def _inject_all_greasemonkey_scripts(self): scripts = self._greasemonkey.all_scripts() self._inject_greasemonkey_scripts(scripts) @@ -1147,7 +1142,7 @@ class _WebEngineScripts(QObject): script.dedup_suffix += 1 seen_names.add(script.full_name()) - new_script = QWebEngineScript() + new_script = webenginecore.QWebEngineScript() try: world = int(script.jsworld) @@ -1175,7 +1170,7 @@ class _WebEngineScripts(QObject): # NOTE that this needs to be done before setSourceCode, so that # QtWebEngine's parsing of GreaseMonkey tags will override it if there is a # @run-at comment. - new_script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) + new_script.setInjectionPoint(webenginecore.QWebEngineScript.InjectionPoint.DocumentReady) new_script.setSourceCode(script.code()) new_script.setName(script.full_name()) @@ -1184,7 +1179,7 @@ class _WebEngineScripts(QObject): if script.needs_document_end_workaround(): log.greasemonkey.debug( f"Forcing @run-at document-end for {script.name}") - new_script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) + new_script.setInjectionPoint(webenginecore.QWebEngineScript.InjectionPoint.DocumentReady) log.greasemonkey.debug(f'adding script: {new_script.name()}') page_scripts.insert(new_script) @@ -1198,8 +1193,8 @@ class _WebEngineScripts(QObject): quirks = [ _Quirk( 'whatsapp_web', - injection_point=QWebEngineScript.InjectionPoint.DocumentReady, - world=QWebEngineScript.ScriptWorldId.ApplicationWorld, + injection_point=webenginecore.QWebEngineScript.InjectionPoint.DocumentReady, + world=webenginecore.QWebEngineScript.ScriptWorldId.ApplicationWorld, ), _Quirk('discord'), _Quirk( @@ -1273,9 +1268,9 @@ class WebEngineTab(browsertab.AbstractTab): down. """ - abort_questions = pyqtSignal() + abort_questions = core.pyqtSignal() - _widget: QWebEngineView + _widget: webenginewidgets.QWebEngineView search: WebEngineSearch audio: WebEngineAudio @@ -1329,7 +1324,7 @@ class WebEngineTab(browsertab.AbstractTab): parent=self) self._widget.installEventFilter(self._child_event_filter) - @pyqtSlot() + @core.pyqtSlot() def _restore_zoom(self): if sip.isdeleted(self._widget): # https://github.com/qutebrowser/qutebrowser/issues/3498 @@ -1366,9 +1361,9 @@ class WebEngineTab(browsertab.AbstractTab): self._widget.page().toHtml(callback) def run_js_async(self, code, callback=None, *, world=None): - world_id_type = Union[QWebEngineScript.ScriptWorldId, int] + world_id_type = Union[webenginecore.QWebEngineScript.ScriptWorldId, int] if world is None: - world_id: world_id_type = QWebEngineScript.ScriptWorldId.ApplicationWorld + world_id: world_id_type = webenginecore.QWebEngineScript.ScriptWorldId.ApplicationWorld elif isinstance(world, int): world_id = world if not 0 <= world_id <= qtutils.MAX_WORLD_ID: @@ -1385,9 +1380,9 @@ class WebEngineTab(browsertab.AbstractTab): def reload(self, *, force=False): if force: - action = QWebEnginePage.WebAction.ReloadAndBypassCache + action = webenginecore.QWebEnginePage.WebAction.ReloadAndBypassCache else: - action = QWebEnginePage.WebAction.Reload + action = webenginecore.QWebEnginePage.WebAction.Reload self._widget.triggerPageAction(action) def stop(self): @@ -1403,7 +1398,7 @@ class WebEngineTab(browsertab.AbstractTab): def icon(self): return self._widget.icon() - def set_html(self, html, base_url=QUrl()): + def set_html(self, html, base_url=core.QUrl()): # FIXME:qtwebengine # check this and raise an exception if too big: # Warning: The content will be percent encoded before being sent to the @@ -1421,7 +1416,7 @@ class WebEngineTab(browsertab.AbstractTab): url=url_string, error=error) self.set_html(error_page) - @pyqtSlot() + @core.pyqtSlot() def _on_history_trigger(self): try: self._widget.page() @@ -1437,10 +1432,10 @@ class WebEngineTab(browsertab.AbstractTab): # Don't save the title if it's generated from the URL title = self.title() - title_url = QUrl(url) + title_url = core.QUrl(url) title_url.setScheme('') title_url_str = title_url.toDisplayString( - QUrl.UrlFormattingOption.RemoveScheme) # type: ignore[arg-type] + core.QUrl.UrlFormattingOption.RemoveScheme) # type: ignore[arg-type] if title == title_url_str.strip('/'): title = "" @@ -1451,26 +1446,26 @@ class WebEngineTab(browsertab.AbstractTab): self.history_item_triggered.emit(url, requested_url, title) - @pyqtSlot(QUrl, 'QAuthenticator*', 'QString') + @core.pyqtSlot(core.QUrl, 'QAuthenticator*', 'QString') def _on_proxy_authentication_required(self, url, authenticator, proxy_host): """Called when a proxy needs authentication.""" msg = "{} requires a username and password.".format( html_utils.escape(proxy_host)) - urlstr = url.toString(QUrl.UrlFormattingOption.RemovePassword | QUrl.ComponentFormattingOption.FullyEncoded) + urlstr = url.toString(core.QUrl.UrlFormattingOption.RemovePassword | core.QUrl.ComponentFormattingOption.FullyEncoded) answer = message.ask( title="Proxy authentication required", text=msg, mode=usertypes.PromptMode.user_pwd, abort_on=[self.abort_questions], url=urlstr) if answer is None: - sip.assign(authenticator, QAuthenticator()) + sip.assign(authenticator, network.QAuthenticator()) return authenticator.setUser(answer.user) authenticator.setPassword(answer.password) - @pyqtSlot(QUrl, 'QAuthenticator*') + @core.pyqtSlot(core.QUrl, 'QAuthenticator*') def _on_authentication_required(self, url, authenticator): log.network.debug("Authentication requested for {}, netrc_used {}" .format(url.toDisplayString(), self.data.netrc_used)) @@ -1486,9 +1481,9 @@ class WebEngineTab(browsertab.AbstractTab): url, authenticator, abort_on=[self.abort_questions]) if not netrc_success and answer is None: log.network.debug("Aborting auth") - sip.assign(authenticator, QAuthenticator()) + sip.assign(authenticator, network.QAuthenticator()) - @pyqtSlot() + @core.pyqtSlot() def _on_load_started(self): """Clear search when a new load is started if needed.""" # WORKAROUND for @@ -1498,27 +1493,27 @@ class WebEngineTab(browsertab.AbstractTab): super()._on_load_started() self.data.netrc_used = False - @pyqtSlot('qint64') + @core.pyqtSlot('qint64') def _on_renderer_process_pid_changed(self, pid): log.webview.debug("Renderer process PID for tab {}: {}" .format(self.tab_id, pid)) - @pyqtSlot(QWebEnginePage.RenderProcessTerminationStatus, int) + @core.pyqtSlot(webenginecore.QWebEnginePage.RenderProcessTerminationStatus, int) def _on_render_process_terminated(self, status, exitcode): """Show an error when the renderer process terminated.""" - if (status == QWebEnginePage.RenderProcessTerminationStatus.AbnormalTerminationStatus and + if (status == webenginecore.QWebEnginePage.RenderProcessTerminationStatus.AbnormalTerminationStatus and exitcode == 256): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-58697 - status = QWebEnginePage.RenderProcessTerminationStatus.CrashedTerminationStatus + status = webenginecore.QWebEnginePage.RenderProcessTerminationStatus.CrashedTerminationStatus status_map = { - QWebEnginePage.RenderProcessTerminationStatus.NormalTerminationStatus: + webenginecore.QWebEnginePage.RenderProcessTerminationStatus.NormalTerminationStatus: browsertab.TerminationStatus.normal, - QWebEnginePage.RenderProcessTerminationStatus.AbnormalTerminationStatus: + webenginecore.QWebEnginePage.RenderProcessTerminationStatus.AbnormalTerminationStatus: browsertab.TerminationStatus.abnormal, - QWebEnginePage.RenderProcessTerminationStatus.CrashedTerminationStatus: + webenginecore.QWebEnginePage.RenderProcessTerminationStatus.CrashedTerminationStatus: browsertab.TerminationStatus.crashed, - QWebEnginePage.RenderProcessTerminationStatus.KilledTerminationStatus: + webenginecore.QWebEnginePage.RenderProcessTerminationStatus.KilledTerminationStatus: browsertab.TerminationStatus.killed, -1: browsertab.TerminationStatus.unknown, @@ -1546,7 +1541,7 @@ class WebEngineTab(browsertab.AbstractTab): self._show_error_page(self.url(), error=error) - @pyqtSlot(int) + @core.pyqtSlot(int) def _on_load_progress(self, perc: int) -> None: """QtWebEngine-specific loadProgress workarounds.""" super()._on_load_progress(perc) @@ -1557,7 +1552,7 @@ class WebEngineTab(browsertab.AbstractTab): ): self._update_load_status(ok=True) - @pyqtSlot(bool) + @core.pyqtSlot(bool) def _on_load_finished(self, ok: bool) -> None: """QtWebEngine-specific loadFinished code.""" super()._on_load_finished(ok) @@ -1571,7 +1566,7 @@ class WebEngineTab(browsertab.AbstractTab): self._error_page_workaround, self.settings.test_attribute('content.javascript.enabled'))) - @pyqtSlot(certificateerror.CertificateErrorWrapper) + @core.pyqtSlot(certificateerror.CertificateErrorWrapper) def _on_ssl_errors(self, error): url = error.url() self._insecure_hosts.add(url.host()) @@ -1599,7 +1594,7 @@ class WebEngineTab(browsertab.AbstractTab): log.network.debug("ignore {}, URL {}, requested {}".format( error.ignore, url, self.url(requested=True))) - @pyqtSlot() + @core.pyqtSlot() def _on_print_requested(self): """Slot for window.print() in JS.""" try: @@ -1607,7 +1602,7 @@ class WebEngineTab(browsertab.AbstractTab): except browsertab.WebTabError as e: message.error(str(e)) - @pyqtSlot(usertypes.NavigationRequest) + @core.pyqtSlot(usertypes.NavigationRequest) def _on_navigation_request(self, navigation): super()._on_navigation_request(navigation) diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index 61dfafb30..0f19902d3 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -21,11 +21,7 @@ from typing import List, Iterable -from qutebrowser.qt import machinery -from qutebrowser.qt.core import pyqtSignal, pyqtSlot, QUrl -from qutebrowser.qt.gui import QPalette -from qutebrowser.qt.webenginewidgets import QWebEngineView -from qutebrowser.qt.webenginecore import QWebEnginePage, QWebEngineCertificateError +from qutebrowser.qt import webenginewidgets, webenginecore, gui, core, machinery from qutebrowser.browser import shared from qutebrowser.browser.webengine import webenginesettings, certificateerror @@ -34,8 +30,8 @@ from qutebrowser.utils import log, debug, usertypes _QB_FILESELECTION_MODES = { - QWebEnginePage.FileSelectionMode.FileSelectOpen: shared.FileSelectionMode.single_file, - QWebEnginePage.FileSelectionMode.FileSelectOpenMultiple: shared.FileSelectionMode.multiple_files, + webenginecore.QWebEnginePage.FileSelectionMode.FileSelectOpen: shared.FileSelectionMode.single_file, + webenginecore.QWebEnginePage.FileSelectionMode.FileSelectOpenMultiple: shared.FileSelectionMode.multiple_files, # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-91489 # # QtWebEngine doesn't expose this value from its internal @@ -43,11 +39,11 @@ _QB_FILESELECTION_MODES = { # the public QWebEnginePage::FileSelectionMode enum). # However, QWebEnginePage::chooseFiles is still called with the matching value # (2) when a file input with "webkitdirectory" is used. - QWebEnginePage.FileSelectionMode(2): shared.FileSelectionMode.folder, + webenginecore.QWebEnginePage.FileSelectionMode(2): shared.FileSelectionMode.folder, } -class WebEngineView(QWebEngineView): +class WebEngineView(webenginewidgets.QWebEngineView): """Custom QWebEngineView subclass with qutebrowser-specific features.""" @@ -56,7 +52,7 @@ class WebEngineView(QWebEngineView): self._win_id = win_id self._tabdata = tabdata - theme_color = self.style().standardPalette().color(QPalette.ColorRole.Base) + theme_color = self.style().standardPalette().color(gui.QPalette.ColorRole.Base) if private: assert webenginesettings.private_profile is not None profile = webenginesettings.private_profile @@ -102,27 +98,27 @@ class WebEngineView(QWebEngineView): Return: The new QWebEngineView object. """ - debug_type = debug.qenum_key(QWebEnginePage, wintype) + debug_type = debug.qenum_key(webenginecore.QWebEnginePage, wintype) background = config.val.tabs.background log.webview.debug("createWindow with type {}, background {}".format( debug_type, background)) - if wintype == QWebEnginePage.WebWindowType.WebBrowserWindow: + if wintype == webenginecore.QWebEnginePage.WebWindowType.WebBrowserWindow: # Shift-Alt-Click target = usertypes.ClickTarget.window - elif wintype == QWebEnginePage.WebWindowType.WebDialog: + elif wintype == webenginecore.QWebEnginePage.WebWindowType.WebDialog: log.webview.warning("{} requested, but we don't support " "that!".format(debug_type)) target = usertypes.ClickTarget.tab - elif wintype == QWebEnginePage.WebWindowType.WebBrowserTab: + elif wintype == webenginecore.QWebEnginePage.WebWindowType.WebBrowserTab: # Middle-click / Ctrl-Click with Shift # FIXME:qtwebengine this also affects target=_blank links... if background: target = usertypes.ClickTarget.tab else: target = usertypes.ClickTarget.tab_bg - elif wintype == QWebEnginePage.WebWindowType.WebBrowserBackgroundTab: + elif wintype == webenginecore.QWebEnginePage.WebWindowType.WebBrowserBackgroundTab: # Middle-click / Ctrl-Click if background: target = usertypes.ClickTarget.tab_bg @@ -142,7 +138,7 @@ class WebEngineView(QWebEngineView): super().contextMenuEvent(ev) -class WebEnginePage(QWebEnginePage): +class WebEnginePage(webenginecore.QWebEnginePage): """Custom QWebEnginePage subclass with qutebrowser-specific features. @@ -159,33 +155,33 @@ class WebEnginePage(QWebEnginePage): navigation_request: Emitted on acceptNavigationRequest. """ - certificate_error = pyqtSignal(certificateerror.CertificateErrorWrapper) - shutting_down = pyqtSignal() - navigation_request = pyqtSignal(usertypes.NavigationRequest) + certificate_error = core.pyqtSignal(certificateerror.CertificateErrorWrapper) + shutting_down = core.pyqtSignal() + navigation_request = core.pyqtSignal(usertypes.NavigationRequest) _JS_LOG_LEVEL_MAPPING = { - QWebEnginePage.JavaScriptConsoleMessageLevel.InfoMessageLevel: + webenginecore.QWebEnginePage.JavaScriptConsoleMessageLevel.InfoMessageLevel: usertypes.JsLogLevel.info, - QWebEnginePage.JavaScriptConsoleMessageLevel.WarningMessageLevel: + webenginecore.QWebEnginePage.JavaScriptConsoleMessageLevel.WarningMessageLevel: usertypes.JsLogLevel.warning, - QWebEnginePage.JavaScriptConsoleMessageLevel.ErrorMessageLevel: + webenginecore.QWebEnginePage.JavaScriptConsoleMessageLevel.ErrorMessageLevel: usertypes.JsLogLevel.error, } _NAVIGATION_TYPE_MAPPING = { - QWebEnginePage.NavigationType.NavigationTypeLinkClicked: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeLinkClicked: usertypes.NavigationRequest.Type.link_clicked, - QWebEnginePage.NavigationType.NavigationTypeTyped: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeTyped: usertypes.NavigationRequest.Type.typed, - QWebEnginePage.NavigationType.NavigationTypeFormSubmitted: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeFormSubmitted: usertypes.NavigationRequest.Type.form_submitted, - QWebEnginePage.NavigationType.NavigationTypeBackForward: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeBackForward: usertypes.NavigationRequest.Type.back_forward, - QWebEnginePage.NavigationType.NavigationTypeReload: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeReload: usertypes.NavigationRequest.Type.reload, - QWebEnginePage.NavigationType.NavigationTypeOther: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeOther: usertypes.NavigationRequest.Type.other, - QWebEnginePage.NavigationType.NavigationTypeRedirect: + webenginecore.QWebEnginePage.NavigationType.NavigationTypeRedirect: usertypes.NavigationRequest.Type.redirect, } @@ -212,7 +208,7 @@ class WebEnginePage(QWebEnginePage): self._is_shutting_down = True self.shutting_down.emit() - @pyqtSlot(QWebEngineCertificateError) + @core.pyqtSlot(webenginecore.QWebEngineCertificateError) def _handle_certificate_error(self, qt_error): """Handle certificate errors coming from Qt.""" error = certificateerror.create(qt_error) @@ -259,8 +255,8 @@ class WebEnginePage(QWebEnginePage): shared.javascript_log_message(self._JS_LOG_LEVEL_MAPPING[level], source, line, msg) def acceptNavigationRequest(self, - url: QUrl, - typ: QWebEnginePage.NavigationType, + url: core.QUrl, + typ: webenginecore.QWebEnginePage.NavigationType, is_main_frame: bool) -> bool: """Override acceptNavigationRequest to forward it to the tab API.""" navigation = usertypes.NavigationRequest( @@ -273,7 +269,7 @@ class WebEnginePage(QWebEnginePage): def chooseFiles( self, - mode: QWebEnginePage.FileSelectionMode, + mode: webenginecore.QWebEnginePage.FileSelectionMode, old_files: Iterable[str], accepted_mimetypes: Iterable[str], ) -> List[str]: diff --git a/qutebrowser/browser/webkit/cache.py b/qutebrowser/browser/webkit/cache.py index 2b5b07c46..98644fb38 100644 --- a/qutebrowser/browser/webkit/cache.py +++ b/qutebrowser/browser/webkit/cache.py @@ -22,7 +22,7 @@ from typing import cast import os.path -from qutebrowser.qt.network import QNetworkDiskCache +from qutebrowser.qt import network from qutebrowser.config import config from qutebrowser.utils import utils, standarddir @@ -31,7 +31,7 @@ from qutebrowser.utils import utils, standarddir diskcache = cast('DiskCache', None) -class DiskCache(QNetworkDiskCache): +class DiskCache(network.QNetworkDiskCache): """Disk cache which sets correct cache dir and size.""" diff --git a/qutebrowser/browser/webkit/certificateerror.py b/qutebrowser/browser/webkit/certificateerror.py index 553538193..4552fb5b9 100644 --- a/qutebrowser/browser/webkit/certificateerror.py +++ b/qutebrowser/browser/webkit/certificateerror.py @@ -21,16 +21,15 @@ from typing import Sequence, Optional -from qutebrowser.qt.network import QSslError, QNetworkReply - from qutebrowser.utils import usertypes, utils, debug, jinja, urlutils +from qutebrowser.qt import network class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): """A wrapper over a list of QSslErrors.""" - def __init__(self, reply: QNetworkReply, errors: Sequence[QSslError]) -> None: + def __init__(self, reply: network.QNetworkReply, errors: Sequence[network.QSslError]) -> None: super().__init__() self._reply = reply self._errors = tuple(errors) # needs to be hashable @@ -45,7 +44,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): def __repr__(self) -> str: return utils.get_repr( self, - errors=[debug.qenum_key(QSslError, err.error()) for err in self._errors], + errors=[debug.qenum_key(network.QSslError, err.error()) for err in self._errors], string=str(self)) def __hash__(self) -> int: diff --git a/qutebrowser/browser/webkit/cookies.py b/qutebrowser/browser/webkit/cookies.py index fed819cee..1dcbeef7b 100644 --- a/qutebrowser/browser/webkit/cookies.py +++ b/qutebrowser/browser/webkit/cookies.py @@ -21,19 +21,17 @@ from typing import Sequence -from qutebrowser.qt.network import QNetworkCookie, QNetworkCookieJar -from qutebrowser.qt.core import pyqtSignal, QDateTime - from qutebrowser.config import config from qutebrowser.utils import utils, standarddir, objreg, log from qutebrowser.misc import lineparser, objects +from qutebrowser.qt import network, core cookie_jar = None ram_cookie_jar = None -class RAMCookieJar(QNetworkCookieJar): +class RAMCookieJar(network.QNetworkCookieJar): """An in-RAM cookie jar. @@ -41,7 +39,7 @@ class RAMCookieJar(QNetworkCookieJar): changed: Emitted when the cookie store was changed. """ - changed = pyqtSignal() + changed = core.pyqtSignal() def __repr__(self): return utils.get_repr(self, count=len(self.allCookies())) @@ -93,9 +91,9 @@ class CookieJar(RAMCookieJar): def parse_cookies(self): """Parse cookies from lineparser and store them.""" - cookies: Sequence[QNetworkCookie] = [] + cookies: Sequence[network.QNetworkCookie] = [] for line in self._lineparser: - line_cookies = QNetworkCookie.parseCookies(line) + line_cookies = network.QNetworkCookie.parseCookies(line) cookies += line_cookies # type: ignore[operator] self.setAllCookies(cookies) @@ -103,7 +101,7 @@ class CookieJar(RAMCookieJar): """Purge expired cookies from the cookie jar.""" # Based on: # https://doc.qt.io/archives/qt-5.5/qtwebkitexamples-webkitwidgets-browser-cookiejar-cpp.html - now = QDateTime.currentDateTime() + now = core.QDateTime.currentDateTime() cookies = [c for c in self.allCookies() if c.isSessionCookie() or c.expirationDate() >= now] # type: ignore[operator] diff --git a/qutebrowser/browser/webkit/http.py b/qutebrowser/browser/webkit/http.py index 104abf2d3..dbc862d81 100644 --- a/qutebrowser/browser/webkit/http.py +++ b/qutebrowser/browser/webkit/http.py @@ -25,7 +25,7 @@ import dataclasses import os.path from typing import Type -from qutebrowser.qt.network import QNetworkRequest +from qutebrowser.qt import network from qutebrowser.utils import log, utils @@ -191,7 +191,7 @@ def parse_content_type(reply): A [mimetype, rest] list, or [None, None] if unset. Rest can be None. """ - content_type = reply.header(QNetworkRequest.KnownHeaders.ContentTypeHeader) + content_type = reply.header(network.QNetworkRequest.KnownHeaders.ContentTypeHeader) if content_type is None: return [None, None] if ';' in content_type: diff --git a/qutebrowser/browser/webkit/mhtml.py b/qutebrowser/browser/webkit/mhtml.py index 56ad4fb4f..6b9fbb8d1 100644 --- a/qutebrowser/browser/webkit/mhtml.py +++ b/qutebrowser/browser/webkit/mhtml.py @@ -36,7 +36,7 @@ import quopri import dataclasses from typing import MutableMapping, Set, Tuple, Callable -from qutebrowser.qt.core import QUrl +from qutebrowser.qt import core from qutebrowser.browser import downloads from qutebrowser.browser.webkit import webkitelem @@ -137,7 +137,7 @@ class MHTMLWriter: self.root_content = root_content self.content_location = content_location self.content_type = content_type - self._files: MutableMapping[QUrl, _File] = {} + self._files: MutableMapping[core.QUrl, _File] = {} def add_file(self, location, content, content_type=None, transfer_encoding=E_QUOPRI): @@ -192,7 +192,7 @@ class MHTMLWriter: return msg -_PendingDownloadType = Set[Tuple[QUrl, downloads.AbstractDownloadItem]] +_PendingDownloadType = Set[Tuple[core.QUrl, downloads.AbstractDownloadItem]] class _Downloader: @@ -259,7 +259,7 @@ class _Downloader: else: # Might be a local