Override QWebPage::acceptNavigationRequest.
We now do this instead of using linkDelegationPolicy and the linkClicked signal of QWebView, as we are unable to get the target frame with linkClicked, causing frames to open full-page instead of where they should. See https://bugs.webkit.org/show_bug.cgi?id=37847
This commit is contained in:
parent
ca4336cab3
commit
c18027f3ae
@ -32,7 +32,7 @@ import qutebrowser.config.config as config
|
|||||||
import qutebrowser.utils.log as log
|
import qutebrowser.utils.log as log
|
||||||
from qutebrowser.utils.misc import read_file
|
from qutebrowser.utils.misc import read_file
|
||||||
from qutebrowser.utils.qt import check_print_compat
|
from qutebrowser.utils.qt import check_print_compat
|
||||||
from qutebrowser.utils.usertypes import PromptMode
|
from qutebrowser.utils.usertypes import PromptMode, ClickTarget
|
||||||
|
|
||||||
|
|
||||||
class BrowserPage(QWebPage):
|
class BrowserPage(QWebPage):
|
||||||
@ -41,16 +41,19 @@ class BrowserPage(QWebPage):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
_extension_handlers: Mapping of QWebPage extensions to their handlers.
|
_extension_handlers: Mapping of QWebPage extensions to their handlers.
|
||||||
|
_view: The QWebView associated with this page.
|
||||||
network_access_manager: The QNetworkAccessManager used.
|
network_access_manager: The QNetworkAccessManager used.
|
||||||
|
|
||||||
Signals:
|
Signals:
|
||||||
start_download: Emitted when a file should be downloaded.
|
start_download: Emitted when a file should be downloaded.
|
||||||
|
change_title: Emitted when the title should be changed.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
start_download = pyqtSignal('QNetworkReply*')
|
start_download = pyqtSignal('QNetworkReply*')
|
||||||
|
change_title = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, view):
|
||||||
super().__init__(parent)
|
super().__init__(view)
|
||||||
self._extension_handlers = {
|
self._extension_handlers = {
|
||||||
QWebPage.ErrorPageExtension: self._handle_errorpage,
|
QWebPage.ErrorPageExtension: self._handle_errorpage,
|
||||||
QWebPage.ChooseMultipleFilesExtension: self._handle_multiple_files,
|
QWebPage.ChooseMultipleFilesExtension: self._handle_multiple_files,
|
||||||
@ -60,6 +63,7 @@ class BrowserPage(QWebPage):
|
|||||||
self.setForwardUnsupportedContent(True)
|
self.setForwardUnsupportedContent(True)
|
||||||
self.printRequested.connect(self.on_print_requested)
|
self.printRequested.connect(self.on_print_requested)
|
||||||
self.downloadRequested.connect(self.on_download_requested)
|
self.downloadRequested.connect(self.on_download_requested)
|
||||||
|
self._view = view
|
||||||
|
|
||||||
if PYQT_VERSION > 0x050300:
|
if PYQT_VERSION > 0x050300:
|
||||||
# This breaks in <= 5.3.0, but in anything later it hopefully
|
# This breaks in <= 5.3.0, but in anything later it hopefully
|
||||||
@ -232,3 +236,36 @@ class BrowserPage(QWebPage):
|
|||||||
if answer is None:
|
if answer is None:
|
||||||
answer = True
|
answer = True
|
||||||
return answer
|
return answer
|
||||||
|
|
||||||
|
def acceptNavigationRequest(self, _frame, request, typ):
|
||||||
|
"""Override acceptNavigationRequest to handle clicked links.
|
||||||
|
|
||||||
|
Setting linkDelegationPolicy to DelegateAllLinks and using a slot bound
|
||||||
|
to linkClicked won't work correctly, because when in a frameset, we
|
||||||
|
have no idea in which frame the link should be opened.
|
||||||
|
|
||||||
|
Checks if it should open it in a tab (middle-click or control) or not,
|
||||||
|
and then opens the URL.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
_frame: QWebFrame (target frame)
|
||||||
|
request: QNetworkRequest
|
||||||
|
typ: QWebPage::NavigationType
|
||||||
|
"""
|
||||||
|
if typ != QWebPage.NavigationTypeLinkClicked:
|
||||||
|
return True
|
||||||
|
url = request.url()
|
||||||
|
urlstr = url.toDisplayString()
|
||||||
|
if not url.isValid():
|
||||||
|
message.error("Invalid link {} clicked!".format(urlstr))
|
||||||
|
log.webview.debug(url.errorString())
|
||||||
|
return False
|
||||||
|
if self._view.open_target == ClickTarget.tab:
|
||||||
|
self._view.tabbedbrowser.tabopen(url, False)
|
||||||
|
return False
|
||||||
|
elif self._view.open_target == ClickTarget.tab_bg:
|
||||||
|
self._view.tabbedbrowser.tabopen(url, True)
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.change_title.emit(urlstr)
|
||||||
|
return True
|
||||||
|
@ -235,6 +235,9 @@ class NeighborList(collections.abc.Sequence):
|
|||||||
# The mode of a Question.
|
# The mode of a Question.
|
||||||
PromptMode = enum('yesno', 'text', 'user_pwd', 'alert')
|
PromptMode = enum('yesno', 'text', 'user_pwd', 'alert')
|
||||||
|
|
||||||
|
# Where to open a clicked link.
|
||||||
|
ClickTarget = enum('normal', 'tab', 'tab_bg')
|
||||||
|
|
||||||
|
|
||||||
class Question(QObject):
|
class Question(QObject):
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
import functools
|
import functools
|
||||||
|
|
||||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt, QUrl
|
from PyQt5.QtCore import pyqtSignal, pyqtSlot, Qt
|
||||||
from PyQt5.QtWidgets import QApplication
|
from PyQt5.QtWidgets import QApplication
|
||||||
from PyQt5.QtWebKit import QWebSettings
|
from PyQt5.QtWebKit import QWebSettings
|
||||||
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
|
from PyQt5.QtWebKitWidgets import QWebView, QWebPage
|
||||||
@ -35,11 +35,10 @@ from qutebrowser.utils.misc import elide
|
|||||||
from qutebrowser.utils.qt import qt_ensure_valid
|
from qutebrowser.utils.qt import qt_ensure_valid
|
||||||
from qutebrowser.browser.webpage import BrowserPage
|
from qutebrowser.browser.webpage import BrowserPage
|
||||||
from qutebrowser.browser.hints import HintManager
|
from qutebrowser.browser.hints import HintManager
|
||||||
from qutebrowser.utils.usertypes import NeighborList, enum
|
from qutebrowser.utils.usertypes import NeighborList, ClickTarget, enum
|
||||||
from qutebrowser.commands.exceptions import CommandError
|
from qutebrowser.commands.exceptions import CommandError
|
||||||
|
|
||||||
|
|
||||||
Target = enum('normal', 'tab', 'tab_bg')
|
|
||||||
LoadStatus = enum('none', 'success', 'error', 'warn', 'loading')
|
LoadStatus = enum('none', 'success', 'error', 'warn', 'loading')
|
||||||
|
|
||||||
|
|
||||||
@ -58,6 +57,7 @@ class WebView(QWebView):
|
|||||||
scroll_pos: The current scroll position as (x%, y%) tuple.
|
scroll_pos: The current scroll position as (x%, y%) tuple.
|
||||||
statusbar_message: The current javscript statusbar message.
|
statusbar_message: The current javscript statusbar message.
|
||||||
inspector: The QWebInspector used for this webview.
|
inspector: The QWebInspector used for this webview.
|
||||||
|
open_target: Where to open the next tab ("normal", "tab", "tab_bg")
|
||||||
_page: The QWebPage behind the view
|
_page: The QWebPage behind the view
|
||||||
_url_text: The current URL as string.
|
_url_text: The current URL as string.
|
||||||
Accessed via url_text property.
|
Accessed via url_text property.
|
||||||
@ -67,7 +67,6 @@ class WebView(QWebView):
|
|||||||
_zoom: A NeighborList with the zoom levels.
|
_zoom: A NeighborList with the zoom levels.
|
||||||
_old_scroll_pos: The old scroll position.
|
_old_scroll_pos: The old scroll position.
|
||||||
_shutdown_callback: Callback to be called after shutdown.
|
_shutdown_callback: Callback to be called after shutdown.
|
||||||
_open_target: Where to open the next tab ("normal", "tab", "tab_bg")
|
|
||||||
_force_open_target: Override for _open_target.
|
_force_open_target: Override for _open_target.
|
||||||
_shutdown_callback: The callback to call after shutting down.
|
_shutdown_callback: The callback to call after shutting down.
|
||||||
_destroyed: Dict of all items to be destroyed on shtudown.
|
_destroyed: Dict of all items to be destroyed on shtudown.
|
||||||
@ -95,7 +94,7 @@ class WebView(QWebView):
|
|||||||
self.statusbar_message = ''
|
self.statusbar_message = ''
|
||||||
self._old_scroll_pos = (-1, -1)
|
self._old_scroll_pos = (-1, -1)
|
||||||
self._shutdown_callback = None
|
self._shutdown_callback = None
|
||||||
self._open_target = Target.normal
|
self.open_target = ClickTarget.normal
|
||||||
self._force_open_target = None
|
self._force_open_target = None
|
||||||
self._destroyed = {}
|
self._destroyed = {}
|
||||||
self._zoom = None
|
self._zoom = None
|
||||||
@ -108,10 +107,9 @@ class WebView(QWebView):
|
|||||||
self.hintmanager = HintManager(self)
|
self.hintmanager = HintManager(self)
|
||||||
self.hintmanager.mouse_event.connect(self.on_mouse_event)
|
self.hintmanager.mouse_event.connect(self.on_mouse_event)
|
||||||
self.hintmanager.set_open_target.connect(self.set_force_open_target)
|
self.hintmanager.set_open_target.connect(self.set_force_open_target)
|
||||||
self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks)
|
|
||||||
self.page().linkHovered.connect(self.linkHovered)
|
self.page().linkHovered.connect(self.linkHovered)
|
||||||
self.linkClicked.connect(self.on_link_clicked)
|
|
||||||
self.page().mainFrame().loadStarted.connect(self.on_load_started)
|
self.page().mainFrame().loadStarted.connect(self.on_load_started)
|
||||||
|
self.page().change_title.connect(self.titleChanged)
|
||||||
self.urlChanged.connect(self.on_url_changed)
|
self.urlChanged.connect(self.on_url_changed)
|
||||||
self.loadFinished.connect(self.on_load_finished)
|
self.loadFinished.connect(self.on_load_finished)
|
||||||
self.loadProgress.connect(lambda p: setattr(self, 'progress', p))
|
self.loadProgress.connect(lambda p: setattr(self, 'progress', p))
|
||||||
@ -236,20 +234,20 @@ class WebView(QWebView):
|
|||||||
e: The QMouseEvent.
|
e: The QMouseEvent.
|
||||||
"""
|
"""
|
||||||
if self._force_open_target is not None:
|
if self._force_open_target is not None:
|
||||||
self._open_target = self._force_open_target
|
self.open_target = self._force_open_target
|
||||||
self._force_open_target = None
|
self._force_open_target = None
|
||||||
log.mouse.debug("Setting force target: {}".format(
|
log.mouse.debug("Setting force target: {}".format(
|
||||||
Target[self._open_target]))
|
ClickTarget[self.open_target]))
|
||||||
elif (e.button() == Qt.MidButton or
|
elif (e.button() == Qt.MidButton or
|
||||||
e.modifiers() & Qt.ControlModifier):
|
e.modifiers() & Qt.ControlModifier):
|
||||||
if config.get('general', 'background-tabs'):
|
if config.get('general', 'background-tabs'):
|
||||||
self._open_target = Target.tab_bg
|
self.open_target = ClickTarget.tab_bg
|
||||||
else:
|
else:
|
||||||
self._open_target = Target.tab
|
self.open_target = ClickTarget.tab
|
||||||
log.mouse.debug("Middle click, setting target: {}".format(
|
log.mouse.debug("Middle click, setting target: {}".format(
|
||||||
Target[self._open_target]))
|
ClickTarget[self.open_target]))
|
||||||
else:
|
else:
|
||||||
self._open_target = Target.normal
|
self.open_target = ClickTarget.normal
|
||||||
log.mouse.debug("Normal click, setting normal target")
|
log.mouse.debug("Normal click, setting normal target")
|
||||||
|
|
||||||
def openurl(self, url):
|
def openurl(self, url):
|
||||||
@ -354,28 +352,6 @@ class WebView(QWebView):
|
|||||||
qt_ensure_valid(url)
|
qt_ensure_valid(url)
|
||||||
self.url_text = url.toDisplayString()
|
self.url_text = url.toDisplayString()
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def on_link_clicked(self, urlstr):
|
|
||||||
"""Handle a link.
|
|
||||||
|
|
||||||
Called from the linkClicked signal. Checks if it should open it in a
|
|
||||||
tab (middle-click or control) or not, and does so.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
urlstr: The URL to handle, as string.
|
|
||||||
"""
|
|
||||||
url = QUrl(urlstr)
|
|
||||||
if not url.isValid():
|
|
||||||
message.error("Invalid link {} clicked!".format(urlstr))
|
|
||||||
log.webview.debug(url.errorString())
|
|
||||||
return
|
|
||||||
if self._open_target == Target.tab:
|
|
||||||
self.tabbedbrowser.tabopen(url, False)
|
|
||||||
elif self._open_target == Target.tab_bg:
|
|
||||||
self.tabbedbrowser.tabopen(url, True)
|
|
||||||
else:
|
|
||||||
self.openurl(url)
|
|
||||||
|
|
||||||
@pyqtSlot(str, str)
|
@pyqtSlot(str, str)
|
||||||
def on_config_changed(self, section, option):
|
def on_config_changed(self, section, option):
|
||||||
"""Update tab config when config was changed."""
|
"""Update tab config when config was changed."""
|
||||||
@ -425,7 +401,7 @@ class WebView(QWebView):
|
|||||||
Args:
|
Args:
|
||||||
target: A string to set self._force_open_target to.
|
target: A string to set self._force_open_target to.
|
||||||
"""
|
"""
|
||||||
t = getattr(Target, target)
|
t = getattr(ClickTarget, target)
|
||||||
log.webview.debug("Setting force target to {}/{}".format(target, t))
|
log.webview.debug("Setting force target to {}/{}".format(target, t))
|
||||||
self._force_open_target = t
|
self._force_open_target = t
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user