-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
wx backends: don't use ClientDC any more #11944
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
wx backends: don't use ClientDC any more #11944
Conversation
@anntzer : would you mind reviewing this one? |
Tagged this as 3.1 for now. Please re-milestone if it needs to be backported. |
@@ -761,29 +763,6 @@ def _get_imagesave_wildcards(self): | |||
wildcards = '|'.join(wildcards) | |||
return wildcards, extensions, filter_index | |||
|
|||
def gui_repaint(self, drawDC=None, origin='WX'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add an API change note (it's mostly an implementation detail so not going to ask a deprecation period, which probably wouldn't make sense anyways).
# Macs. N.B. In future versions of wx it may be possible to | ||
# detect Retina displays with window.GetContentScaleFactor() | ||
# and/or dc.GetContentScaleFactor() | ||
self.retinaFix = 'wxMac' in wx.PlatformInfo |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All these attributes need removal notices.
|
||
if previous_rubberband: | ||
# extend by one pixel to avoid residuals on Mac OS | ||
if left > 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tend to write these left = max(left - 1, 0)
as the bound is clearer (you don't need to check whether it was > or >=). Not that it really matters here, just a suggestion.
self.gui_repaint(drawDC=drawDC) | ||
drawDC.Destroy() | ||
# draw without transparency which is buggy on Retina displays | ||
dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The blue seems a bit deeper than in the original version. Also none of the other backends (well, dunno for macos) actually color the rectangle, so perhaps we may just leave it as transparent).
|
||
class FigureCanvasWx(_FigureCanvasWxBase): | ||
# Rendering to a Wx canvas using the deprecated Wx renderer. | ||
|
||
def draw(self, drawDC=None): | ||
def draw(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add note re: API change.
I don't know the details of the wx drawing model, but for Qt we do call
so we're not overdoing things. How are things on wx's side? |
@anntzer About the rubberband: I will add notes about the API changes. I will come back to you when I've done the changes. (I need to push the commits to be able to test on Mac OS.) |
retinaFix can be made private if it moves somewhere else, it's not as if it was ever intended as a public API anyways. |
If it can be a dashed line drawn with XOR -- that's ideal for making it visible against any backround. Now suer that that interacts with Overlay, though |
@ChrisBarker-NOAA : thanks, but this does not seem to work. I think that this also did not work with ClientDC on Mac OS. The only way to get this behaviour would be to modify the canvas' bitmap, as it was done with the previous implementation of NavigationToolbar2Wx on Mac OS. This is something that I would like to avoid, though. |
""" | ||
DEBUG_MSG("draw()", 1, self) | ||
def _draw(self): | ||
DEBUG_MSG("_draw()", 1, self) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just kill these DEBUG_MSGs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. Will do so.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are also some functions debug_on_error
, fake_stderr
and raise_msg_to_str
which probably do not serve a purpose. It would probably be best to remove these as well. What dou you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can always remove them later (or now if you want), the point was just not to introduce more of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And/or replace by logging messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe combine _draw()
and draw()
by adding a refresh=True
argument to draw()
that controls whether self.Refresh()
is called, and then using self.draw(refresh=False)
instead of self._draw()
.
@ChrisBarker-NOAA : using anything than a simple drawing function would also cause problems on Retina displays, as the overlay background is scaled wrongly. I think that was the reason why overlays were not used on Mac OS previously. |
I just looked at some old overlay code of mine -- and indeed, not XOR. So what I did is draw a dashed black and white line:
|
Ah, thanks, that's probably the best option. I will take this one for Mac OS. |
|
@anntzer : Doesn't the supplied code for
Unfortunately, |
Fedora 28 (in case anyone wonders, my Arch machine is momentarily out of service...).
Actually a basic pop-up-a-plot work, it's animation that doesn't work (e.g. examples/animation/strip_chart.py), sorry, should have clarified that. I can't (don't want to) use the codepath from backend_wxcairo because that disables blitting (you redraw the whole figure at every iteration). backend_wxcairo correctly inherits supports_blitting = False from backend_cairo (even though technically it's only gtk3cairo that doesn't support blitting (because it needs to draw directly on the X surface that gtk3 handles to it, whereas wxcairo could just stash the ImageSurface and blit normally from it), but that's an unrelated point...), but for mplcairo.wx I have no reason not to support blitting. |
OK, so in I don't have a Fedora 28 VM. So I need some time to install one. |
Replacing gui_repaint by Refresh works in the old codebase (before this PR). After this PR, if I replace gui_repaint by Refresh, it looks like something is preventing wx from running its event loop, unless I try to throw events at it: the plot stays blank (except for the axes), but if I click on the window, or on one of the buttons (let's say the mouse is initially out of the window) then I get one or two updates to the animation, which then freezes again, and so on. |
OK, maybe you can attach a script that uses mplcairo for animation. If I got it right, then I need to place the contents from mplcairo somewhere next to such a script and then just run the script, right? I could then try at least on Ubuntu with and without Wayland. |
That behavior of Refresh() is expected: https://wxpython.org/Phoenix/docs/html/wx.Window.html#wx.Window.Refresh .Refesh() tell wx that the Window needs to be repainted, but it doesn't trigger a Paint event right then. The usual way to get it done NOW is:
followed by
BTW, not sure if there is any point to using a BufferedDC. The idea behind double buffering is that you only repaint the screen once the drawing is complete on an offscreen buffer. But int his case, all the drawing is being done by AGG or Cairo to an offscreen buffer anyway, and the Draw() call is simply blitting that image to the Screen. -- no need to blit it to an offscreen buffer first, only to have to transfer it again. NOTE: I'm working off ten year(or more!) old information here, back when I did a lot with wx drawing, (And BufferedDC didn't exist, so I wrote my own) but I suspect this part is the same. |
Honestly, I have never used Update. Would be worth a try, but in my tests the Refresh with later repaint was enough. It could be that Update has the same problems as ClientDC, but that would need testing. I would not expect BufferedDC to make an additional copy, as it just receives the buffer bitmap that was filled from AGG or Cairo: |
No, Update is not quite as aggressive as ClientDC about "NOW!" -- At least on OS-X, Client DC does it really right now, which may interfere with other drawing the OS is doing, whereas Update() puts it on the queue for the OS right away, but still lets the OS schedule it. Due to this, on the past, on OS-X, using Refresh(), Update() and drawing in a PaintDC was not fast enough to follow the mouse... As for the BufferedDC -- if it's not writing to a buffer, then what's the point ??? Note also that OS-X (and some others?) is already double-buffered by the OS anyway. Maybe wx.Window.IsDoubleBuffered() would help here? |
Hmm -- not sure the point of wxBufferedPaintDC if you aren't drawing to it anyway... (as opposed to simply doing a PaintDC.DrawBitmap() call, but it looks like you are right. I did see this note in the BufferedDC docs: "Finally, please note that GTK+ 2.0 as well as OS X provide double buffering themselves natively. You can either use wx.Window.IsDoubleBuffered to determine whether you need to use buffering or not, or use wx.AutoBufferedPaintDC to avoid needless double buffering on the systems which already do it automatically." |
(unrelated point: the timer bug was fixed in #12023, you can just rebase on top of it) |
re-milestoned to 3.4 and removed the release critical label. |
(Neither of my examples are using Wayland.) |
@anntzer Thanks. Could you please check whether these are all gtk2 builds? From the recipe file, I would guess that the conda build is gtk2. |
it's gtk2/wxWidgets 3.0.5 on fedora, gtk3/wxWidgets 3.0.4 on arch. |
I have just spent too much time again with the ArchLinux2018.09 VM. The platform upgrade command I'm not willing to work on fixing platform problems after all the experiences with the Arch and Fedora VMs. |
Is it possible to resurrect the non-Wayland parts of this PR? If not, what is the todo here? |
Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it. |
PR Summary
This is work in progress and needs some testing...
Fix for
At the moment the wx backends have problems on Wayland as ClientDC is not working.
This PR changes the backends to trigger a Refresh instead and then paint everything in the
EVT_PAINT
handler. Also,BufferedPaintDC
is used now as this is the standard approach for double-buffering.Overlays are used for drawing rubberbands. This is also done on Mac OS now, but only with a border, not with a half-transparent box, as this does not work on Retina displays.
PR Checklist