fix(window): the destructor cancels the frame callback; a window without a display or swapchain

wl_surface_frame_done re-armed the frame callback through its local and
left the member stale, so the destructor could not cancel it and a done
already queued would dispatch into the freed window; the member now
names the live callback and the destructor destroys it. The destructor
also flushed a null display for a window created without
Device::Initialize (tests do that) and freed never-created command
buffers (a default-constructed Window after Initialize); both guarded.
And wp_scale was one inline static for every window, which the destructor
destroyed on behalf of all of them: it is a member now, like the viewport.
This commit is contained in:
Jorijn van der Graaf 2026-10-18 03:27:50 +02:00
commit c8b5739e1a
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
2 changed files with 12 additions and 10 deletions

View file

@ -256,7 +256,7 @@ export namespace Crafter {
constexpr static wp_fractional_scale_v1_listener wp_fractional_scale_v1_listener = {
.preferred_scale = xdg_surface_handle_preferred_scale,
};
inline static wp_fractional_scale_v1* wp_scale = nullptr;
wp_fractional_scale_v1* wp_scale = nullptr;
#endif
#ifndef CRAFTER_GRAPHICS_WINDOW_DOM
@ -298,7 +298,7 @@ export namespace Crafter {
// lazily in Render() (post-acquire) rather than up front.
std::array<bool, numFrames> imageInitialised{};
std::thread thread;
VkCommandBuffer drawCmdBuffers[numFrames];
VkCommandBuffer drawCmdBuffers[numFrames] = {};
// Per-frame Vulkan info structs whose contents are almost entirely
// invariant. Initialised once in the constructor; Render() patches only
// the few fields that change each frame (the two barriers' image and