We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
The Python process hangs after demos on Windows, Qt backend
If I run any demo, it works, then I close the window, and the process is still running. CTRL+C does not end the process, I have to kill it manually, which is kind of annoying.


--- 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/backends/_qt.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 # Copyright (c) 2014, Vispy Development Team.
3 # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4 
5 """
6 vispy backend for Qt (PySide and PyQt4).
7 """
8 
9 from __future__ import division
10 from time import sleep, time
11 
12 from ... import config
13 from ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend
14 from ...util import keys
15 from . import ATTEMPTED_BACKENDS
16 from ...util.six import text_type
17 
18 # Get what qt lib to try
19 if len(ATTEMPTED_BACKENDS):
20     qt_lib = ATTEMPTED_BACKENDS[-1].lower()
21     if qt_lib.lower() == 'qt':
22         qt_lib = config['qt_lib'].lower()
23     # in case the last app we ran was something else (e.g., Pyglet)
24     if qt_lib not in ['pyqt', 'pyqt4', 'pyside', 'qt']:
25         qt_lib = 'any'
26 else:
27     qt_lib = 'any'
28 
29 # Import PySide or PyQt4
30 if qt_lib in ('any', 'qt'):
31     try:
32         from PyQt4 import QtGui, QtCore, QtOpenGL
33     except ImportError:
34         from PySide import QtGui, QtCore, QtOpenGL
35 elif qt_lib in ('pyqt', 'pyqt4'):
36     from PyQt4 import QtGui, QtCore, QtOpenGL
37 elif qt_lib == 'pyside':
38     from PySide import QtGui, QtCore, QtOpenGL
39 else:
40     raise Exception("Do not recognize Qt library '%s'. Options are "
41                     "'pyqt4', 'pyside', or 'qt'])." % str(qt_lib))
42 
43 # todo: add support for distinguishing left and right shift/ctrl/alt keys.
44 # Linux scan codes:  (left, right)
45 #   Shift  50, 62
46 #   Ctrl   37, 105
47 #   Alt    64, 108
48 KEYMAP = {
49     QtCore.Qt.Key_Shift: keys.SHIFT,
50     QtCore.Qt.Key_Control: keys.CONTROL,
51     QtCore.Qt.Key_Alt: keys.ALT,
52     QtCore.Qt.Key_AltGr: keys.ALT,
53     QtCore.Qt.Key_Meta: keys.META,
54 
55     QtCore.Qt.Key_Left: keys.LEFT,
56     QtCore.Qt.Key_Up: keys.UP,
57     QtCore.Qt.Key_Right: keys.RIGHT,
58     QtCore.Qt.Key_Down: keys.DOWN,
59     QtCore.Qt.Key_PageUp: keys.PAGEUP,
60     QtCore.Qt.Key_PageDown: keys.PAGEDOWN,
61 
62     QtCore.Qt.Key_Insert: keys.INSERT,
63     QtCore.Qt.Key_Delete: keys.DELETE,
64     QtCore.Qt.Key_Home: keys.HOME,
65     QtCore.Qt.Key_End: keys.END,
66 
67     QtCore.Qt.Key_Escape: keys.ESCAPE,
68     QtCore.Qt.Key_Backspace: keys.BACKSPACE,
69 
70     QtCore.Qt.Key_F1: keys.F1,
71     QtCore.Qt.Key_F2: keys.F2,
72     QtCore.Qt.Key_F3: keys.F3,
73     QtCore.Qt.Key_F4: keys.F4,
74     QtCore.Qt.Key_F5: keys.F5,
75     QtCore.Qt.Key_F6: keys.F6,
76     QtCore.Qt.Key_F7: keys.F7,
77     QtCore.Qt.Key_F8: keys.F8,
78     QtCore.Qt.Key_F9: keys.F9,
79     QtCore.Qt.Key_F10: keys.F10,
80     QtCore.Qt.Key_F11: keys.F11,
81     QtCore.Qt.Key_F12: keys.F12,
82 
83     QtCore.Qt.Key_Space: keys.SPACE,
84     QtCore.Qt.Key_Enter: keys.ENTER,
85     QtCore.Qt.Key_Return: keys.ENTER,
86     QtCore.Qt.Key_Tab: keys.TAB,
87 }
88 
89 BUTTONMAP = {0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5}
90 
91 
92 class ApplicationBackend(BaseApplicationBackend):
93 
94     def __init__(self):
95         BaseApplicationBackend.__init__(self)
96 
97     def _vispy_get_backend_name(self):
98         if 'pyside' in QtCore.__name__.lower():
99             return 'PySide (qt)'
100         else:
101             return 'PyQt4 (qt)'
102 
103     def _vispy_process_events(self):
104         app = self._vispy_get_native_app()
105         app.flush()
106         app.processEvents()
107 
108     def _vispy_run(self):
109         app = self._vispy_get_native_app()
110         if hasattr(app, '_in_event_loop') and app._in_event_loop:
111             pass  # Already in event loop
112         else:
113             return app.exec_()
114 
115     def _vispy_quit(self):
116         return self._vispy_get_native_app().quit()
117 
118     def _vispy_get_native_app(self):
119         # Get native app in save way. Taken from guisupport.py
120         app = QtGui.QApplication.instance()
121         if app is None:
122             app = QtGui.QApplication([''])
123         # Store so it won't be deleted, but not on a vispy object,
124         # or an application may produce error when closed
125         QtGui._qApp = app
126         # Return
127         return app
128 
129 
130 class CanvasBackend(QtOpenGL.QGLWidget, BaseCanvasBackend):
131 
132     """Qt backend for Canvas abstract class."""
133 
134     def __init__(self, *args, **kwargs):
135         BaseCanvasBackend.__init__(self)
136         QtOpenGL.QGLWidget.__init__(self, *args, **kwargs)
137         self.setAutoBufferSwap(False)  # to make consistent with other backends
138         self.setMouseTracking(True)
139 
140     def _vispy_warmup(self):
141         etime = time() + 0.25
142         while time() < etime:
143             sleep(0.01)
144             self._vispy_set_current()
145             self._vispy_canvas.app.process_events()
146 
147     def _vispy_set_current(self):
148         # Make this the current context
149         self.makeCurrent()
150 
151     def _vispy_swap_buffers(self):
152         # Swap front and back buffer
153         self.swapBuffers()
154 
155     def _vispy_set_title(self, title):
156         # Set the window title. Has no effect for widgets
157         self.setWindowTitle(title)
158 
159     def _vispy_set_size(self, w, h):
160         # Set size of the widget or window
161         self.resize(w, h)
162 
163     def _vispy_set_position(self, x, y):
164         # Set location of the widget or window. May have no effect for widgets
165         self.move(x, y)
166 
167     def _vispy_set_visible(self, visible):
168         # Show or hide the window or widget
169         if visible:
170             self.show()
171         else:
172             self.hide()
173 
174     def _vispy_update(self):
175         # Invoke a redraw
176         self.update()
177 
178     def _vispy_close(self):
179         # Force the window or widget to shut down
180         self.close()
181 
182     def _vispy_get_position(self):
183         g = self.geometry()
184         return g.x(), g.y()
185 
186     def _vispy_get_size(self):
187         g = self.geometry()
188         return g.width(), g.height()
189 
190     def initializeGL(self):
191         if self._vispy_canvas is None:
192             return
193         self._vispy_canvas.events.initialize()
194 
195     def resizeGL(self, w, h):
196         if self._vispy_canvas is None:
197             return
198         self._vispy_canvas.events.resize(size=(w, h))
199 
200     def paintGL(self):
201         if self._vispy_canvas is None:
202             return
203         # (0, 0, self.width(), self.height()))
204         self._vispy_set_current()
205         self._vispy_canvas.events.paint(region=None)
206 
207     def closeEvent(self, ev):
208         if self._vispy_canvas is None:
209             return
210         self._vispy_canvas.events.close()
211         # Destroy if this is a toplevel widget
212         if self.parent() is None:
213             self.destroy()
214 
215     def mousePressEvent(self, ev):
216         if self._vispy_canvas is None:
217             return
218         self._vispy_mouse_press(
219             native=ev,
220             pos=(ev.pos().x(), ev.pos().y()),
221             button=BUTTONMAP.get(ev.button(), 0),
222             modifiers = self._modifiers(ev),
223         )
224 
225     def mouseReleaseEvent(self, ev):
226         if self._vispy_canvas is None:
227             return
228         self._vispy_mouse_release(
229             native=ev,
230             pos=(ev.pos().x(), ev.pos().y()),
231             button=BUTTONMAP[ev.button()],
232             modifiers = self._modifiers(ev),
233         )
234 
235     def mouseMoveEvent(self, ev):
236         if self._vispy_canvas is None:
237             return
238         self._vispy_mouse_move(
239             native=ev,
240             pos=(ev.pos().x(), ev.pos().y()),
241             modifiers=self._modifiers(ev),
242         )
243 
244     def wheelEvent(self, ev):
245         if self._vispy_canvas is None:
246             return
247         # Get scrolling
248         deltax, deltay = 0.0, 0.0
249         if ev.orientation == QtCore.Qt.Horizontal:
250             deltax = ev.delta() / 120.0
251         else:
252             deltay = ev.delta() / 120.0
253         # Emit event
254         self._vispy_canvas.events.mouse_wheel(
255             native=ev,
256             delta=(deltax, deltay),
257             pos=(ev.pos().x(), ev.pos().y()),
258             modifiers=self._modifiers(ev),
259         )
260 
261     def keyPressEvent(self, ev):
262         self._vispy_canvas.events.key_press(
263             native=ev,
264             key=self._processKey(ev),
265             text=text_type(ev.text()),
266             modifiers=self._modifiers(ev),
267         )
268 
269     def keyReleaseEvent(self, ev):
270         # if ev.isAutoRepeat():
271             # return # Skip release auto repeat events
272         self._vispy_canvas.events.key_release(
273             native=ev,
274             key=self._processKey(ev),
275             text=text_type(ev.text()),
276             modifiers=self._modifiers(ev),
277         )
278 
279     def _processKey(self, event):
280         # evaluates the keycode of qt, and transform to vispy key.
281         key = int(event.key())
282         if key in KEYMAP:
283             return KEYMAP[key]
284         elif key >= 32 and key <= 127:
285             return keys.Key(chr(key))
286         else:
287             return None
288 
289     def _modifiers(self, event):
290         # Convert the QT modifier state into a tuple of active modifier keys.
291         mod = ()
292         qtmod = event.modifiers()
293         if QtCore.Qt.ShiftModifier & qtmod:
294             mod += keys.SHIFT,
295         if QtCore.Qt.ControlModifier & qtmod:
296             mod += keys.CONTROL,
297         if QtCore.Qt.AltModifier & qtmod:
298             mod += keys.ALT,
299         if QtCore.Qt.MetaModifier & qtmod:
300             mod += keys.META,
301         return mod
302 
303 
304 # class QtMouseEvent(MouseEvent):
305 # special subclass of MouseEvent for propagating acceptance info back to Qt.
306 #     @MouseEvent.handled.setter
307 #     def handled(self, val):
308 #         self._handled = val
309 #         if val:
310 #             self.qt_event.accept()
311 #         else:
312 #             self.qt_event.ignore()
313 class TimerBackend(BaseTimerBackend, QtCore.QTimer):
314 
315     def __init__(self, vispy_timer):
316         if QtGui.QApplication.instance() is None:
317             global QAPP
318             QAPP = QtGui.QApplication([])
319         BaseTimerBackend.__init__(self, vispy_timer)
320         QtCore.QTimer.__init__(self)
321         self.timeout.connect(self._vispy_timeout)
322 
323     def _vispy_start(self, interval):
324         self.start(interval * 1000.)
325 
326     def _vispy_stop(self):
327         self.stop()
328 
329     def _vispy_timeout(self):
330         self._vispy_timer._timeout()
331
```
--- 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/backends/_qt.py b/vispy/app/backends/_qt.py
--- a/vispy/app/backends/_qt.py
+++ b/vispy/app/backends/_qt.py
@@ -208,9 +208,6 @@
         if self._vispy_canvas is None:
             return
         self._vispy_canvas.events.close()
-        # Destroy if this is a toplevel widget
-        if self.parent() is None:
-            self.destroy()
 
     def mousePressEvent(self, ev):
         if self._vispy_canvas is None:
@@ -300,6 +297,12 @@
             mod += keys.META,
         return mod
 
+    def __del__(self):
+        # Destroy if this is a toplevel widget
+        if self.parent() is None:
+            self.destroy()
+        QtOpenGL.QGLWidget.__del__(self)
+
 
 # class QtMouseEvent(MouseEvent):
 # special subclass of MouseEvent for propagating acceptance info back to Qt.

{"golden_diff": "diff --git a/vispy/app/backends/_qt.py b/vispy/app/backends/_qt.py\n--- a/vispy/app/backends/_qt.py\n+++ b/vispy/app/backends/_qt.py\n@@ -208,9 +208,6 @@\n         if self._vispy_canvas is None:\n             return\n         self._vispy_canvas.events.close()\n-        # Destroy if this is a toplevel widget\n-        if self.parent() is None:\n-            self.destroy()\n \n     def mousePressEvent(self, ev):\n         if self._vispy_canvas is None:\n@@ -300,6 +297,12 @@\n             mod += keys.META,\n         return mod\n \n+    def __del__(self):\n+        # Destroy if this is a toplevel widget\n+        if self.parent() is None:\n+            self.destroy()\n+        QtOpenGL.QGLWidget.__del__(self)\n+\n \n # class QtMouseEvent(MouseEvent):\n # special subclass of MouseEvent for propagating acceptance info back to Qt.\n", "issue": "The Python process hangs after demos on Windows, Qt backend\nIf I run any demo, it works, then I close the window, and the process is still running. CTRL+C does not end the process, I have to kill it manually, which is kind of annoying.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2014, Vispy Development Team.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\n\"\"\"\nvispy backend for Qt (PySide and PyQt4).\n\"\"\"\n\nfrom __future__ import division\nfrom time import sleep, time\n\nfrom ... import config\nfrom ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend\nfrom ...util import keys\nfrom . import ATTEMPTED_BACKENDS\nfrom ...util.six import text_type\n\n# Get what qt lib to try\nif len(ATTEMPTED_BACKENDS):\n    qt_lib = ATTEMPTED_BACKENDS[-1].lower()\n    if qt_lib.lower() == 'qt':\n        qt_lib = config['qt_lib'].lower()\n    # in case the last app we ran was something else (e.g., Pyglet)\n    if qt_lib not in ['pyqt', 'pyqt4', 'pyside', 'qt']:\n        qt_lib = 'any'\nelse:\n    qt_lib = 'any'\n\n# Import PySide or PyQt4\nif qt_lib in ('any', 'qt'):\n    try:\n        from PyQt4 import QtGui, QtCore, QtOpenGL\n    except ImportError:\n        from PySide import QtGui, QtCore, QtOpenGL\nelif qt_lib in ('pyqt', 'pyqt4'):\n    from PyQt4 import QtGui, QtCore, QtOpenGL\nelif qt_lib == 'pyside':\n    from PySide import QtGui, QtCore, QtOpenGL\nelse:\n    raise Exception(\"Do not recognize Qt library '%s'. Options are \"\n                    \"'pyqt4', 'pyside', or 'qt']).\" % str(qt_lib))\n\n# todo: add support for distinguishing left and right shift/ctrl/alt keys.\n# Linux scan codes:  (left, right)\n#   Shift  50, 62\n#   Ctrl   37, 105\n#   Alt    64, 108\nKEYMAP = {\n    QtCore.Qt.Key_Shift: keys.SHIFT,\n    QtCore.Qt.Key_Control: keys.CONTROL,\n    QtCore.Qt.Key_Alt: keys.ALT,\n    QtCore.Qt.Key_AltGr: keys.ALT,\n    QtCore.Qt.Key_Meta: keys.META,\n\n    QtCore.Qt.Key_Left: keys.LEFT,\n    QtCore.Qt.Key_Up: keys.UP,\n    QtCore.Qt.Key_Right: keys.RIGHT,\n    QtCore.Qt.Key_Down: keys.DOWN,\n    QtCore.Qt.Key_PageUp: keys.PAGEUP,\n    QtCore.Qt.Key_PageDown: keys.PAGEDOWN,\n\n    QtCore.Qt.Key_Insert: keys.INSERT,\n    QtCore.Qt.Key_Delete: keys.DELETE,\n    QtCore.Qt.Key_Home: keys.HOME,\n    QtCore.Qt.Key_End: keys.END,\n\n    QtCore.Qt.Key_Escape: keys.ESCAPE,\n    QtCore.Qt.Key_Backspace: keys.BACKSPACE,\n\n    QtCore.Qt.Key_F1: keys.F1,\n    QtCore.Qt.Key_F2: keys.F2,\n    QtCore.Qt.Key_F3: keys.F3,\n    QtCore.Qt.Key_F4: keys.F4,\n    QtCore.Qt.Key_F5: keys.F5,\n    QtCore.Qt.Key_F6: keys.F6,\n    QtCore.Qt.Key_F7: keys.F7,\n    QtCore.Qt.Key_F8: keys.F8,\n    QtCore.Qt.Key_F9: keys.F9,\n    QtCore.Qt.Key_F10: keys.F10,\n    QtCore.Qt.Key_F11: keys.F11,\n    QtCore.Qt.Key_F12: keys.F12,\n\n    QtCore.Qt.Key_Space: keys.SPACE,\n    QtCore.Qt.Key_Enter: keys.ENTER,\n    QtCore.Qt.Key_Return: keys.ENTER,\n    QtCore.Qt.Key_Tab: keys.TAB,\n}\n\nBUTTONMAP = {0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5}\n\n\nclass ApplicationBackend(BaseApplicationBackend):\n\n    def __init__(self):\n        BaseApplicationBackend.__init__(self)\n\n    def _vispy_get_backend_name(self):\n        if 'pyside' in QtCore.__name__.lower():\n            return 'PySide (qt)'\n        else:\n            return 'PyQt4 (qt)'\n\n    def _vispy_process_events(self):\n        app = self._vispy_get_native_app()\n        app.flush()\n        app.processEvents()\n\n    def _vispy_run(self):\n        app = self._vispy_get_native_app()\n        if hasattr(app, '_in_event_loop') and app._in_event_loop:\n            pass  # Already in event loop\n        else:\n            return app.exec_()\n\n    def _vispy_quit(self):\n        return self._vispy_get_native_app().quit()\n\n    def _vispy_get_native_app(self):\n        # Get native app in save way. Taken from guisupport.py\n        app = QtGui.QApplication.instance()\n        if app is None:\n            app = QtGui.QApplication([''])\n        # Store so it won't be deleted, but not on a vispy object,\n        # or an application may produce error when closed\n        QtGui._qApp = app\n        # Return\n        return app\n\n\nclass CanvasBackend(QtOpenGL.QGLWidget, BaseCanvasBackend):\n\n    \"\"\"Qt backend for Canvas abstract class.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        BaseCanvasBackend.__init__(self)\n        QtOpenGL.QGLWidget.__init__(self, *args, **kwargs)\n        self.setAutoBufferSwap(False)  # to make consistent with other backends\n        self.setMouseTracking(True)\n\n    def _vispy_warmup(self):\n        etime = time() + 0.25\n        while time() < etime:\n            sleep(0.01)\n            self._vispy_set_current()\n            self._vispy_canvas.app.process_events()\n\n    def _vispy_set_current(self):\n        # Make this the current context\n        self.makeCurrent()\n\n    def _vispy_swap_buffers(self):\n        # Swap front and back buffer\n        self.swapBuffers()\n\n    def _vispy_set_title(self, title):\n        # Set the window title. Has no effect for widgets\n        self.setWindowTitle(title)\n\n    def _vispy_set_size(self, w, h):\n        # Set size of the widget or window\n        self.resize(w, h)\n\n    def _vispy_set_position(self, x, y):\n        # Set location of the widget or window. May have no effect for widgets\n        self.move(x, y)\n\n    def _vispy_set_visible(self, visible):\n        # Show or hide the window or widget\n        if visible:\n            self.show()\n        else:\n            self.hide()\n\n    def _vispy_update(self):\n        # Invoke a redraw\n        self.update()\n\n    def _vispy_close(self):\n        # Force the window or widget to shut down\n        self.close()\n\n    def _vispy_get_position(self):\n        g = self.geometry()\n        return g.x(), g.y()\n\n    def _vispy_get_size(self):\n        g = self.geometry()\n        return g.width(), g.height()\n\n    def initializeGL(self):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.initialize()\n\n    def resizeGL(self, w, h):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.resize(size=(w, h))\n\n    def paintGL(self):\n        if self._vispy_canvas is None:\n            return\n        # (0, 0, self.width(), self.height()))\n        self._vispy_set_current()\n        self._vispy_canvas.events.paint(region=None)\n\n    def closeEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.close()\n        # Destroy if this is a toplevel widget\n        if self.parent() is None:\n            self.destroy()\n\n    def mousePressEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_press(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            button=BUTTONMAP.get(ev.button(), 0),\n            modifiers = self._modifiers(ev),\n        )\n\n    def mouseReleaseEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_release(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            button=BUTTONMAP[ev.button()],\n            modifiers = self._modifiers(ev),\n        )\n\n    def mouseMoveEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_move(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def wheelEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        # Get scrolling\n        deltax, deltay = 0.0, 0.0\n        if ev.orientation == QtCore.Qt.Horizontal:\n            deltax = ev.delta() / 120.0\n        else:\n            deltay = ev.delta() / 120.0\n        # Emit event\n        self._vispy_canvas.events.mouse_wheel(\n            native=ev,\n            delta=(deltax, deltay),\n            pos=(ev.pos().x(), ev.pos().y()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def keyPressEvent(self, ev):\n        self._vispy_canvas.events.key_press(\n            native=ev,\n            key=self._processKey(ev),\n            text=text_type(ev.text()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def keyReleaseEvent(self, ev):\n        # if ev.isAutoRepeat():\n            # return # Skip release auto repeat events\n        self._vispy_canvas.events.key_release(\n            native=ev,\n            key=self._processKey(ev),\n            text=text_type(ev.text()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def _processKey(self, event):\n        # evaluates the keycode of qt, and transform to vispy key.\n        key = int(event.key())\n        if key in KEYMAP:\n            return KEYMAP[key]\n        elif key >= 32 and key <= 127:\n            return keys.Key(chr(key))\n        else:\n            return None\n\n    def _modifiers(self, event):\n        # Convert the QT modifier state into a tuple of active modifier keys.\n        mod = ()\n        qtmod = event.modifiers()\n        if QtCore.Qt.ShiftModifier & qtmod:\n            mod += keys.SHIFT,\n        if QtCore.Qt.ControlModifier & qtmod:\n            mod += keys.CONTROL,\n        if QtCore.Qt.AltModifier & qtmod:\n            mod += keys.ALT,\n        if QtCore.Qt.MetaModifier & qtmod:\n            mod += keys.META,\n        return mod\n\n\n# class QtMouseEvent(MouseEvent):\n# special subclass of MouseEvent for propagating acceptance info back to Qt.\n#     @MouseEvent.handled.setter\n#     def handled(self, val):\n#         self._handled = val\n#         if val:\n#             self.qt_event.accept()\n#         else:\n#             self.qt_event.ignore()\nclass TimerBackend(BaseTimerBackend, QtCore.QTimer):\n\n    def __init__(self, vispy_timer):\n        if QtGui.QApplication.instance() is None:\n            global QAPP\n            QAPP = QtGui.QApplication([])\n        BaseTimerBackend.__init__(self, vispy_timer)\n        QtCore.QTimer.__init__(self)\n        self.timeout.connect(self._vispy_timeout)\n\n    def _vispy_start(self, interval):\n        self.start(interval * 1000.)\n\n    def _vispy_stop(self):\n        self.stop()\n\n    def _vispy_timeout(self):\n        self._vispy_timer._timeout()\n", "path": "vispy/app/backends/_qt.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n# Copyright (c) 2014, Vispy Development Team.\n# Distributed under the (new) BSD License. See LICENSE.txt for more info.\n\n\"\"\"\nvispy backend for Qt (PySide and PyQt4).\n\"\"\"\n\nfrom __future__ import division\nfrom time import sleep, time\n\nfrom ... import config\nfrom ..base import BaseApplicationBackend, BaseCanvasBackend, BaseTimerBackend\nfrom ...util import keys\nfrom . import ATTEMPTED_BACKENDS\nfrom ...util.six import text_type\n\n# Get what qt lib to try\nif len(ATTEMPTED_BACKENDS):\n    qt_lib = ATTEMPTED_BACKENDS[-1].lower()\n    if qt_lib.lower() == 'qt':\n        qt_lib = config['qt_lib'].lower()\n    # in case the last app we ran was something else (e.g., Pyglet)\n    if qt_lib not in ['pyqt', 'pyqt4', 'pyside', 'qt']:\n        qt_lib = 'any'\nelse:\n    qt_lib = 'any'\n\n# Import PySide or PyQt4\nif qt_lib in ('any', 'qt'):\n    try:\n        from PyQt4 import QtGui, QtCore, QtOpenGL\n    except ImportError:\n        from PySide import QtGui, QtCore, QtOpenGL\nelif qt_lib in ('pyqt', 'pyqt4'):\n    from PyQt4 import QtGui, QtCore, QtOpenGL\nelif qt_lib == 'pyside':\n    from PySide import QtGui, QtCore, QtOpenGL\nelse:\n    raise Exception(\"Do not recognize Qt library '%s'. Options are \"\n                    \"'pyqt4', 'pyside', or 'qt']).\" % str(qt_lib))\n\n# todo: add support for distinguishing left and right shift/ctrl/alt keys.\n# Linux scan codes:  (left, right)\n#   Shift  50, 62\n#   Ctrl   37, 105\n#   Alt    64, 108\nKEYMAP = {\n    QtCore.Qt.Key_Shift: keys.SHIFT,\n    QtCore.Qt.Key_Control: keys.CONTROL,\n    QtCore.Qt.Key_Alt: keys.ALT,\n    QtCore.Qt.Key_AltGr: keys.ALT,\n    QtCore.Qt.Key_Meta: keys.META,\n\n    QtCore.Qt.Key_Left: keys.LEFT,\n    QtCore.Qt.Key_Up: keys.UP,\n    QtCore.Qt.Key_Right: keys.RIGHT,\n    QtCore.Qt.Key_Down: keys.DOWN,\n    QtCore.Qt.Key_PageUp: keys.PAGEUP,\n    QtCore.Qt.Key_PageDown: keys.PAGEDOWN,\n\n    QtCore.Qt.Key_Insert: keys.INSERT,\n    QtCore.Qt.Key_Delete: keys.DELETE,\n    QtCore.Qt.Key_Home: keys.HOME,\n    QtCore.Qt.Key_End: keys.END,\n\n    QtCore.Qt.Key_Escape: keys.ESCAPE,\n    QtCore.Qt.Key_Backspace: keys.BACKSPACE,\n\n    QtCore.Qt.Key_F1: keys.F1,\n    QtCore.Qt.Key_F2: keys.F2,\n    QtCore.Qt.Key_F3: keys.F3,\n    QtCore.Qt.Key_F4: keys.F4,\n    QtCore.Qt.Key_F5: keys.F5,\n    QtCore.Qt.Key_F6: keys.F6,\n    QtCore.Qt.Key_F7: keys.F7,\n    QtCore.Qt.Key_F8: keys.F8,\n    QtCore.Qt.Key_F9: keys.F9,\n    QtCore.Qt.Key_F10: keys.F10,\n    QtCore.Qt.Key_F11: keys.F11,\n    QtCore.Qt.Key_F12: keys.F12,\n\n    QtCore.Qt.Key_Space: keys.SPACE,\n    QtCore.Qt.Key_Enter: keys.ENTER,\n    QtCore.Qt.Key_Return: keys.ENTER,\n    QtCore.Qt.Key_Tab: keys.TAB,\n}\n\nBUTTONMAP = {0: 0, 1: 1, 2: 2, 4: 3, 8: 4, 16: 5}\n\n\nclass ApplicationBackend(BaseApplicationBackend):\n\n    def __init__(self):\n        BaseApplicationBackend.__init__(self)\n\n    def _vispy_get_backend_name(self):\n        if 'pyside' in QtCore.__name__.lower():\n            return 'PySide (qt)'\n        else:\n            return 'PyQt4 (qt)'\n\n    def _vispy_process_events(self):\n        app = self._vispy_get_native_app()\n        app.flush()\n        app.processEvents()\n\n    def _vispy_run(self):\n        app = self._vispy_get_native_app()\n        if hasattr(app, '_in_event_loop') and app._in_event_loop:\n            pass  # Already in event loop\n        else:\n            return app.exec_()\n\n    def _vispy_quit(self):\n        return self._vispy_get_native_app().quit()\n\n    def _vispy_get_native_app(self):\n        # Get native app in save way. Taken from guisupport.py\n        app = QtGui.QApplication.instance()\n        if app is None:\n            app = QtGui.QApplication([''])\n        # Store so it won't be deleted, but not on a vispy object,\n        # or an application may produce error when closed\n        QtGui._qApp = app\n        # Return\n        return app\n\n\nclass CanvasBackend(QtOpenGL.QGLWidget, BaseCanvasBackend):\n\n    \"\"\"Qt backend for Canvas abstract class.\"\"\"\n\n    def __init__(self, *args, **kwargs):\n        BaseCanvasBackend.__init__(self)\n        QtOpenGL.QGLWidget.__init__(self, *args, **kwargs)\n        self.setAutoBufferSwap(False)  # to make consistent with other backends\n        self.setMouseTracking(True)\n\n    def _vispy_warmup(self):\n        etime = time() + 0.25\n        while time() < etime:\n            sleep(0.01)\n            self._vispy_set_current()\n            self._vispy_canvas.app.process_events()\n\n    def _vispy_set_current(self):\n        # Make this the current context\n        self.makeCurrent()\n\n    def _vispy_swap_buffers(self):\n        # Swap front and back buffer\n        self.swapBuffers()\n\n    def _vispy_set_title(self, title):\n        # Set the window title. Has no effect for widgets\n        self.setWindowTitle(title)\n\n    def _vispy_set_size(self, w, h):\n        # Set size of the widget or window\n        self.resize(w, h)\n\n    def _vispy_set_position(self, x, y):\n        # Set location of the widget or window. May have no effect for widgets\n        self.move(x, y)\n\n    def _vispy_set_visible(self, visible):\n        # Show or hide the window or widget\n        if visible:\n            self.show()\n        else:\n            self.hide()\n\n    def _vispy_update(self):\n        # Invoke a redraw\n        self.update()\n\n    def _vispy_close(self):\n        # Force the window or widget to shut down\n        self.close()\n\n    def _vispy_get_position(self):\n        g = self.geometry()\n        return g.x(), g.y()\n\n    def _vispy_get_size(self):\n        g = self.geometry()\n        return g.width(), g.height()\n\n    def initializeGL(self):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.initialize()\n\n    def resizeGL(self, w, h):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.resize(size=(w, h))\n\n    def paintGL(self):\n        if self._vispy_canvas is None:\n            return\n        # (0, 0, self.width(), self.height()))\n        self._vispy_set_current()\n        self._vispy_canvas.events.paint(region=None)\n\n    def closeEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_canvas.events.close()\n\n    def mousePressEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_press(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            button=BUTTONMAP.get(ev.button(), 0),\n            modifiers = self._modifiers(ev),\n        )\n\n    def mouseReleaseEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_release(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            button=BUTTONMAP[ev.button()],\n            modifiers = self._modifiers(ev),\n        )\n\n    def mouseMoveEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        self._vispy_mouse_move(\n            native=ev,\n            pos=(ev.pos().x(), ev.pos().y()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def wheelEvent(self, ev):\n        if self._vispy_canvas is None:\n            return\n        # Get scrolling\n        deltax, deltay = 0.0, 0.0\n        if ev.orientation == QtCore.Qt.Horizontal:\n            deltax = ev.delta() / 120.0\n        else:\n            deltay = ev.delta() / 120.0\n        # Emit event\n        self._vispy_canvas.events.mouse_wheel(\n            native=ev,\n            delta=(deltax, deltay),\n            pos=(ev.pos().x(), ev.pos().y()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def keyPressEvent(self, ev):\n        self._vispy_canvas.events.key_press(\n            native=ev,\n            key=self._processKey(ev),\n            text=text_type(ev.text()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def keyReleaseEvent(self, ev):\n        # if ev.isAutoRepeat():\n            # return # Skip release auto repeat events\n        self._vispy_canvas.events.key_release(\n            native=ev,\n            key=self._processKey(ev),\n            text=text_type(ev.text()),\n            modifiers=self._modifiers(ev),\n        )\n\n    def _processKey(self, event):\n        # evaluates the keycode of qt, and transform to vispy key.\n        key = int(event.key())\n        if key in KEYMAP:\n            return KEYMAP[key]\n        elif key >= 32 and key <= 127:\n            return keys.Key(chr(key))\n        else:\n            return None\n\n    def _modifiers(self, event):\n        # Convert the QT modifier state into a tuple of active modifier keys.\n        mod = ()\n        qtmod = event.modifiers()\n        if QtCore.Qt.ShiftModifier & qtmod:\n            mod += keys.SHIFT,\n        if QtCore.Qt.ControlModifier & qtmod:\n            mod += keys.CONTROL,\n        if QtCore.Qt.AltModifier & qtmod:\n            mod += keys.ALT,\n        if QtCore.Qt.MetaModifier & qtmod:\n            mod += keys.META,\n        return mod\n\n    def __del__(self):\n        # Destroy if this is a toplevel widget\n        if self.parent() is None:\n            self.destroy()\n        QtOpenGL.QGLWidget.__del__(self)\n\n\n# class QtMouseEvent(MouseEvent):\n# special subclass of MouseEvent for propagating acceptance info back to Qt.\n#     @MouseEvent.handled.setter\n#     def handled(self, val):\n#         self._handled = val\n#         if val:\n#             self.qt_event.accept()\n#         else:\n#             self.qt_event.ignore()\nclass TimerBackend(BaseTimerBackend, QtCore.QTimer):\n\n    def __init__(self, vispy_timer):\n        if QtGui.QApplication.instance() is None:\n            global QAPP\n            QAPP = QtGui.QApplication([])\n        BaseTimerBackend.__init__(self, vispy_timer)\n        QtCore.QTimer.__init__(self)\n        self.timeout.connect(self._vispy_timeout)\n\n    def _vispy_start(self, interval):\n        self.start(interval * 1000.)\n\n    def _vispy_stop(self):\n        self.stop()\n\n    def _vispy_timeout(self):\n        self._vispy_timer._timeout()\n", "path": "vispy/app/backends/_qt.py"}]}