diff --git a/src/KDGui/platform/linux/xcb/linux_xcb_platform_event_loop.cpp b/src/KDGui/platform/linux/xcb/linux_xcb_platform_event_loop.cpp index 7d3bb30..fbfc227 100644 --- a/src/KDGui/platform/linux/xcb/linux_xcb_platform_event_loop.cpp +++ b/src/KDGui/platform/linux/xcb/linux_xcb_platform_event_loop.cpp @@ -114,8 +114,10 @@ void LinuxXcbPlatformEventLoop::processXcbEvents() const auto w = configureEvent->width; const auto h = configureEvent->height; auto window = m_platformIntegration->window(configureEvent->window); - SPDLOG_LOGGER_DEBUG(m_logger, "{}: Resize of window to {} x {}", xcbEvent->sequence, w, h); - window->handleResize(w, h); + if (window) { + SPDLOG_LOGGER_DEBUG(m_logger, "{}: Resize of window to {} x {}", xcbEvent->sequence, w, h); + window->handleResize(w, h); + } break; } @@ -136,6 +138,8 @@ void LinuxXcbPlatformEventLoop::processXcbEvents() case XCB_BUTTON_PRESS: { const auto buttonEvent = reinterpret_cast(xcbEvent); auto window = m_platformIntegration->window(buttonEvent->event); + if (window == nullptr) + break; auto button = buttonEvent->detail; switch (button) { @@ -217,6 +221,8 @@ void LinuxXcbPlatformEventLoop::processXcbEvents() case XCB_BUTTON_RELEASE: { const auto buttonEvent = reinterpret_cast(xcbEvent); auto window = m_platformIntegration->window(buttonEvent->event); + if (window == nullptr) + break; SPDLOG_LOGGER_DEBUG(m_logger, "Mouse release event for button {} at pos ({}, {})", buttonEvent->detail, @@ -233,6 +239,8 @@ void LinuxXcbPlatformEventLoop::processXcbEvents() case XCB_MOTION_NOTIFY: { const auto mouseMoveEvent = reinterpret_cast(xcbEvent); auto window = m_platformIntegration->window(mouseMoveEvent->event); + if (window == nullptr) + break; SPDLOG_LOGGER_DEBUG(m_logger, "{}: Mouse move event for button {} at pos ({}, {})", xcbEvent->sequence, diff --git a/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.cpp b/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.cpp index b35c6f0..1995334 100644 --- a/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.cpp +++ b/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.cpp @@ -66,6 +66,14 @@ LinuxXkbKeyboard *LinuxXcbPlatformIntegration::keyboard() return m_keyboard.get(); } +LinuxXcbPlatformWindow *LinuxXcbPlatformIntegration::window(xcb_window_t xcbWindow) const +{ + auto it = m_windows.find(xcbWindow); + if (it == m_windows.end()) + return nullptr; + return it->second; +} + LinuxXcbPlatformEventLoop *LinuxXcbPlatformIntegration::createPlatformEventLoopImpl() { // We ensure that the logger has been created here rather than in the ctor so that diff --git a/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.h b/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.h index eec6bf2..0c5fe3e 100644 --- a/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.h +++ b/src/KDGui/platform/linux/xcb/linux_xcb_platform_integration.h @@ -46,7 +46,7 @@ class KDGUI_API LinuxXcbPlatformIntegration : public AbstractGuiPlatformIntegrat m_windows.insert({ xcbWindow, window }); } void unregisterWindowForEvents(xcb_window_t xcbWindow) { m_windows.erase(xcbWindow); } - LinuxXcbPlatformWindow *window(xcb_window_t xcbWindow) { return m_windows.at(xcbWindow); } + LinuxXcbPlatformWindow *window(xcb_window_t xcbWindow) const; private: LinuxXcbPlatformEventLoop *createPlatformEventLoopImpl() override; diff --git a/src/KDGui/platform/win32/win32_platform_window.cpp b/src/KDGui/platform/win32/win32_platform_window.cpp index 04feab9..acd7ab6 100644 --- a/src/KDGui/platform/win32/win32_platform_window.cpp +++ b/src/KDGui/platform/win32/win32_platform_window.cpp @@ -169,7 +169,6 @@ Win32PlatformWindow::Win32PlatformWindow(Win32GuiPlatformIntegration *platformIn Win32PlatformWindow::~Win32PlatformWindow() { - destroy(); delete m_rawInputData; m_rawInputData = nullptr; m_rawInputDataSize = 0; diff --git a/src/KDGui/window.cpp b/src/KDGui/window.cpp index 0a56afc..0c4569f 100644 --- a/src/KDGui/window.cpp +++ b/src/KDGui/window.cpp @@ -33,7 +33,11 @@ Window::Window() rawMouseInputEnabled.valueChanged().connect(&Window::onRawMouseInputEnabledChanged, this); } -Window::~Window() = default; +Window::~Window() +{ + if (m_platformWindow) + destroy(); +} Window::Window(Window &&other) noexcept = default; Window &Window::operator=(Window &&other) noexcept = default; @@ -80,6 +84,7 @@ void Window::destroy() return; m_platformWindow->destroy(); + m_platformWindow = nullptr; } void Window::registerEventReceiver(Object *receiver) diff --git a/tests/auto/gui/window/tst_window.cpp b/tests/auto/gui/window/tst_window.cpp index 5c7b19e..de23e58 100644 --- a/tests/auto/gui/window/tst_window.cpp +++ b/tests/auto/gui/window/tst_window.cpp @@ -80,4 +80,23 @@ TEST_CASE("Creation") REQUIRE(w->platformWindow()->type() == AbstractPlatformWindow::Type::Cocoa); #endif } + + SUBCASE("doesn't crash if Window destroyed with pending platform events") + { + // GIVEN + GuiApplication app; + auto window = std::make_unique(); + window->width = 512; + window->height = 512; + window->create(); + + REQUIRE(window->platformWindow() != nullptr); + + // WHEN -> Trigger a resize (this should trigger platform events, at least it does for XCB) + window->width = 256; + window->height = 256; + + // THEN -> Shouldn't crash if platform backend is trying to deliver resize events on app exit + // to window that is now destroyed + } }