We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Low fps with high-frequency mouse
If mouse frequency is set to 1000Hz (for a specialized gaming mouses), the rendering speed falls dramatically for vispy-widgets that use scene graph.

Moving a 125Hz mouse around: 80-120 fps
Moving a 1000Hz mouse around: 5-20 fps

Code:

``` python
import numpy as np
from vispy import app, scene
from vispy.visuals import MarkersVisual

app.use_app("PyQt4")
canvas = scene.SceneCanvas(show=True)
canvas.measure_fps()

view = canvas.central_widget.add_view()
view.camera = 'panzoom'
view.camera.rect = (0, 0, 800, 800)

Markers = scene.visuals.create_visual_node(MarkersVisual)
vis = Markers()
vis.set_data(np.array([[100, 100, 0], [400, 100, 0], [400, 400, 0], [100, 400, 0]], dtype=np.float32))
view.add(vis)
app.run()
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `vispy/app/base.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2015, Vispy Development Team.
3 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4 
5 from ..util import SimpleBunch
6 import time
7 
8 
9 class BaseApplicationBackend(object):
10     """BaseApplicationBackend()
11 
12     Abstract class that provides an interface between backends and Application.
13     Each backend must implement a subclass of ApplicationBackend, and
14     implement all its _vispy_xxx methods.
15     """
16 
17     def _vispy_get_backend_name(self):
18         raise NotImplementedError()
19 
20     def _vispy_process_events(self):
21         raise NotImplementedError()
22 
23     def _vispy_run(self):
24         raise NotImplementedError()
25 
26     def _vispy_reuse(self):
27         # Does nothing by default.
28         pass
29 
30     def _vispy_quit(self):
31         raise NotImplementedError()
32 
33     def _vispy_get_native_app(self):
34         # Should return the native application object
35         return self
36 
37     # is called by inputhook.py for pauses
38     # to remove CPU stress
39     # this is virtual so that some backends which have specialize
40     # functionality to deal with user input / latency can use those methods
41     def _vispy_sleep(self, duration_sec):
42         time.sleep(duration_sec)
43 
44 
45 class BaseCanvasBackend(object):
46     """BaseCanvasBackend(vispy_canvas, capability, context_type)
47 
48     Abstract class that provides an interface between backends and Canvas.
49     Each backend must implement a subclass of CanvasBackend, and
50     implement all its _vispy_xxx methods. Also, also a backend must
51     make sure to generate the following events: 'initialize', 'resize',
52     'draw', 'mouse_press', 'mouse_release', 'mouse_move',
53     'mouse_wheel', 'key_press', 'key_release'. When a backend detects
54     that the canvas should be closed, the backend should call
55     'self._vispy_canvas.close', because the close event is handled within
56     the canvas itself.
57     """
58 
59     def __init__(self, vispy_canvas):
60         from .canvas import Canvas  # Avoid circular import
61         assert isinstance(vispy_canvas, Canvas)
62         self._vispy_canvas = vispy_canvas
63 
64         # We set the _backend attribute of the vispy_canvas to self,
65         # because at the end of the __init__ of the CanvasBackend
66         # implementation there might be a call to show or draw. By
67         # setting it here, we ensure that the Canvas is "ready to go".
68         vispy_canvas._backend = self
69 
70         # Data used in the construction of new mouse events
71         self._vispy_mouse_data = {
72             'buttons': [],
73             'press_event': None,
74             'last_event': None,
75             'last_mouse_press': None,
76         }
77 
78     def _process_backend_kwargs(self, kwargs):
79         """ Simple utility to retrieve kwargs in predetermined order.
80         Also checks whether the values of the backend arguments do not
81         violate the backend capabilities.
82         """
83         # Verify given argument with capability of the backend
84         app = self._vispy_canvas.app
85         capability = app.backend_module.capability
86         if kwargs['context'].shared.name:  # name already assigned: shared
87             if not capability['context']:
88                 raise RuntimeError('Cannot share context with this backend')
89         for key in [key for (key, val) in capability.items() if not val]:
90             if key in ['context', 'multi_window', 'scroll']:
91                 continue
92             invert = key in ['resizable', 'decorate']
93             if bool(kwargs[key]) - invert:
94                 raise RuntimeError('Config %s is not supported by backend %s'
95                                    % (key, app.backend_name))
96 
97         # Return items in sequence
98         out = SimpleBunch()
99         keys = ['title', 'size', 'position', 'show', 'vsync', 'resizable',
100                 'decorate', 'fullscreen', 'parent', 'context', 'always_on_top',
101                 ]
102         for key in keys:
103             out[key] = kwargs[key]
104         return out
105 
106     def _vispy_set_current(self):
107         # Make this the current context
108         raise NotImplementedError()
109 
110     def _vispy_swap_buffers(self):
111         # Swap front and back buffer
112         raise NotImplementedError()
113 
114     def _vispy_set_title(self, title):
115         # Set the window title. Has no effect for widgets
116         raise NotImplementedError()
117 
118     def _vispy_set_size(self, w, h):
119         # Set size of the widget or window
120         raise NotImplementedError()
121 
122     def _vispy_set_position(self, x, y):
123         # Set location of the widget or window. May have no effect for widgets
124         raise NotImplementedError()
125 
126     def _vispy_set_visible(self, visible):
127         # Show or hide the window or widget
128         raise NotImplementedError()
129 
130     def _vispy_set_fullscreen(self, fullscreen):
131         # Set fullscreen mode
132         raise NotImplementedError()
133 
134     def _vispy_update(self):
135         # Invoke a redraw
136         raise NotImplementedError()
137 
138     def _vispy_close(self):
139         # Force the window or widget to shut down
140         raise NotImplementedError()
141 
142     def _vispy_get_size(self):
143         # Should return widget size
144         raise NotImplementedError()
145 
146     def _vispy_get_physical_size(self):
147         # Should return physical widget size (actual number of screen pixels).
148         # This may differ from _vispy_get_size on backends that expose HiDPI
149         # screens. If not overriden, return the logical sizeself.
150         return self._vispy_get_size()
151 
152     def _vispy_get_position(self):
153         # Should return widget position
154         raise NotImplementedError()
155 
156     def _vispy_get_fullscreen(self):
157         # Should return bool for fullscreen status
158         raise NotImplementedError()
159 
160     def _vispy_get_geometry(self):
161         # Should return widget (x, y, w, h)
162         x, y = self._vispy_get_position()
163         w, h = self._vispy_get_size()
164         return x, y, w, h
165 
166     def _vispy_get_native_canvas(self):
167         # Should return the native widget object
168         # Most backends would not need to implement this
169         return self
170 
171     def _vispy_mouse_press(self, **kwargs):
172         # default method for delivering mouse press events to the canvas
173         kwargs.update(self._vispy_mouse_data)
174         ev = self._vispy_canvas.events.mouse_press(**kwargs)
175         if self._vispy_mouse_data['press_event'] is None:
176             self._vispy_mouse_data['press_event'] = ev
177 
178         self._vispy_mouse_data['buttons'].append(ev.button)
179         self._vispy_mouse_data['last_event'] = ev
180 
181         if not getattr(self, '_double_click_supported', False):
182             # double-click events are not supported by this backend, so we
183             # detect them manually
184             self._vispy_detect_double_click(ev)
185 
186         return ev
187 
188     def _vispy_mouse_move(self, **kwargs):
189         # default method for delivering mouse move events to the canvas
190         kwargs.update(self._vispy_mouse_data)
191 
192         # Break the chain of prior mouse events if no buttons are pressed
193         # (this means that during a mouse drag, we have full access to every
194         # move event generated since the drag started)
195         if self._vispy_mouse_data['press_event'] is None:
196             last_event = self._vispy_mouse_data['last_event']
197             if last_event is not None:
198                 last_event._forget_last_event()
199         else:
200             kwargs['button'] = self._vispy_mouse_data['press_event'].button
201 
202         ev = self._vispy_canvas.events.mouse_move(**kwargs)
203         self._vispy_mouse_data['last_event'] = ev
204         return ev
205 
206     def _vispy_mouse_release(self, **kwargs):
207         # default method for delivering mouse release events to the canvas
208         kwargs.update(self._vispy_mouse_data)
209 
210         ev = self._vispy_canvas.events.mouse_release(**kwargs)
211         if (self._vispy_mouse_data['press_event']
212                 and self._vispy_mouse_data['press_event'].button == ev.button):
213             self._vispy_mouse_data['press_event'] = None
214 
215         if ev.button in self._vispy_mouse_data['buttons']:
216             self._vispy_mouse_data['buttons'].remove(ev.button)
217         self._vispy_mouse_data['last_event'] = ev
218 
219         return ev
220 
221     def _vispy_mouse_double_click(self, **kwargs):
222         # default method for delivering double-click events to the canvas
223         kwargs.update(self._vispy_mouse_data)
224 
225         ev = self._vispy_canvas.events.mouse_double_click(**kwargs)
226         self._vispy_mouse_data['last_event'] = ev
227         return ev
228 
229     def _vispy_detect_double_click(self, ev, **kwargs):
230         # Called on every mouse_press or mouse_release, and calls
231         # _vispy_mouse_double_click if a double-click is calculated.
232         # Should be overridden with an empty function on backends which
233         # natively support double-clicking.
234 
235         dt_max = 0.3  # time in seconds for a double-click detection
236 
237         lastev = self._vispy_mouse_data['last_mouse_press']
238 
239         if lastev is None:
240             self._vispy_mouse_data['last_mouse_press'] = ev
241             return
242 
243         assert lastev.type == 'mouse_press'
244         assert ev.type == 'mouse_press'
245 
246         # For a double-click to be detected, the button should be the same,
247         # the position should be the same, and the two mouse-presses should
248         # be within dt_max.
249         if ((ev.time - lastev.time <= dt_max) &
250            (lastev.pos[0] - ev.pos[0] == 0) &
251            (lastev.pos[1] - ev.pos[1] == 0) &
252            (lastev.button == ev.button)):
253             self._vispy_mouse_double_click(**kwargs)
254 
255         self._vispy_mouse_data['last_mouse_press'] = ev
256 
257 
258 class BaseTimerBackend(object):
259     """BaseTimerBackend(vispy_timer)
260 
261     Abstract class that provides an interface between backends and Timer.
262     Each backend must implement a subclass of TimerBackend, and
263     implement all its _vispy_xxx methods.
264     """
265 
266     def __init__(self, vispy_timer):
267         self._vispy_timer = vispy_timer
268 
269     def _vispy_start(self, interval):
270         raise NotImplementedError
271 
272     def _vispy_stop(self):
273         raise NotImplementedError
274 
275     def _vispy_get_native_timer(self):
276         # Should return the native timer object
277         # Most backends would not need to implement this
278         return self
279
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/vispy/app/base.py b/vispy/app/base.py
--- a/vispy/app/base.py
+++ b/vispy/app/base.py
@@ -4,6 +4,7 @@
 
 from ..util import SimpleBunch
 import time
+from timeit import default_timer
 
 
 class BaseApplicationBackend(object):
@@ -60,6 +61,7 @@
         from .canvas import Canvas  # Avoid circular import
         assert isinstance(vispy_canvas, Canvas)
         self._vispy_canvas = vispy_canvas
+        self._last_time = 0
 
         # We set the _backend attribute of the vispy_canvas to self,
         # because at the end of the __init__ of the CanvasBackend
@@ -186,6 +188,10 @@
         return ev
 
     def _vispy_mouse_move(self, **kwargs):
+        if default_timer() - self._last_time < .01:
+            return
+        self._last_time = default_timer()
+
         # default method for delivering mouse move events to the canvas
         kwargs.update(self._vispy_mouse_data)

{"golden_diff": "diff --git a/vispy/app/base.py b/vispy/app/base.py\n--- a/vispy/app/base.py\n+++ b/vispy/app/base.py\n@@ -4,6 +4,7 @@\n \n from ..util import SimpleBunch\n import time\n+from timeit import default_timer\n \n \n class BaseApplicationBackend(object):\n@@ -60,6 +61,7 @@\n         from .canvas import Canvas  # Avoid circular import\n         assert isinstance(vispy_canvas, Canvas)\n         self._vispy_canvas = vispy_canvas\n+        self._last_time = 0\n \n         # We set the _backend attribute of the vispy_canvas to self,\n         # because at the end of the __init__ of the CanvasBackend\n@@ -186,6 +188,10 @@\n         return ev\n \n     def _vispy_mouse_move(self, **kwargs):\n+        if default_timer() - self._last_time < .01:\n+            return\n+        self._last_time = default_timer()\n+\n         # default method for delivering mouse move events to the canvas\n         kwargs.update(self._vispy_mouse_data)\n", "issue": "Low fps with high-frequency mouse\nIf mouse frequency is set to 1000Hz (for a specialized gaming mouses), the rendering speed falls dramatically for vispy-widgets that use scene graph.\n\nMoving a 125Hz mouse around: 80-120 fps\nMoving a 1000Hz mouse around: 5-20 fps\n\nCode:\n\n``` python\nimport numpy as np\nfrom vispy import app, scene\nfrom vispy.visuals import MarkersVisual\n\napp.use_app(\"PyQt4\")\ncanvas = scene.SceneCanvas(show=True)\ncanvas.measure_fps()\n\nview = canvas.central_widget.add_view()\nview.camera = 'panzoom'\nview.camera.rect = (0, 0, 800, 800)\n\nMarkers = scene.visuals.create_visual_node(MarkersVisual)\nvis = Markers()\nvis.set_data(np.array([[100, 100, 0], [400, 100, 0], [400, 400, 0], [100, 400, 0]], dtype=np.float32))\nview.add(vis)\napp.run()\n```\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2015, Vispy Development Team.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\nfrom ..util import SimpleBunch\nimport time\n\n\nclass BaseApplicationBackend(object):\n    \"\"\"BaseApplicationBackend()\n\n    Abstract class that provides an interface between backends and Application.\n    Each backend must implement a subclass of ApplicationBackend, and\n    implement all its _vispy_xxx methods.\n    \"\"\"\n\n    def _vispy_get_backend_name(self):\n        raise NotImplementedError()\n\n    def _vispy_process_events(self):\n        raise NotImplementedError()\n\n    def _vispy_run(self):\n        raise NotImplementedError()\n\n    def _vispy_reuse(self):\n        # Does nothing by default.\n        pass\n\n    def _vispy_quit(self):\n        raise NotImplementedError()\n\n    def _vispy_get_native_app(self):\n        # Should return the native application object\n        return self\n\n    # is called by inputhook.py for pauses\n    # to remove CPU stress\n    # this is virtual so that some backends which have specialize\n    # functionality to deal with user input / latency can use those methods\n    def _vispy_sleep(self, duration_sec):\n        time.sleep(duration_sec)\n\n\nclass BaseCanvasBackend(object):\n    \"\"\"BaseCanvasBackend(vispy_canvas, capability, context_type)\n\n    Abstract class that provides an interface between backends and Canvas.\n    Each backend must implement a subclass of CanvasBackend, and\n    implement all its _vispy_xxx methods. Also, also a backend must\n    make sure to generate the following events: 'initialize', 'resize',\n    'draw', 'mouse_press', 'mouse_release', 'mouse_move',\n    'mouse_wheel', 'key_press', 'key_release'. When a backend detects\n    that the canvas should be closed, the backend should call\n    'self._vispy_canvas.close', because the close event is handled within\n    the canvas itself.\n    \"\"\"\n\n    def __init__(self, vispy_canvas):\n        from .canvas import Canvas  # Avoid circular import\n        assert isinstance(vispy_canvas, Canvas)\n        self._vispy_canvas = vispy_canvas\n\n        # We set the _backend attribute of the vispy_canvas to self,\n        # because at the end of the __init__ of the CanvasBackend\n        # implementation there might be a call to show or draw. By\n        # setting it here, we ensure that the Canvas is \"ready to go\".\n        vispy_canvas._backend = self\n\n        # Data used in the construction of new mouse events\n        self._vispy_mouse_data = {\n            'buttons': [],\n            'press_event': None,\n            'last_event': None,\n            'last_mouse_press': None,\n        }\n\n    def _process_backend_kwargs(self, kwargs):\n        \"\"\" Simple utility to retrieve kwargs in predetermined order.\n        Also checks whether the values of the backend arguments do not\n        violate the backend capabilities.\n        \"\"\"\n        # Verify given argument with capability of the backend\n        app = self._vispy_canvas.app\n        capability = app.backend_module.capability\n        if kwargs['context'].shared.name:  # name already assigned: shared\n            if not capability['context']:\n                raise RuntimeError('Cannot share context with this backend')\n        for key in [key for (key, val) in capability.items() if not val]:\n            if key in ['context', 'multi_window', 'scroll']:\n                continue\n            invert = key in ['resizable', 'decorate']\n            if bool(kwargs[key]) - invert:\n                raise RuntimeError('Config %s is not supported by backend %s'\n                                   % (key, app.backend_name))\n\n        # Return items in sequence\n        out = SimpleBunch()\n        keys = ['title', 'size', 'position', 'show', 'vsync', 'resizable',\n                'decorate', 'fullscreen', 'parent', 'context', 'always_on_top',\n                ]\n        for key in keys:\n            out[key] = kwargs[key]\n        return out\n\n    def _vispy_set_current(self):\n        # Make this the current context\n        raise NotImplementedError()\n\n    def _vispy_swap_buffers(self):\n        # Swap front and back buffer\n        raise NotImplementedError()\n\n    def _vispy_set_title(self, title):\n        # Set the window title. Has no effect for widgets\n        raise NotImplementedError()\n\n    def _vispy_set_size(self, w, h):\n        # Set size of the widget or window\n        raise NotImplementedError()\n\n    def _vispy_set_position(self, x, y):\n        # Set location of the widget or window. May have no effect for widgets\n        raise NotImplementedError()\n\n    def _vispy_set_visible(self, visible):\n        # Show or hide the window or widget\n        raise NotImplementedError()\n\n    def _vispy_set_fullscreen(self, fullscreen):\n        # Set fullscreen mode\n        raise NotImplementedError()\n\n    def _vispy_update(self):\n        # Invoke a redraw\n        raise NotImplementedError()\n\n    def _vispy_close(self):\n        # Force the window or widget to shut down\n        raise NotImplementedError()\n\n    def _vispy_get_size(self):\n        # Should return widget size\n        raise NotImplementedError()\n\n    def _vispy_get_physical_size(self):\n        # Should return physical widget size (actual number of screen pixels).\n        # This may differ from _vispy_get_size on backends that expose HiDPI\n        # screens. If not overriden, return the logical sizeself.\n        return self._vispy_get_size()\n\n    def _vispy_get_position(self):\n        # Should return widget position\n        raise NotImplementedError()\n\n    def _vispy_get_fullscreen(self):\n        # Should return bool for fullscreen status\n        raise NotImplementedError()\n\n    def _vispy_get_geometry(self):\n        # Should return widget (x, y, w, h)\n        x, y = self._vispy_get_position()\n        w, h = self._vispy_get_size()\n        return x, y, w, h\n\n    def _vispy_get_native_canvas(self):\n        # Should return the native widget object\n        # Most backends would not need to implement this\n        return self\n\n    def _vispy_mouse_press(self, **kwargs):\n        # default method for delivering mouse press events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n        ev = self._vispy_canvas.events.mouse_press(**kwargs)\n        if self._vispy_mouse_data['press_event'] is None:\n            self._vispy_mouse_data['press_event'] = ev\n\n        self._vispy_mouse_data['buttons'].append(ev.button)\n        self._vispy_mouse_data['last_event'] = ev\n\n        if not getattr(self, '_double_click_supported', False):\n            # double-click events are not supported by this backend, so we\n            # detect them manually\n            self._vispy_detect_double_click(ev)\n\n        return ev\n\n    def _vispy_mouse_move(self, **kwargs):\n        # default method for delivering mouse move events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        # Break the chain of prior mouse events if no buttons are pressed\n        # (this means that during a mouse drag, we have full access to every\n        # move event generated since the drag started)\n        if self._vispy_mouse_data['press_event'] is None:\n            last_event = self._vispy_mouse_data['last_event']\n            if last_event is not None:\n                last_event._forget_last_event()\n        else:\n            kwargs['button'] = self._vispy_mouse_data['press_event'].button\n\n        ev = self._vispy_canvas.events.mouse_move(**kwargs)\n        self._vispy_mouse_data['last_event'] = ev\n        return ev\n\n    def _vispy_mouse_release(self, **kwargs):\n        # default method for delivering mouse release events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        ev = self._vispy_canvas.events.mouse_release(**kwargs)\n        if (self._vispy_mouse_data['press_event']\n                and self._vispy_mouse_data['press_event'].button == ev.button):\n            self._vispy_mouse_data['press_event'] = None\n\n        if ev.button in self._vispy_mouse_data['buttons']:\n            self._vispy_mouse_data['buttons'].remove(ev.button)\n        self._vispy_mouse_data['last_event'] = ev\n\n        return ev\n\n    def _vispy_mouse_double_click(self, **kwargs):\n        # default method for delivering double-click events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        ev = self._vispy_canvas.events.mouse_double_click(**kwargs)\n        self._vispy_mouse_data['last_event'] = ev\n        return ev\n\n    def _vispy_detect_double_click(self, ev, **kwargs):\n        # Called on every mouse_press or mouse_release, and calls\n        # _vispy_mouse_double_click if a double-click is calculated.\n        # Should be overridden with an empty function on backends which\n        # natively support double-clicking.\n\n        dt_max = 0.3  # time in seconds for a double-click detection\n\n        lastev = self._vispy_mouse_data['last_mouse_press']\n\n        if lastev is None:\n            self._vispy_mouse_data['last_mouse_press'] = ev\n            return\n\n        assert lastev.type == 'mouse_press'\n        assert ev.type == 'mouse_press'\n\n        # For a double-click to be detected, the button should be the same,\n        # the position should be the same, and the two mouse-presses should\n        # be within dt_max.\n        if ((ev.time - lastev.time <= dt_max) &\n           (lastev.pos[0] - ev.pos[0] == 0) &\n           (lastev.pos[1] - ev.pos[1] == 0) &\n           (lastev.button == ev.button)):\n            self._vispy_mouse_double_click(**kwargs)\n\n        self._vispy_mouse_data['last_mouse_press'] = ev\n\n\nclass BaseTimerBackend(object):\n    \"\"\"BaseTimerBackend(vispy_timer)\n\n    Abstract class that provides an interface between backends and Timer.\n    Each backend must implement a subclass of TimerBackend, and\n    implement all its _vispy_xxx methods.\n    \"\"\"\n\n    def __init__(self, vispy_timer):\n        self._vispy_timer = vispy_timer\n\n    def _vispy_start(self, interval):\n        raise NotImplementedError\n\n    def _vispy_stop(self):\n        raise NotImplementedError\n\n    def _vispy_get_native_timer(self):\n        # Should return the native timer object\n        # Most backends would not need to implement this\n        return self\n", "path": "vispy/app/base.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2015, Vispy Development Team.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\nfrom ..util import SimpleBunch\nimport time\nfrom timeit import default_timer\n\n\nclass BaseApplicationBackend(object):\n    \"\"\"BaseApplicationBackend()\n\n    Abstract class that provides an interface between backends and Application.\n    Each backend must implement a subclass of ApplicationBackend, and\n    implement all its _vispy_xxx methods.\n    \"\"\"\n\n    def _vispy_get_backend_name(self):\n        raise NotImplementedError()\n\n    def _vispy_process_events(self):\n        raise NotImplementedError()\n\n    def _vispy_run(self):\n        raise NotImplementedError()\n\n    def _vispy_reuse(self):\n        # Does nothing by default.\n        pass\n\n    def _vispy_quit(self):\n        raise NotImplementedError()\n\n    def _vispy_get_native_app(self):\n        # Should return the native application object\n        return self\n\n    # is called by inputhook.py for pauses\n    # to remove CPU stress\n    # this is virtual so that some backends which have specialize\n    # functionality to deal with user input / latency can use those methods\n    def _vispy_sleep(self, duration_sec):\n        time.sleep(duration_sec)\n\n\nclass BaseCanvasBackend(object):\n    \"\"\"BaseCanvasBackend(vispy_canvas, capability, context_type)\n\n    Abstract class that provides an interface between backends and Canvas.\n    Each backend must implement a subclass of CanvasBackend, and\n    implement all its _vispy_xxx methods. Also, also a backend must\n    make sure to generate the following events: 'initialize', 'resize',\n    'draw', 'mouse_press', 'mouse_release', 'mouse_move',\n    'mouse_wheel', 'key_press', 'key_release'. When a backend detects\n    that the canvas should be closed, the backend should call\n    'self._vispy_canvas.close', because the close event is handled within\n    the canvas itself.\n    \"\"\"\n\n    def __init__(self, vispy_canvas):\n        from .canvas import Canvas  # Avoid circular import\n        assert isinstance(vispy_canvas, Canvas)\n        self._vispy_canvas = vispy_canvas\n        self._last_time = 0\n\n        # We set the _backend attribute of the vispy_canvas to self,\n        # because at the end of the __init__ of the CanvasBackend\n        # implementation there might be a call to show or draw. By\n        # setting it here, we ensure that the Canvas is \"ready to go\".\n        vispy_canvas._backend = self\n\n        # Data used in the construction of new mouse events\n        self._vispy_mouse_data = {\n            'buttons': [],\n            'press_event': None,\n            'last_event': None,\n            'last_mouse_press': None,\n        }\n\n    def _process_backend_kwargs(self, kwargs):\n        \"\"\" Simple utility to retrieve kwargs in predetermined order.\n        Also checks whether the values of the backend arguments do not\n        violate the backend capabilities.\n        \"\"\"\n        # Verify given argument with capability of the backend\n        app = self._vispy_canvas.app\n        capability = app.backend_module.capability\n        if kwargs['context'].shared.name:  # name already assigned: shared\n            if not capability['context']:\n                raise RuntimeError('Cannot share context with this backend')\n        for key in [key for (key, val) in capability.items() if not val]:\n            if key in ['context', 'multi_window', 'scroll']:\n                continue\n            invert = key in ['resizable', 'decorate']\n            if bool(kwargs[key]) - invert:\n                raise RuntimeError('Config %s is not supported by backend %s'\n                                   % (key, app.backend_name))\n\n        # Return items in sequence\n        out = SimpleBunch()\n        keys = ['title', 'size', 'position', 'show', 'vsync', 'resizable',\n                'decorate', 'fullscreen', 'parent', 'context', 'always_on_top',\n                ]\n        for key in keys:\n            out[key] = kwargs[key]\n        return out\n\n    def _vispy_set_current(self):\n        # Make this the current context\n        raise NotImplementedError()\n\n    def _vispy_swap_buffers(self):\n        # Swap front and back buffer\n        raise NotImplementedError()\n\n    def _vispy_set_title(self, title):\n        # Set the window title. Has no effect for widgets\n        raise NotImplementedError()\n\n    def _vispy_set_size(self, w, h):\n        # Set size of the widget or window\n        raise NotImplementedError()\n\n    def _vispy_set_position(self, x, y):\n        # Set location of the widget or window. May have no effect for widgets\n        raise NotImplementedError()\n\n    def _vispy_set_visible(self, visible):\n        # Show or hide the window or widget\n        raise NotImplementedError()\n\n    def _vispy_set_fullscreen(self, fullscreen):\n        # Set fullscreen mode\n        raise NotImplementedError()\n\n    def _vispy_update(self):\n        # Invoke a redraw\n        raise NotImplementedError()\n\n    def _vispy_close(self):\n        # Force the window or widget to shut down\n        raise NotImplementedError()\n\n    def _vispy_get_size(self):\n        # Should return widget size\n        raise NotImplementedError()\n\n    def _vispy_get_physical_size(self):\n        # Should return physical widget size (actual number of screen pixels).\n        # This may differ from _vispy_get_size on backends that expose HiDPI\n        # screens. If not overriden, return the logical sizeself.\n        return self._vispy_get_size()\n\n    def _vispy_get_position(self):\n        # Should return widget position\n        raise NotImplementedError()\n\n    def _vispy_get_fullscreen(self):\n        # Should return bool for fullscreen status\n        raise NotImplementedError()\n\n    def _vispy_get_geometry(self):\n        # Should return widget (x, y, w, h)\n        x, y = self._vispy_get_position()\n        w, h = self._vispy_get_size()\n        return x, y, w, h\n\n    def _vispy_get_native_canvas(self):\n        # Should return the native widget object\n        # Most backends would not need to implement this\n        return self\n\n    def _vispy_mouse_press(self, **kwargs):\n        # default method for delivering mouse press events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n        ev = self._vispy_canvas.events.mouse_press(**kwargs)\n        if self._vispy_mouse_data['press_event'] is None:\n            self._vispy_mouse_data['press_event'] = ev\n\n        self._vispy_mouse_data['buttons'].append(ev.button)\n        self._vispy_mouse_data['last_event'] = ev\n\n        if not getattr(self, '_double_click_supported', False):\n            # double-click events are not supported by this backend, so we\n            # detect them manually\n            self._vispy_detect_double_click(ev)\n\n        return ev\n\n    def _vispy_mouse_move(self, **kwargs):\n        if default_timer() - self._last_time < .01:\n            return\n        self._last_time = default_timer()\n\n        # default method for delivering mouse move events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        # Break the chain of prior mouse events if no buttons are pressed\n        # (this means that during a mouse drag, we have full access to every\n        # move event generated since the drag started)\n        if self._vispy_mouse_data['press_event'] is None:\n            last_event = self._vispy_mouse_data['last_event']\n            if last_event is not None:\n                last_event._forget_last_event()\n        else:\n            kwargs['button'] = self._vispy_mouse_data['press_event'].button\n\n        ev = self._vispy_canvas.events.mouse_move(**kwargs)\n        self._vispy_mouse_data['last_event'] = ev\n        return ev\n\n    def _vispy_mouse_release(self, **kwargs):\n        # default method for delivering mouse release events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        ev = self._vispy_canvas.events.mouse_release(**kwargs)\n        if (self._vispy_mouse_data['press_event']\n                and self._vispy_mouse_data['press_event'].button == ev.button):\n            self._vispy_mouse_data['press_event'] = None\n\n        if ev.button in self._vispy_mouse_data['buttons']:\n            self._vispy_mouse_data['buttons'].remove(ev.button)\n        self._vispy_mouse_data['last_event'] = ev\n\n        return ev\n\n    def _vispy_mouse_double_click(self, **kwargs):\n        # default method for delivering double-click events to the canvas\n        kwargs.update(self._vispy_mouse_data)\n\n        ev = self._vispy_canvas.events.mouse_double_click(**kwargs)\n        self._vispy_mouse_data['last_event'] = ev\n        return ev\n\n    def _vispy_detect_double_click(self, ev, **kwargs):\n        # Called on every mouse_press or mouse_release, and calls\n        # _vispy_mouse_double_click if a double-click is calculated.\n        # Should be overridden with an empty function on backends which\n        # natively support double-clicking.\n\n        dt_max = 0.3  # time in seconds for a double-click detection\n\n        lastev = self._vispy_mouse_data['last_mouse_press']\n\n        if lastev is None:\n            self._vispy_mouse_data['last_mouse_press'] = ev\n            return\n\n        assert lastev.type == 'mouse_press'\n        assert ev.type == 'mouse_press'\n\n        # For a double-click to be detected, the button should be the same,\n        # the position should be the same, and the two mouse-presses should\n        # be within dt_max.\n        if ((ev.time - lastev.time <= dt_max) &\n           (lastev.pos[0] - ev.pos[0] == 0) &\n           (lastev.pos[1] - ev.pos[1] == 0) &\n           (lastev.button == ev.button)):\n            self._vispy_mouse_double_click(**kwargs)\n\n        self._vispy_mouse_data['last_mouse_press'] = ev\n\n\nclass BaseTimerBackend(object):\n    \"\"\"BaseTimerBackend(vispy_timer)\n\n    Abstract class that provides an interface between backends and Timer.\n    Each backend must implement a subclass of TimerBackend, and\n    implement all its _vispy_xxx methods.\n    \"\"\"\n\n    def __init__(self, vispy_timer):\n        self._vispy_timer = vispy_timer\n\n    def _vispy_start(self, interval):\n        raise NotImplementedError\n\n    def _vispy_stop(self):\n        raise NotImplementedError\n\n    def _vispy_get_native_timer(self):\n        # Should return the native timer object\n        # Most backends would not need to implement this\n        return self\n", "path": "vispy/app/base.py"}]}