Permalink
Browse files

Move mouse handling to an EventFilter

  • Loading branch information...
The-Compiler committed Aug 10, 2016
1 parent 85a4dc8 commit f908d29a5ff1af283d6f66e181203bdfbb26cce2
@@ -29,6 +29,7 @@
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 @@ def __init__(self, win_id, parent=None):
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 @@ def _set_widget(self, widget):
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."""
@@ -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 @@ def _init_js(self):
# 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 @@ def __init__(self, win_id, mode_manager, parent=None):
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 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 @@ def on_config_changed(self, section, option):
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 @@ def mousePressEvent(self, e):
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
View
@@ -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

0 comments on commit f908d29

Please sign in to comment.