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

Skip to content

Commit e9b7c67

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 0e3dd2d commit e9b7c67

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
@@ -2528,11 +2528,11 @@ def key_press_handler(event, canvas, toolbar=None):
25282528
# pan mnemonic (default key 'p')
25292529
elif event.key in pan_keys:
25302530
toolbar.pan()
2531-
toolbar._set_cursor(event)
2531+
toolbar._update_cursor(event)
25322532
# zoom mnemonic (default key 'o')
25332533
elif event.key in zoom_keys:
25342534
toolbar.zoom()
2535-
toolbar._set_cursor(event)
2535+
toolbar._update_cursor(event)
25362536
# saving current figure (default key 's')
25372537
elif event.key in save_keys:
25382538
toolbar.save_figure()
@@ -2865,7 +2865,18 @@ class implementation.
28652865
"""
28662866
raise NotImplementedError
28672867

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

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

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

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

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

436435
def get_renderer(self, cleared=False):
437436
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
@@ -387,9 +387,6 @@ def _render_figure(self, pixmap, width, height):
387387
def expose_event(self, widget, event):
388388
"""Expose_event for all GTK backends. Should not be overridden.
389389
"""
390-
toolbar = self.toolbar
391-
if toolbar:
392-
toolbar.set_cursor(cursors.WAIT)
393390
if GTK_WIDGET_DRAWABLE(self):
394391
if self._need_redraw:
395392
x, y, w, h = self.allocation
@@ -399,8 +396,6 @@ def expose_event(self, widget, event):
399396
x, y, w, h = event.area
400397
self.window.draw_drawable (self.style.fg_gc[self.state],
401398
self._pixmap, x, y, x, y, w, h)
402-
if toolbar:
403-
toolbar.set_cursor(toolbar._lastCursor)
404399
return False # finish event propagation?
405400

406401
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