From 7803062c6eb295d203da045220d1b0993728cb5e Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 20 Jul 2020 23:31:10 -0400 Subject: [PATCH] gtk/tk: Ensure no flicker when hovering over images. When the mouse is over an image, the status message is two lines long. This causes the toolbar to increase size slightly. On Qt, this is ignored by a sizing policy, but there is no such thing in other toolkits. On GTK this steals space from the canvas, so it re-draws a little bit smaller, until the mouse moves off the image. On Tk, the space is added to the window, _unless_ the window is maximized, and then it's stolen from the canvas as well. As a simple workaround, we add an additional label with invisible text (spaces) on two lines. This forces the toolbar to always be two lines high and thus not flicker. If the message were 3 or more lines long, then the same thing would happen, but we don't have any of those by default. The advantage of using a label is that it saves us having to measure text in some toolkit-specific way, and thus works regardless of theme. --- lib/matplotlib/backends/_backend_tk.py | 8 ++++++++ lib/matplotlib/backends/backend_gtk3.py | 14 +++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 7c1ff265aea3..260a5664e465 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -512,6 +512,14 @@ def __init__(self, canvas, window, *, pack_toolbar=True): if tooltip_text is not None: ToolTip.createToolTip(button, tooltip_text) + # This filler item ensures the toolbar is always at least two text + # lines high. Otherwise the canvas gets redrawn as the mouse hovers + # over images because those use two-line messages which resize the + # toolbar. + label = tk.Label(master=self, + text='\N{NO-BREAK SPACE}\n\N{NO-BREAK SPACE}') + label.pack(side=tk.RIGHT) + self.message = tk.StringVar(master=self) self._message_label = tk.Label(master=self, textvariable=self.message) self._message_label.pack(side=tk.RIGHT) diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index c9094eb1df33..a8b6e801205c 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -521,6 +521,17 @@ def __init__(self, canvas, window): toolitem.set_draw(False) toolitem.set_expand(True) + # This filler item ensures the toolbar is always at least two text + # lines high. Otherwise the canvas gets redrawn as the mouse hovers + # over images because those use two-line messages which resize the + # toolbar. + toolitem = Gtk.ToolItem() + self.insert(toolitem, -1) + label = Gtk.Label() + label.set_markup( + '\N{NO-BREAK SPACE}\n\N{NO-BREAK SPACE}') + toolitem.add(label) + toolitem = Gtk.ToolItem() self.insert(toolitem, -1) self.message = Gtk.Label() @@ -536,7 +547,8 @@ def ctx(self): return self.canvas.get_property("window").cairo_create() def set_message(self, s): - self.message.set_label(s) + escaped = GLib.markup_escape_text(s) + self.message.set_markup(f'{escaped}') def set_cursor(self, cursor): self.canvas.get_property("window").set_cursor(cursord[cursor])