- Fix empty clip region bug in wx.js clipRect function - Add dropdown mouse interaction tests - Add *.log to gitignore - Make build script clean by default (use --no-clean to skip) - Add wxGLCanvas canvas element fix documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
4.1 KiB
4.1 KiB
06 - wxGLCanvas WASM Canvas Element Integration
This document describes how to fix wxGLCanvas to render visibly in WASM by creating its own canvas element.
Problem
wxGLCanvas currently hardcodes m_canvasTarget = "#canvas" which creates WebGL context on the main wxUniversal 2D canvas, causing a conflict. The GL rendering doesn't appear because it's overwritten by 2D UI rendering.
Key Discovery
The WASM port already supports multiple canvas elements per window:
- Main window uses
#canvasfor 2D rendering - Child windows can each get their own canvas element via
createWindow(id, needsCanvas=true) - Windows are positioned absolutely with z-index layering
- JavaScript (wx.js) manages canvas creation, positioning, and context stacking
How KiCad Uses wxGLCanvas
wxFrame (EDA_DRAW_FRAME)
└── EDA_DRAW_PANEL_GAL (wxScrolledCanvas)
└── OPENGL_GAL (inherits from wxGLCanvas)
- Sized to match parent
- Child window positioned within parent
- Has its own GL context
Key KiCad files:
kicad/common/gal/opengl/opengl_gal.cpp- GL rendering implementationkicad/common/draw_panel_gal.cpp- Creates OPENGL_GAL as child:new OPENGL_GAL(..., this, ...)kicad/include/gal/hidpi_gl_canvas.h- wxGLCanvas wrapper class
Solution
wxGLCanvas should integrate with the existing WASM window system:
- Create its own canvas element - Use
createWindow(id, needsCanvas=true)in JavaScript - Create WebGL context on that canvas - Use selector
#window-{id} canvas - Handle positioning via window system -
setWindowRect()positions the canvas
Key JavaScript Functions (already exist in wx.js)
createWindow(id, needsCanvas, isVisible, classList)
setWindowRect(id, x, y, width, height)
setWindowVisibility(id, isVisible)
destroyWindow(id)
Implementation
Step 1: Modify Create() to create canvas element
In wxwidgets/src/wasm/glcanvas.cpp:
bool wxGLCanvas::Create(wxWindow *parent, ...)
{
if ( !wxWindow::Create(parent, id, pos, size, style, name) )
return false;
// Create a window with canvas element in JavaScript
int cssId = GetCSSId();
EM_ASM({
createWindow($0, true, true, "glcanvas");
}, cssId);
// Position the canvas
wxPoint screenPos = GetScreenPosition();
wxSize clientSize = GetClientSize();
EM_ASM({
setWindowRect($0, $1, $2, $3, $4);
}, cssId, screenPos.x, screenPos.y, clientSize.GetWidth(), clientSize.GetHeight());
// Set dynamic canvas selector
m_canvasTarget = wxString::Format("#window-%d canvas", cssId).ToStdString();
return CreateWebGLContext(dispAttrs);
}
Step 2: Override DoSetSize for resize handling
void wxGLCanvas::DoSetSize(int x, int y, int width, int height, int sizeFlags)
{
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
wxPoint screenPos = GetScreenPosition();
wxSize clientSize = GetClientSize();
EM_ASM({
setWindowRect($0, $1, $2, $3, $4);
}, GetCSSId(), screenPos.x, screenPos.y, clientSize.GetWidth(), clientSize.GetHeight());
}
Step 3: Handle visibility
void wxGLCanvas::DoShow(bool show)
{
wxWindow::DoShow(show);
EM_ASM({
setWindowVisibility($0, $1);
}, GetCSSId(), show);
}
Step 4: Clean up in destructor
wxGLCanvas::~wxGLCanvas()
{
if ( m_webglContext > 0 )
{
emscripten_webgl_destroy_context(m_webglContext);
m_webglContext = 0;
}
EM_ASM({
destroyWindow($0);
}, GetCSSId());
}
Files to Modify
| File | Changes |
|---|---|
wxwidgets/src/wasm/glcanvas.cpp |
Main implementation - create own canvas, dynamic selector, resize/visibility handling |
wxwidgets/include/wx/wasm/glcanvas.h |
Add DoSetSize, DoShow declarations if needed |
Testing
The existing test app in tests/wasm-app/ with the OpenGL tab will verify:
- Canvas element is created in DOM
- WebGL context is on the correct canvas
- GL rendering appears in the canvas area
- Legacy GL emulation works (via
-sLEGACY_GL_EMULATION)