From df32aa482c05312e0244e7da5449b10b9a25ab34 Mon Sep 17 00:00:00 2001 From: Jimmy Date: Sat, 16 Apr 2022 14:11:26 +1200 Subject: Re-write PyQt5 imports to be via our wrapper. Still some manual fixes to make, see #995 and linked PRs. This was done like: date ; for mod in QtCore QtDBus QtGui QtNetwork QtPrintSupport QtQml QtSql QtWebEngine QtWebEngineCore QtWebEngineWidgets QtWebKit QtWebKitWidgets QtWidgets; do echo "renaming $mod" python3 -m libcst.tool codemod rename_pyqt.RenameCommand qutebrowser/ tests --old_name=PyQt5.$mod.* --new_name=qutebrowser.qt:$mod.* --no-format done ; dat Where the list of modules was obtained via: semgrep --lang=py -e 'from PyQt5.$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 | 36 ++- qutebrowser/browser/browsertab.py | 178 ++++++----- qutebrowser/browser/commands.py | 70 +++-- qutebrowser/browser/downloads.py | 103 +++---- qutebrowser/browser/downloadview.py | 34 +-- qutebrowser/browser/eventfilter.py | 35 ++- qutebrowser/browser/greasemonkey.py | 13 +- qutebrowser/browser/hints.py | 46 +-- qutebrowser/browser/history.py | 44 ++- qutebrowser/browser/inspector.py | 32 +- 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 | 60 ++-- qutebrowser/browser/qutescheme.py | 76 +++-- qutebrowser/browser/shared.py | 23 +- qutebrowser/browser/signalfilter.py | 4 +- qutebrowser/browser/urlmarks.py | 13 +- qutebrowser/browser/webelem.py | 49 ++- qutebrowser/browser/webengine/certificateerror.py | 9 +- qutebrowser/browser/webengine/interceptor.py | 63 ++-- qutebrowser/browser/webengine/notification.py | 176 +++++------ qutebrowser/browser/webengine/tabhistory.py | 11 +- .../browser/webengine/webenginedownloads.py | 51 ++-- qutebrowser/browser/webengine/webengineelem.py | 27 +- .../browser/webengine/webengineinspector.py | 14 +- .../browser/webengine/webenginequtescheme.py | 44 ++- qutebrowser/browser/webengine/webenginesettings.py | 104 ++++--- qutebrowser/browser/webengine/webenginetab.py | 238 +++++++-------- qutebrowser/browser/webengine/webview.py | 60 ++-- qutebrowser/browser/webkit/cache.py | 4 +- qutebrowser/browser/webkit/certificateerror.py | 6 +- 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 | 218 +++++++------- qutebrowser/browser/webkit/webpage.py | 102 +++---- 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 | 103 +++---- 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 | 11 +- qutebrowser/components/utils/blockutils.py | 15 +- qutebrowser/config/config.py | 13 +- qutebrowser/config/configcommands.py | 8 +- qutebrowser/config/configfiles.py | 26 +- qutebrowser/config/configinit.py | 4 +- qutebrowser/config/configtypes.py | 60 ++-- qutebrowser/config/configutils.py | 14 +- qutebrowser/config/qtargs.py | 7 +- qutebrowser/config/stylesheet.py | 11 +- 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 | 300 +++++++++--------- qutebrowser/keyinput/modeman.py | 45 ++- qutebrowser/keyinput/modeparsers.py | 63 ++-- qutebrowser/mainwindow/mainwindow.py | 66 ++-- qutebrowser/mainwindow/messageview.py | 26 +- qutebrowser/mainwindow/prompt.py | 99 +++--- qutebrowser/mainwindow/statusbar/bar.py | 41 ++- qutebrowser/mainwindow/statusbar/command.py | 39 ++- qutebrowser/mainwindow/statusbar/keystring.py | 4 +- qutebrowser/mainwindow/statusbar/percentage.py | 7 +- qutebrowser/mainwindow/statusbar/progress.py | 14 +- qutebrowser/mainwindow/statusbar/tabindex.py | 4 +- qutebrowser/mainwindow/statusbar/textbase.py | 18 +- qutebrowser/mainwindow/statusbar/url.py | 14 +- qutebrowser/mainwindow/tabbedbrowser.py | 112 ++++--- qutebrowser/mainwindow/tabwidget.py | 168 +++++------ qutebrowser/mainwindow/windowundo.py | 8 +- qutebrowser/misc/autoupdate.py | 13 +- qutebrowser/misc/backendproblem.py | 45 ++- qutebrowser/misc/cmdhistory.py | 9 +- qutebrowser/misc/consolewidget.py | 30 +- qutebrowser/misc/crashdialog.py | 88 +++--- qutebrowser/misc/crashsignal.py | 31 +- qutebrowser/misc/earlyinit.py | 31 +- qutebrowser/misc/editor.py | 21 +- qutebrowser/misc/elf.py | 4 +- qutebrowser/misc/guiprocess.py | 64 ++-- qutebrowser/misc/httpclient.py | 27 +- qutebrowser/misc/ipc.py | 55 ++-- qutebrowser/misc/keyhintwidget.py | 14 +- qutebrowser/misc/lineparser.py | 9 +- qutebrowser/misc/miscwidgets.py | 85 +++--- qutebrowser/misc/msgbox.py | 15 +- qutebrowser/misc/objects.py | 2 +- 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 | 2 + qutebrowser/utils/message.py | 19 +- qutebrowser/utils/objreg.py | 15 +- qutebrowser/utils/qtutils.py | 109 ++++--- qutebrowser/utils/standarddir.py | 57 ++-- qutebrowser/utils/urlmatch.py | 6 +- qutebrowser/utils/urlutils.py | 81 +++-- qutebrowser/utils/usertypes.py | 32 +- qutebrowser/utils/utils.py | 28 +- qutebrowser/utils/version.py | 44 ++- 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 | 21 +- 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/testutils.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_pdfjs.py | 14 +- tests/unit/browser/test_qutescheme.py | 44 +-- tests/unit/browser/test_signalfilter.py | 14 +- tests/unit/browser/test_urlmarks.py | 26 +- .../browser/webengine/test_webengine_cookies.py | 12 +- .../browser/webengine/test_webenginedownloads.py | 4 +- .../browser/webengine/test_webengineinterceptor.py | 6 +- 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 | 8 +- 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 | 7 +- 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 | 96 +++--- 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 | 335 ++++++++++----------- tests/unit/keyinput/test_modeman.py | 17 +- 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 | 10 +- 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 | 73 +++-- 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 | 4 +- tests/unit/misc/test_utilcmds.py | 4 +- tests/unit/test_app.py | 4 +- tests/unit/utils/test_debug.py | 57 ++-- tests/unit/utils/test_error.py | 9 +- tests/unit/utils/test_jinja.py | 6 +- tests/unit/utils/test_log.py | 1 + tests/unit/utils/test_qtutils.py | 175 ++++++----- tests/unit/utils/test_standarddir.py | 10 +- tests/unit/utils/test_urlmatch.py | 42 +-- tests/unit/utils/test_urlutils.py | 155 +++++----- tests/unit/utils/test_utils.py | 17 +- tests/unit/utils/test_version.py | 11 +- tests/unit/utils/usertypes/test_timer.py | 4 +- 225 files changed, 3719 insertions(+), 4001 deletions(-) diff --git a/qutebrowser/api/config.py b/qutebrowser/api/config.py index 19e2b3c3e..cfb726840 100644 --- a/qutebrowser/api/config.py +++ b/qutebrowser/api/config.py @@ -21,7 +21,7 @@ from typing import cast, Any -from PyQt5.QtCore import QUrl +from qutebrowser.qt import QtCore 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: QtCore.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 cd33f5709..54902b711 100644 --- a/qutebrowser/api/downloads.py +++ b/qutebrowser/api/downloads.py @@ -23,20 +23,19 @@ import io -from PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QUrl - from qutebrowser.browser import downloads, qtnetworkdownloads from qutebrowser.utils import objreg +from qutebrowser.qt import QtCore UnsupportedAttribute = downloads.UnsupportedAttribute -class TempDownload(QObject): +class TempDownload(QtCore.QObject): """A download of some data into a file object.""" - finished = pyqtSignal() + finished = QtCore.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() + @QtCore.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: QtCore.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 c046475b5..54b19a44f 100644 --- a/qutebrowser/app.py +++ b/qutebrowser/app.py @@ -46,10 +46,6 @@ import datetime import argparse from typing import Iterable, Optional -from PyQt5.QtWidgets import QApplication, QWidget -from PyQt5.QtGui import QDesktopServices, QPixmap, QIcon -from PyQt5.QtCore import pyqtSlot, QUrl, QObject, QEvent, pyqtSignal, Qt - import qutebrowser from qutebrowser.commands import runners from qutebrowser.config import (config, websettings, configfiles, configinit, @@ -73,6 +69,8 @@ from qutebrowser.utils import (log, version, message, utils, urlutils, objreg, from qutebrowser.mainwindow.statusbar import command from qutebrowser.misc import utilcmds from qutebrowser.browser import commands +from qutebrowser.qt import QtWidgets, QtGui, QtCore + # pylint: enable=unused-import @@ -146,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(QtWidgets.QApplication.closeAllWindows) _init_icon() _init_pulseaudio() @@ -170,7 +168,7 @@ def init(*, args: argparse.Namespace) -> None: _process_args(args) for scheme in ['http', 'https', 'qute']: - QDesktopServices.setUrlHandler( + QtGui.QDesktopServices.setUrlHandler( scheme, open_desktopservices_url) log.init.debug("Init done!") @@ -179,16 +177,16 @@ def init(*, args: argparse.Namespace) -> None: def _init_icon(): """Initialize the icon of qutebrowser.""" - fallback_icon = QIcon() + fallback_icon = QtGui.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 = QtGui.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 = QtGui.QIcon.fromTheme('qutebrowser', fallback_icon) if icon.isNull(): log.init.warning("Failed to load icon") else: @@ -381,7 +379,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(QtCore.QUrl(url), background=False) general_sect[state] = '1' # Show changelog on new releases @@ -408,7 +406,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(QtCore.QUrl(changelog_url), background=False) def on_focus_changed(_old, new): @@ -416,7 +414,7 @@ def on_focus_changed(_old, new): if new is None: return - if not isinstance(new, QWidget): + if not isinstance(new, QtWidgets.QWidget): log.misc.debug("on_focus_changed called with non-QWidget {!r}".format( new)) return @@ -527,7 +525,7 @@ def _init_modules(*, args): windowundo.init() -class Application(QApplication): +class Application(QtWidgets.QApplication): """Main application instance. @@ -540,8 +538,8 @@ class Application(QApplication): window_closing: A window is being closed. """ - new_window = pyqtSignal(mainwindow.MainWindow) - window_closing = pyqtSignal(mainwindow.MainWindow) + new_window = QtCore.pyqtSignal(mainwindow.MainWindow) + window_closing = QtCore.pyqtSignal(mainwindow.MainWindow) def __init__(self, args): """Constructor. @@ -564,16 +562,16 @@ class Application(QApplication): self.launch_time = datetime.datetime.now() self.focusObjectChanged.connect( # type: ignore[attr-defined] self.on_focus_object_changed) - self.setAttribute(Qt.AA_UseHighDpiPixmaps, True) + self.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) self.new_window.connect(self._on_new_window) - @pyqtSlot(mainwindow.MainWindow) + @QtCore.pyqtSlot(mainwindow.MainWindow) def _on_new_window(self, window): window.tabbed_browser.shutting_down.connect(functools.partial( self.window_closing.emit, window)) - @pyqtSlot(QObject) + @QtCore.pyqtSlot(QtCore.QObject) def on_focus_object_changed(self, obj): """Log when the focus object changed.""" output = repr(obj) @@ -583,7 +581,7 @@ class Application(QApplication): def event(self, e): """Handle macOS FileOpen events.""" - if e.type() != QEvent.FileOpen: + if e.type() != QtCore.QEvent.FileOpen: return super().event(e) url = e.url() diff --git a/qutebrowser/browser/browsertab.py b/qutebrowser/browser/browsertab.py index 661c5f68b..1ee429b70 100644 --- a/qutebrowser/browser/browsertab.py +++ b/qutebrowser/browser/browsertab.py @@ -25,17 +25,11 @@ import functools import dataclasses from typing import (cast, TYPE_CHECKING, Any, Callable, Iterable, List, Optional, Sequence, Set, Type, Union) - -from PyQt5.QtCore import (pyqtSignal, pyqtSlot, QUrl, QObject, QSizeF, Qt, - QEvent, QPoint, QRect) -from PyQt5.QtGui import QKeyEvent, QIcon, QPixmap -from PyQt5.QtWidgets import QWidget, QApplication, QDialog -from PyQt5.QtPrintSupport import QPrintDialog, QPrinter -from PyQt5.QtNetwork import QNetworkAccessManager +from qutebrowser.qt import QtWidgets, QtWebKitWidgets, QtPrintSupport, QtNetwork if TYPE_CHECKING: from PyQt5.QtWebKit import QWebHistory, QWebHistoryItem - from PyQt5.QtWebKitWidgets import QWebPage + from qutebrowser.qt import QWebPage from PyQt5.QtWebEngineWidgets import ( QWebEngineHistory, QWebEngineHistoryItem, QWebEnginePage) @@ -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 QtGui, QtCore, sip if TYPE_CHECKING: from qutebrowser.browser import webelem @@ -57,7 +51,7 @@ tab_id_gen = itertools.count(0) def create(win_id: int, private: bool, - parent: QWidget = None) -> 'AbstractTab': + parent: QtWidgets.QWidget = None) -> 'AbstractTab': """Get a QtWebKit/QtWebEngine tab object. Args: @@ -156,7 +150,7 @@ class AbstractAction: action_base: Type[Union['QWebPage.WebAction', 'QWebEnginePage.WebAction']] def __init__(self, tab: 'AbstractTab') -> None: - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._tab = tab def exit_fullscreen(self) -> None: @@ -229,7 +223,7 @@ class AbstractPrinting: """Attribute ``printing`` of AbstractTab for printing the page.""" def __init__(self, tab: 'AbstractTab') -> None: - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._tab = tab def check_pdf_support(self) -> None: @@ -252,7 +246,7 @@ class AbstractPrinting: """Print the tab to a PDF with the given filename.""" raise NotImplementedError - def to_printer(self, printer: QPrinter, + def to_printer(self, printer: QtPrintSupport.QPrinter, callback: Callable[[bool], None] = None) -> None: """Print the tab. @@ -275,17 +269,17 @@ class AbstractPrinting: """Called when the dialog was closed.""" self.to_printer(diag.printer(), print_callback) - diag = QPrintDialog(self._tab) + diag = QtPrintSupport.QPrintDialog(self._tab) if utils.is_mac: # For some reason we get a segfault when using open() on macOS ret = diag.exec() - if ret == QDialog.Accepted: + if ret == QtWidgets.QDialog.Accepted: do_print() else: diag.open(do_print) -class AbstractSearch(QObject): +class AbstractSearch(QtCore.QObject): """Attribute ``search`` of AbstractTab for doing searches. @@ -299,16 +293,16 @@ class AbstractSearch(QObject): #: Signal emitted when a search was finished #: (True if the text was found, False otherwise) - finished = pyqtSignal(bool) + finished = QtCore.pyqtSignal(bool) #: Signal emitted when an existing search was cleared. - cleared = pyqtSignal() + cleared = QtCore.pyqtSignal() _Callback = Callable[[bool], None] - def __init__(self, tab: 'AbstractTab', parent: QWidget = None): + def __init__(self, tab: 'AbstractTab', parent: QtWidgets.QWidget = None): super().__init__(parent) self._tab = tab - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self.text: Optional[str] = None self.search_displayed = False @@ -365,21 +359,21 @@ class AbstractSearch(QObject): raise NotImplementedError -class AbstractZoom(QObject): +class AbstractZoom(QtCore.QObject): """Attribute ``zoom`` of AbstractTab for controlling zoom.""" - def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None: + def __init__(self, tab: 'AbstractTab', parent: QtWidgets.QWidget = None) -> None: super().__init__(parent) self._tab = tab - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) # Whether zoom was changed from the default. self._default_zoom_changed = False self._init_neighborlist() config.instance.changed.connect(self._on_config_changed) self._zoom_factor = float(config.val.zoom.default) / 100 - @pyqtSlot(str) + @QtCore.pyqtSlot(str) def _on_config_changed(self, option: str) -> None: if option in ['zoom.levels', 'zoom.default']: if not self._default_zoom_changed: @@ -452,21 +446,21 @@ class SelectionState(enum.Enum): line = enum.auto() -class AbstractCaret(QObject): +class AbstractCaret(QtCore.QObject): """Attribute ``caret`` of AbstractTab for caret browsing.""" #: Signal emitted when the selection was toggled. - selection_toggled = pyqtSignal(SelectionState) + selection_toggled = QtCore.pyqtSignal(SelectionState) #: Emitted when a ``follow_selection`` action is done. - follow_selected_done = pyqtSignal() + follow_selected_done = QtCore.pyqtSignal() def __init__(self, tab: 'AbstractTab', mode_manager: modeman.ModeManager, - parent: QWidget = None) -> None: + parent: QtWidgets.QWidget = None) -> None: super().__init__(parent) - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._mode_manager = mode_manager mode_manager.entered.connect(self._on_mode_entered) mode_manager.left.connect(self._on_mode_left) @@ -538,37 +532,37 @@ 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_Enter, modifier=Qt.ControlModifier) + self._tab.fake_key_press(QtCore.Qt.Key_Enter, modifier=QtCore.Qt.ControlModifier) else: - self._tab.fake_key_press(Qt.Key_Enter) + self._tab.fake_key_press(QtCore.Qt.Key_Enter) def follow_selected(self, *, tab: bool = False) -> None: raise NotImplementedError -class AbstractScroller(QObject): +class AbstractScroller(QtCore.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 = QtCore.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 = QtCore.pyqtSignal() - def __init__(self, tab: 'AbstractTab', parent: QWidget = None): + def __init__(self, tab: 'AbstractTab', parent: QtWidgets.QWidget = None): super().__init__(parent) self._tab = tab - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) if 'log-scroll-pos' in objects.debug_flags: self.perc_changed.connect(self._log_scroll_pos_change) - @pyqtSlot() + @QtCore.pyqtSlot() def _log_scroll_pos_change(self) -> None: log.webview.vdebug( # type: ignore[attr-defined] "Scroll position changed to {}".format(self.pos_px())) - def _init_widget(self, widget: QWidget) -> None: + def _init_widget(self, widget: QtWidgets.QWidget) -> None: self._widget = widget def pos_px(self) -> int: @@ -580,7 +574,7 @@ class AbstractScroller(QObject): def to_perc(self, x: int = None, y: int = None) -> None: raise NotImplementedError - def to_point(self, point: QPoint) -> None: + def to_point(self, point: QtCore.QPoint) -> None: raise NotImplementedError def to_anchor(self, name: str) -> None: @@ -711,7 +705,7 @@ class AbstractElements: _ErrorCallback = Callable[[Exception], None] def __init__(self, tab: 'AbstractTab') -> None: - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._tab = tab def find_css(self, selector: str, @@ -750,7 +744,7 @@ class AbstractElements: """ raise NotImplementedError - def find_at_pos(self, pos: QPoint, callback: _SingleCallback) -> None: + def find_at_pos(self, pos: QtCore.QPoint, callback: _SingleCallback) -> None: """Find the element at the given position async. This is also called "hit test" elsewhere. @@ -763,16 +757,16 @@ class AbstractElements: raise NotImplementedError -class AbstractAudio(QObject): +class AbstractAudio(QtCore.QObject): """Handling of audio/muting for this tab.""" - muted_changed = pyqtSignal(bool) - recently_audible_changed = pyqtSignal(bool) + muted_changed = QtCore.pyqtSignal(bool) + recently_audible_changed = QtCore.pyqtSignal(bool) - def __init__(self, tab: 'AbstractTab', parent: QWidget = None) -> None: + def __init__(self, tab: 'AbstractTab', parent: QtWidgets.QWidget = None) -> None: super().__init__(parent) - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._tab = tab def set_muted(self, muted: bool, override: bool = False) -> None: @@ -804,11 +798,11 @@ class AbstractTabPrivate: def __init__(self, mode_manager: modeman.ModeManager, tab: 'AbstractTab') -> None: - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._tab = tab self._mode_manager = mode_manager - def event_target(self) -> QWidget: + def event_target(self) -> QtWidgets.QWidget: """Return the widget events should be sent to.""" raise NotImplementedError @@ -837,7 +831,7 @@ class AbstractTabPrivate: def clear_ssl_errors(self) -> None: raise NotImplementedError - def networkaccessmanager(self) -> Optional[QNetworkAccessManager]: + def networkaccessmanager(self) -> Optional[QtNetwork.QNetworkAccessManager]: """Get the QNetworkAccessManager for this tab. This is only implemented for QtWebKit. @@ -882,7 +876,7 @@ class AbstractTabPrivate: def _init_inspector(self, splitter: 'miscwidgets.InspectorSplitter', win_id: int, - parent: QWidget = None) -> 'AbstractWebInspector': + parent: QtWidgets.QWidget = None) -> 'AbstractWebInspector': """Get a WebKitInspector/WebEngineInspector. Args: @@ -893,49 +887,49 @@ class AbstractTabPrivate: raise NotImplementedError -class AbstractTab(QWidget): +class AbstractTab(QtWidgets.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 = QtCore.pyqtSignal() #: Signal emitted when a link is hovered (the hover text) - link_hovered = pyqtSignal(str) + link_hovered = QtCore.pyqtSignal(str) #: Signal emitted when a page started loading - load_started = pyqtSignal() + load_started = QtCore.pyqtSignal() #: Signal emitted when a page is loading (progress percentage) - load_progress = pyqtSignal(int) + load_progress = QtCore.pyqtSignal(int) #: Signal emitted when a page finished loading (success as bool) - load_finished = pyqtSignal(bool) + load_finished = QtCore.pyqtSignal(bool) #: Signal emitted when a page's favicon changed (icon as QIcon) - icon_changed = pyqtSignal(QIcon) + icon_changed = QtCore.pyqtSignal(QtGui.QIcon) #: Signal emitted when a page's title changed (new title as str) - title_changed = pyqtSignal(str) + title_changed = QtCore.pyqtSignal(str) #: Signal emitted when this tab was pinned/unpinned (new pinned state as bool) - pinned_changed = pyqtSignal(bool) + pinned_changed = QtCore.pyqtSignal(bool) #: Signal emitted when a new tab should be opened (url as QUrl) - new_tab_requested = pyqtSignal(QUrl) + new_tab_requested = QtCore.pyqtSignal(QtCore.QUrl) #: Signal emitted when a page's URL changed (url as QUrl) - url_changed = pyqtSignal(QUrl) + url_changed = QtCore.pyqtSignal(QtCore.QUrl) #: Signal emitted when a tab's content size changed #: (new size as QSizeF) - contents_size_changed = pyqtSignal(QSizeF) + contents_size_changed = QtCore.pyqtSignal(QtCore.QSizeF) #: Signal emitted when a page requested full-screen (bool) - fullscreen_requested = pyqtSignal(bool) + fullscreen_requested = QtCore.pyqtSignal(bool) #: Signal emitted before load starts (URL as QUrl) - before_load_started = pyqtSignal(QUrl) + before_load_started = QtCore.pyqtSignal(QtCore.QUrl) # Signal emitted when a page's load status changed # (argument: usertypes.LoadStatus) - load_status_changed = pyqtSignal(usertypes.LoadStatus) + load_status_changed = QtCore.pyqtSignal(usertypes.LoadStatus) # Signal emitted before shutting down - shutting_down = pyqtSignal() + shutting_down = QtCore.pyqtSignal() # Signal emitted when a history item should be added - history_item_triggered = pyqtSignal(QUrl, QUrl, str) + history_item_triggered = QtCore.pyqtSignal(QtCore.QUrl, QtCore.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 = QtCore.pyqtSignal(TerminationStatus, int) # Hosts for which a certificate error happened. Shared between all tabs. # @@ -947,7 +941,7 @@ class AbstractTab(QWidget): def __init__(self, *, win_id: int, mode_manager: 'modeman.ModeManager', private: bool, - parent: QWidget = None) -> None: + parent: QtWidgets.QWidget = None) -> None: utils.unused(mode_manager) # needed for mypy self.is_private = private self.win_id = win_id @@ -962,7 +956,7 @@ class AbstractTab(QWidget): self.data = TabData() self._layout = miscwidgets.WrapperLayout(self) - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._progress = 0 self._load_status = usertypes.LoadStatus.none self._tab_event_filter = eventfilter.TabEventFilter( @@ -976,7 +970,7 @@ class AbstractTab(QWidget): self.before_load_started.connect(self._on_before_load_started) - def _set_widget(self, widget: QWidget) -> None: + def _set_widget(self, widget: QtWidgets.QWidget) -> None: # pylint: disable=protected-access self._widget = widget self.data.splitter = miscwidgets.InspectorSplitter( @@ -1009,7 +1003,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: QtCore.QEvent) -> None: """Send the given event to the underlying widget. The event will be sent via QApplication.postEvent. @@ -1028,35 +1022,35 @@ class AbstractTab(QWidget): return evt.posted = True # type: ignore[attr-defined] - QApplication.postEvent(recipient, evt) + QtWidgets.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: + @QtCore.pyqtSlot(QtCore.QUrl) + def _on_before_load_started(self, url: QtCore.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: + @QtCore.pyqtSlot(QtCore.QUrl) + def _on_url_changed(self, url: QtCore.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() + @QtCore.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) + @QtCore.pyqtSlot(usertypes.NavigationRequest) def _on_navigation_request( self, navigation: usertypes.NavigationRequest @@ -1084,7 +1078,7 @@ class AbstractTab(QWidget): navigation.url.errorString())) navigation.accepted = False - @pyqtSlot(bool) + @QtCore.pyqtSlot(bool) def _on_load_finished(self, ok: bool) -> None: assert self._widget is not None if sip.isdeleted(self._widget): @@ -1121,17 +1115,17 @@ class AbstractTab(QWidget): self._set_load_status(loadstatus) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_history_trigger(self) -> None: """Emit history_item_triggered based on backend-specific signal.""" raise NotImplementedError - @pyqtSlot(int) + @QtCore.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) -> QtCore.QUrl: raise NotImplementedError def progress(self) -> int: @@ -1140,11 +1134,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: QtCore.QUrl) -> None: qtutils.ensure_valid(url) self.before_load_started.emit(url) - def load_url(self, url: QUrl) -> None: + def load_url(self, url: QtCore.QUrl) -> None: raise NotImplementedError def reload(self, *, force: bool = False) -> None: @@ -1154,11 +1148,11 @@ class AbstractTab(QWidget): raise NotImplementedError def fake_key_press(self, - key: Qt.Key, - modifier: Qt.KeyboardModifier = Qt.NoModifier) -> None: + key: QtCore.Qt.Key, + modifier: QtCore.Qt.KeyboardModifier = QtCore.Qt.NoModifier) -> None: """Send a fake key event to this tab.""" - press_evt = QKeyEvent(QEvent.KeyPress, key, modifier, 0, 0, 0) - release_evt = QKeyEvent(QEvent.KeyRelease, key, modifier, + press_evt = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key, modifier, 0, 0, 0) + release_evt = QtGui.QKeyEvent(QtCore.QEvent.KeyRelease, key, modifier, 0, 0, 0) self.send_event(press_evt) self.send_event(release_evt) @@ -1198,7 +1192,7 @@ class AbstractTab(QWidget): def icon(self) -> None: raise NotImplementedError - def set_html(self, html: str, base_url: QUrl = QUrl()) -> None: + def set_html(self, html: str, base_url: QtCore.QUrl = QtCore.QUrl()) -> None: raise NotImplementedError def set_pinned(self, pinned: bool) -> None: @@ -1213,7 +1207,7 @@ class AbstractTab(QWidget): """ raise NotImplementedError - def grab_pixmap(self, rect: QRect = None) -> Optional[QPixmap]: + def grab_pixmap(self, rect: QtCore.QRect = None) -> Optional[QtGui.QPixmap]: """Grab a QPixmap of the displayed page. Returns None if we got a null pixmap from Qt. @@ -1233,7 +1227,7 @@ class AbstractTab(QWidget): try: qurl = self.url() url = qurl.toDisplayString( - QUrl.EncodeUnicode) # type: ignore[arg-type] + QtCore.QUrl.EncodeUnicode) # type: ignore[arg-type] except (AttributeError, RuntimeError) as exc: url = '<{}>'.format(exc.__class__.__name__) else: diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index 00d5e521f..af5cc2223 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 PyQt5.QtWidgets import QApplication, QTabBar -from PyQt5.QtCore 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 QtWidgets, QtCore class CommandDispatcher: @@ -197,16 +195,16 @@ class CommandDispatcher: """ cmdutils.check_exclusive((prev, next_, opposite), 'pno') if prev: - return QTabBar.SelectLeftTab + return QtWidgets.QTabBar.SelectLeftTab elif next_: - return QTabBar.SelectRightTab + return QtWidgets.QTabBar.SelectRightTab elif opposite: conf_selection = config.val.tabs.select_on_remove - if conf_selection == QTabBar.SelectLeftTab: - return QTabBar.SelectRightTab - elif conf_selection == QTabBar.SelectRightTab: - return QTabBar.SelectLeftTab - elif conf_selection == QTabBar.SelectPreviousTab: + if conf_selection == QtWidgets.QTabBar.SelectLeftTab: + return QtWidgets.QTabBar.SelectRightTab + elif conf_selection == QtWidgets.QTabBar.SelectRightTab: + return QtWidgets.QTabBar.SelectLeftTab + elif conf_selection == QtWidgets.QTabBar.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, QtCore.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[..., QtCore.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.RemovePassword | QUrl.DecodeReserved + flags = QtCore.QUrl.RemovePassword | QtCore.QUrl.DecodeReserved else: - flags = QUrl.RemovePassword | QUrl.FullyEncoded + flags = QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded - url = QUrl(self._current_url()) - url_query = QUrlQuery() + url = QtCore.QUrl(self._current_url()) + url_query = QtCore.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 = QtWidgets.QApplication.activeWindow() if active_win is None: # Not sure how you enter a command without an active window... raise cmdutils.CommandError( @@ -1099,7 +1097,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(QtCore.QUrl(f'qute://process/{proc.pid}'), newtab=True) if userscript: def _selection_callback(s): @@ -1163,7 +1161,7 @@ class CommandDispatcher: except qtutils.QtValueError: pass else: - env['QUTE_URL'] = url.toString(QUrl.FullyEncoded) + env['QUTE_URL'] = url.toString(QtCore.QUrl.FullyEncoded) try: runner = userscripts.run_async( @@ -1294,8 +1292,8 @@ class CommandDispatcher: current page's url. """ if url is None: - url = self._current_url().toString(QUrl.RemovePassword | - QUrl.FullyEncoded) + url = self._current_url().toString(QtCore.QUrl.RemovePassword | + QtCore.QUrl.FullyEncoded) try: objreg.get('bookmark-manager').delete(url) except KeyError: @@ -1312,7 +1310,7 @@ class CommandDispatcher: window: Open in a new window. jump: Jump to the "bookmarks" header. """ - url = QUrl('qute://bookmarks/') + url = QtCore.QUrl('qute://bookmarks/') if jump: url.setFragment('bookmarks') self._open(url, tab, bg, window) @@ -1341,7 +1339,7 @@ class CommandDispatcher: if mhtml_: raise cmdutils.CommandError("Can only download the current " "page as mhtml.") - url = QUrl.fromUserInput(url) + url = QtCore.QUrl.fromUserInput(url) urlutils.raise_cmdexc_if_invalid(url) download_manager.get(url, target=target) elif mhtml_: @@ -1406,7 +1404,7 @@ class CommandDispatcher: bg: Open in a background tab. window: Open in a new window. """ - url = QUrl('qute://history/') + url = QtCore.QUrl('qute://history/') self._open(url, tab, bg, window) @cmdutils.register(instance='command-dispatcher', name='help', @@ -1442,7 +1440,7 @@ class CommandDispatcher: path = 'settings.html#{}'.format(topic) else: raise cmdutils.CommandError("Invalid help topic {}!".format(topic)) - url = QUrl('qute://help/{}'.format(path)) + url = QtCore.QUrl('qute://help/{}'.format(path)) self._open(url, tab, bg, window) @cmdutils.register(instance='command-dispatcher', scope='window') @@ -1465,7 +1463,7 @@ class CommandDispatcher: if level.upper() not in log.LOG_LEVELS: raise cmdutils.CommandError("Invalid log level {}!".format(level)) - query = QUrlQuery() + query = QtCore.QUrlQuery() query.addQueryItem('level', level) if plain: query.addQueryItem('plain', cast(str, None)) @@ -1477,7 +1475,7 @@ class CommandDispatcher: raise cmdutils.CommandError(e) query.addQueryItem('logfilter', logfilter) - url = QUrl('qute://log') + url = QtCore.QUrl('qute://log') url.setQuery(query) self._open(url, tab, bg, window) @@ -1730,7 +1728,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(QtCore.QUrl(js_code)) except urlutils.Error as e: raise cmdutils.CommandError(str(e)) @@ -1758,15 +1756,15 @@ class CommandDispatcher: raise cmdutils.CommandError(str(e)) for keyinfo in sequence: - press_event = keyinfo.to_event(QEvent.KeyPress) - release_event = keyinfo.to_event(QEvent.KeyRelease) + press_event = keyinfo.to_event(QtCore.QEvent.KeyPress) + release_event = keyinfo.to_event(QtCore.QEvent.KeyRelease) if global_: - window = QApplication.focusWindow() + window = QtWidgets.QApplication.focusWindow() if window is None: raise cmdutils.CommandError("No focused window!") - QApplication.postEvent(window, press_event) - QApplication.postEvent(window, release_event) + QtWidgets.QApplication.postEvent(window, press_event) + QtWidgets.QApplication.postEvent(window, release_event) else: tab = self._current_widget() tab.send_event(press_event) @@ -1866,9 +1864,9 @@ class CommandDispatcher: if not window.isFullScreen(): window.state_before_fullscreen = window.windowState() if enter: - window.setWindowState(window.windowState() | Qt.WindowFullScreen) + window.setWindowState(window.windowState() | QtCore.Qt.WindowFullScreen) else: - window.setWindowState(window.windowState() ^ Qt.WindowFullScreen) + window.setWindowState(window.windowState() ^ QtCore.Qt.WindowFullScreen) log.misc.debug('state before fullscreen: {}'.format( - debug.qflags_key(Qt, window.state_before_fullscreen))) + debug.qflags_key(QtCore.Qt, window.state_before_fullscreen))) diff --git a/qutebrowser/browser/downloads.py b/qutebrowser/browser/downloads.py index 32bfd2693..b4dd859d8 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 PyQt5.QtCore 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 QtCore, sip class ModelRole(enum.IntEnum): """Custom download model roles.""" - item = Qt.UserRole + item = QtCore.Qt.UserRole # Remember the last used directory @@ -78,7 +75,7 @@ def init(): config.instance.changed.connect(_clear_last_used) -@pyqtSlot() +@QtCore.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.RemovePassword | QUrl.FullyEncoded) + q.url = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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(QtCore.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') + @QtCore.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(QtCore.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 = QtCore.pyqtSignal() + finished = QtCore.pyqtSignal() + error = QtCore.pyqtSignal(str) + cancelled = QtCore.pyqtSignal() + remove_requested = QtCore.pyqtSignal() + pdfjs_requested = QtCore.pyqtSignal(str, QtCore.QUrl) def __init__(self, manager, parent=None): super().__init__(parent) @@ -565,7 +562,7 @@ class AbstractDownloadItem(QObject): """Actual cancel implementation.""" raise NotImplementedError - @pyqtSlot() + @QtCore.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() + @QtCore.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() + @QtCore.pyqtSlot() def retry(self): """Retry a failed download.""" raise NotImplementedError - @pyqtSlot() + @QtCore.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) -> QtCore.QUrl: """Get the download's URL (i.e. where the file is downloaded from).""" raise NotImplementedError - def origin(self) -> QUrl: + def origin(self) -> QtCore.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() + @QtCore.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)) + QtCore.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(QtCore.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 = QtCore.pyqtSignal(int) + end_remove_row = QtCore.pyqtSignal() + begin_insert_row = QtCore.pyqtSignal(int) + end_insert_row = QtCore.pyqtSignal() + data_changed = QtCore.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() + @QtCore.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: + @QtCore.pyqtSlot(str, QtCore.QUrl) + def _on_pdfjs_requested(self, filename: str, original_url: QtCore.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: QtCore.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) + @QtCore.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) + @QtCore.pyqtSlot(str) def _on_error(self, msg): """Display error message on download errors.""" message.error("Download error: {}".format(msg)) - @pyqtSlot(AbstractDownloadItem) + @QtCore.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() + @QtCore.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(QtCore.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(QtCore.QModelIndex(), 0, -1) return assert idx >= 0, idx if webengine: idx += len(self._qtnetwork_manager.downloads) - self.beginInsertRows(QModelIndex(), idx, idx) + self.beginInsertRows(QtCore.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(QtCore.QModelIndex(), 0, -1) return assert idx >= 0, idx if webengine: idx += len(self._qtnetwork_manager.downloads) - self.beginRemoveRows(QModelIndex(), idx, idx) + self.beginRemoveRows(QtCore.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.DisplayRole): + def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole): """Simple constant header.""" - if (section == 0 and orientation == Qt.Horizontal and - role == Qt.DisplayRole): + if (section == 0 and orientation == QtCore.Qt.Horizontal and + role == QtCore.Qt.DisplayRole): return "Downloads" else: return "" @@ -1283,15 +1280,15 @@ class DownloadModel(QAbstractListModel): return None item = self[index.row()] - if role == Qt.DisplayRole: + if role == QtCore.Qt.DisplayRole: data: Any = str(item) - elif role == Qt.ForegroundRole: + elif role == QtCore.Qt.ForegroundRole: data = item.get_status_color('fg') - elif role == Qt.BackgroundRole: + elif role == QtCore.Qt.BackgroundRole: data = item.get_status_color('bg') elif role == ModelRole.item: data = item - elif role == Qt.ToolTipRole: + elif role == QtCore.Qt.ToolTipRole: if item.error_msg is None: data = None else: @@ -1306,10 +1303,10 @@ class DownloadModel(QAbstractListModel): The default would be Qt.ItemIsEnabled | Qt.ItemIsSelectable. """ if not index.isValid(): - return Qt.ItemFlags() - return Qt.ItemIsEnabled | Qt.ItemNeverHasChildren + return QtCore.Qt.ItemFlags() + return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemNeverHasChildren - def rowCount(self, parent=QModelIndex()): + def rowCount(self, parent=QtCore.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 69c58741a..5edead500 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 PyQt5.QtCore import pyqtSlot, QSize, Qt -from PyQt5.QtWidgets 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 QtWidgets, QtCore _ActionListType = MutableSequence[ @@ -38,7 +36,7 @@ _ActionListType = MutableSequence[ ] -class DownloadView(QListView): +class DownloadView(QtWidgets.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(QtWidgets.QStyleFactory.create('Fusion')) stylesheet.set_register(self) - self.setResizeMode(QListView.Adjust) - self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) - self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) - self.setFocusPolicy(Qt.NoFocus) - self.setFlow(QListView.LeftToRight) + self.setResizeMode(QtWidgets.QListView.Adjust) + self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.setSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed) + self.setFocusPolicy(QtCore.Qt.NoFocus) + self.setFlow(QtWidgets.QListView.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.CustomContextMenu) + self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) self.customContextMenuRequested.connect(self.show_context_menu) self.clicked.connect(self.on_clicked) @@ -86,7 +84,7 @@ class DownloadView(QListView): count = model.rowCount() return utils.get_repr(self, count=count) - @pyqtSlot() + @QtCore.pyqtSlot() def _update_geometry(self): """Wrapper to call updateGeometry. @@ -95,7 +93,7 @@ class DownloadView(QListView): """ self.updateGeometry() - @pyqtSlot(bool) + @QtCore.pyqtSlot(bool) def on_fullscreen_requested(self, on): """Hide/show the downloadview when entering/leaving fullscreen.""" if on: @@ -103,7 +101,7 @@ class DownloadView(QListView): else: self.show() - @pyqtSlot('QModelIndex') + @QtCore.pyqtSlot('QModelIndex') def on_clicked(self, index): """Handle clicking of an item. @@ -149,7 +147,7 @@ class DownloadView(QListView): actions.append(("Remove all finished", model.download_clear)) return actions - @pyqtSlot('QPoint') + @QtCore.pyqtSlot('QPoint') def show_context_menu(self, point): """Show the context menu.""" index = self.indexAt(point) @@ -157,7 +155,7 @@ class DownloadView(QListView): item = self.model().data(index, downloads.ModelRole.item) else: item = None - self._menu = QMenu(self) + self._menu = QtWidgets.QMenu(self) actions = self._get_menu_actions(item) for (name, handler) in actions: if name is None and handler is None: @@ -182,8 +180,8 @@ class DownloadView(QListView): margins = self.contentsMargins() height = (bottom + margins.top() + margins.bottom() + 2 * self.spacing()) - size = QSize(0, height) + size = QtCore.QSize(0, height) else: - size = QSize(0, 0) + size = QtCore.QSize(0, 0) qtutils.ensure_valid(size) return size diff --git a/qutebrowser/browser/eventfilter.py b/qutebrowser/browser/eventfilter.py index 0b5fab096..0af93482a 100644 --- a/qutebrowser/browser/eventfilter.py +++ b/qutebrowser/browser/eventfilter.py @@ -19,15 +19,14 @@ """Event handling for a browser tab.""" -from PyQt5.QtCore import QObject, QEvent, Qt, QTimer - from qutebrowser.config import config from qutebrowser.utils import message, log, usertypes, qtutils from qutebrowser.misc import objects from qutebrowser.keyinput import modeman +from qutebrowser.qt import QtCore -class ChildEventFilter(QObject): +class ChildEventFilter(QtCore.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.ChildAdded: + if event.type() == QtCore.QEvent.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.ChildRemoved: + elif event.type() == QtCore.QEvent.ChildRemoved: child = event.child() log.misc.debug("{}: removed child {}".format(obj, child)) return False -class TabEventFilter(QObject): +class TabEventFilter(QtCore.QObject): """Handle mouse/keyboard events on a tab. @@ -81,10 +80,10 @@ class TabEventFilter(QObject): super().__init__(parent) self._tab = tab self._handlers = { - QEvent.MouseButtonPress: self._handle_mouse_press, - QEvent.MouseButtonRelease: self._handle_mouse_release, - QEvent.Wheel: self._handle_wheel, - QEvent.KeyRelease: self._handle_key_release, + QtCore.QEvent.MouseButtonPress: self._handle_mouse_press, + QtCore.QEvent.MouseButtonRelease: self._handle_mouse_release, + QtCore.QEvent.Wheel: self._handle_wheel, + QtCore.QEvent.KeyRelease: self._handle_key_release, } self._ignore_wheel_event = False self._check_insertmode_on_release = False @@ -99,9 +98,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.LeftButton | Qt.RightButton) + e.buttons() == QtCore.Qt.LeftButton | QtCore.Qt.RightButton) - if e.button() in [Qt.XButton1, Qt.XButton2] or is_rocker_gesture: + if e.button() in [QtCore.Qt.XButton1, QtCore.Qt.XButton2] or is_rocker_gesture: self._mousepress_backforward(e) return True @@ -112,7 +111,7 @@ class TabEventFilter(QObject): log.mouse.warning("Ignoring invalid click at {}".format(pos)) return False - if e.button() != Qt.NoButton: + if e.button() != QtCore.Qt.NoButton: self._tab.elements.find_at_pos(pos, self._mousepress_insertmode_cb) return False @@ -128,7 +127,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) + QtCore.QTimer.singleShot(0, self._mouserelease_insertmode) return False def _handle_wheel(self, e): @@ -150,7 +149,7 @@ class TabEventFilter(QObject): if mode == usertypes.KeyMode.hint: return True - elif e.modifiers() & Qt.ControlModifier: + elif e.modifiers() & QtCore.Qt.ControlModifier: if mode == usertypes.KeyMode.passthrough: return False @@ -240,17 +239,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.XButton1, Qt.XButton2]): + e.button() in [QtCore.Qt.XButton1, QtCore.Qt.XButton2]): # Back and forward on mice are disabled return - if e.button() in [Qt.XButton1, Qt.LeftButton]: + if e.button() in [QtCore.Qt.XButton1, QtCore.Qt.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.XButton2, Qt.RightButton]: + elif e.button() in [QtCore.Qt.XButton2, QtCore.Qt.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 5abb9a137..61594b329 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 -from PyQt5.QtCore 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 QtCore gm_manager = cast('GreasemonkeyManager', None) @@ -221,7 +220,7 @@ class MatchingScripts: """All userscripts registered to run on a particular url.""" - url: QUrl + url: QtCore.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) @@ -238,7 +237,7 @@ class GreasemonkeyMatcher: def __init__(self, url): self._url = url - self._url_string = url.toString(QUrl.FullyEncoded) + self._url_string = url.toString(QtCore.QUrl.FullyEncoded) self.is_greaseable = url.scheme() in self.GREASEABLE_SCHEMES def _match_pattern(self, pattern): @@ -263,7 +262,7 @@ class GreasemonkeyMatcher: return (matching_includes or matching_match) and not matching_excludes -class GreasemonkeyManager(QObject): +class GreasemonkeyManager(QtCore.QObject): """Manager of userscripts and a Greasemonkey compatible environment. @@ -273,7 +272,7 @@ class GreasemonkeyManager(QObject): considered obsolete. """ - scripts_reloaded = pyqtSignal() + scripts_reloaded = QtCore.pyqtSignal() def __init__(self, parent=None): super().__init__(parent) @@ -412,7 +411,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(QtCore.QUrl(url), target=target, auto_remove=True) download.requested_url = url self._in_progress_dls.append(download) diff --git a/qutebrowser/browser/hints.py b/qutebrowser/browser/hints.py index 2e4e8e4b4..4e5157cf0 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 PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, Qt, QUrl -from PyQt5.QtWidgets import QLabel +from qutebrowser.qt import QtWidgets 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 QtCore + 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(QtWidgets.QLabel): """A label for a link. @@ -92,12 +92,12 @@ class HintLabel(QLabel): self._context = context self.elem = elem - self.setTextFormat(Qt.RichText) + self.setTextFormat(QtCore.Qt.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.WA_StyledBackground, True) + self.setAttribute(QtCore.Qt.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() + @QtCore.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: QtCore.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: QtCore.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.FullyEncoded | QUrl.RemovePassword + flags = QtCore.QUrl.FullyEncoded | QtCore.QUrl.RemovePassword if url.scheme() == 'mailto': - flags |= QUrl.RemoveScheme + flags |= QtCore.QUrl.RemoveScheme urlstr = url.toString(flags) # type: ignore[arg-type] 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: QtCore.QUrl, context: HintContext) -> None: """Run the command based on a hint URL.""" - urlstr = url.toString(QUrl.FullyEncoded) # type: ignore[arg-type] + urlstr = url.toString(QtCore.QUrl.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: QtCore.QUrl, context: HintContext) -> None: """Preset a commandline text based on a hint URL.""" - flags = QUrl.FullyEncoded + flags = QtCore.QUrl.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.FullyEncoded + flags = QtCore.QUrl.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: QtCore.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.FullyEncoded | QUrl.RemovePassword) # type: ignore[arg-type] + QtCore.QUrl.FullyEncoded | QtCore.QUrl.RemovePassword) # type: ignore[arg-type] 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(QtCore.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 = QtCore.pyqtSignal(str) - def __init__(self, win_id: int, parent: QObject = None) -> None: + def __init__(self, win_id: int, parent: QtCore.QObject = None) -> None: """Constructor.""" super().__init__(parent) self._win_id = win_id @@ -856,7 +856,7 @@ class HintManager(QObject): # unpacking gets us the first (and only) key in the dict. self._fire(*visible) - @pyqtSlot(str) + @QtCore.pyqtSlot(str) def handle_partial_key(self, keystr: str) -> None: """Handle a new partial keypress.""" if self._context is None: @@ -1029,7 +1029,7 @@ class HintManager(QObject): else: self._fire(keystring) - @pyqtSlot(usertypes.KeyMode) + @QtCore.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 d2046345f..ab39bed04 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 PyQt5.QtCore import pyqtSlot, QUrl, QObject, pyqtSignal -from PyQt5.QtWidgets 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 QtWidgets, QtCore 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 = QtWidgets.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() + QtWidgets.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() + QtWidgets.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() + QtWidgets.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[QtCore.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[QtCore.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 = QtCore.pyqtSignal() # one url cleared - url_cleared = pyqtSignal(QUrl) + url_cleared = QtCore.pyqtSignal(QtCore.QUrl) def __init__(self, database: sql.Database, progress: HistoryProgress, - parent: Optional[QObject] = None) -> None: + parent: Optional[QtCore.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() + QtWidgets.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() + QtWidgets.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 = QtCore.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() + QtWidgets.QApplication.processEvents() self.completion.insert_batch(data, replace=True) - QApplication.processEvents() + QtWidgets.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 = QtCore.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) + @QtCore.pyqtSlot(QtCore.QUrl, QtCore.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 = QtCore.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.RemovePassword | QUrl.FullyEncoded) + return url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded) def _format_completion_url(self, url): - return url.toString(QUrl.RemovePassword) + return url.toString(QtCore.QUrl.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[QtCore.QObject] = None) -> None: """Initialize the web history. Args: diff --git a/qutebrowser/browser/inspector.py b/qutebrowser/browser/inspector.py index 2b40e97e4..b2c6d91b1 100644 --- a/qutebrowser/browser/inspector.py +++ b/qutebrowser/browser/inspector.py @@ -24,15 +24,15 @@ import binascii import enum from typing import cast, Optional -from PyQt5.QtWidgets import QWidget -from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QEvent -from PyQt5.QtGui import QCloseEvent +from qutebrowser.qt import QtWidgets +from qutebrowser.qt import QtGui from qutebrowser.browser import eventfilter from qutebrowser.config import configfiles from qutebrowser.utils import log, usertypes from qutebrowser.keyinput import modeman from qutebrowser.misc import miscwidgets +from qutebrowser.qt import QtCore class Position(enum.Enum): @@ -51,7 +51,7 @@ class Error(Exception): """Raised when the inspector could not be initialized.""" -class _EventFilter(QObject): +class _EventFilter(QtCore.QObject): """Event filter to enter insert mode when inspector was clicked. @@ -66,16 +66,16 @@ class _EventFilter(QObject): the QWebInspector. """ - clicked = pyqtSignal() + clicked = QtCore.pyqtSignal() - def eventFilter(self, _obj: QObject, event: QEvent) -> bool: + def eventFilter(self, _obj: QtCore.QObject, event: QtCore.QEvent) -> bool: """Translate mouse presses to a clicked signal.""" - if event.type() == QEvent.MouseButtonPress: + if event.type() == QtCore.QEvent.MouseButtonPress: self.clicked.emit() return False -class AbstractWebInspector(QWidget): +class AbstractWebInspector(QtWidgets.QWidget): """Base class for QtWebKit/QtWebEngine inspectors. @@ -87,13 +87,13 @@ class AbstractWebInspector(QWidget): recreate: Emitted when the inspector should be recreated. """ - recreate = pyqtSignal() + recreate = QtCore.pyqtSignal() def __init__(self, splitter: 'miscwidgets.InspectorSplitter', win_id: int, - parent: QWidget = None) -> None: + parent: QtWidgets.QWidget = None) -> None: super().__init__(parent) - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._layout = miscwidgets.WrapperLayout(self) self._splitter = splitter self._position: Optional[Position] = None @@ -105,7 +105,7 @@ class AbstractWebInspector(QWidget): eventfilter=self._event_filter, parent=self) - def _set_widget(self, widget: QWidget) -> None: + def _set_widget(self, widget: QtWidgets.QWidget) -> None: self._widget = widget self._widget.setWindowTitle("Web Inspector") self._widget.installEventFilter(self._child_event_filter) @@ -130,7 +130,7 @@ class AbstractWebInspector(QWidget): """ return False - @pyqtSlot() + @QtCore.pyqtSlot() def _on_clicked(self) -> None: """Enter insert mode if a docked inspector was clicked.""" if self._position != Position.window: @@ -192,17 +192,17 @@ class AbstractWebInspector(QWidget): if not ok: log.init.warning("Error while loading geometry.") - def closeEvent(self, _e: QCloseEvent) -> None: + def closeEvent(self, _e: QtGui.QCloseEvent) -> None: """Save the geometry when closed.""" data = self._widget.saveGeometry().data() geom = base64.b64encode(data).decode('ASCII') configfiles.state['inspector']['window'] = geom - def inspect(self, page: QWidget) -> None: + def inspect(self, page: QtWidgets.QWidget) -> None: """Inspect the given QWeb(Engine)Page.""" raise NotImplementedError - @pyqtSlot() + @QtCore.pyqtSlot() def shutdown(self) -> None: """Clean up the inspector.""" self.close() diff --git a/qutebrowser/browser/navigate.py b/qutebrowser/browser/navigate.py index 6217c8d00..efc36899d 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 PyQt5.QtCore import QUrl +from qutebrowser.qt import QtCore 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.FullyEncoded), - lambda url, host: url.setHost(host, QUrl.StrictMode)), + lambda url: url.host(QtCore.QUrl.FullyEncoded), + lambda url, host: url.setHost(host, QtCore.QUrl.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.FullyEncoded), - lambda url, path: url.setPath(path, QUrl.StrictMode)), + lambda url: url.path(QtCore.QUrl.FullyEncoded), + lambda url, path: url.setPath(path, QtCore.QUrl.StrictMode)), ('query', - lambda url: url.query(QUrl.FullyEncoded), - lambda url, query: url.setQuery(query, QUrl.StrictMode)), + lambda url: url.query(QtCore.QUrl.FullyEncoded), + lambda url, query: url.setQuery(query, QtCore.QUrl.StrictMode)), ('anchor', - lambda url: url.fragment(QUrl.FullyEncoded), - lambda url, fragment: url.setFragment(fragment, QUrl.StrictMode)), + lambda url: url.fragment(QtCore.QUrl.FullyEncoded), + lambda url, fragment: url.setFragment(fragment, QtCore.QUrl.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 = QtCore.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.RemoveFragment | QUrl.RemoveQuery) - path = url.path(QUrl.FullyEncoded) + url = url.adjusted(QtCore.QUrl.RemoveFragment | QtCore.QUrl.RemoveQuery) + path = url.path(QtCore.QUrl.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.StrictMode) + url.setPath(path, QtCore.QUrl.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.RemoveFragment | QUrl.RemoveQuery) + return url.adjusted(QtCore.QUrl.RemoveFragment | QtCore.QUrl.RemoveQuery) def _find_prevnext(prev, elems): diff --git a/qutebrowser/browser/network/pac.py b/qutebrowser/browser/network/pac.py index 3a544c78f..c21e4f982 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 PyQt5.QtCore import QObject, pyqtSignal, pyqtSlot, QUrl -from PyQt5.QtNetwork import (QNetworkProxy, QNetworkRequest, QHostInfo, - QNetworkReply, QNetworkAccessManager, - QHostAddress) -from PyQt5.QtQml import QJSEngine, QJSValue - from qutebrowser.utils import log, utils, qtutils, resources +from qutebrowser.qt import QtQml, QtNetwork, QtCore 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 = QtCore.pyqtSlot(*args, result=QtQml.QJSValue) return deco(new_method) return _decorator -class _PACContext(QObject): +class _PACContext(QtCore.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.NoError or not ips.addresses(): + ips = QtNetwork.QHostInfo.fromName(host) + if ips.error() != QtNetwork.QHostInfo.NoError or not ips.addresses(): err_f = "Failed to resolve host during PAC evaluation: {}" log.network.info(err_f.format(host)) - return QJSValue(QJSValue.NullValue) + return QtQml.QJSValue(QtQml.QJSValue.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.LocalHost).toString() + return QtNetwork.QHostAddress(QtNetwork.QHostAddress.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.NoProxy) + return QtNetwork.QNetworkProxy(QtNetwork.QNetworkProxy.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.HttpProxy, host, port) + return QtNetwork.QNetworkProxy(QtNetwork.QNetworkProxy.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.Socks5Proxy, host, port) + return QtNetwork.QNetworkProxy(QtNetwork.QNetworkProxy.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 = QtQml.QJSEngine() - self._engine.installExtensions(QJSEngine.ConsoleExtension) + self._engine.installExtensions(QtQml.QJSEngine.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.PrettyDecoded + string_flags = QtCore.QUrl.PrettyDecoded else: - string_flags = QUrl.RemoveUserInfo # type: ignore[assignment] + string_flags = QtCore.QUrl.RemoveUserInfo # type: ignore[assignment] if query.url().scheme() == 'https': - string_flags |= QUrl.RemovePath # type: ignore[assignment] - string_flags |= QUrl.RemoveQuery # type: ignore[assignment] + string_flags |= QtCore.QUrl.RemovePath # type: ignore[assignment] + string_flags |= QtCore.QUrl.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(QtCore.QObject): """Asynchronous fetcher of PAC files.""" - finished = pyqtSignal() + finished = QtCore.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.NoProxy)) + self._manager: Optional[QtNetwork.QNetworkAccessManager] = QtNetwork.QNetworkAccessManager() + self._manager.setProxy(QtNetwork.QNetworkProxy(QtNetwork.QNetworkProxy.NoProxy)) self._pac = None self._error_message = None self._reply = None @@ -269,14 +264,14 @@ 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(QtNetwork.QNetworkRequest(self._pac_url)) self._reply.finished.connect( # type: ignore[attr-defined] self._finish) - @pyqtSlot() + @QtCore.pyqtSlot() def _finish(self): assert self._reply is not None - if self._reply.error() != QNetworkReply.NoError: + if self._reply.error() != QtNetwork.QNetworkReply.NoError: error = "Can't fetch PAC file from URL, error code {}: {}" self._error_message = error.format( self._reply.error(), self._reply.errorString()) @@ -335,4 +330,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.HttpProxy, error_host, 9)] + return [QtNetwork.QNetworkProxy(QtNetwork.QNetworkProxy.HttpProxy, error_host, 9)] diff --git a/qutebrowser/browser/network/proxy.py b/qutebrowser/browser/network/proxy.py index 2c0187837..80a08f62a 100644 --- a/qutebrowser/browser/network/proxy.py +++ b/qutebrowser/browser/network/proxy.py @@ -19,13 +19,11 @@ """Handling of proxies.""" -from PyQt5.QtCore import QUrl, pyqtSlot -from PyQt5.QtNetwork 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 QtNetwork, QtCore 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) + QtNetwork.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() +@QtCore.pyqtSlot() def shutdown(): - QNetworkProxyFactory.setApplicationProxyFactory( + QtNetwork.QNetworkProxyFactory.setApplicationProxyFactory( None) # type: ignore[arg-type] -class ProxyFactory(QNetworkProxyFactory): +class ProxyFactory(QtNetwork.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.NoProxy: + if proxy.type() == QtNetwork.QNetworkProxy.NoProxy: return capabilities = proxy.capabilities() - lookup_cap = QNetworkProxy.HostNameLookupCapability + lookup_cap = QtNetwork.QNetworkProxy.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 = QtNetwork.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(QtCore.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 c180c55f8..0942c78c3 100644 --- a/qutebrowser/browser/pdfjs.py +++ b/qutebrowser/browser/pdfjs.py @@ -22,10 +22,9 @@ import os -from PyQt5.QtCore import QUrl, QUrlQuery - from qutebrowser.utils import resources, javascript, jinja, standarddir, log from qutebrowser.config import config +from qutebrowser.qt import QtCore _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 = QtCore.QUrl('qute://pdfjs/file') + url_query = QtCore.QUrlQuery() url_query.addQueryItem('filename', filename) url.setQuery(url_query) js_url = javascript.to_js( - url.toString(QUrl.FullyEncoded)) # type: ignore[arg-type] + url.toString(QtCore.QUrl.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') + QtCore.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: QtCore.QUrl) -> QtCore.QUrl: """Get the URL to be opened to view a local PDF.""" - url = QUrl('qute://pdfjs/web/viewer.html') - query = QUrlQuery() + url = QtCore.QUrl('qute://pdfjs/web/viewer.html') + query = QtCore.QUrlQuery() query.addQueryItem('filename', filename) # read from our JS query.addQueryItem('file', '') # to avoid pdfjs opening the default PDF - urlstr = original_url.toString(QUrl.FullyEncoded) # type: ignore[arg-type] + urlstr = original_url.toString(QtCore.QUrl.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 8adb7ea20..d8f1e645f 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 PyQt5.QtCore import pyqtSlot, pyqtSignal, QTimer, QUrl -from PyQt5.QtWidgets import QApplication -from PyQt5.QtNetwork import QNetworkRequest, QNetworkReply, QNetworkAccessManager +from qutebrowser.qt import QtWidgets 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 QtNetwork, QtCore @dataclasses.dataclass class _RetryInfo: - request: QNetworkRequest - manager: QNetworkAccessManager + request: QtNetwork.QNetworkRequest + manager: QtNetwork.QNetworkAccessManager class DownloadItem(downloads.AbstractDownloadItem): @@ -83,7 +81,7 @@ class DownloadItem(downloads.AbstractDownloadItem): """ _MAX_REDIRECTS = 10 - adopt_download = pyqtSignal(object) # DownloadItem + adopt_download = QtCore.pyqtSignal(object) # DownloadItem def __init__(self, reply, manager): """Constructor. @@ -162,8 +160,8 @@ 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.NoError: - QTimer.singleShot(0, lambda: self._die(reply.errorString())) + if reply.error() != QtNetwork.QNetworkReply.NoError: + QtCore.QTimer.singleShot(0, lambda: self._die(reply.errorString())) def _do_cancel(self): self._read_timer.stop() @@ -176,7 +174,7 @@ class DownloadItem(downloads.AbstractDownloadItem): self.fileobj.close() self.cancelled.emit() - @pyqtSlot() + @QtCore.pyqtSlot() def retry(self): """Retry a failed download.""" assert self.done @@ -199,20 +197,20 @@ class DownloadItem(downloads.AbstractDownloadItem): filename = getattr(self.fileobj, 'name', None) return filename - def url(self) -> QUrl: + def url(self) -> QtCore.QUrl: # Note: self._reply is deleted when the download finishes return self._url - def origin(self) -> QUrl: + def origin(self) -> QtCore.QUrl: if self._reply is None: - return QUrl() + return QtCore.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 QtCore.QUrl() def _ensure_can_set_filename(self, filename): if self.fileobj is not None: # pragma: no cover @@ -286,7 +284,7 @@ class DownloadItem(downloads.AbstractDownloadItem): self.fileobj.write(self._reply.readAll()) if self._autoclose: self.fileobj.close() - self.successful = self._reply.error() == QNetworkReply.NoError + self.successful = self._reply.error() == QtNetwork.QNetworkReply.NoError self._reply.close() self._reply.deleteLater() self._reply = None @@ -295,7 +293,7 @@ class DownloadItem(downloads.AbstractDownloadItem): log.downloads.debug("Download {} finished".format(self.basename)) self.data_changed.emit() - @pyqtSlot() + @QtCore.pyqtSlot() def _on_reply_finished(self): """Clean up when the download was finished. @@ -316,7 +314,7 @@ class DownloadItem(downloads.AbstractDownloadItem): # clean up. self._finish_download() - @pyqtSlot() + @QtCore.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: @@ -331,21 +329,21 @@ class DownloadItem(downloads.AbstractDownloadItem): except OSError as e: self._die(e.strerror) - @pyqtSlot('QNetworkReply::NetworkError') + @QtCore.pyqtSlot('QNetworkReply::NetworkError') def _on_reply_error(self, code): """Handle QNetworkReply errors.""" - if code == QNetworkReply.OperationCanceledError: + if code == QtNetwork.QNetworkReply.OperationCanceledError: return if self._reply is None: error = "Unknown error: {}".format( - debug.qenum_key(QNetworkReply, code)) + debug.qenum_key(QtNetwork.QNetworkReply, code)) else: error = self._reply.errorString() self._die(error) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_read_timer_timeout(self): """Read some bytes from the QNetworkReply periodically.""" assert self._reply is not None @@ -355,7 +353,7 @@ class DownloadItem(downloads.AbstractDownloadItem): if data is not None: self._buffer.write(data) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_meta_data_changed(self): """Update the download's metadata.""" if self._reply is None: @@ -372,7 +370,7 @@ class DownloadItem(downloads.AbstractDownloadItem): """ assert self._reply is not None redirect = self._reply.attribute( - QNetworkRequest.RedirectionTargetAttribute) + QtNetwork.QNetworkRequest.RedirectionTargetAttribute) if redirect is None or redirect.isEmpty(): return False new_url = self._reply.url().resolved(redirect) @@ -430,7 +428,7 @@ class DownloadManager(downloads.AbstractDownloadManager): win_id=None, tab_id=None, private=config.val.content.private_browsing, parent=self) - @pyqtSlot('QUrl') + @QtCore.pyqtSlot('QUrl') def get(self, url, cache=True, **kwargs): """Start a download with a link URL. @@ -446,12 +444,12 @@ class DownloadManager(downloads.AbstractDownloadManager): urlutils.invalid_url_error(url, "start download") return None - req = QNetworkRequest(url) + req = QtNetwork.QNetworkRequest(url) user_agent = websettings.user_agent(url) - req.setHeader(QNetworkRequest.UserAgentHeader, user_agent) + req.setHeader(QtNetwork.QNetworkRequest.UserAgentHeader, user_agent) if not cache: - req.setAttribute(QNetworkRequest.CacheSaveControlAttribute, False) + req.setAttribute(QtNetwork.QNetworkRequest.CacheSaveControlAttribute, False) return self.get_request(req, **kwargs) @@ -511,8 +509,8 @@ class DownloadManager(downloads.AbstractDownloadManager): """ # WORKAROUND for Qt corrupting data loaded from cache: # https://bugreports.qt.io/browse/QTBUG-42757 - request.setAttribute(QNetworkRequest.CacheLoadControlAttribute, - QNetworkRequest.AlwaysNetwork) + request.setAttribute(QtNetwork.QNetworkRequest.CacheLoadControlAttribute, + QtNetwork.QNetworkRequest.AlwaysNetwork) if suggested_fn is None: suggested_fn = self._get_suggested_filename(request) @@ -538,7 +536,7 @@ class DownloadManager(downloads.AbstractDownloadManager): reply = qnam.get(request) return self.fetch(reply, **kwargs) - @pyqtSlot('QNetworkReply') + @QtCore.pyqtSlot('QNetworkReply') def fetch(self, reply, *, target=None, auto_remove=False, suggested_filename=None, prompt_download_directory=None): """Download a QNetworkReply to disk. @@ -608,6 +606,6 @@ class DownloadManager(downloads.AbstractDownloadManager): def init(): """Initialize the global QtNetwork download manager.""" - download_manager = DownloadManager(parent=QApplication.instance()) + download_manager = DownloadManager(parent=QtWidgets.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 68e36d249..c2fc257fc 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 PyQt5.QtCore 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 QtCore, 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: QtCore.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[[QtCore.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: QtCore.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: QtCore.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.NormalizePathSegments | # type: ignore[arg-type] - QUrl.StripTrailingSlash) + QtCore.QUrl.NormalizePathSegments | # type: ignore[arg-type] + QtCore.QUrl.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 = QtCore.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: QtCore.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: QtCore.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 [QtCore.QUrl("qute://tabs/"), QtCore.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: QtCore.QUrl) -> _HandlerRet: """Handler for qute://history. Display and serve history.""" if url.path() == '/data': - q_offset = QUrlQuery(url).queryItemValue("offset") + q_offset = QtCore.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 = QtCore.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: QtCore.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: QtCore.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: QtCore.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: QtCore.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: QtCore.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 = QtCore.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: QtCore.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: QtCore.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: QtCore.QUrl) -> _HandlerRet: """Handler for qute://settings/set.""" - query = QUrlQuery(url) - option = query.queryItemValue('option', QUrl.FullyDecoded) - value = query.queryItemValue('value', QUrl.FullyDecoded) + query = QtCore.QUrlQuery(url) + option = query.queryItemValue('option', QtCore.QUrl.FullyDecoded) + value = query.queryItemValue('value', QtCore.QUrl.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: QtCore.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: QtCore.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: QtCore.QUrl) -> _HandlerRet: """Handler for qute://back. Simple page to free ram / lazy load a site, goes back on focusing the tab. @@ -500,14 +498,14 @@ def qute_back(url: QUrl) -> _HandlerRet: @add_handler('configdiff') -def qute_configdiff(_url: QUrl) -> _HandlerRet: +def qute_configdiff(_url: QtCore.QUrl) -> _HandlerRet: """Handler for qute://configdiff.""" data = config.instance.dump_userconfig().encode('utf-8') return 'text/plain', data @add_handler('pastebin-version') -def qute_pastebin_version(_url: QUrl) -> _HandlerRet: +def qute_pastebin_version(_url: QtCore.QUrl) -> _HandlerRet: """Handler that pastebins the version string.""" version.pastebin_version() return 'text/plain', b'Paste called.' @@ -520,14 +518,14 @@ def _pdf_path(filename: str) -> str: @add_handler('pdfjs') -def qute_pdfjs(url: QUrl) -> _HandlerRet: +def qute_pdfjs(url: QtCore.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 = QtCore.QUrlQuery(url).queryItemValue('filename') if not filename: raise UrlInvalidError("Missing filename") if '/' in filename or os.sep in filename: @@ -541,7 +539,7 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet: return mimetype, data if url.path() == '/web/viewer.html': - query = QUrlQuery(url) + query = QtCore.QUrlQuery(url) filename = query.queryItemValue("filename") if not filename: raise UrlInvalidError("Missing filename") @@ -551,7 +549,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(QtCore.QUrl(source)) data = pdfjs.generate_pdfjs_page(filename, url) return 'text/html', data @@ -571,7 +569,7 @@ def qute_pdfjs(url: QUrl) -> _HandlerRet: @add_handler('warning') -def qute_warning(url: QUrl) -> _HandlerRet: +def qute_warning(url: QtCore.QUrl) -> _HandlerRet: """Handler for qute://warning.""" path = url.path() if path == '/webkit': @@ -588,7 +586,7 @@ def qute_warning(url: QUrl) -> _HandlerRet: @add_handler('resource') -def qute_resource(url: QUrl) -> _HandlerRet: +def qute_resource(url: QtCore.QUrl) -> _HandlerRet: """Handler for qute://resource.""" path = url.path().lstrip('/') mimetype = utils.guess_mimetype(path, fallback=True) diff --git a/qutebrowser/browser/shared.py b/qutebrowser/browser/shared.py index f195bbf28..1b1f1e3d3 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 PyQt5.QtCore 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 QtCore 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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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 ignore_certificate_error( *, - request_url: QUrl, - first_party_url: QUrl, + request_url: QtCore.QUrl, + first_party_url: QtCore.QUrl, error: usertypes.AbstractCertificateErrorWrapper, - abort_on: Iterable[pyqtBoundSignal], + abort_on: Iterable[QtCore.pyqtBoundSignal], ) -> bool: """Display a certificate error question. @@ -187,7 +186,7 @@ def ignore_certificate_error( first_party_url.isValid() and not request_url.matches( first_party_url, - QUrl.RemoveScheme)) # type: ignore[arg-type] + QtCore.QUrl.RemoveScheme)) # type: ignore[arg-type] if conf == 'ask' or conf == 'ask-block-thirdparty' and not is_resource: err_template = jinja.environment.from_string(""" @@ -218,7 +217,7 @@ def ignore_certificate_error( ) urlstr = request_url.toString( - QUrl.RemovePassword | QUrl.FullyEncoded) # type: ignore[arg-type] + QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded) # type: ignore[arg-type] ignore = message.ask(title="Certificate error", text=msg, mode=usertypes.PromptMode.yesno, default=False, abort_on=abort_on, url=urlstr) @@ -260,7 +259,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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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 88ac4a65d..5e2f50860 100644 --- a/qutebrowser/browser/signalfilter.py +++ b/qutebrowser/browser/signalfilter.py @@ -21,12 +21,12 @@ import functools -from PyQt5.QtCore import QObject +from qutebrowser.qt import QtCore from qutebrowser.utils import debug, log, objreg -class SignalFilter(QObject): +class SignalFilter(QtCore.QObject): """A filter for signals. diff --git a/qutebrowser/browser/urlmarks.py b/qutebrowser/browser/urlmarks.py index 944ec23d4..6821ecd76 100644 --- a/qutebrowser/browser/urlmarks.py +++ b/qutebrowser/browser/urlmarks.py @@ -32,12 +32,11 @@ import functools import collections from typing import MutableMapping -from PyQt5.QtCore 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 QtCore class Error(Exception): @@ -60,7 +59,7 @@ class AlreadyExistsError(Error): """Exception emitted when a given URL does already exist.""" -class UrlMarkManager(QObject): +class UrlMarkManager(QtCore.QObject): """Base class for BookmarkManager and QuickmarkManager. @@ -72,7 +71,7 @@ class UrlMarkManager(QObject): changed: Emitted when anything changed. """ - changed = pyqtSignal() + changed = QtCore.pyqtSignal() def __init__(self, parent=None): """Initialize and read quickmarks.""" @@ -149,7 +148,7 @@ class QuickmarkManager(UrlMarkManager): if not url.isValid(): urlutils.invalid_url_error(url, "save quickmark") return - urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded) message.ask_async( "Add quickmark:", usertypes.PromptMode.text, functools.partial(self.quickmark_add, urlstr), @@ -196,7 +195,7 @@ class QuickmarkManager(UrlMarkManager): Use a name instead where possible. """ qtutils.ensure_valid(url) - urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded) try: index = list(self.marks.values()).index(urlstr) @@ -268,7 +267,7 @@ class BookmarkManager(UrlMarkManager): errstr = urlutils.get_errstring(url) raise InvalidUrlError(errstr) - urlstr = url.toString(QUrl.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.FullyEncoded) if urlstr in self.marks: if toggle: diff --git a/qutebrowser/browser/webelem.py b/qutebrowser/browser/webelem.py index 05b0eadb3..a79af7c02 100644 --- a/qutebrowser/browser/webelem.py +++ b/qutebrowser/browser/webelem.py @@ -21,13 +21,12 @@ from typing import cast, TYPE_CHECKING, Iterator, Optional, Set, Union import collections.abc - -from PyQt5.QtCore import QUrl, Qt, QEvent, QTimer, QRect, QPoint -from PyQt5.QtGui import QMouseEvent +from qutebrowser.qt import QtGui from qutebrowser.config import config from qutebrowser.keyinput import modeman from qutebrowser.utils import log, usertypes, utils, qtutils, objreg +from qutebrowser.qt import QtCore 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: QtCore.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) -> QtCore.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: QtCore.QRect = None, + no_js: bool = False) -> QtCore.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: QtCore.QUrl) -> Optional[QtCore.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 = QtCore.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) -> QPoint: + def _mouse_pos(self) -> QtCore.QPoint: """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 @@ -338,7 +337,7 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a raise NotImplementedError def _click_fake_event(self, click_target: usertypes.ClickTarget, - button: Qt.MouseButton = Qt.LeftButton) -> None: + button: QtCore.Qt.MouseButton = QtCore.Qt.LeftButton) -> None: """Send a fake click event to the element.""" pos = self._mouse_pos() @@ -346,28 +345,28 @@ class AbstractWebElement(collections.abc.MutableMapping): # type: ignore[type-a "target {}".format(self, pos, click_target)) target_modifiers = { - usertypes.ClickTarget.normal: Qt.NoModifier, - usertypes.ClickTarget.window: Qt.AltModifier | Qt.ShiftModifier, - usertypes.ClickTarget.tab: Qt.ControlModifier, - usertypes.ClickTarget.tab_bg: Qt.ControlModifier, + usertypes.ClickTarget.normal: QtCore.Qt.NoModifier, + usertypes.ClickTarget.window: QtCore.Qt.AltModifier | QtCore.Qt.ShiftModifier, + usertypes.ClickTarget.tab: QtCore.Qt.ControlModifier, + usertypes.ClickTarget.tab_bg: QtCore.Qt.ControlModifier, } if config.val.tabs.background: - target_modifiers[usertypes.ClickTarget.tab] |= Qt.ShiftModifier + target_modifiers[usertypes.ClickTarget.tab] |= QtCore.Qt.ShiftModifier else: - target_modifiers[usertypes.ClickTarget.tab_bg] |= Qt.ShiftModifier + target_modifiers[usertypes.ClickTarget.tab_bg] |= QtCore.Qt.ShiftModifier - modifiers = cast(Qt.KeyboardModifiers, target_modifiers[click_target]) + modifiers = cast(QtCore.Qt.KeyboardModifiers, target_modifiers[click_target]) events = [ - QMouseEvent(QEvent.MouseMove, pos, Qt.NoButton, Qt.NoButton, Qt.NoModifier), - QMouseEvent(QEvent.MouseButtonPress, pos, button, button, modifiers), - QMouseEvent(QEvent.MouseButtonRelease, pos, button, Qt.NoButton, modifiers), + QtGui.QMouseEvent(QtCore.QEvent.MouseMove, pos, QtCore.Qt.NoButton, QtCore.Qt.NoButton, QtCore.Qt.NoModifier), + QtGui.QMouseEvent(QtCore.QEvent.MouseButtonPress, pos, button, button, modifiers), + QtGui.QMouseEvent(QtCore.QEvent.MouseButtonRelease, pos, button, QtCore.Qt.NoButton, modifiers), ] for evt in events: self._tab.send_event(evt) - QTimer.singleShot(0, self._move_text_cursor) + QtCore.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.MouseMove, pos, Qt.NoButton, Qt.NoButton, - Qt.NoModifier) + event = QtGui.QMouseEvent(QtCore.QEvent.MouseMove, pos, QtCore.Qt.NoButton, QtCore.Qt.NoButton, + QtCore.Qt.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.RightButton) + button=QtCore.Qt.RightButton) diff --git a/qutebrowser/browser/webengine/certificateerror.py b/qutebrowser/browser/webengine/certificateerror.py index 4df7ce8ab..d057c47f3 100644 --- a/qutebrowser/browser/webengine/certificateerror.py +++ b/qutebrowser/browser/webengine/certificateerror.py @@ -19,8 +19,7 @@ """Wrapper over a QWebEngineCertificateError.""" -from PyQt5.QtCore import QUrl -from PyQt5.QtWebEngineWidgets import QWebEngineCertificateError +from qutebrowser.qt import QtWebEngineWidgets, QtCore from qutebrowser.utils import usertypes, utils, debug @@ -29,7 +28,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): """A wrapper over a QWebEngineCertificateError.""" - def __init__(self, error: QWebEngineCertificateError) -> None: + def __init__(self, error: QtWebEngineWidgets.QWebEngineCertificateError) -> None: self._error = error self.ignore = False @@ -39,10 +38,10 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): def __repr__(self) -> str: return utils.get_repr( self, - error=debug.qenum_key(QWebEngineCertificateError, self._error.error()), + error=debug.qenum_key(QtWebEngineWidgets.QWebEngineCertificateError, self._error.error()), string=str(self)) - def url(self) -> QUrl: + def url(self) -> QtCore.QUrl: return self._error.url() def is_overridable(self) -> bool: diff --git a/qutebrowser/browser/webengine/interceptor.py b/qutebrowser/browser/webengine/interceptor.py index 0b1040c4d..91557f4df 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 PyQt5.QtCore import QUrl, QByteArray -from PyQt5.QtWebEngineCore import (QWebEngineUrlRequestInterceptor, - QWebEngineUrlRequestInfo) - from qutebrowser.config import websettings, config from qutebrowser.browser import shared from qutebrowser.utils import utils, log, debug, qtutils from qutebrowser.extensions import interceptors from qutebrowser.misc import objects +from qutebrowser.qt import QtWebEngineCore, QtCore class WebEngineRequest(interceptors.Request): """QtWebEngine-specific request interceptor functionality.""" - _WHITELISTED_REQUEST_METHODS = {QByteArray(b'GET'), QByteArray(b'HEAD')} + _WHITELISTED_REQUEST_METHODS = {QtCore.QByteArray(b'GET'), QtCore.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: QtCore.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(QtWebEngineCore.QWebEngineUrlRequestInterceptor): """Handle ad blocking and custom headers.""" def __init__(self, parent=None): @@ -71,50 +68,50 @@ class RequestInterceptor(QWebEngineUrlRequestInterceptor): # extension ResourceTypes. If a ResourceType is added to Qt, this table # should be updated too. self._resource_types = { - QWebEngineUrlRequestInfo.ResourceTypeMainFrame: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeMainFrame: interceptors.ResourceType.main_frame, - QWebEngineUrlRequestInfo.ResourceTypeSubFrame: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeSubFrame: interceptors.ResourceType.sub_frame, - QWebEngineUrlRequestInfo.ResourceTypeStylesheet: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeStylesheet: interceptors.ResourceType.stylesheet, - QWebEngineUrlRequestInfo.ResourceTypeScript: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeScript: interceptors.ResourceType.script, - QWebEngineUrlRequestInfo.ResourceTypeImage: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeImage: interceptors.ResourceType.image, - QWebEngineUrlRequestInfo.ResourceTypeFontResource: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeFontResource: interceptors.ResourceType.font_resource, - QWebEngineUrlRequestInfo.ResourceTypeSubResource: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeSubResource: interceptors.ResourceType.sub_resource, - QWebEngineUrlRequestInfo.ResourceTypeObject: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeObject: interceptors.ResourceType.object, - QWebEngineUrlRequestInfo.ResourceTypeMedia: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeMedia: interceptors.ResourceType.media, - QWebEngineUrlRequestInfo.ResourceTypeWorker: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeWorker: interceptors.ResourceType.worker, - QWebEngineUrlRequestInfo.ResourceTypeSharedWorker: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeSharedWorker: interceptors.ResourceType.shared_worker, - QWebEngineUrlRequestInfo.ResourceTypePrefetch: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypePrefetch: interceptors.ResourceType.prefetch, - QWebEngineUrlRequestInfo.ResourceTypeFavicon: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeFavicon: interceptors.ResourceType.favicon, - QWebEngineUrlRequestInfo.ResourceTypeXhr: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeXhr: interceptors.ResourceType.xhr, - QWebEngineUrlRequestInfo.ResourceTypePing: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypePing: interceptors.ResourceType.ping, - QWebEngineUrlRequestInfo.ResourceTypeServiceWorker: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeServiceWorker: interceptors.ResourceType.service_worker, - QWebEngineUrlRequestInfo.ResourceTypeCspReport: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeCspReport: interceptors.ResourceType.csp_report, - QWebEngineUrlRequestInfo.ResourceTypePluginResource: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypePluginResource: interceptors.ResourceType.plugin_resource, - QWebEngineUrlRequestInfo.ResourceTypeUnknown: + QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeUnknown: interceptors.ResourceType.unknown, } try: - preload_main_frame = (QWebEngineUrlRequestInfo. + preload_main_frame = (QtWebEngineCore.QWebEngineUrlRequestInfo. ResourceTypeNavigationPreloadMainFrame) - preload_sub_frame = (QWebEngineUrlRequestInfo. + preload_sub_frame = (QtWebEngineCore.QWebEngineUrlRequestInfo. ResourceTypeNavigationPreloadSubFrame) except AttributeError: # Added in Qt 5.14 @@ -152,9 +149,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(QtWebEngineCore.QWebEngineUrlRequestInfo, info.resourceType()) - navigation_type_str = debug.qenum_key(QWebEngineUrlRequestInfo, + navigation_type_str = debug.qenum_key(QtWebEngineCore.QWebEngineUrlRequestInfo, info.navigationType()) log.network.debug("{} {}, first-party {}, resource {}, " "navigation {}".format( @@ -177,15 +174,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(QtWebEngineCore.QWebEngineUrlRequestInfo, info.resourceType()))) resource_type = interceptors.ResourceType.unknown - is_xhr = info.resourceType() == QWebEngineUrlRequestInfo.ResourceTypeXhr + is_xhr = info.resourceType() == QtWebEngineCore.QWebEngineUrlRequestInfo.ResourceTypeXhr if ((url.scheme(), url.host(), url.path()) == ('qute', 'settings', '/set')): - if first_party != QUrl('qute://settings/') or not is_xhr: + if first_party != QtCore.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 2b77a5ac4..7ab769659 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_CHECKING - -from PyQt5.QtCore import (Qt, QObject, QVariant, QMetaType, QByteArray, pyqtSlot, - pyqtSignal, QTimer, QProcess, QUrl) -from PyQt5.QtGui import QImage, QIcon, QPixmap -from PyQt5.QtDBus import (QDBusConnection, QDBusInterface, QDBus, QDBusServiceWatcher, - QDBusArgument, QDBusMessage, QDBusError) -from PyQt5.QtWidgets import QSystemTrayIcon +from qutebrowser.qt import QtWidgets if TYPE_CHECKING: # putting these behind TYPE_CHECKING also means this module is importable # on installs that don't have these - from PyQt5.QtWebEngineCore import QWebEngineNotification - from PyQt5.QtWebEngineWidgets import QWebEngineProfile + from qutebrowser.qt import QtWebEngineWidgets, QtWebEngineCore, 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, version, objreg, resources, ) -from qutebrowser.qt import sip +from qutebrowser.qt import QtWebEngine, QtGui, QtDBus, QtCore, sip bridge: Optional['NotificationBridgePresenter'] = None @@ -105,7 +99,7 @@ class Error(Exception): """Raised when something goes wrong with notifications.""" -class AbstractNotificationAdapter(QObject): +class AbstractNotificationAdapter(QtCore.QObject): """An adapter taking notifications and displaying them. @@ -118,14 +112,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 = QtCore.pyqtSignal(int) + click_id = QtCore.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 = QtCore.pyqtSignal(str) + clear_all = QtCore.pyqtSignal() def present( self, @@ -143,7 +137,7 @@ class AbstractNotificationAdapter(QObject): """ raise NotImplementedError - def _should_include_origin(self, origin: QUrl) -> bool: + def _should_include_origin(self, origin: QtCore.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 @@ -154,13 +148,13 @@ class AbstractNotificationAdapter(QObject): config.instance.get('content.notifications.show_origin', url=origin), ) - @pyqtSlot(int) + @QtCore.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(QtCore.QObject): """Notification presenter which bridges notifications to an adapter. @@ -171,7 +165,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: QtCore.QObject = None) -> None: super().__init__(parent) assert _notifications_supported() @@ -235,13 +229,7 @@ class NotificationBridgePresenter(QObject): def install(self, profile: "QWebEngineProfile") -> None: """Set the profile to use this bridge as the presenter.""" - # WORKAROUND for - # https://www.riverbankcomputing.com/pipermail/pyqt/2020-May/042916.html - # Fixed in PyQtWebEngine 5.15.0 - # PYQT_WEBENGINE_VERSION was added with PyQtWebEngine 5.13, but if we're here, - # we already did a version check above. - from PyQt5.QtWebEngine import PYQT_WEBENGINE_VERSION - if PYQT_WEBENGINE_VERSION < 0x050F00: + if QtWebEngine.PYQT_WEBENGINE_VERSION < 0x050F00: # PyQtWebEngine unrefs the callback after it's called, for some # reason. So we call setNotificationPresenter again to *increase* # its refcount to prevent it from getting GC'd. Otherwise, random @@ -323,7 +311,7 @@ class NotificationBridgePresenter(QObject): log.misc.debug("Did not find match") return None - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def _on_adapter_closed(self, notification_id: int) -> None: """A notification was closed by the adapter (usually due to the user). @@ -347,7 +335,7 @@ class NotificationBridgePresenter(QObject): log.misc.debug(f"Ignoring close request for notification {notification_id} " "due to PyQt bug") - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def _on_adapter_clicked(self, notification_id: int) -> None: """A notification was clicked by the adapter (usually due to the user). @@ -377,7 +365,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.RemovePath): + if tab.url().matches(notification.origin(), QtCore.QUrl.RemovePath): tabbedbrowser.widget.setCurrentIndex(idx) return log.misc.debug(f"No matching tab found for {notification.origin()}") @@ -395,7 +383,7 @@ class NotificationBridgePresenter(QObject): self._adapter = None self._on_adapter_clear_all() - @pyqtSlot() + @QtCore.pyqtSlot() def _on_adapter_clear_all(self) -> None: """Called when the adapter requests clearing all notifications. @@ -409,7 +397,7 @@ class NotificationBridgePresenter(QObject): for notification_id in list(self._active_notifications): self._on_adapter_closed(notification_id) - @pyqtSlot(str) + @QtCore.pyqtSlot(str) def _on_adapter_error(self, error: str) -> None: """A fatal error happened in the adapter. @@ -440,14 +428,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: QtCore.QObject = None) -> None: super().__init__(parent) - if not QSystemTrayIcon.isSystemTrayAvailable(): + if not QtWidgets.QSystemTrayIcon.isSystemTrayAvailable(): raise Error("No system tray available") - if not QSystemTrayIcon.supportsMessages(): + if not QtWidgets.QSystemTrayIcon.supportsMessages(): raise Error("System tray does not support messages") - self._systray = QSystemTrayIcon(self) + self._systray = QtWidgets.QSystemTrayIcon(self) self._systray.setIcon(objects.qapp.windowIcon()) self._systray.messageClicked.connect(self._on_systray_clicked) @@ -468,27 +456,27 @@ class SystrayNotificationAdapter(AbstractNotificationAdapter): return self.NOTIFICATION_ID - def _convert_icon(self, image: QImage) -> QIcon: + def _convert_icon(self, image: QtGui.QImage) -> QtGui.QIcon: """Convert a QImage to a QIcon.""" if image.isNull(): - return QIcon() - pixmap = QPixmap.fromImage(image, Qt.NoFormatConversion) + return QtGui.QIcon() + pixmap = QtGui.QPixmap.fromImage(image, QtCore.Qt.NoFormatConversion) assert not pixmap.isNull() - icon = QIcon(pixmap) + icon = QtGui.QIcon(pixmap) assert not icon.isNull() return icon - def _format_message(self, text: str, origin: QUrl) -> str: + def _format_message(self, text: str, origin: QtCore.QUrl) -> str: """Format the message to display.""" if not self._should_include_origin(origin): return text return origin.toDisplayString() + '\n\n' + text - @pyqtSlot() + @QtCore.pyqtSlot() def _on_systray_clicked(self) -> None: self.click_id.emit(self.NOTIFICATION_ID) - @pyqtSlot(int) + @QtCore.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): @@ -509,7 +497,7 @@ class MessagesNotificationAdapter(AbstractNotificationAdapter): NAME = "messages" - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: QtCore.QObject = None) -> None: super().__init__(parent) self._id_gen = itertools.count(1) @@ -525,12 +513,12 @@ class MessagesNotificationAdapter(AbstractNotificationAdapter): message.info(markup, replace=f'notifications-{new_id}') # Faking closing, timing might not be 100% accurate - QTimer.singleShot( + QtCore.QTimer.singleShot( config.val.messages.timeout, lambda: self.close_id.emit(new_id)) return new_id - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def on_web_closed(self, _notification_id: int) -> None: """We can't close messages.""" @@ -561,7 +549,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): NAME = "herbe" - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: QtCore.QObject = None) -> None: super().__init__(parent) # Also cleans up potentially hanging semaphores from herbe. # https://github.com/dudik/herbe#notifications-dont-show-up @@ -582,7 +570,7 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): if replaces_id is not None: self.on_web_closed(replaces_id) - proc = QProcess(self) + proc = QtCore.QProcess(self) proc.errorOccurred.connect(self._on_error) lines = list(self._message_lines(qt_notification)) @@ -610,7 +598,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: QtCore.QProcess.ExitStatus) -> None: """Handle a closing herbe process. From the GitHub page: @@ -623,7 +611,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.CrashExit: + if status == QtCore.QProcess.CrashExit: return if code == 0: @@ -635,14 +623,14 @@ class HerbeNotificationAdapter(AbstractNotificationAdapter): stderr = proc.readAllStandardError() raise Error(f'herbe exited with status {code}: {stderr}') - @pyqtSlot(QProcess.ProcessError) - def _on_error(self, error: QProcess.ProcessError) -> None: - if error == QProcess.Crashed: + @QtCore.pyqtSlot(QtCore.QProcess.ProcessError) + def _on_error(self, error: QtCore.QProcess.ProcessError) -> None: + if error == QtCore.QProcess.Crashed: return - name = debug.qenum_key(QProcess.ProcessError, error) + name = debug.qenum_key(QtCore.QProcess.ProcessError, error) raise Error(f'herbe process error: {name}') - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: """Handle closing the notification from JS. @@ -689,10 +677,10 @@ class _ServerCapabilities: ) -def _as_uint32(x: int) -> QVariant: +def _as_uint32(x: int) -> QtCore.QVariant: """Convert the given int to an uint32 for DBus.""" - variant = QVariant(x) - successful = variant.convert(QVariant.UInt) + variant = QtCore.QVariant(x) + successful = variant.convert(QtCore.QVariant.UInt) assert successful return variant @@ -734,7 +722,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): "org.freedesktop.DBus.Error.Spawn.ChildSignaled", } - def __init__(self, parent: QObject = None) -> None: + def __init__(self, parent: QtCore.QObject = None) -> None: super().__init__(parent) assert _notifications_supported() @@ -745,16 +733,16 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): # possible to run DBus there. raise Error("libnotify is not supported on Windows") - bus = QDBusConnection.sessionBus() + bus = QtDBus.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 = QtDBus.QDBusServiceWatcher( self.SERVICE, bus, - QDBusServiceWatcher.WatchForUnregistration, + QtDBus.QDBusServiceWatcher.WatchForUnregistration, self, ) self._watcher.serviceUnregistered.connect( # type: ignore[attr-defined] @@ -763,7 +751,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): test_service = 'test-notification-service' in objects.debug_flags service = self.TEST_SERVICE if test_service else self.SERVICE - self.interface = QDBusInterface(service, self.PATH, self.INTERFACE, bus) + self.interface = QtDBus.QDBusInterface(service, self.PATH, self.INTERFACE, bus) if not self.interface.isValid(): raise Error( "Could not construct a DBus interface: " + @@ -790,7 +778,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): else: self._fetch_capabilities() - @pyqtSlot(str) + @QtCore.pyqtSlot(str) def _on_service_unregistered(self) -> None: """Make sure we know when the notification daemon exits. @@ -867,8 +855,8 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _get_server_info(self) -> None: """Query notification server information and set quirks.""" - reply = self.interface.call(QDBus.BlockWithGui, "GetServerInformation") - self._verify_message(reply, "ssss", QDBusMessage.ReplyMessage) + reply = self.interface.call(QtDBus.QDBus.BlockWithGui, "GetServerInformation") + self._verify_message(reply, "ssss", QtDBus.QDBusMessage.ReplyMessage) name, vendor, ver, spec_version = reply.arguments() log.misc.debug( @@ -895,7 +883,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: QtDBus.QDBusError) -> str: """Get a string for a DBus error.""" if not error.isValid(): return "Unknown error" @@ -903,20 +891,20 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _verify_message( self, - msg: QDBusMessage, + msg: QtDBus.QDBusMessage, expected_signature: str, - expected_type: QDBusMessage.MessageType, + expected_type: QtDBus.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.ErrorMessage, - QDBusMessage.InvalidMessage, + QtDBus.QDBusMessage.ErrorMessage, + QtDBus.QDBusMessage.InvalidMessage, ], expected_type - if msg.type() == QDBusMessage.ErrorMessage: + if msg.type() == QtDBus.QDBusMessage.ErrorMessage: err = msg.errorName() if err in self._NON_FATAL_ERRORS: self.error.emit(msg.errorMessage()) @@ -932,8 +920,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(QtDBus.QDBusMessage.MessageType, typ) + expected_type_str = debug.qenum_key(QtDBus.QDBusMessage.MessageType, expected_type) raise Error( f"Got a message of type {type_str} but expected {expected_type_str}" f"(args: {msg.arguments()})") @@ -951,7 +939,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): actions = [] if self._capabilities.actions: actions = ['default', 'Activate'] # key, name - actions_arg = QDBusArgument(actions, QMetaType.QStringList) + actions_arg = QtDBus.QDBusArgument(actions, QtCore.QMetaType.QStringList) origin_url_str = qt_notification.origin().toDisplayString() hints: Dict[str, Any] = { @@ -968,7 +956,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): icon = qt_notification.icon() if icon.isNull(): filename = 'icons/qutebrowser-64x64.png' - icon = QImage.fromData(resources.read_file_binary(filename)) + icon = QtGui.QImage.fromData(resources.read_file_binary(filename)) key = self._quirks.icon_key or "image-data" data = self._convert_image(icon) @@ -981,7 +969,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): title = html.escape(title, quote=False) reply = self.interface.call( - QDBus.BlockWithGui, + QtDBus.QDBus.BlockWithGui, "Notify", "qutebrowser", # application name _as_uint32(replaces_id), # replaces notification id @@ -992,7 +980,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): hints, -1, # timeout; -1 means 'use default' ) - self._verify_message(reply, "u", QDBusMessage.ReplyMessage) + self._verify_message(reply, "u", QtDBus.QDBusMessage.ReplyMessage) notification_id = reply.arguments()[0] @@ -1008,7 +996,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): return notification_id - def _convert_image(self, qimage: QImage) -> Optional[QDBusArgument]: + def _convert_image(self, qimage: QtGui.QImage) -> Optional[QtDBus.QDBusArgument]: """Convert a QImage to the structure DBus expects. https://specifications.freedesktop.org/notification-spec/latest/ar01s05.html#icons-and-images-formats @@ -1016,10 +1004,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): bits_per_color = 8 has_alpha = qimage.hasAlphaChannel() if has_alpha: - image_format = QImage.Format_RGBA8888 + image_format = QtGui.QImage.Format_RGBA8888 channel_count = 4 else: - image_format = QImage.Format_RGB888 + image_format = QtGui.QImage.Format_RGB888 channel_count = 3 qimage.convertTo(image_format) @@ -1027,7 +1015,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): width = qimage.width() height = qimage.height() - image_data = QDBusArgument() + image_data = QtDBus.QDBusArgument() image_data.beginStructure() image_data.add(width) image_data.add(height) @@ -1076,31 +1064,31 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): return None bits = qimage.constBits().asstring(size) - image_data.add(QByteArray(bits)) + image_data.add(QtCore.QByteArray(bits)) image_data.endStructure() return image_data - @pyqtSlot(QDBusMessage) - def _handle_close(self, msg: QDBusMessage) -> None: + @QtCore.pyqtSlot(QtDBus.QDBusMessage) + def _handle_close(self, msg: QtDBus.QDBusMessage) -> None: """Handle NotificationClosed from DBus.""" - self._verify_message(msg, "uu", QDBusMessage.SignalMessage) + self._verify_message(msg, "uu", QtDBus.QDBusMessage.SignalMessage) notification_id, _close_reason = msg.arguments() self.close_id.emit(notification_id) - @pyqtSlot(QDBusMessage) - def _handle_action(self, msg: QDBusMessage) -> None: + @QtCore.pyqtSlot(QtDBus.QDBusMessage) + def _handle_action(self, msg: QtDBus.QDBusMessage) -> None: """Handle ActionInvoked from DBus.""" - self._verify_message(msg, "us", QDBusMessage.SignalMessage) + self._verify_message(msg, "us", QtDBus.QDBusMessage.SignalMessage) notification_id, action_key = msg.arguments() if action_key == "default": self.click_id.emit(notification_id) - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def on_web_closed(self, notification_id: int) -> None: """Send CloseNotification if a notification was closed from JS.""" self.interface.call( - QDBus.NoBlock, + QtDBus.QDBus.NoBlock, "CloseNotification", _as_uint32(notification_id), ) @@ -1108,10 +1096,10 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): def _fetch_capabilities(self) -> None: """Fetch capabilities from the notification server.""" reply = self.interface.call( - QDBus.BlockWithGui, + QtDBus.QDBus.BlockWithGui, "GetCapabilities", ) - self._verify_message(reply, "as", QDBusMessage.ReplyMessage) + self._verify_message(reply, "as", QtDBus.QDBusMessage.ReplyMessage) caplist = reply.arguments()[0] self._capabilities = _ServerCapabilities.from_list(caplist) @@ -1122,7 +1110,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: QtCore.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 @@ -1138,7 +1126,7 @@ class DBusNotificationAdapter(AbstractNotificationAdapter): prefix = None elif self._capabilities.body_markup and self._capabilities.body_hyperlinks: href = html.escape( - origin_url.toString(QUrl.FullyEncoded) # type: ignore[arg-type] + origin_url.toString(QtCore.QUrl.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 ab4b05fe9..37a8d7542 100644 --- a/qutebrowser/browser/webengine/tabhistory.py +++ b/qutebrowser/browser/webengine/tabhistory.py @@ -19,9 +19,8 @@ """QWebHistory serializer for QtWebEngine.""" -from PyQt5.QtCore import QByteArray, QDataStream, QIODevice, QUrl - from qutebrowser.utils import qtutils +from qutebrowser.qt import QtCore # 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, QtCore.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, QtCore.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.ReadWrite) + data = QtCore.QByteArray() + stream = QtCore.QDataStream(data, QtCore.QIODevice.ReadWrite) cur_user_data = None current_idx = None diff --git a/qutebrowser/browser/webengine/webenginedownloads.py b/qutebrowser/browser/webengine/webenginedownloads.py index a6a2a1b93..2bae19952 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 PyQt5.QtCore import pyqtSlot, Qt, QUrl, QObject -from PyQt5.QtWebEngineWidgets import QWebEngineDownloadItem +from qutebrowser.qt import QtWebEngineWidgets from qutebrowser.browser import downloads, pdfjs from qutebrowser.utils import (debug, usertypes, message, log, objreg, urlutils, utils, version) +from qutebrowser.qt import QtCore class DownloadItem(downloads.AbstractDownloadItem): @@ -39,9 +38,9 @@ class DownloadItem(downloads.AbstractDownloadItem): _qt_item: The wrapped item. """ - def __init__(self, qt_item: QWebEngineDownloadItem, + def __init__(self, qt_item: QtWebEngineWidgets.QWebEngineDownloadItem, manager: downloads.AbstractDownloadManager, - parent: QObject = None) -> None: + parent: QtCore.QObject = None) -> None: super().__init__(manager=manager, parent=manager) self._qt_item = qt_item qt_item.downloadProgress.connect( # type: ignore[attr-defined] @@ -56,19 +55,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() != - QWebEngineDownloadItem.UnknownSaveFormat) + QtWebEngineWidgets.QWebEngineDownloadItem.UnknownSaveFormat) - @pyqtSlot(QWebEngineDownloadItem.DownloadState) + @QtCore.pyqtSlot(QtWebEngineWidgets.QWebEngineDownloadItem.DownloadState) def _on_state_changed(self, state): - state_name = debug.qenum_key(QWebEngineDownloadItem, state) + state_name = debug.qenum_key(QtWebEngineWidgets.QWebEngineDownloadItem, state) log.downloads.debug("State for {!r} changed to {}".format( self, state_name)) - if state == QWebEngineDownloadItem.DownloadRequested: + if state == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadRequested: pass - elif state == QWebEngineDownloadItem.DownloadInProgress: + elif state == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadInProgress: pass - elif state == QWebEngineDownloadItem.DownloadCompleted: + elif state == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadCompleted: log.downloads.debug("Download {} finished".format(self.basename)) if self._is_page_download(): # Same logging as QtWebKit mhtml downloads. @@ -77,12 +76,12 @@ class DownloadItem(downloads.AbstractDownloadItem): self.done = True self.finished.emit() self.stats.finish() - elif state == QWebEngineDownloadItem.DownloadCancelled: + elif state == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadCancelled: self.successful = False self.done = True self.cancelled.emit() self.stats.finish() - elif state == QWebEngineDownloadItem.DownloadInterrupted: + elif state == QtWebEngineWidgets.QWebEngineDownloadItem.DownloadInterrupted: self.successful = False reason = self._qt_item.interruptReasonString() self._die(reason) @@ -93,22 +92,22 @@ class DownloadItem(downloads.AbstractDownloadItem): def _do_die(self): progress_signal = self._qt_item.downloadProgress progress_signal.disconnect() # type: ignore[attr-defined] - if self._qt_item.state() != QWebEngineDownloadItem.DownloadInterrupted: + if self._qt_item.state() != QtWebEngineWidgets.QWebEngineDownloadItem.DownloadInterrupted: self._qt_item.cancel() def _do_cancel(self): state = self._qt_item.state() - state_name = debug.qenum_key(QWebEngineDownloadItem, state) - assert state not in [QWebEngineDownloadItem.DownloadCompleted, - QWebEngineDownloadItem.DownloadCancelled], state_name + state_name = debug.qenum_key(QtWebEngineWidgets.QWebEngineDownloadItem, state) + assert state not in [QtWebEngineWidgets.QWebEngineDownloadItem.DownloadCompleted, + QtWebEngineWidgets.QWebEngineDownloadItem.DownloadCancelled], state_name self._qt_item.cancel() def retry(self): state = self._qt_item.state() - if state != QWebEngineDownloadItem.DownloadInterrupted: + if state != QtWebEngineWidgets.QWebEngineDownloadItem.DownloadInterrupted: log.downloads.warning( "Refusing to retry download in state {}".format( - debug.qenum_key(QWebEngineDownloadItem, state))) + debug.qenum_key(QtWebEngineWidgets.QWebEngineDownloadItem, state))) return self._qt_item.resume() @@ -116,12 +115,12 @@ class DownloadItem(downloads.AbstractDownloadItem): def _get_open_filename(self): return self._filename - def url(self) -> QUrl: + def url(self) -> QtCore.QUrl: return self._qt_item.url() - def origin(self) -> QUrl: + def origin(self) -> QtCore.QUrl: page = self._qt_item.page() - return page.url() if page else QUrl() + return page.url() if page else QtCore.QUrl() def _set_fileobj(self, fileobj, *, autoclose=True): raise downloads.UnsupportedOperationError @@ -133,8 +132,8 @@ class DownloadItem(downloads.AbstractDownloadItem): def _ensure_can_set_filename(self, filename): state = self._qt_item.state() - if state != QWebEngineDownloadItem.DownloadRequested: - state_name = debug.qenum_key(QWebEngineDownloadItem, state) + if state != QtWebEngineWidgets.QWebEngineDownloadItem.DownloadRequested: + state_name = debug.qenum_key(QtWebEngineWidgets.QWebEngineDownloadItem, state) raise ValueError("Trying to set filename {} on {!r} which is " "state {} (not in requested state)!".format( filename, self, state_name)) @@ -247,9 +246,9 @@ class DownloadManager(downloads.AbstractDownloadManager): def install(self, profile): """Set up the download manager on a QWebEngineProfile.""" profile.downloadRequested.connect(self.handle_download, - Qt.DirectConnection) + QtCore.Qt.DirectConnection) - @pyqtSlot(QWebEngineDownloadItem) + @QtCore.pyqtSlot(QtWebEngineWidgets.QWebEngineDownloadItem) def handle_download(self, qt_item): """Start a download coming from a QWebEngineProfile.""" qt_filename = os.path.basename(qt_item.path()) # FIXME use 5.14 API diff --git a/qutebrowser/browser/webengine/webengineelem.py b/qutebrowser/browser/webengine/webengineelem.py index 5d4c6ad9a..8068e2278 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 PyQt5.QtCore import QRect, QEventLoop -from PyQt5.QtWidgets import QApplication -from PyQt5.QtWebEngineWidgets import QWebEngineSettings +from qutebrowser.qt import QtWidgets +from qutebrowser.qt import QtWebEngineWidgets from qutebrowser.utils import log, javascript, urlutils, usertypes, utils from qutebrowser.browser import webelem +from qutebrowser.qt import QtCore if TYPE_CHECKING: from qutebrowser.browser.webengine import webenginetab @@ -114,9 +113,9 @@ class WebEngineElement(webelem.AbstractWebElement): def has_frame(self) -> bool: return True - def geometry(self) -> QRect: + def geometry(self) -> QtCore.QRect: log.stub() - return QRect() + return QtCore.QRect() def classes(self) -> Set[str]: """Get a list of classes assigned to this element.""" @@ -163,8 +162,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: QtCore.QRect = None, + no_js: bool = False) -> QtCore.QRect: """Get the geometry of the element relative to the webview. Skipping of small rectangles is due to elements containing other @@ -193,7 +192,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 = QtCore.QRect(int(left * zoom), int(top * zoom), int(width * zoom), int(height * zoom)) # FIXME:qtwebengine # frame = self._elem.webFrame() @@ -205,7 +204,7 @@ class WebEngineElement(webelem.AbstractWebElement): return rect log.webelem.debug("Couldn't find rectangle for {!r} ({})".format( self, rects)) - return QRect() + return QtCore.QRect() def remove_blank_target(self) -> None: if self._js_dict['attributes'].get('target') == '_blank': @@ -240,7 +239,7 @@ class WebEngineElement(webelem.AbstractWebElement): view = self._tab._widget assert view is not None # pylint: enable=protected-access - attribute = QWebEngineSettings.JavascriptCanOpenWindows + attribute = QtWebEngineWidgets.QWebEngineSettings.JavascriptCanOpenWindows could_open_windows = view.settings().testAttribute(attribute) view.settings().setAttribute(attribute, True) @@ -248,9 +247,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( # type: ignore[call-overload] - QEventLoop.ExcludeSocketNotifiers | - QEventLoop.ExcludeUserInputEvents) + QtWidgets.QApplication.processEvents( # type: ignore[call-overload] + QtCore.QEventLoop.ExcludeSocketNotifiers | + QtCore.QEventLoop.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 ae31c0bee..a7384913a 100644 --- a/qutebrowser/browser/webengine/webengineinspector.py +++ b/qutebrowser/browser/webengine/webengineinspector.py @@ -21,9 +21,7 @@ import pathlib -from PyQt5.QtCore import QLibraryInfo -from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage -from PyQt5.QtWidgets import QWidget +from qutebrowser.qt import QtWidgets, QtWebEngineWidgets, QtCore from qutebrowser.browser import inspector from qutebrowser.browser.webengine import webenginesettings @@ -32,7 +30,7 @@ from qutebrowser.utils import version, usertypes from qutebrowser.keyinput import modeman -class WebEngineInspectorView(QWebEngineView): +class WebEngineInspectorView(QtWebEngineWidgets.QWebEngineView): """The QWebEngineView used for the inspector. @@ -41,7 +39,7 @@ class WebEngineInspectorView(QWebEngineView): """ def createWindow(self, - wintype: QWebEnginePage.WebWindowType) -> QWebEngineView: + wintype: QtWebEngineWidgets.QWebEnginePage.WebWindowType) -> QtWebEngineWidgets.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 @@ -58,7 +56,7 @@ class WebEngineInspector(inspector.AbstractWebInspector): def __init__(self, splitter: miscwidgets.InspectorSplitter, win_id: int, - parent: QWidget = None) -> None: + parent: QtWidgets.QWidget = None) -> None: super().__init__(splitter, win_id, parent) self._check_devtools_resources() @@ -89,14 +87,14 @@ class WebEngineInspector(inspector.AbstractWebInspector): if dist is None or dist.parsed != version.Distribution.fedora: return - data_path = pathlib.Path(QLibraryInfo.location(QLibraryInfo.DataPath)) + data_path = pathlib.Path(QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.DataPath)) pak = data_path / 'resources' / 'qtwebengine_devtools_resources.pak' if not pak.exists(): raise inspector.Error("QtWebEngine devtools resources not found, " "please install the qt5-qtwebengine-devtools " "Fedora package.") - def inspect(self, page: QWebEnginePage) -> None: # type: ignore[override] + def inspect(self, page: QtWebEngineWidgets.QWebEnginePage) -> None: # type: ignore[override] inspector_page = self._widget.page() inspector_page.setInspectedPage(page) self._settings.update_for_url(inspector_page.requestedUrl()) diff --git a/qutebrowser/browser/webengine/webenginequtescheme.py b/qutebrowser/browser/webengine/webenginequtescheme.py index 64361f7c4..0a21d967f 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 PyQt5.QtCore import QBuffer, QIODevice, QUrl -from PyQt5.QtWebEngineCore import (QWebEngineUrlSchemeHandler, - QWebEngineUrlRequestJob, - QWebEngineUrlScheme) - from qutebrowser.browser import qutescheme from qutebrowser.utils import log, qtutils +from qutebrowser.qt import QtWebEngineCore, QtCore -class QuteSchemeHandler(QWebEngineUrlSchemeHandler): +class QuteSchemeHandler(QtWebEngineCore.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 QtWebEngineCore.QWebEngineUrlScheme is not None: + assert QtWebEngineCore.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 == QtCore.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.RequestDenied) + job.fail(QtWebEngineCore.QWebEngineUrlRequestJob.RequestDenied) return False return True @@ -87,7 +83,7 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): return if job.requestMethod() != b'GET': - job.fail(QWebEngineUrlRequestJob.RequestDenied) + job.fail(QtWebEngineCore.QWebEngineUrlRequestJob.RequestDenied) return assert url.scheme() == 'qute' @@ -98,15 +94,15 @@ class QuteSchemeHandler(QWebEngineUrlSchemeHandler): except qutescheme.Error as e: errors = { qutescheme.NotFoundError: - QWebEngineUrlRequestJob.UrlNotFound, + QtWebEngineCore.QWebEngineUrlRequestJob.UrlNotFound, qutescheme.UrlInvalidError: - QWebEngineUrlRequestJob.UrlInvalid, + QtWebEngineCore.QWebEngineUrlRequestJob.UrlInvalid, qutescheme.RequestDeniedError: - QWebEngineUrlRequestJob.RequestDenied, + QtWebEngineCore.QWebEngineUrlRequestJob.RequestDenied, qutescheme.SchemeOSError: - QWebEngineUrlRequestJob.UrlNotFound, + QtWebEngineCore.QWebEngineUrlRequestJob.UrlNotFound, qutescheme.Error: - QWebEngineUrlRequestJob.RequestFailed, + QtWebEngineCore.QWebEngineUrlRequestJob.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.WriteOnly) + buf = QtCore.QBuffer(parent=self) + buf.open(QtCore.QIODevice.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 QtWebEngineCore.QWebEngineUrlScheme is not None: + assert not QtWebEngineCore.QWebEngineUrlScheme.schemeByName(b'qute').name() + scheme = QtWebEngineCore.QWebEngineUrlScheme(b'qute') scheme.setFlags( - QWebEngineUrlScheme.LocalScheme | # type: ignore[arg-type] - QWebEngineUrlScheme.LocalAccessAllowed) - QWebEngineUrlScheme.registerScheme(scheme) + QtWebEngineCore.QWebEngineUrlScheme.LocalScheme | # type: ignore[arg-type] + QtWebEngineCore.QWebEngineUrlScheme.LocalAccessAllowed) + QtWebEngineCore.QWebEngineUrlScheme.registerScheme(scheme) diff --git a/qutebrowser/browser/webengine/webenginesettings.py b/qutebrowser/browser/webengine/webenginesettings.py index 5430cec77..55cbd3f08 100644 --- a/qutebrowser/browser/webengine/webenginesettings.py +++ b/qutebrowser/browser/webengine/webenginesettings.py @@ -28,9 +28,7 @@ import os import operator from typing import cast, Any, List, Optional, Tuple, Union, TYPE_CHECKING -from PyQt5.QtGui import QFont -from PyQt5.QtWidgets import QApplication -from PyQt5.QtWebEngineWidgets import QWebEngineSettings, QWebEngineProfile +from qutebrowser.qt import QtWidgets, QtWebEngineWidgets, QtGui from qutebrowser.browser import history from qutebrowser.browser.webengine import (spell, webenginequtescheme, cookies, @@ -43,9 +41,9 @@ if TYPE_CHECKING: from qutebrowser.browser.webengine import interceptor # The default QWebEngineProfile -default_profile = cast(QWebEngineProfile, None) +default_profile = cast(QtWebEngineWidgets.QWebEngineProfile, None) # The QWebEngineProfile used for private (off-the-record) windows -private_profile: Optional[QWebEngineProfile] = None +private_profile: Optional[QtWebEngineWidgets.QWebEngineProfile] = None # The global WebEngineSettings object _global_settings = cast('WebEngineSettings', None) @@ -110,93 +108,93 @@ class WebEngineSettings(websettings.AbstractSettings): _ATTRIBUTES = { 'content.xss_auditing': - Attr(QWebEngineSettings.XSSAuditingEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.XSSAuditingEnabled), 'content.images': - Attr(QWebEngineSettings.AutoLoadImages), + Attr(QtWebEngineWidgets.QWebEngineSettings.AutoLoadImages), 'content.javascript.enabled': - Attr(QWebEngineSettings.JavascriptEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.JavascriptEnabled), 'content.javascript.can_open_tabs_automatically': - Attr(QWebEngineSettings.JavascriptCanOpenWindows), + Attr(QtWebEngineWidgets.QWebEngineSettings.JavascriptCanOpenWindows), 'content.javascript.can_access_clipboard': - Attr(QWebEngineSettings.JavascriptCanAccessClipboard), + Attr(QtWebEngineWidgets.QWebEngineSettings.JavascriptCanAccessClipboard), 'content.plugins': - Attr(QWebEngineSettings.PluginsEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.PluginsEnabled), 'content.hyperlink_auditing': - Attr(QWebEngineSettings.HyperlinkAuditingEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.HyperlinkAuditingEnabled), 'content.local_content_can_access_remote_urls': - Attr(QWebEngineSettings.LocalContentCanAccessRemoteUrls), + Attr(QtWebEngineWidgets.QWebEngineSettings.LocalContentCanAccessRemoteUrls), 'content.local_content_can_access_file_urls': - Attr(QWebEngineSettings.LocalContentCanAccessFileUrls), + Attr(QtWebEngineWidgets.QWebEngineSettings.LocalContentCanAccessFileUrls), 'content.webgl': - Attr(QWebEngineSettings.WebGLEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.WebGLEnabled), 'content.local_storage': - Attr(QWebEngineSettings.LocalStorageEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.LocalStorageEnabled), 'content.desktop_capture': - Attr(QWebEngineSettings.ScreenCaptureEnabled, + Attr(QtWebEngineWidgets.QWebEngineSettings.ScreenCaptureEnabled, converter=lambda val: True if val == 'ask' else val), # 'ask' is handled via the permission system 'input.spatial_navigation': - Attr(QWebEngineSettings.SpatialNavigationEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.SpatialNavigationEnabled), 'input.links_included_in_focus_chain': - Attr(QWebEngineSettings.LinksIncludedInFocusChain), + Attr(QtWebEngineWidgets.QWebEngineSettings.LinksIncludedInFocusChain), 'scrolling.smooth': - Attr(QWebEngineSettings.ScrollAnimatorEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.ScrollAnimatorEnabled), 'content.print_element_backgrounds': - Attr(QWebEngineSettings.PrintElementBackgrounds), + Attr(QtWebEngineWidgets.QWebEngineSettings.PrintElementBackgrounds), 'content.autoplay': - Attr(QWebEngineSettings.PlaybackRequiresUserGesture, + Attr(QtWebEngineWidgets.QWebEngineSettings.PlaybackRequiresUserGesture, converter=operator.not_), 'content.dns_prefetch': - Attr(QWebEngineSettings.DnsPrefetchEnabled), + Attr(QtWebEngineWidgets.QWebEngineSettings.DnsPrefetchEnabled), 'tabs.favicons.show': - Attr(QWebEngineSettings.AutoLoadIconsForPage, + Attr(QtWebEngineWidgets.QWebEngineSettings.AutoLoadIconsForPage, converter=lambda val: val != 'never'), } _FONT_SIZES = { 'fonts.web.size.minimum': - QWebEngineSettings.MinimumFontSize, + QtWebEngineWidgets.QWebEngineSettings.MinimumFontSize, 'fonts.web.size.minimum_logical': - QWebEngineSettings.MinimumLogicalFontSize, + QtWebEngineWidgets.QWebEngineSettings.MinimumLogicalFontSize, 'fonts.web.size.default': - QWebEngineSettings.DefaultFontSize, + QtWebEngineWidgets.QWebEngineSettings.DefaultFontSize, 'fonts.web.size.default_fixed': - QWebEngineSettings.DefaultFixedFontSize, + QtWebEngineWidgets.QWebEngineSettings.DefaultFixedFontSize, } _FONT_FAMILIES = { - 'fonts.web.family.standard': QWebEngineSettings.StandardFont, - 'fonts.web.family.fixed': QWebEngineSettings.FixedFont, - 'fonts.web.family.serif': QWebEngineSettings.SerifFont, - 'fonts.web.family.sans_serif': QWebEngineSettings.SansSerifFont, - 'fonts.web.family.cursive': QWebEngineSettings.CursiveFont, - 'fonts.web.family.fantasy': QWebEngineSettings.FantasyFont, + 'fonts.web.family.standard': QtWebEngineWidgets.QWebEngineSettings.StandardFont, + 'fonts.web.family.fixed': QtWebEngineWidgets.QWebEngineSettings.FixedFont, + 'fonts.web.family.serif': QtWebEngineWidgets.QWebEngineSettings.SerifFont, + 'fonts.web.family.sans_serif': QtWebEngineWidgets.QWebEngineSettings.SansSerifFont, + 'fonts.web.family.cursive': QtWebEngineWidgets.QWebEngineSettings.CursiveFont, + 'fonts.web.family.fantasy': QtWebEngineWidgets.QWebEngineSettings.FantasyFont, } _UNKNOWN_URL_SCHEME_POLICY = { 'disallow': - QWebEngineSettings.DisallowUnknownUrlSchemes, + QtWebEngineWidgets.QWebEngineSettings.DisallowUnknownUrlSchemes, 'allow-from-user-interaction': - QWebEngineSettings.AllowUnknownUrlSchemesFromUserInteraction, + QtWebEngineWidgets.QWebEngineSettings.AllowUnknownUrlSchemesFromUserInteraction, 'allow-all': - QWebEngineSettings.AllowAllUnknownUrlSchemes, + QtWebEngineWidgets.QWebEngineSettings.AllowAllUnknownUrlSchemes, } # Mapping from WebEngineSettings::initDefaults in # qtwebengine/src/core/web_engine_settings.cpp _FONT_TO_QFONT = { - QWebEngineSettings.StandardFont: QFont.Serif, - QWebEngineSettings.FixedFont: QFont.Monospace, - QWebEngineSettings.SerifFont: QFont.Serif, - QWebEngineSettings.SansSerifFont: QFont.SansSerif, - QWebEngineSettings.CursiveFont: QFont.Cursive, - QWebEngineSettings.FantasyFont: QFont.Fantasy, + QtWebEngineWidgets.QWebEngineSettings.StandardFont: QtGui.QFont.Serif, + QtWebEngineWidgets.QWebEngineSettings.FixedFont: QtGui.QFont.Monospace, + QtWebEngineWidgets.QWebEngineSettings.SerifFont: QtGui.QFont.Serif, + QtWebEngineWidgets.QWebEngineSettings.SansSerifFont: QtGui.QFont.SansSerif, + QtWebEngineWidgets.QWebEngineSettings.CursiveFont: QtGui.QFont.Cursive, + QtWebEngineWidgets.QWebEngineSettings.FantasyFont: QtGui.QFont.Fantasy, } def set_unknown_url_scheme_policy( @@ -265,12 +263,12 @@ class ProfileSetter: settings = self._profile.settings() settings.setAttribute( - QWebEngineSettings.FullScreenSupportEnabled, True) + QtWebEngineWidgets.QWebEngineSettings.FullScreenSupportEnabled, True) settings.setAttribute( - QWebEngineSettings.FocusOnNavigationEnabled, False) + QtWebEngineWidgets.QWebEngineSettings.FocusOnNavigationEnabled, False) try: - settings.setAttribute(QWebEngineSettings.PdfViewerEnabled, False) + settings.setAttribute(QtWebEngineWidgets.QWebEngineSettings.PdfViewerEnabled, False) except AttributeError: # Added in Qt 5.13 pass @@ -305,9 +303,9 @@ class ProfileSetter: if self._profile.isOffTheRecord(): return if config.val.content.cookies.store: - value = QWebEngineProfile.AllowPersistentCookies + value = QtWebEngineWidgets.QWebEngineProfile.AllowPersistentCookies else: - value = QWebEngineProfile.NoPersistentCookies + value = QtWebEngineWidgets.QWebEngineProfile.NoPersistentCookies self._profile.setPersistentCookiesPolicy(value) def set_dictionary_language(self): @@ -343,10 +341,10 @@ def _init_user_agent_str(ua): def init_user_agent(): - _init_user_agent_str(QWebEngineProfile.defaultProfile().httpUserAgent()) + _init_user_agent_str(QtWebEngineWidgets.QWebEngineProfile.defaultProfile().httpUserAgent()) -def _init_profile(profile: QWebEngineProfile) -> None: +def _init_profile(profile: QtWebEngineWidgets.QWebEngineProfile) -> None: """Initialize a new QWebEngineProfile. This currently only contains the steps which are shared between a private and a @@ -375,7 +373,7 @@ def _init_default_profile(): """Init the default QWebEngineProfile.""" global default_profile - default_profile = QWebEngineProfile.defaultProfile() + default_profile = QtWebEngineWidgets.QWebEngineProfile.defaultProfile() assert parsed_user_agent is None # avoid earlier profile initialization non_ua_version = version.qtwebengine_versions(avoid_init=True) @@ -404,7 +402,7 @@ def init_private_profile(): if qtutils.is_single_process(): return - private_profile = QWebEngineProfile() + private_profile = QtWebEngineWidgets.QWebEngineProfile() assert private_profile.isOffTheRecord() _init_profile(private_profile) @@ -491,7 +489,7 @@ def init(): # won't work... # https://www.riverbankcomputing.com/pipermail/pyqt/2016-September/038075.html global _qute_scheme_handler - app = QApplication.instance() + app = QtWidgets.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 7d355d10e..a0a83d7a7 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 PyQt5.QtCore import (pyqtSignal, pyqtSlot, Qt, QPoint, QPointF, QTimer, QUrl, - QObject) -from PyQt5.QtNetwork import QAuthenticator -from PyQt5.QtWidgets import QWidget -from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineScript, QWebEngineHistory +from qutebrowser.qt import QtWidgets, QtWebEngineWidgets, QtWebEngineCore, QtNetwork 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 QtCore, sip from qutebrowser.misc import objects, miscwidgets # Mapping worlds from usertypes.JsWorld to QWebEngineScript world IDs. _JS_WORLD_MAP = { - usertypes.JsWorld.main: QWebEngineScript.MainWorld, - usertypes.JsWorld.application: QWebEngineScript.ApplicationWorld, - usertypes.JsWorld.user: QWebEngineScript.UserWorld, - usertypes.JsWorld.jseval: QWebEngineScript.UserWorld + 1, + usertypes.JsWorld.main: QtWebEngineWidgets.QWebEngineScript.MainWorld, + usertypes.JsWorld.application: QtWebEngineWidgets.QWebEngineScript.ApplicationWorld, + usertypes.JsWorld.user: QtWebEngineWidgets.QWebEngineScript.UserWorld, + usertypes.JsWorld.jseval: QtWebEngineWidgets.QWebEngineScript.UserWorld + 1, } @@ -57,22 +52,22 @@ class WebEngineAction(browsertab.AbstractAction): """QtWebEngine implementations related to web actions.""" - action_class = QWebEnginePage - action_base = QWebEnginePage.WebAction + action_class = QtWebEngineWidgets.QWebEnginePage + action_base = QtWebEngineWidgets.QWebEnginePage.WebAction def exit_fullscreen(self): - self._widget.triggerPageAction(QWebEnginePage.ExitFullScreen) + self._widget.triggerPageAction(QtWebEngineWidgets.QWebEnginePage.ExitFullScreen) def save_page(self): """Save the current page.""" - self._widget.triggerPageAction(QWebEnginePage.SavePage) + self._widget.triggerPageAction(QtWebEngineWidgets.QWebEnginePage.SavePage) def show_source(self, pygments=False): if pygments: self._show_source_pygments() return - self._widget.triggerPageAction(QWebEnginePage.ViewSource) + self._widget.triggerPageAction(QtWebEngineWidgets.QWebEnginePage.ViewSource) class WebEnginePrinting(browsertab.AbstractPrinting): @@ -125,8 +120,7 @@ class _WebEngineSearchWrapHandler: return try: - # pylint: disable=unused-import - from PyQt5.QtWebEngineCore import QWebEngineFindTextResult + pass except ImportError: # WORKAROUND for some odd PyQt/packaging bug where the # findTextResult signal is available, but QWebEngineFindTextResult @@ -199,14 +193,14 @@ class WebEngineSearch(browsertab.AbstractSearch): self._wrap_handler = _WebEngineSearchWrapHandler() def _empty_flags(self): - return QWebEnginePage.FindFlags(0) # type: ignore[call-overload] + return QtWebEngineWidgets.QWebEnginePage.FindFlags(0) # type: ignore[call-overload] def _args_to_flags(self, reverse, ignore_case): flags = self._empty_flags() if self._is_case_sensitive(ignore_case): - flags |= QWebEnginePage.FindCaseSensitively + flags |= QtWebEngineWidgets.QWebEnginePage.FindCaseSensitively if reverse: - flags |= QWebEnginePage.FindBackward + flags |= QtWebEngineWidgets.QWebEnginePage.FindBackward return flags def connect_signals(self): @@ -238,7 +232,7 @@ class WebEngineSearch(browsertab.AbstractSearch): found_text = 'found' if found else "didn't find" if flags: flag_text = 'with flags {}'.format(debug.qflags_key( - QWebEnginePage, flags, klass=QWebEnginePage.FindFlag)) + QtWebEngineWidgets.QWebEnginePage, flags, klass=QtWebEngineWidgets.QWebEnginePage.FindFlag)) else: flag_text = '' log.webview.debug(' '.join([caller, found_text, text, flag_text]) @@ -275,20 +269,20 @@ class WebEngineSearch(browsertab.AbstractSearch): def prev_result(self, *, result_cb=None): # The int() here makes sure we get a copy of the flags. - flags = QWebEnginePage.FindFlags( + flags = QtWebEngineWidgets.QWebEnginePage.FindFlags( int(self._flags)) # type: ignore[call-overload] - if flags & QWebEnginePage.FindBackward: + if flags & QtWebEngineWidgets.QWebEnginePage.FindBackward: if self._wrap_handler.prevent_wrapping(going_up=False): return - flags &= ~QWebEnginePage.FindBackward + flags &= ~QtWebEngineWidgets.QWebEnginePage.FindBackward else: if self._wrap_handler.prevent_wrapping(going_up=True): return - flags |= QWebEnginePage.FindBackward + flags |= QtWebEngineWidgets.QWebEnginePage.FindBackward self._find(self.text, flags, result_cb, 'prev_result') def next_result(self, *, result_cb=None): - going_up = self._flags & QWebEnginePage.FindBackward + going_up = self._flags & QtWebEngineWidgets.QWebEnginePage.FindBackward if self._wrap_handler.prevent_wrapping(going_up=going_up): return self._find(self.text, self._flags, result_cb, 'next_result') @@ -307,7 +301,7 @@ class WebEngineCaret(browsertab.AbstractCaret): flags.add('windows') return list(flags) - @pyqtSlot(usertypes.KeyMode) + @QtCore.pyqtSlot(usertypes.KeyMode) def _on_mode_entered(self, mode): if mode != usertypes.KeyMode.caret: return @@ -335,7 +329,7 @@ class WebEngineCaret(browsertab.AbstractCaret): else: self.selection_toggled.emit(browsertab.SelectionState.none) - @pyqtSlot(usertypes.KeyMode) + @QtCore.pyqtSlot(usertypes.KeyMode) def _on_mode_left(self, mode): if mode != usertypes.KeyMode.caret: return @@ -496,7 +490,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 = QtCore.QPoint() self._at_bottom = False def _init_widget(self, widget): @@ -504,12 +498,12 @@ class WebEngineScroller(browsertab.AbstractScroller): page = widget.page() page.scrollPositionChanged.connect(self._update_pos) - def _repeated_key_press(self, key, count=1, modifier=Qt.NoModifier): + def _repeated_key_press(self, key, count=1, modifier=QtCore.Qt.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) + @QtCore.pyqtSlot(QtCore.QPointF) def _update_pos(self, pos): """Update the scroll position attributes when it changed.""" self._pos_px = pos.toPoint() @@ -583,28 +577,28 @@ class WebEngineScroller(browsertab.AbstractScroller): self._tab.run_js_async(js_code) def up(self, count=1): - self._repeated_key_press(Qt.Key_Up, count) + self._repeated_key_press(QtCore.Qt.Key_Up, count) def down(self, count=1): - self._repeated_key_press(Qt.Key_Down, count) + self._repeated_key_press(QtCore.Qt.Key_Down, count) def left(self, count=1): - self._repeated_key_press(Qt.Key_Left, count) + self._repeated_key_press(QtCore.Qt.Key_Left, count) def right(self, count=1): - self._repeated_key_press(Qt.Key_Right, count) + self._repeated_key_press(QtCore.Qt.Key_Right, count) def top(self): - self._tab.fake_key_press(Qt.Key_Home) + self._tab.fake_key_press(QtCore.Qt.Key_Home) def bottom(self): - self._tab.fake_key_press(Qt.Key_End) + self._tab.fake_key_press(QtCore.Qt.Key_End) def page_up(self, count=1): - self._repeated_key_press(Qt.Key_PageUp, count) + self._repeated_key_press(QtCore.Qt.Key_PageUp, count) def page_down(self, count=1): - self._repeated_key_press(Qt.Key_PageDown, count) + self._repeated_key_press(QtCore.Qt.Key_PageDown, count) def at_top(self): return self.pos_px().y() == 0 @@ -619,7 +613,7 @@ class WebEngineHistoryPrivate(browsertab.AbstractHistoryPrivate): def __init__(self, tab: 'WebEngineTab') -> None: self._tab = tab - self._history = cast(QWebEngineHistory, None) + self._history = cast(QtWebEngineWidgets.QWebEngineHistory, None) def serialize(self): return qtutils.serialize(self._history) @@ -659,7 +653,7 @@ class WebEngineHistoryPrivate(browsertab.AbstractHistoryPrivate): stream, _data, cur_data = tabhistory.serialize(items) qtutils.deserialize_stream(stream, self._history) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_load_finished(): self._tab.scroller.to_point(cur_data['scroll-pos']) self._tab.load_finished.disconnect(_on_load_finished) @@ -668,7 +662,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() == QtCore.QPoint(0, 0)): self._tab.load_finished.connect(_on_load_finished) @@ -806,7 +800,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 = QtCore.QTimer(self) self._silence_timer.setSingleShot(True) self._silence_timer.setInterval(delay_ms) @@ -854,7 +848,7 @@ class WebEngineAudio(browsertab.AbstractAudio): page = self._widget.page() return page.recentlyAudible() - @pyqtSlot(QUrl) + @QtCore.pyqtSlot(QtCore.QUrl) def _on_url_changed(self, url): if self._overridden or not url.isValid(): return @@ -866,7 +860,7 @@ class WebEngineAudio(browsertab.AbstractAudio): self._on_url_changed(self._tab.url()) -class _WebEnginePermissions(QObject): +class _WebEnginePermissions(QtCore.QObject): """Handling of various permission-related signals.""" @@ -875,30 +869,30 @@ class _WebEnginePermissions(QObject): _options = { 0: 'content.notifications.enabled', - QWebEnginePage.Geolocation: 'content.geolocation', - QWebEnginePage.MediaAudioCapture: 'content.media.audio_capture', - QWebEnginePage.MediaVideoCapture: 'content.media.video_capture', - QWebEnginePage.MediaAudioVideoCapture: 'content.media.audio_video_capture', - QWebEnginePage.MouseLock: 'content.mouse_lock', - QWebEnginePage.DesktopVideoCapture: 'content.desktop_capture', - QWebEnginePage.DesktopAudioVideoCapture: 'content.desktop_capture', + QtWebEngineWidgets.QWebEnginePage.Geolocation: 'content.geolocation', + QtWebEngineWidgets.QWebEnginePage.MediaAudioCapture: 'content.media.audio_capture', + QtWebEngineWidgets.QWebEnginePage.MediaVideoCapture: 'content.media.video_capture', + QtWebEngineWidgets.QWebEnginePage.MediaAudioVideoCapture: 'content.media.audio_video_capture', + QtWebEngineWidgets.QWebEnginePage.MouseLock: 'content.mouse_lock', + QtWebEngineWidgets.QWebEnginePage.DesktopVideoCapture: 'content.desktop_capture', + QtWebEngineWidgets.QWebEnginePage.DesktopAudioVideoCapture: 'content.desktop_capture', } _messages = { 0: 'show notifications', - QWebEnginePage.Geolocation: 'access your location', - QWebEnginePage.MediaAudioCapture: 'record audio', - QWebEnginePage.MediaVideoCapture: 'record video', - QWebEnginePage.MediaAudioVideoCapture: 'record audio/video', - QWebEnginePage.MouseLock: 'hide your mouse pointer', - QWebEnginePage.DesktopVideoCapture: 'capture your desktop', - QWebEnginePage.DesktopAudioVideoCapture: 'capture your desktop and audio', + QtWebEngineWidgets.QWebEnginePage.Geolocation: 'access your location', + QtWebEngineWidgets.QWebEnginePage.MediaAudioCapture: 'record audio', + QtWebEngineWidgets.QWebEnginePage.MediaVideoCapture: 'record video', + QtWebEngineWidgets.QWebEnginePage.MediaAudioVideoCapture: 'record audio/video', + QtWebEngineWidgets.QWebEnginePage.MouseLock: 'hide your mouse pointer', + QtWebEngineWidgets.QWebEnginePage.DesktopVideoCapture: 'capture your desktop', + QtWebEngineWidgets.QWebEnginePage.DesktopAudioVideoCapture: 'capture your desktop and audio', } def __init__(self, tab, parent=None): super().__init__(parent) self._tab = tab - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) assert self._options.keys() == self._messages.keys() def connect_signals(self): @@ -913,7 +907,7 @@ class _WebEnginePermissions(QObject): page.registerProtocolHandlerRequested.connect( self._on_register_protocol_handler_requested) - @pyqtSlot('QWebEngineFullScreenRequest') + @QtCore.pyqtSlot('QWebEngineFullScreenRequest') def _on_fullscreen_requested(self, request): request.accept() on = request.toggleOn() @@ -927,18 +921,18 @@ class _WebEnginePermissions(QObject): notif.set_timeout(timeout) notif.show() - @pyqtSlot(QUrl, 'QWebEnginePage::Feature') + @QtCore.pyqtSlot(QtCore.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.PermissionGrantedByUser) + QtWebEngineWidgets.QWebEnginePage.PermissionGrantedByUser) deny_permission = functools.partial( page.setFeaturePermission, url, feature, - QWebEnginePage.PermissionDeniedByUser) + QtWebEngineWidgets.QWebEnginePage.PermissionDeniedByUser) - permission_str = debug.qenum_key(QWebEnginePage, feature) + permission_str = debug.qenum_key(QtWebEngineWidgets.QWebEnginePage, feature) if not url.isValid(): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-85116 @@ -946,7 +940,7 @@ class _WebEnginePermissions(QObject): compiled=False, exact=True) and self._tab.is_private and - feature == QWebEnginePage.Notifications) + feature == QtWebEngineWidgets.QWebEnginePage.Notifications) logger = log.webview.debug if is_qtbug else log.webview.warning logger("Ignoring feature permission {} for invalid URL {}".format( permission_str, url)) @@ -960,8 +954,8 @@ class _WebEnginePermissions(QObject): return if ( - feature in [QWebEnginePage.DesktopVideoCapture, - QWebEnginePage.DesktopAudioVideoCapture] and + feature in [QtWebEngineWidgets.QWebEnginePage.DesktopVideoCapture, + QtWebEngineWidgets.QWebEnginePage.DesktopAudioVideoCapture] and qtutils.version_check('5.13', compiled=False) and not qtutils.version_check('5.13.2', compiled=False) ): @@ -972,7 +966,7 @@ class _WebEnginePermissions(QObject): return question = shared.feature_permission( - url=url.adjusted(QUrl.RemovePath), + url=url.adjusted(QtCore.QUrl.RemovePath), option=self._options[feature], msg=self._messages[feature], yes_action=grant_permission, no_action=deny_permission, abort_on=[self._tab.abort_questions]) @@ -999,7 +993,7 @@ class _WebEnginePermissions(QObject): def _on_quota_requested(self, request): size = utils.format_size(request.requestedSize()) shared.feature_permission( - url=request.origin().adjusted(QUrl.RemovePath), + url=request.origin().adjusted(QtCore.QUrl.RemovePath), option='content.persistent_storage', msg='use {} of persistent storage'.format(size), yes_action=request.accept, no_action=request.reject, @@ -1008,7 +1002,7 @@ class _WebEnginePermissions(QObject): def _on_register_protocol_handler_requested(self, request): shared.feature_permission( - url=request.origin().adjusted(QUrl.RemovePath), + url=request.origin().adjusted(QtCore.QUrl.RemovePath), option='content.register_protocol_handler', msg='open all {} links'.format(request.scheme()), yes_action=request.accept, no_action=request.reject, @@ -1020,9 +1014,9 @@ class _WebEnginePermissions(QObject): class _Quirk: filename: str - injection_point: QWebEngineScript.InjectionPoint = ( - QWebEngineScript.DocumentCreation) - world: QWebEngineScript.ScriptWorldId = QWebEngineScript.MainWorld + injection_point: QtWebEngineWidgets.QWebEngineScript.InjectionPoint = ( + QtWebEngineWidgets.QWebEngineScript.DocumentCreation) + world: QtWebEngineWidgets.QWebEngineScript.ScriptWorldId = QtWebEngineWidgets.QWebEngineScript.MainWorld predicate: bool = True name: Optional[str] = None @@ -1031,12 +1025,12 @@ class _Quirk: self.name = f"js-{self.filename.replace('_', '-')}" -class _WebEngineScripts(QObject): +class _WebEngineScripts(QtCore.QObject): def __init__(self, tab, parent=None): super().__init__(parent) self._tab = tab - self._widget = cast(QWidget, None) + self._widget = cast(QtWidgets.QWidget, None) self._greasemonkey = greasemonkey.gm_manager def connect_signals(self): @@ -1047,13 +1041,13 @@ class _WebEngineScripts(QObject): self._update_stylesheet, searching=False)) self._tab.search.finished.connect(self._update_stylesheet) - @pyqtSlot(str) + @QtCore.pyqtSlot(str) def _on_config_changed(self, option): if option in ['scrolling.bar', 'content.user_stylesheets']: self._init_stylesheet() self._update_stylesheet() - @pyqtSlot(bool) + @QtCore.pyqtSlot(bool) def _update_stylesheet(self, searching=False): """Update the custom stylesheet in existing tabs.""" css = shared.get_user_stylesheet(searching=searching) @@ -1061,11 +1055,11 @@ class _WebEngineScripts(QObject): self._tab.run_js_async(code) def _inject_js(self, name, js_code, *, - world=QWebEngineScript.ApplicationWorld, - injection_point=QWebEngineScript.DocumentCreation, + world=QtWebEngineWidgets.QWebEngineScript.ApplicationWorld, + injection_point=QtWebEngineWidgets.QWebEngineScript.DocumentCreation, subframes=False): """Inject the given script to run early on a page load.""" - script = QWebEngineScript() + script = QtWebEngineWidgets.QWebEngineScript() script.setInjectionPoint(injection_point) script.setSourceCode(js_code) script.setWorldId(world) @@ -1112,7 +1106,7 @@ class _WebEngineScripts(QObject): ) self._inject_js('stylesheet', js_code, subframes=True) - @pyqtSlot() + @QtCore.pyqtSlot() def _inject_all_greasemonkey_scripts(self): scripts = self._greasemonkey.all_scripts() self._inject_greasemonkey_scripts(scripts) @@ -1149,7 +1143,7 @@ class _WebEngineScripts(QObject): script.dedup_suffix += 1 seen_names.add(script.full_name()) - new_script = QWebEngineScript() + new_script = QtWebEngineWidgets.QWebEngineScript() try: world = int(script.jsworld) @@ -1177,7 +1171,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.DocumentReady) + new_script.setInjectionPoint(QtWebEngineWidgets.QWebEngineScript.DocumentReady) new_script.setSourceCode(script.code()) new_script.setName(script.full_name()) @@ -1186,7 +1180,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.DocumentReady) + new_script.setInjectionPoint(QtWebEngineWidgets.QWebEngineScript.DocumentReady) log.greasemonkey.debug(f'adding script: {new_script.name()}') page_scripts.insert(new_script) @@ -1200,8 +1194,8 @@ class _WebEngineScripts(QObject): quirks = [ _Quirk( 'whatsapp_web', - injection_point=QWebEngineScript.DocumentReady, - world=QWebEngineScript.ApplicationWorld, + injection_point=QtWebEngineWidgets.QWebEngineScript.DocumentReady, + world=QtWebEngineWidgets.QWebEngineScript.ApplicationWorld, ), _Quirk('discord'), _Quirk( @@ -1273,7 +1267,7 @@ class WebEngineTab(browsertab.AbstractTab): down. """ - abort_questions = pyqtSignal() + abort_questions = QtCore.pyqtSignal() def __init__(self, *, win_id, mode_manager, private, parent=None): super().__init__(win_id=win_id, @@ -1322,7 +1316,7 @@ class WebEngineTab(browsertab.AbstractTab): parent=self) self._widget.installEventFilter(self._child_event_filter) - @pyqtSlot() + @QtCore.pyqtSlot() def _restore_zoom(self): if sip.isdeleted(self._widget): # https://github.com/qutebrowser/qutebrowser/issues/3498 @@ -1359,9 +1353,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[QtWebEngineWidgets.QWebEngineScript.ScriptWorldId, int] if world is None: - world_id: world_id_type = QWebEngineScript.ApplicationWorld + world_id: world_id_type = QtWebEngineWidgets.QWebEngineScript.ApplicationWorld elif isinstance(world, int): world_id = world if not 0 <= world_id <= qtutils.MAX_WORLD_ID: @@ -1378,9 +1372,9 @@ class WebEngineTab(browsertab.AbstractTab): def reload(self, *, force=False): if force: - action = QWebEnginePage.ReloadAndBypassCache + action = QtWebEngineWidgets.QWebEnginePage.ReloadAndBypassCache else: - action = QWebEnginePage.Reload + action = QtWebEngineWidgets.QWebEnginePage.Reload self._widget.triggerPageAction(action) def stop(self): @@ -1400,7 +1394,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=QtCore.QUrl()): # FIXME:qtwebengine # check this and raise an exception if too big: # Warning: The content will be percent encoded before being sent to the @@ -1418,7 +1412,7 @@ class WebEngineTab(browsertab.AbstractTab): url=url_string, error=error) self.set_html(error_page) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_history_trigger(self): try: self._widget.page() @@ -1434,10 +1428,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 = QtCore.QUrl(url) title_url.setScheme('') title_url_str = title_url.toDisplayString( - QUrl.RemoveScheme) # type: ignore[arg-type] + QtCore.QUrl.RemoveScheme) # type: ignore[arg-type] if title == title_url_str.strip('/'): title = "" @@ -1448,26 +1442,26 @@ class WebEngineTab(browsertab.AbstractTab): self.history_item_triggered.emit(url, requested_url, title) - @pyqtSlot(QUrl, 'QAuthenticator*', 'QString') + @QtCore.pyqtSlot(QtCore.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.RemovePassword | QUrl.FullyEncoded) + urlstr = url.toString(QtCore.QUrl.RemovePassword | QtCore.QUrl.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, QtNetwork.QAuthenticator()) return authenticator.setUser(answer.user) authenticator.setPassword(answer.password) - @pyqtSlot(QUrl, 'QAuthenticator*') + @QtCore.pyqtSlot(QtCore.QUrl, 'QAuthenticator*') def _on_authentication_required(self, url, authenticator): log.network.debug("Authentication requested for {}, netrc_used {}" .format(url.toDisplayString(), self.data.netrc_used)) @@ -1483,9 +1477,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, QtNetwork.QAuthenticator()) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_load_started(self): """Clear search when a new load is started if needed.""" # WORKAROUND for @@ -1495,27 +1489,27 @@ class WebEngineTab(browsertab.AbstractTab): super()._on_load_started() self.data.netrc_used = False - @pyqtSlot('qint64') + @QtCore.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) + @QtCore.pyqtSlot(QtWebEngineWidgets.QWebEnginePage.RenderProcessTerminationStatus, int) def _on_render_process_terminated(self, status, exitcode): """Show an error when the renderer process terminated.""" - if (status == QWebEnginePage.AbnormalTerminationStatus and + if (status == QtWebEngineWidgets.QWebEnginePage.AbnormalTerminationStatus and exitcode == 256): # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-58697 - status = QWebEnginePage.CrashedTerminationStatus + status = QtWebEngineWidgets.QWebEnginePage.CrashedTerminationStatus status_map = { - QWebEnginePage.NormalTerminationStatus: + QtWebEngineWidgets.QWebEnginePage.NormalTerminationStatus: browsertab.TerminationStatus.normal, - QWebEnginePage.AbnormalTerminationStatus: + QtWebEngineWidgets.QWebEnginePage.AbnormalTerminationStatus: browsertab.TerminationStatus.abnormal, - QWebEnginePage.CrashedTerminationStatus: + QtWebEngineWidgets.QWebEnginePage.CrashedTerminationStatus: browsertab.TerminationStatus.crashed, - QWebEnginePage.KilledTerminationStatus: + QtWebEngineWidgets.QWebEnginePage.KilledTerminationStatus: browsertab.TerminationStatus.killed, -1: browsertab.TerminationStatus.unknown, @@ -1543,7 +1537,7 @@ class WebEngineTab(browsertab.AbstractTab): self._show_error_page(self.url(), error=error) - @pyqtSlot(int) + @QtCore.pyqtSlot(int) def _on_load_progress(self, perc: int) -> None: """QtWebEngine-specific loadProgress workarounds. @@ -1554,7 +1548,7 @@ class WebEngineTab(browsertab.AbstractTab): self.load_status() != usertypes.LoadStatus.error): self._update_load_status(ok=True) - @pyqtSlot(bool) + @QtCore.pyqtSlot(bool) def _on_load_finished(self, ok: bool) -> None: """QtWebEngine-specific loadFinished workarounds.""" super()._on_load_finished(ok) @@ -1567,7 +1561,7 @@ class WebEngineTab(browsertab.AbstractTab): self._error_page_workaround, self.settings.test_attribute('content.javascript.enabled'))) - @pyqtSlot(certificateerror.CertificateErrorWrapper) + @QtCore.pyqtSlot(certificateerror.CertificateErrorWrapper) def _on_ssl_errors(self, error): url = error.url() self._insecure_hosts.add(url.host()) @@ -1613,11 +1607,11 @@ class WebEngineTab(browsertab.AbstractTab): # have happened when loading some resource. is_resource = ( first_party_url.isValid() and - url.matches(first_party_url, QUrl.RemoveScheme)) + url.matches(first_party_url, QtCore.QUrl.RemoveScheme)) if show_non_overr_cert_error and is_resource: self._show_error_page(url, str(error)) - @pyqtSlot() + @QtCore.pyqtSlot() def _on_print_requested(self): """Slot for window.print() in JS.""" try: @@ -1625,8 +1619,8 @@ class WebEngineTab(browsertab.AbstractTab): except browsertab.WebTabError as e: message.error(str(e)) - @pyqtSlot(QUrl) - def _on_url_changed(self, url: QUrl) -> None: + @QtCore.pyqtSlot(QtCore.QUrl) + def _on_url_changed(self, url: QtCore.QUrl) -> None: """Update settings for the current URL. Normally this is done below in _on_navigation_request, but we also need @@ -1642,7 +1636,7 @@ class WebEngineTab(browsertab.AbstractTab): not qtutils.version_check('5.14')): self.settings.update_for_url(url) - @pyqtSlot(usertypes.NavigationRequest) + @QtCore.pyqtSlot(usertypes.NavigationRequest) def _on_navigation_request(self, navigation): super()._on_navigation_request(navigation) @@ -1699,9 +1693,7 @@ class WebEngineTab(browsertab.AbstractTab): page.printRequested.connect(self._on_print_requested) try: - # pylint: disable=unused-import - from PyQt5.QtWebEngineWidgets import ( - QWebEngineClientCertificateSelection) + pass except ImportError: pass else: diff --git a/qutebrowser/browser/webengine/webview.py b/qutebrowser/browser/webengine/webview.py index 76ce1a42e..bf9440c22 100644 --- a/qutebrowser/browser/webengine/webview.py +++ b/qutebrowser/browser/webengine/webview.py @@ -20,20 +20,18 @@ """The main browser widget for QtWebEngine.""" from typing import List, Iterable - -from PyQt5.QtCore import pyqtSignal, QUrl -from PyQt5.QtGui import QPalette -from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage +from qutebrowser.qt import QtWebEngineWidgets, QtGui from qutebrowser.browser import shared from qutebrowser.browser.webengine import webenginesettings, certificateerror from qutebrowser.config import config from qutebrowser.utils import log, debug, usertypes +from qutebrowser.qt import QtCore _QB_FILESELECTION_MODES = { - QWebEnginePage.FileSelectOpen: shared.FileSelectionMode.single_file, - QWebEnginePage.FileSelectOpenMultiple: shared.FileSelectionMode.multiple_files, + QtWebEngineWidgets.QWebEnginePage.FileSelectOpen: shared.FileSelectionMode.single_file, + QtWebEngineWidgets.QWebEnginePage.FileSelectOpenMultiple: shared.FileSelectionMode.multiple_files, # WORKAROUND for https://bugreports.qt.io/browse/QTBUG-91489 # # QtWebEngine doesn't expose this value from its internal @@ -41,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, + QtWebEngineWidgets.QWebEnginePage.FileSelectionMode(2): shared.FileSelectionMode.folder, } -class WebEngineView(QWebEngineView): +class WebEngineView(QtWebEngineWidgets.QWebEngineView): """Custom QWebEngineView subclass with qutebrowser-specific features.""" @@ -54,7 +52,7 @@ class WebEngineView(QWebEngineView): self._win_id = win_id self._tabdata = tabdata - theme_color = self.style().standardPalette().color(QPalette.Base) + theme_color = self.style().standardPalette().color(QtGui.QPalette.Base) if private: assert webenginesettings.private_profile is not None profile = webenginesettings.private_profile @@ -97,27 +95,27 @@ class WebEngineView(QWebEngineView): Return: The new QWebEngineView object. """ - debug_type = debug.qenum_key(QWebEnginePage, wintype) + debug_type = debug.qenum_key(QtWebEngineWidgets.QWebEnginePage, wintype) background = config.val.tabs.background log.webview.debug("createWindow with type {}, background {}".format( debug_type, background)) - if wintype == QWebEnginePage.WebBrowserWindow: + if wintype == QtWebEngineWidgets.QWebEnginePage.WebBrowserWindow: # Shift-Alt-Click target = usertypes.ClickTarget.window - elif wintype == QWebEnginePage.WebDialog: + elif wintype == QtWebEngineWidgets.QWebEnginePage.WebDialog: log.webview.warning("{} requested, but we don't support " "that!".format(debug_type)) target = usertypes.ClickTarget.tab - elif wintype == QWebEnginePage.WebBrowserTab: + elif wintype == QtWebEngineWidgets.QWebEnginePage.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.WebBrowserBackgroundTab: + elif wintype == QtWebEngineWidgets.QWebEnginePage.WebBrowserBackgroundTab: # Middle-click / Ctrl-Click if background: target = usertypes.ClickTarget.tab_bg @@ -137,7 +135,7 @@ class WebEngineView(QWebEngineView): super().contextMenuEvent(ev) -class WebEnginePage(QWebEnginePage): +class WebEnginePage(QtWebEngineWidgets.QWebEnginePage): """Custom QWebEnginePage subclass with qutebrowser-specific features. @@ -153,9 +151,9 @@ class WebEnginePage(QWebEnginePage): navigation_request: Emitted on acceptNavigationRequest. """ - certificate_error = pyqtSignal(certificateerror.CertificateErrorWrapper) - shutting_down = pyqtSignal() - navigation_request = pyqtSignal(usertypes.NavigationRequest) + certificate_error = QtCore.pyqtSignal(certificateerror.CertificateErrorWrapper) + shutting_down = QtCore.pyqtSignal() + navigation_request = QtCore.pyqtSignal(usertypes.NavigationRequest) def __init__(self, *, theme_color, profile, parent=None): super().__init__(profile, parent) @@ -214,33 +212,33 @@ class WebEnginePage(QWebEnginePage): def javaScriptConsoleMessage(self, level, msg, line, source): """Log javascript messages to qutebrowser's log.""" level_map = { - QWebEnginePage.InfoMessageLevel: usertypes.JsLogLevel.info, - QWebEnginePage.WarningMessageLevel: usertypes.JsLogLevel.warning, - QWebEnginePage.ErrorMessageLevel: usertypes.JsLogLevel.error, + QtWebEngineWidgets.QWebEnginePage.InfoMessageLevel: usertypes.JsLogLevel.info, + QtWebEngineWidgets.QWebEnginePage.WarningMessageLevel: usertypes.JsLogLevel.warning, + QtWebEngineWidgets.QWebEnginePage.ErrorMessageLevel: usertypes.JsLogLevel.error, } shared.javascript_log_message(level_map[level], source, line, msg) def acceptNavigationRequest(self, - url: QUrl, - typ: QWebEnginePage.NavigationType, + url: QtCore.QUrl, + typ: QtWebEngineWidgets.QWebEnginePage.NavigationType, is_main_frame: bool) -> bool: """Override acceptNavigationRequest to forward it to the tab API.""" type_map = { - QWebEnginePage.NavigationTypeLinkClicked: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeLinkClicked: usertypes.NavigationRequest.Type.link_clicked, - QWebEnginePage.NavigationTypeTyped: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeTyped: usertypes.NavigationRequest.Type.typed, - QWebEnginePage.NavigationTypeFormSubmitted: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeFormSubmitted: usertypes.NavigationRequest.Type.form_submitted, - QWebEnginePage.NavigationTypeBackForward: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeBackForward: usertypes.NavigationRequest.Type.back_forward, - QWebEnginePage.NavigationTypeReload: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeReload: usertypes.NavigationRequest.Type.reloaded, - QWebEnginePage.NavigationTypeOther: + QtWebEngineWidgets.QWebEnginePage.NavigationTypeOther: usertypes.NavigationRequest.Type.other, } try: - type_map[QWebEnginePage.NavigationTypeRedirect] = ( + type_map[QtWebEngineWidgets.QWebEnginePage.NavigationTypeRedirect] = ( usertypes.NavigationRequest.Type.redirect) except AttributeError: # Added in Qt 5.14 @@ -256,7 +254,7 @@ class WebEnginePage(QWebEnginePage): def chooseFiles( self, - mode: QWebEnginePage.FileSelectionMode, + mode: QtWebEngineWidgets.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 8494a8477..74c682ed3 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 PyQt5.QtNetwork import QNetworkDiskCache +from qutebrowser.qt import QtNetwork 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(QtNetwork.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 09237dae9..569df3988 100644 --- a/qutebrowser/browser/webkit/certificateerror.py +++ b/qutebrowser/browser/webkit/certificateerror.py @@ -21,7 +21,7 @@ from typing import Sequence -from PyQt5.QtNetwork import QSslError +from qutebrowser.qt import QtNetwork from qutebrowser.utils import usertypes, utils, debug, jinja @@ -30,7 +30,7 @@ class CertificateErrorWrapper(usertypes.AbstractCertificateErrorWrapper): """A wrapper over a list of QSslErrors.""" - def __init__(self, errors: Sequence[QSslError]) -> None: + def __init__(self, errors: Sequence[QtNetwork.QSslError]) -> None: self._errors = tuple(errors) # needs to be hashable def __str__(self) -> str: @@ -39,7 +39,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(QtNetwork.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 055ef64d8..e44f4532b 100644 --- a/qutebrowser/browser/webkit/cookies.py +++ b/qutebrowser/browser/webkit/cookies.py @@ -21,19 +21,17 @@ from typing import Sequence -from PyQt5.QtNetwork import QNetworkCookie, QNetworkCookieJar -from PyQt5.QtCore 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 QtNetwork, QtCore cookie_jar = None ram_cookie_jar = None -class RAMCookieJar(QNetworkCookieJar): +class RAMCookieJar(QtNetwork.QNetworkCookieJar): """An in-RAM cookie jar. @@ -41,7 +39,7 @@ class RAMCookieJar(QNetworkCookieJar): changed: Emitted when the cookie store was changed. """ - changed = pyqtSignal() + changed = QtCore.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[QtNetwork.QNetworkCookie] = [] for line in self._lineparser: - line_cookies = QNetworkCookie.parseCookies(line) + line_cookies = QtNetwork.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 = QtCore.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 5a7cd8b34..148e8b7f0 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 PyQt5.QtNetwork import QNetworkRequest +from qutebrowser.qt import QtNetwork from qutebrowser.utils import log, utils @@ -188,7 +188,7 @@ def parse_content_type(reply): A [mimetype, rest] list, or [None, None] if unset. Rest can be None. """ - content_type = reply.header(QNetworkRequest.ContentTypeHeader) + content_type = reply.header(QtNetwork.QNetworkRequest.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 d9f2d484e..7e106a57e 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 PyQt5.QtCore import QUrl +from qutebrowser.qt import QtCore 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[QtCore.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[QtCore.QUrl, downloads.AbstractDownloadItem]] class _Downloader: @@ -259,7 +259,7 @@ class _Downloader: else: # Might be a local