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

Skip to content

Commit d8a4539

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 c46525a commit d8a4539

File tree

5 files changed

+62
-41
lines changed

5 files changed

+62
-41
lines changed

lib/matplotlib/backend_bases.py

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2532,11 +2532,11 @@ def key_press_handler(event, canvas, toolbar=None):
25322532
# pan mnemonic (default key 'p')
25332533
elif event.key in pan_keys:
25342534
toolbar.pan()
2535-
toolbar._set_cursor(event)
2535+
toolbar._update_cursor(event)
25362536
# zoom mnemonic (default key 'o')
25372537
elif event.key in zoom_keys:
25382538
toolbar.zoom()
2539-
toolbar._set_cursor(event)
2539+
toolbar._update_cursor(event)
25402540
# saving current figure (default key 's')
25412541
elif event.key in save_keys:
25422542
toolbar.save_figure()
@@ -2861,7 +2861,18 @@ class implementation.
28612861
"""
28622862
raise NotImplementedError
28632863

2864-
def _set_cursor(self, event):
2864+
def set_cursor(self, cursor):
2865+
"""Set the current cursor to one of the :class:`Cursors` enums values.
2866+
2867+
If required by the backend, this method should trigger an update in
2868+
the backend event loop after the cursor is set, as this method may be
2869+
called e.g. before a long-running task during which the GUI is not
2870+
updated.
2871+
"""
2872+
2873+
def _update_cursor(self, event):
2874+
"""Update the cursor after a mouse move event or a tool (de)activation.
2875+
"""
28652876
if not event.inaxes or not self._active:
28662877
if self._lastCursor != cursors.POINTER:
28672878
self.set_cursor(cursors.POINTER)
@@ -2876,8 +2887,29 @@ def _set_cursor(self, event):
28762887
self.set_cursor(cursors.MOVE)
28772888
self._lastCursor = cursors.MOVE
28782889

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

28822914
if event.inaxes and event.inaxes.get_navigate():
28832915

@@ -3164,15 +3196,6 @@ def save_figure(self, *args):
31643196
"""Save the current figure."""
31653197
raise NotImplementedError
31663198

3167-
def set_cursor(self, cursor):
3168-
"""Set the current cursor to one of the :class:`Cursors` enums values.
3169-
3170-
If required by the backend, this method should trigger an update in
3171-
the backend event loop after the cursor is set, as this method may be
3172-
called e.g. before a long-running task during which the GUI is not
3173-
updated.
3174-
"""
3175-
31763199
def update(self):
31773200
"""Reset the axes stack."""
31783201
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 cbook, rcParams, __version__
3238
from matplotlib.backend_bases import (
3339
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase, cursors)
@@ -422,18 +428,11 @@ def draw(self):
422428
Draw the figure using the renderer
423429
"""
424430
self.renderer = self.get_renderer(cleared=True)
425-
# acquire a lock on the shared font cache
426-
RendererAgg.lock.acquire()
427-
428-
toolbar = self.toolbar
429-
try:
430-
if toolbar:
431-
toolbar.set_cursor(cursors.WAIT)
431+
# Acquire a lock on the shared font cache.
432+
with RendererAgg.lock, (
433+
self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
434+
else ExitStack()):
432435
self.figure.draw(self.renderer)
433-
finally:
434-
if toolbar:
435-
toolbar.set_cursor(toolbar._lastCursor)
436-
RendererAgg.lock.release()
437436

438437
def get_renderer(self, cleared=False):
439438
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 & 9 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
@@ -34,15 +39,11 @@ def _render_figure(self, width, height):
3439

3540
def on_draw_event(self, widget, ctx):
3641
"""GtkDrawable draw event."""
37-
toolbar = self.toolbar
38-
if toolbar:
39-
toolbar.set_cursor(cursors.WAIT)
40- self._renderer.set_context(ctx)
41-
allocation = self.get_allocation()
42-
self._render_figure(allocation.width, allocation.height)
43-
if toolbar:
44-
toolbar.set_cursor(toolbar._lastCursor)
45-
return False # finish event propagation?
42+
with (self.toolbar._wait_cursor_for_draw_cm() if self.toolbar
43+
else ExitStack()):
44+
self._renderer.set_context(ctx)
45+
allocation = self.get_allocation()
46+
self._render_figure(allocation.width, allocation.height)
4647

4748

4849
class FigureManagerGTK3Cairo(backend_gtk3.FigureManagerGTK3):

setupext.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,10 @@ def get_install_requires(self):
14621462
"six>=1.10",
14631463
]
14641464
if sys.version_info < (3,):
1465-
install_requires += ["backports.functools_lru_cache"]
1465+
install_requires += [
1466+
"backports.functools_lru_cache",
1467+
"contextlib2",
1468+
]
14661469
if sys.version_info < (3,) and os.name == "posix":
14671470
install_requires += ["subprocess32"]
14681471
return install_requires

0 commit comments

Comments
 (0)
0