Skip to content
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
@@ -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.