Skip to content

wxGUI/nviz: fix 'window must be shown' error message during docking undocked 3D view window - #7819

Merged
echoix merged 3 commits into
OSGeo:mainfrom
tmszi:fix-wxgui-nviz-dock-3d-view
Oct 2, 2026
Merged

echoix merged 3 commits into
OSGeo:mainfrom
tmszi:fix-wxgui-nviz-dock-3d-view

Conversation

@tmszi

@tmszi tmszi commented Aug 10, 2026

Copy link
Copy Markdown
Member

Fixes #7668.

@tmszi tmszi added bug Something isn't working GUI wxGUI related Python Related code is in Python backport to 8.5 PR needs to be backported to release branch 8.5 labels Aug 10, 2026
@echoix

echoix commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Did you run this change (recently) once built? I made an AI agent try out this PR, and it hit a circular import that isn’t on main with this. Even when working around that problem, it doesn’t seem enough. It also thinks that this fix only masks the problem, being a timing problem.

It suggests another fix. You can read below if you’d like, I also included the files.

Used Opus 5.5 Medium.

Details (process)

I've read the PR and the issue; now installing build dependencies so I can build GRASS and run the GUI under a virtual display.

Configuring the build; fixing missing dependencies one at a time.

Build succeeded. First check: the PR adds mapdisp.frame → main_window.notebook, while notebook already imports mapdisp.frame — a possible circular import.

Run inside a real GRASS session instead.

Circular import in every order. Confirm at the real surface: launch the GUI on the PR head vs. main.

GUI exits silently. Run wxgui.py directly inside a session to see its stderr.

The PR head can't even start the GUI. Checking the build output matches the PR source, then reproducing the original bug on main for comparison.

Writing a driver that runs the real GUI and triggers the same handlers the toolbar buttons call (3D combo → AddToolbar("nviz"), (Un)dock button → OnDockUndock).

Stdout is captured by the GUI's own console. Let me look at the screenshots, then send logs to a file.

Confirmed the bug on main: docking triggers the wxAssertionError about SetCurrent() needing a shown window (the locale dialog is just sandbox noise). Next, I'll redirect driver output to a file and test the PR's approach with the circular import worked around.

Baseline logged. Now the PR's approach, with only the import changed (duck-typed hasattr check instead of isinstance(…, MainNotebook)) so the GUI can start.

Startup was slower after the rebuild (no GMFrame at 8 s yet). Re-running.

GUI didn't come up. Checking the log and for leftover processes.

Build-tree mismatch from switching to the older PR base. Simpler and more representative: apply the PR diff onto current main (what a merge would produce).

PR-as-is on top of current main: GUI still fails to start with the circular import. Now the workaround variant:

Workaround variant: no assertion. Probe: resize the undocked window before re-docking — with EVT_SIZE unbound for 1 s, does the GL viewport miss the resize back to the notebook size?

Both variants leave the stored size stale (698×374) while the canvas is 940×800. Let me look at what that means visually.

The stale viewport issue after resize+redock exists on main as well, so the PR just masks it rather than fixing it. Next I'll check whether EVT_SIZE is actually re-bound after the 1-second delay.

Re-binding works: a later resize updates the viewport again. Cleaning up the working tree and sending the evidence.

Details (Final summary)

Files: prAsIs_3d_docked main_3d_redocked_later compare_resize

drive.py

Verification: wxGUI/nviz, the "window must be shown" error when re-docking the 3D view (PR #7819)

Verdict: FAIL. As submitted, the PR stops the GUI from starting at all.

What the bug is and what the PR does

When you dock a 3D view back into the notebook, DockPage() calls page.Reparent(self). That fires a resize event on the OpenGL canvas before the canvas is visible in its new parent. The resize handler, OnSize, then calls SetCurrent(self.context). On Linux/GTK, wx refuses to make an OpenGL context current on a window that isn't shown yet, so it raises the assertion.

The PR's fix is a timing workaround, not a real fix:

  1. It adds a dockPage signal to MainNotebook and sends it at the start of DockPage(), before Reparent.
  2. When the 3D view is first created, the map display (MapPanel) connects that signal to a new method, NvizMapWindow.dockPage().
  3. dockPage() turns off the resize handler, then turns it back on after 1 second (wx.CallLater(1000, …)), on the assumption that the window will be shown by then.

So the resize that crashes is simply ignored, and resizes are handled again after 1 s.

Why it isn't correct as written

The new line from main_window.notebook import MainNotebook in mapdisp/frame.py creates a circular import: notebook.py already starts with from mapdisp.frame import MapPanel. Whichever module loads first, the other isn't fully loaded yet, so the import fails every time.

Method

I built current main with CMake and launched the real GUI (single-window mode) under a virtual display, with a synthetic elevation raster. A small script triggered the same handlers the toolbar controls use: the "3D view" choice, then the (Un)dock button twice.

Steps

  1. ✅ main, reproducing the bug: Undock the 3D view, then dock it again. The error from the issue appears:
    EXC: wx._core.wxAssertionError: C++ assertion ""xid"" failed at ./src/unix/glx11.cpp(584) in SetCurrent(): window must be shown
    
  2. ❌ PR as submitted (on its own branch, and applied on top of main): Launch the GUI. It never opens; you only get a black screen and:
    File ".../mapdisp/frame.py", line 48, in <module>
        from main_window.notebook import MainNotebook
    ImportError: cannot import name 'MainNotebook' from partially initialized module 'main_window.notebook' (most likely due to a circular import)
    
    Importing the modules directly fails in every order I tried (mapdisp.frame, main_window.notebook, main_window.frame, lmgr.frame).
  3. ✅ The PR's approach with only the import changed: I dropped that import and replaced isinstance(self.parent, MainNotebook) with hasattr(self.parent, "dockPage"). The same undock/dock sequence then gives no error. So the idea itself does stop the message.
  4. 🔍 Resize the undocked window (to 700×450), then dock it: afterwards the canvas is 940×800, but the 3D view keeps its old size of 698×374. The scene draws only in the bottom-left corner. main does exactly the same thing, because there the handler crashes before it records the new size. So the PR doesn't cause this, but it doesn't fix it either; it only hides the error.
  5. 🔍 Resize the main window 2.5 s after docking: the view updates correctly (740×700). The resize handler does come back after the 1 s delay.

Findings

  • ⚠️ Blocker: the circular import stops the GUI from starting, in single-window and multi-window mode alike. This means the PR can't have been tested in its current form.
  • ⚠️ It hides the symptom, not the cause. Any resize during the 1 s window is ignored for good, so the 3D view stays wrong until the user resizes again (screenshot 3). A fixed 1000 ms delay is also a guess: nothing guarantees the window is shown by then.
  • A simpler fix I'd suggest: in OnSize, when the canvas isn't shown on screen yet, skip without saving the new size, so a later resize or paint picks it up. That would need no signal, no import between the two modules, and no timer. I have not tested this.
  • The signal fires when any page is docked, so docking an unrelated 2D map display also turns off resize handling on every 3D view for 1 s. Harmless, but broader than needed.
  • Setup notes: the build needs /usr/bin/python3.12, because the Ubuntu wxPython package is built for 3.12 and the default python3 here is 3.11. The "Cannot set locale" dialog in the screenshots is noise from the sandbox, not a GUI problem.

I sent four files: the reproduced error on main, the black screen with the PR as-is, the side-by-side of the stale view, and the GUI driver script (drive.py), so the steps can be replayed. The working tree is back to a clean main, and nothing was committed or pushed.

@tmszi

tmszi commented Sep 30, 2026

Copy link
Copy Markdown
Member Author

Did you run this change (recently) once built?

Yes you are right, with last code from the main Git branch, this PR make Python ImportError (which didin't exist in time of publish this PR):

GRASS tmpproject/PERMANENT:~ > g.gui
Launching <wxpython> GUI in the background, please wait...
Traceback (most recent call last):
  File "/usr/lib/python3.13/site-packages/wx/core.py", line 3425, in <lambda>
    lambda event: event.callable(*event.args, **event.kw) )
                  ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/grass86/gui/wxpython/wxgui.py", line 86, in show_main_gui
    from main_window.frame import GMFrame
  File "/usr/lib64/grass86/gui/wxpython/main_window/frame.py", line 60, in <module>
    from main_window.notebook import MainNotebook
  File "/usr/lib64/grass86/gui/wxpython/main_window/notebook.py", line 24, in <module>
    from mapdisp.frame import MapPanel
  File "/usr/lib64/grass86/gui/wxpython/mapdisp/frame.py", line 46, in <module>
    from main_window.notebook import MainNotebook
ImportError: cannot import name 'MainNotebook' from partially initialized module 'main_window.notebook' (most likely due to a circular import) (/usr/lib64/grass86/gui/wxpython/main_window/notebook.py)

@tmszi
tmszi force-pushed the fix-wxgui-nviz-dock-3d-view branch from 7e4b9ea to 37abc47 Compare September 30, 2026 07:39
…ocking undocked 3D view window"

There is a simpler solution.

This reverts commit d0a9d578b318598b40827b07db346c3882dcd69d.
…on the screen

Fix 'window must be shown' error message during docking undocked 3D view window.
@tmszi

tmszi commented Sep 30, 2026 •

Copy link
Copy Markdown
Member Author

Successfully refactored and retested to much simpler and better solution 37abc47.

@echoix echoix left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Made it retry it and it worked. There's still the existing issue when resizing that it only gets done on a subsequent resize, but that's the same on main too.

@echoix
echoix merged commit 4e0a6aa into OSGeo:main Oct 2, 2026
26 checks passed
tmszi added a commit that referenced this pull request Oct 2, 2026
…ndocked 3D view window (#7819)

* wxGUI/nviz: fix handling window resize event only if window is shown on the screen

Fix 'window must be shown' error message during docking undocked 3D view window.
@tmszi tmszi removed the backport to 8.5 PR needs to be backported to release branch 8.5 label Oct 2, 2026
@tmszi
tmszi deleted the fix-wxgui-nviz-dock-3d-view branch October 2, 2026 03:52
@github-actions github-actions Bot added this to the 8.6.0 milestone Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working GUI wxGUI related Python Related code is in Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] wxGUI/nviz: an error message is printed during docking undocked 3D view window

2 participants