Move mouse handling to an EventFilter
This commit is contained in:
parent
85a4dc808e
commit
f908d29a5f
@ -29,6 +29,7 @@ from qutebrowser.keyinput import modeman
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import utils, objreg, usertypes, message, log, qtutils
|
||||
from qutebrowser.misc import miscwidgets
|
||||
from qutebrowser.browser import mouse
|
||||
|
||||
|
||||
tab_id_gen = itertools.count(0)
|
||||
@ -481,8 +482,12 @@ class AbstractTab(QWidget):
|
||||
self._progress = 0
|
||||
self._has_ssl_errors = False
|
||||
self._load_status = usertypes.LoadStatus.none
|
||||
self._mouse_event_filter = mouse.MouseEventFilter(self, parent=self)
|
||||
self.backend = None
|
||||
|
||||
def _event_filter_target(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def _set_widget(self, widget):
|
||||
# pylint: disable=protected-access
|
||||
self._widget = widget
|
||||
@ -494,6 +499,8 @@ class AbstractTab(QWidget):
|
||||
self.search._widget = widget
|
||||
self.printing._widget = widget
|
||||
widget.mouse_wheel_zoom.connect(self.zoom._on_mouse_wheel_zoom)
|
||||
event_filter_target = self._event_filter_target()
|
||||
event_filter_target.installEventFilter(self._mouse_event_filter)
|
||||
|
||||
def _set_load_status(self, val):
|
||||
"""Setter for load_status."""
|
||||
|
77
qutebrowser/browser/mouse.py
Normal file
77
qutebrowser/browser/mouse.py
Normal file
@ -0,0 +1,77 @@
|
||||
# vim: ft=python fileencoding=utf-8 sts=4 sw=4 et:
|
||||
|
||||
# Copyright 2016 Florian Bruhin (The Compiler) <mail@qutebrowser.org>
|
||||
#
|
||||
# This file is part of qutebrowser.
|
||||
#
|
||||
# qutebrowser is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# qutebrowser is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with qutebrowser. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""Mouse handling for a browser tab."""
|
||||
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.utils import message
|
||||
|
||||
|
||||
from PyQt5.QtCore import QObject, QEvent, Qt
|
||||
|
||||
|
||||
class MouseEventFilter(QObject):
|
||||
|
||||
"""Handle mouse events on a tab."""
|
||||
|
||||
def __init__(self, tab, parent=None):
|
||||
super().__init__(parent)
|
||||
self._tab = tab
|
||||
self._handlers = {
|
||||
QEvent.MouseButtonPress: self._handle_mouse_press,
|
||||
}
|
||||
|
||||
def _handle_mouse_press(self, e):
|
||||
"""Handle pressing of a mouse button."""
|
||||
is_rocker_gesture = (config.get('input', 'rocker-gestures') and
|
||||
e.buttons() == Qt.LeftButton | Qt.RightButton)
|
||||
|
||||
if e.button() in [Qt.XButton1, Qt.XButton2] or is_rocker_gesture:
|
||||
self._mousepress_backforward(e)
|
||||
return True
|
||||
return False
|
||||
|
||||
def _mousepress_backforward(self, e):
|
||||
"""Handle back/forward mouse button presses.
|
||||
|
||||
Args:
|
||||
e: The QMouseEvent.
|
||||
"""
|
||||
if e.button() in [Qt.XButton1, 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(self._tab.win_id, "At beginning of history.",
|
||||
immediately=True)
|
||||
elif e.button() in [Qt.XButton2, Qt.RightButton]:
|
||||
# Forward button on mice which have it, or rocker gesture
|
||||
if self._tab.history.can_go_forward():
|
||||
self._tab.history.forward()
|
||||
else:
|
||||
message.error(self._tab.win_id, "At end of history.",
|
||||
immediately=True)
|
||||
|
||||
def eventFilter(self, _obj, event):
|
||||
"""Filter events going to a QWeb(Engine)View."""
|
||||
evtype = event.type()
|
||||
if evtype not in self._handlers:
|
||||
return False
|
||||
return self._handlers[evtype](event)
|
@ -359,6 +359,9 @@ class WebEngineTab(browsertab.AbstractTab):
|
||||
# FIXME:qtwebengine what about runsOnSubFrames?
|
||||
page.scripts().insert(script)
|
||||
|
||||
def _event_filter_target(self):
|
||||
return self._widget.focusProxy()
|
||||
|
||||
def openurl(self, url):
|
||||
self._openurl_prepare(url)
|
||||
self._widget.load(url)
|
||||
|
@ -510,6 +510,9 @@ class WebKitTab(browsertab.AbstractTab):
|
||||
self.zoom.set_default()
|
||||
self.backend = usertypes.Backend.QtWebKit
|
||||
|
||||
def _event_filter_target(self):
|
||||
return self._widget
|
||||
|
||||
def openurl(self, url):
|
||||
self._openurl_prepare(url)
|
||||
self._widget.openurl(url)
|
||||
|
@ -29,7 +29,7 @@ from PyQt5.QtWebKitWidgets import QWebView, QWebPage, QWebFrame
|
||||
|
||||
from qutebrowser.config import config
|
||||
from qutebrowser.keyinput import modeman
|
||||
from qutebrowser.utils import message, log, usertypes, utils, qtutils, objreg
|
||||
from qutebrowser.utils import log, usertypes, utils, qtutils, objreg
|
||||
from qutebrowser.browser import hints
|
||||
from qutebrowser.browser.webkit import webpage, webkitelem
|
||||
|
||||
@ -138,27 +138,6 @@ class WebView(QWebView):
|
||||
elif section == 'colors' and option == 'webpage.bg':
|
||||
self._set_bg_color()
|
||||
|
||||
def _mousepress_backforward(self, e):
|
||||
"""Handle back/forward mouse button presses.
|
||||
|
||||
Args:
|
||||
e: The QMouseEvent.
|
||||
"""
|
||||
if e.button() in [Qt.XButton1, Qt.LeftButton]:
|
||||
# Back button on mice which have it, or rocker gesture
|
||||
if self.page().history().canGoBack():
|
||||
self.back()
|
||||
else:
|
||||
message.error(self.win_id, "At beginning of history.",
|
||||
immediately=True)
|
||||
elif e.button() in [Qt.XButton2, Qt.RightButton]:
|
||||
# Forward button on mice which have it, or rocker gesture
|
||||
if self.page().history().canGoForward():
|
||||
self.forward()
|
||||
else:
|
||||
message.error(self.win_id, "At end of history.",
|
||||
immediately=True)
|
||||
|
||||
def _mousepress_insertmode(self, e):
|
||||
"""Switch to insert mode when an editable element was clicked.
|
||||
|
||||
@ -407,13 +386,6 @@ class WebView(QWebView):
|
||||
Return:
|
||||
The superclass return value.
|
||||
"""
|
||||
is_rocker_gesture = (config.get('input', 'rocker-gestures') and
|
||||
e.buttons() == Qt.LeftButton | Qt.RightButton)
|
||||
|
||||
if e.button() in [Qt.XButton1, Qt.XButton2] or is_rocker_gesture:
|
||||
self._mousepress_backforward(e)
|
||||
super().mousePressEvent(e)
|
||||
return
|
||||
self._mousepress_insertmode(e)
|
||||
self._mousepress_opentarget(e)
|
||||
self._ignore_wheel_event = True
|
||||
|
16
tests/manual/mouse.html
Normal file
16
tests/manual/mouse.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Mouse control</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
<li>Middle- or Ctrl-click on a <a href="https://www.qutebrowser.org">link</a> should open it in a new tab (fg/bg according to <code>tabs -> background-tabs</code>)</li>
|
||||
<li>When clicking the link with shift, <code>background-tabs</code> should be reversed accordingly.</li>
|
||||
<li>Ctrl + Mousewheel should zoom in/out</li>
|
||||
<li>Back/forward keys on mouse should navigate back/forward</li>
|
||||
<li>With <code>input -> rocker-gestures</code> set, no context menu should be shown, but pressing left+right/right+left buttons should navigate back/forward</li>
|
||||
<li>When setting <code>input -> rocker-gestures</code> dynamically, the context menu should be hidden/shown accordingly.</li>
|
||||
</body>
|
||||
</html>
|
@ -91,26 +91,35 @@ def tab(request, default_config, qtbot, tab_registry, cookiejar_and_cache):
|
||||
objreg.delete('mode-manager', scope='window', window=0)
|
||||
|
||||
|
||||
class Tab(browsertab.AbstractTab):
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
|
||||
def __init__(self, win_id, parent=None):
|
||||
super().__init__(win_id, parent)
|
||||
mode_manager = modeman.ModeManager(0)
|
||||
self.history = browsertab.AbstractHistory(self)
|
||||
self.scroller = browsertab.AbstractScroller(self, parent=self)
|
||||
self.caret = browsertab.AbstractCaret(win_id=self.win_id,
|
||||
mode_manager=mode_manager,
|
||||
tab=self, parent=self)
|
||||
self.zoom = browsertab.AbstractZoom(win_id=self.win_id)
|
||||
self.search = browsertab.AbstractSearch(parent=self)
|
||||
self.printing = browsertab.AbstractPrinting()
|
||||
|
||||
def _event_filter_target(self):
|
||||
return self._widget
|
||||
|
||||
|
||||
@pytest.mark.skipif(PYQT_VERSION < 0x050600,
|
||||
reason='Causes segfaults, see #1638')
|
||||
def test_tab(qtbot, view, config_stub, tab_registry):
|
||||
tab_w = browsertab.AbstractTab(win_id=0)
|
||||
tab_w = Tab(win_id=0)
|
||||
qtbot.add_widget(tab_w)
|
||||
|
||||
assert tab_w.win_id == 0
|
||||
assert tab_w._widget is None
|
||||
|
||||
mode_manager = modeman.ModeManager(0)
|
||||
|
||||
tab_w.history = browsertab.AbstractHistory(tab_w)
|
||||
tab_w.scroller = browsertab.AbstractScroller(tab_w, parent=tab_w)
|
||||
tab_w.caret = browsertab.AbstractCaret(win_id=tab_w.win_id,
|
||||
mode_manager=mode_manager,
|
||||
tab=tab_w, parent=tab_w)
|
||||
tab_w.zoom = browsertab.AbstractZoom(win_id=tab_w.win_id)
|
||||
tab_w.search = browsertab.AbstractSearch(parent=tab_w)
|
||||
tab_w.printing = browsertab.AbstractPrinting()
|
||||
|
||||
tab_w._set_widget(view)
|
||||
assert tab_w._widget is view
|
||||
assert tab_w.history._tab is tab_w
|
||||
|
Loading…
Reference in New Issue
Block a user