Skip to content

Conversation

@Ryan3141
Copy link

@Ryan3141 Ryan3141 commented Apr 8, 2025

This fixes button flickering on linux #127. This seems to be due to attaching wx widgets directly to a bare wx.GLCanvas and also using bare wx.BoxSizers. With minor modification this may help for macOS, though I have no way to test it.

I fixed this by adding a member variable to the BaseCanvas class called _opengl_canvas. For Windows this member variable is simply set to self. For linux the BaseCanvas now inherits from wx.Window and _opengl_canvas points to a GLCanvas. The surrounding code was updated refer to _opengl_canvas whenever relevant rather than the BaseCanvas widget. On linux the _opengl_canvas also needed to forward all of its input events to the BaseCanvas.

Another issue causing the flickering seemed to be the use of raw wx.BoxSizers for layouts. I fixed this in several cases by adding a containing wx.Panel for linux and a solid background color. To facilitate this, several classes required a separation of references to the canvas and to their wx parent class.

Fixes #127

@CLAassistant
Copy link

CLAassistant commented Apr 8, 2025

CLA assistant check
All committers have signed the CLA.

@EvilSupahFly
Copy link

Just out of curiosity, how does removing the following from amulet_map_editor/programs/edit/api/ui/file.py help the flickering? Changing the canvas-related things I understand, but not this.

from math import floor, log10

def _format_float(num: float) -> str:
    if num < 100:
        return f"{num:.0{max(0, 2 - floor(log10(num)))}f}".rstrip("0").rstrip(".")
    else:
        return f"{num:.0f}"

EvilSupahFly added a commit to EvilSupahFly/Amulet-Flatpak that referenced this pull request May 10, 2025
Incorporated changes to wxCanvas implementation (Amulet-Team/Amulet-Map-Editor#1150), after updating base to 0.10.42
@EvilSupahFly
Copy link

I implemented your fix into my flatpak project, but all I get is this now:

<class 'wx._glcanvas.GLAttributes'> returned a result with an exception set
NotImplementedError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/framework/pages/world_page.py", line 178, in _enable_page
    self.GetPage(page).enable()
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/edit.py", line 69, in enable
    self._canvas = EditCanvas(self, self._world)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/api/canvas/edit_canvas.py", line 151, in __init__
    super().__init__(parent, world)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py", line 63, in __init__
    super().__init__(parent)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/opengl/canvas/event_canvas.py", line 15, in __init__
    super().__init__(parent)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/opengl/canvas/canvas.py", line 46, in __init__
    display_attributes = GLAttributes()
                         ^^^^^^^^^^^^^^
SystemError: <class 'wx._glcanvas.GLAttributes'> returned a result with an exception set

What did you test this on? I'm running in a 3.12.9 VENV, and in Flatpak which is also 3.12.

@gentlegiantJGC
Copy link
Member

I have been busy working on other things so I haven't had a chance to look over this.
This is an issue that I would like to fix but didn't know how to.
Does the linux behaviour also work on windows? I would prefer to have as little platform dependent code as possible.

how does removing the following

I don't see this in the diff. This was something I changed recently. The diff seems a bit messed up so maybe something bugged.

SystemError: <class 'wx._glcanvas.GLAttributes'> returned a result with an exception set

I think you have experienced this issue before. Does it happen without these changes?

@EvilSupahFly
Copy link

I have been busy working on other things so I haven't had a chance to look over this. This is an issue that I would like to fix but didn't know how to. Does the linux behaviour also work on windows? I would prefer to have as little platform dependent code as possible.

how does removing the following

I don't see this in the diff. This was something I changed recently. The diff seems a bit messed up so maybe something bugged.

SystemError: <class 'wx._glcanvas.GLAttributes'> returned a result with an exception set

I think you have experienced this issue before. Does it happen without these changes?

When I revert the source and remove the changes, it doesn't happen. As for platform independence, wxPython behaves differently on each platform. During my adventures in Python Problem Solving (which has been quite the infuriating ride sometimes!), here's what I've learned about the platform differences in wxPython:

  1. Native Control Implementations
  • Windows: Uses the Win32 API under the hood. Usually the most feature-complete and stable.
  • macOS: Uses Cocoa (via Objective-C bridges). Certain controls (like wx.ComboBox, wx.TreeCtrl) behave differently or have limitations.
  • Linux: Uses GTK (usually GTK3), even under KDE. Layout and font rendering can be subtly different; some features like drag-and-drop may vary in behaviour.
  1. GLCanvas & OpenGL Contexts
  • wx.glcanvas.GLCanvas works differently due to backend support:
  • Windows: Usually works out-of-the-box.
  • macOS: Can be finicky; Apple deprecated OpenGL and prefers Metal.
  • Linux: Depends on proper OpenGL and X11/Wayland setup. May fail on Wayland without XWayland or fallbacks.
  1. HiDPI and Font Scaling
  • macOS: Automatically uses HiDPI (Retina) scaling. You must test UI scaling.
  • Windows: Needs manifest or explicit scaling support.
  • Linux: wxPython depends on GTK settings and environment variables like GDK_SCALE - again, even under KDE - unless over-ridden.
  1. Path and File System Handling
  • macOS/Linux: Case-sensitive paths.
  • Windows: Case-insensitive paths.
  • You may need to normalize paths using os.path.normcase() or Path.resolve().
  1. System Themes and Widget Styles
  • GTK and Cocoa draw widgets differently from Win32.
  • Buttons, dialogs, and menus may look and behave differently.

This means that there's no universally functional way to implement wxPython - you have to do some sort of platform or feature detection to make everything work everywhere. I was also informed that platform detection (which was used in this fix) is less reliable than using feature detection with wx.Platform:

import wx

if wx.Platform == "__WXMSW__":
    # Windows-specific tweak
elif wx.Platform == "__WXMAC__":
    # macOS-specific workaround
elif wx.Platform == "__WXGTK__":
    # something for Linux

And of course, within Linux, sometimes you have to further differentiate between X11 and Wayland, though wxPlatform won't give you that - you have to check the environment variables, though the only time I encountered this was with my original flatpak, something that has since been resolved.

@gentlegiantJGC
Copy link
Member

Some of those are just platform differences that there are no way around.
Some are not issues in Qt which is why we are switching to that.

@EvilSupahFly
Copy link

Switching to QT means a complete re-write. Like, from the ground up - total overhaul. I mean, you could mix and match, but would probably be a coding nightmare. Wayland support would improve at least, and since that seems to be where they want to go anyway, keeping X11 support in the long term probably doesn't make sense.

@gentlegiantJGC
Copy link
Member

I have completely rewritten the core library so the GUI needs rewriting anyway

@Ryan3141
Copy link
Author

Just out of curiosity, how does removing the following from amulet_map_editor/programs/edit/api/ui/file.py help the flickering? Changing the canvas-related things I understand, but not this.

from math import floor, log10

def _format_float(num: float) -> str:
    if num < 100:
        return f"{num:.0{max(0, 2 - floor(log10(num)))}f}".rstrip("0").rstrip(".")
    else:
        return f"{num:.0f}"

I believe this is just a merge conflict with #1161 because we are both changing the line creating self._location_button (currently line 74 in file.py). The code you referenced came from their commit.

My change was simply to switch from using the canvas to the newly created wx_parent. I have tried to resolve the merge conflict, but I'm not super familiar with github and resolving merge conflicts, so let me know if I've messed it up.

@Ryan3141
Copy link
Author

I implemented your fix into my flatpak project, but all I get is this now:

<class 'wx._glcanvas.GLAttributes'> returned a result with an exception set
NotImplementedError

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/framework/pages/world_page.py", line 178, in _enable_page
    self.GetPage(page).enable()
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/edit.py", line 69, in enable
    self._canvas = EditCanvas(self, self._world)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/api/canvas/edit_canvas.py", line 151, in __init__
    super().__init__(parent, world)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/programs/edit/api/canvas/base_edit_canvas.py", line 63, in __init__
    super().__init__(parent)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/opengl/canvas/event_canvas.py", line 15, in __init__
    super().__init__(parent)
  File "/app/lib/python3.12/site-packages/amulet_map_editor/api/opengl/canvas/canvas.py", line 46, in __init__
    display_attributes = GLAttributes()
                         ^^^^^^^^^^^^^^
SystemError: <class 'wx._glcanvas.GLAttributes'> returned a result with an exception set

What did you test this on? I'm running in a 3.12.9 VENV, and in Flatpak which is also 3.12.

Hmmm, that's strange. I'm using anaconda on Manjaro. I originally tested with python 3.11, but just tried it with python 3.12 and it seems to be ok, I will try pulling down your code and see if I can troubleshoot.

It looks like it is crashing in the wx._glcanvas.GLAttributes function which should be unrelated to my changes, but I'll try checking it out.

Comment on lines +167 to +178
if sys.platform == "linux":
self.panel = wx.Panel(self, style=wx.STAY_ON_TOP)
self.button_sizer = wx.BoxSizer(wx.HORIZONTAL)
self.button_sizer.AddStretchSpacer(1)
self.button_sizer.Add(self.panel, 0, wx.EXPAND, 0)
self._file_panel = FilePanel(self, self.panel)
self.panel.SetSizer(self._file_panel)
self.panel.SetBackgroundColour((155, 178, 216, 255))
self._canvas_sizer.Add(self.button_sizer, 0, wx.EXPAND, 0)
else:
self._file_panel = FilePanel(self, self)
self._canvas_sizer.Add(self._file_panel, 0, wx.EXPAND, 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue exists on macos as well. Your check only applies the custom behaviour to linux.
Can the linux behaviour be used on windows and macos as well?
I would prefer to have your custom behaviour on all platforms if it works on all platforms.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this as well in the long run, but this was a quick way to keep the same windows behavior while making the linux side usable again.

The 2 switches on sys.platform I had to use were:

  1. Make the BaseCanvas inherit from wx.Window instead of wx.glcanvas.GLCanvas. This seems to be related to some underlying difference in the implementation of wx.glcanvas.GLCanvas, though I am not extremely familiar with wx widgets. I think switching to Qt in the future is the solution to this.

  2. Giving the FilePanel an underlying panel on linux. Since linux seems unable to support transparent backgrounds for wx elements on top of a GLCanvas, I added this panel with a solid background. We could do the same on windows, but the buttons would no longer have a transparent background. Not the end of the world, but I'd say a slightly negative change, so I maintained the previous behavior for windows. I'm fine with it either way though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I understand

Comment on lines +32 to +35
if sys.platform == "linux":
Canvas_Type = wx.Window
else:
Canvas_Type = GLCanvas
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer one consistent behaviour across all platforms.
Does the wx.Window behaviour work across all platforms?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems to not work correctly on Windows. Similar (though different) flickering behavior occurs when trying to use the Linux solution on Windows.

@Alastair-L
Copy link

Alastair-L commented Aug 12, 2025

I was having this error (to the point of unnusability) and this branch fixed it for me - thank you! Not sure what's useful so I'll just dump a few specs here.
Linux mint 22
KDE Plasma 5.27.12 x11
NVIDIA GeForce RTX 2060 SUPER/PCIe/SSE2

Also for people who may be installing this branch from source like me - note I separately needed to install OpenGL_accelerate to fix a crash.

However, the canvas seems to be a small size? The mouse pointer location is similarly scaled to the smaller size (i.e. mouse in the middle of the window highlights the block in the middle of the (smaller) canvas). It's usable if I scale the window size down to the canvas size though! My monitor is 1920x1080
image

@gentlegiantJGC
Copy link
Member

I have created an Ubuntu virtual environment to review this.
The rendering behaviour of the old code is really weird.
The GUI is visible over the floor and ceiling geometry but invisible everywhere else.

@gentlegiantJGC
Copy link
Member

The VM was working well yesterday but has been a nightmare to work with today for some reason.
I have lost track of the number of times and ways it has crashed.

Ultimately I think these changes are a bit too intrusive and I am worried they may break some things I can't think of.

I have come up with a much less intrusive solution in #1203 that hooks into the EVT_PAINT event on linux.
For some reason it causes flickering on Windows so I have left the old behaviour there. I don't know which will work best for macOS.

This does not 100% solve the flickering issue. There is the odd frame where the overlay is not rendered for some reason but it is a lot better than it was before.

@Ryan3141 @EvilSupahFly @Alastair-L please can you review #1203 and let me know how it behaves on your computers.

@gentlegiantJGC gentlegiantJGC changed the base branch from 0.10__ to 0.10 October 17, 2025 08:50
@gentlegiantJGC
Copy link
Member

Apparently my attempted fix does not work correctly.

I am hesitant to merge this because there are a few breaking changes and I don't know what effect that will have.
I will leave this here for anyone who wants to use it as a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[linux/macOS] Flickering UI on canvas

5 participants