8000 Only set the wait cursor if the last draw was >1s ago. · matplotlib/matplotlib@01fe73d · GitHub
[go: up one dir, main page]

Skip to content

Commit 01fe73d

Browse files
committed
Only set the wait cursor if the last draw was >1s ago.
This avoids setting the wait cursor when panning or zooming (that behavior was somewhat annoying), or during an animation that renders at least one frame per second. Rename `_set_cursor` to `_update_cursor` as it is fairly different from `set_cursor` and the previous name could cause confusion. Move the defintion of cursor-related methods to a single place. In the case of gtk, just strip out the offending cursor related code as the backend is deprecated and slated for removal anyways.
1 parent 6336f2d commit 01fe73d

File tree

5 files changed

+62
-42
lines changed

5 files changed

+62
-42
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2529,11 +2529,11 @@ def key_press_handler(event, canvas, toolbar=None):
25292529
# pan mnemonic (default key 'p')
25302530
elif event.key in pan_keys:
25312531
toolbar.pan()
2532-
toolbar._set_cursor(event)
2532+
toolbar._update_cursor(event)
25332533
# zoom mnemonic (default key 'o')
25342534
elif event.key in zoom_keys:
25352535
toolbar.zoom()
2536-
toolbar._set_cursor(event)
2536+
toolbar._update_cursor(event)
25372537
# saving current figure (default key 's')
25382538
elif event.key in save_keys:
25392539
toolbar.save_figure()
@@ -2866,7 +2866,18 @@ class implementation.
28662866
"""
28672867
raise NotImplementedError
28682868

2869-
def _set_cursor(self, event):
2869+
def set_cursor(self, cursor):
2870+
"""Set the current cursor to one of the :class:`Cursors` enums values.
2871+
2872+
If required by the backend, this method should trigger an update in
2873+
the backend event loop after the cursor is set, as this method may be
2874+
called e.g. before a long-running task during which the GUI is not
2875+
updated.
2876+
"""
2877+
2878+
def _update_cursor(self, event):
2879+
"""Update the cursor after a mouse move event or a tool (de)activation.
2880+
"""
28702881
if not event.inaxes or not self._active:
28712882
if self._lastCursor != cursors.POINTER:
28722883
self.set_cursor(cursors.POINTER)
@@ -2881,8 +2892,29 @@ def _set_cursor(self, event):
28812892
self.set_cursor(cursors.MOVE)
28822893
self._lastCursor = cursors.MOVE
28832894

2895+
@contextmanager
2896+
def _wait_cursor_for_draw_cm(self):
2897+
"""Set the cursor to a wait cursor when drawing the canvas.
2898+
2899+
In order to avoid constantly changing the cursor when the canvas
2900+
changes frequently, do nothing if this context was triggered during the
2901+
last second. (Optimally we'd prefer only setting the wait cursor if
2902+
the *current* draw takes too long, but the current draw blocks the GUI
2903+
thread.
2904+
"""
2905+
self._draw_time, last_draw_time = (
2906+
time.time(), getattr(self, "_draw_time", -np.inf))
2907+
if self._draw_time - last_draw_time > 1:
2908+
try:
2909+
self.set_cursor(cursors.WAIT)
2910+
yield
2911+
finally:
2912+
self.set_cursor(self._lastCursor)
2913+
else:
2914+
yield
2915+
28842916
def mouse_move(self, event):
2885-
self._set_cursor(event)
2917+
self._update_cursor(event)
28862918

28872919
if event.inaxes and event.inaxes.get_navigate():
28882920

@@ -3161,15 +3193,6 @@ def save_figure(self, *args):
31613193
"""Save the current figure."""
31623194
raise NotImplementedError
31633195

3164-
def set_cursor(self, cursor):
3165-
"""Set the current cursor to one of the :class:`Cursors` enums values.
3166-
3167-
If required by the backend, this method should trigger an update in
3168-
the backend event loop after the cursor is set, as this method may be
3169-
called e.g. before a long-running task during which the GUI is not
3170-
updated.
3171-
"""
3172-
31733196
def update(self):
31743197
"""Reset the axes stack."""
31753198
self._nav_stack.clear()

lib/matplotlib/backends/backend_agg.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,16 @@
2424

2525
import six
2626

27-
import threading
28-
import numpy as np
2927
from collections import OrderedDict
28+
try:
29+
from contextlib import ExitStack
30+
except ImportError:
31+
from contextlib2 import ExitStack # Py2
32+
import threading
3033
from math import radians, cos, sin
34+
35+
import numpy as np
36+
3137
from matplotlib import rcParams, __version__
3238
from matplotlib.backend_bases import (
3339
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors)
@@ -417,18 +423,11 @@ def draw(self):
417423
Draw the figure using the renderer
418424
"""
419425
self.renderer = self.get_renderer(cleared=True)
420-
# acquire a lock on the shared font cache
421-
RendererAgg.lock.acquire()
422-
423-
toolbar = self.toolbar
424-
try:
425-
if toolbar:
426-
toolbar.set_cursor(cursors.WAIT)
426+
# Acquire a lock on the shared font cache.
427+
with RendererAgg.lock, (
428+
self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
429+
else ExitStack()):
427430
self.figure.draw(self.renderer)
428-
finally:
429-
if toolbar:
430-
toolbar.set_cursor(toolbar._lastCursor)
431-
RendererAgg.lock.release()
432431

433432
def get_renderer(self, cleared=False):
434433
l, b, w, h = self.figure.bbox.bounds

lib/matplotlib/backends/backend_gtk.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -392,9 +392,6 @@ def _render_figure(self, pixmap, width, height):
392392
def expose_event(self, widget, event):
393393
"""Expose_event for all GTK backends. Should not be overridden.
394394
"""
395-
toolbar = self.toolbar
396-
if toolbar:
397-
toolbar.set_cursor(cursors.WAIT)
398395
if GTK_WIDGET_DRAWABLE(self):
399396
if self._need_redraw:
400397
x, y, w, h = self.allocation
@@ -404,8 +401,6 @@ def expose_event(self, widget, event):
404401
x, y, w, h = event.area
405402
self.window.draw_drawable (self.style.fg_gc[self.state],
406403
self._pixmap, x, y, x, y, w, h)
407-
if toolbar:
408-
toolbar.set_cursor(toolbar._lastCursor)
409404
return False # finish event propagation?
410405

411406
filetypes = FigureCanvasBase.filetypes.copy()

lib/matplotlib/backends/backend_gtk3cairo.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33

44
import six
55

6+
try:
7+
from contextlib import ExitStack
8+
except ImportError:
9+
from contextlib2 import ExitStack # Py2
10+
611
from . import backend_cairo, backend_gtk3
712
from .backend_cairo import cairo, HAS_CAIRO_CFFI
813
from .backend_gtk3 import _BackendGTK3
@@ -36,16 +41,11 @@ def _render_figure(self, width, height):
3641
def on_draw_event(self, widget, ctx):
3742
""" GtkDrawable draw event, like expose_event in GTK 2.X
3843
"""
39-
toolbar = self.toolbar
40-
if toolbar:
41-
toolbar.set_cursor(cursors.WAIT)
42-
self._renderer.set_context(ctx)
43-
allocation = self.get_allocation()
44-
x, y, w, h = allocation.x, allocation.y, allocation.width, allocation.height
45-
self._render_figure(w, h)
46-
if toolbar:
47-
toolbar.set_cursor(toolbar._lastCursor)
48-
return False # finish event propagation?
44+
with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
45+
else ExitStack()):
46+
self._renderer.set_context(ctx)
47+
allocation = self.get_allocation()
48+
self._render_figure(allocation.width, allocation.height)
4949

5050

5151
class FigureManagerGTK3Cairo(backend_gtk3.FigureManagerGTK3):

setupext.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1470,7 +1470,10 @@ def get_install_requires(self):
14701470
"six>=1.10",
14711471
]
14721472
if sys.version_info < (3,):
1473-
install_requires += ["backports.functools_lru_cache"]
1473+
install_requires += [
1474+
"backports.functools_lru_cache",
1475+
"contextlib2",
1476+
]
14741477
if sys.version_info < (3,) and os.name == "posix":
14751478
install_requires += ["subprocess32"]
14761479
return install_requires

0 commit comments

Comments
 (0)
0