From 215d3dd3dfeb8d00a89530e67325f1f54ff1c852 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Sat, 30 May 2026 17:01:40 -0300 Subject: [PATCH] sync changes from auto-updater branch Co-Authored-By: Marcus Minhorst --- include/zwidget/core/widget.h | 6 +- include/zwidget/window/window.h | 7 +- src/core/widget.cpp | 9 ++- src/window/sdl2/sdl2_display_backend.cpp | 4 +- src/window/sdl2/sdl2_display_backend.h | 2 +- src/window/sdl2/sdl2_display_window.cpp | 75 ++++++++++++++++++---- src/window/sdl2/sdl2_display_window.h | 5 +- src/window/win32/win32_display_backend.cpp | 4 +- src/window/win32/win32_display_backend.h | 2 +- src/window/win32/win32_display_window.cpp | 13 +++- src/window/win32/win32_display_window.h | 4 +- src/window/window.cpp | 4 +- 12 files changed, 107 insertions(+), 28 deletions(-) diff --git a/include/zwidget/core/widget.h b/include/zwidget/core/widget.h index 50f769b..881d407 100644 --- a/include/zwidget/core/widget.h +++ b/include/zwidget/core/widget.h @@ -19,7 +19,8 @@ enum class WidgetType { Child, Window, - Popup + Popup, + Utility }; enum class WidgetEvent @@ -192,6 +193,9 @@ class Widget : DisplayWindowHost virtual void OnSetFocus() { } virtual void OnLostFocus() { } virtual void OnEnableChanged() { } + void OnWindowNotified() override {}; + + void NotifyWindow(); // used to wake up a window from another thread virtual void Notify(Widget* source, const WidgetEvent type) { }; diff --git a/include/zwidget/window/window.h b/include/zwidget/window/window.h index 23645e8..aaaa007 100644 --- a/include/zwidget/window/window.h +++ b/include/zwidget/window/window.h @@ -145,13 +145,14 @@ class DisplayWindowHost virtual void OnWindowActivated() = 0; virtual void OnWindowDeactivated() = 0; virtual void OnWindowDpiScaleChanged() = 0; + virtual void OnWindowNotified() = 0; virtual bool OnFileDrop(std::string path) = 0; }; class DisplayWindow { public: - static std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable); + static std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility); static void ProcessEvents(); static void RunLoop(); @@ -209,6 +210,8 @@ class DisplayWindow virtual std::vector GetVulkanInstanceExtensions() = 0; virtual VkSurfaceKHR CreateVulkanSurface(VkInstance instance) = 0; + + virtual void NotifyWindow() = 0; }; class DisplayBackend @@ -227,7 +230,7 @@ class DisplayBackend virtual bool IsWin32() { return false; } virtual bool IsSDL2() { return false; } - virtual std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) = 0; + virtual std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) = 0; virtual void ProcessEvents() = 0; virtual void RunLoop() = 0; virtual void ExitLoop() = 0; diff --git a/src/core/widget.cpp b/src/core/widget.cpp index 9623f27..cdda4d8 100644 --- a/src/core/widget.cpp +++ b/src/core/widget.cpp @@ -11,7 +11,7 @@ Widget::Widget(Widget* parent, WidgetType type, RenderAPI renderAPI, bool window if (type != WidgetType::Child) { Widget* owner = parent ? parent->Window() : nullptr; - DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup, owner ? owner->DispWindow.get() : nullptr, renderAPI, windowResizable); + DispWindow = DisplayWindow::Create(this, type == WidgetType::Popup, owner ? owner->DispWindow.get() : nullptr, renderAPI, windowResizable, type == WidgetType::Utility); if (renderAPI == RenderAPI::Unspecified || renderAPI == RenderAPI::Bitmap) { DispCanvas = Canvas::create(); @@ -1051,3 +1051,10 @@ Colorf Widget::GetStyleColor(const std::string& propertyName) const WidgetStyle* style = WidgetTheme::GetTheme()->GetStyle(StyleClass); return style ? style->GetColor(StyleState, propertyName) : Colorf::transparent(); } + +void Widget::NotifyWindow() +{ + Widget* w = Window(); + if (w && w->DispWindow) + w->DispWindow->NotifyWindow(); +} diff --git a/src/window/sdl2/sdl2_display_backend.cpp b/src/window/sdl2/sdl2_display_backend.cpp index fa36023..4a7c187 100644 --- a/src/window/sdl2/sdl2_display_backend.cpp +++ b/src/window/sdl2/sdl2_display_backend.cpp @@ -61,9 +61,9 @@ SDL2DisplayBackend::SDL2DisplayBackend() } } -std::unique_ptr SDL2DisplayBackend::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) +std::unique_ptr SDL2DisplayBackend::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) { - return std::make_unique(windowHost, popupWindow, static_cast(owner), renderAPI, UIScale, resizable); + return std::make_unique(windowHost, popupWindow, static_cast(owner), renderAPI, UIScale, resizable, utility); } void SDL2DisplayBackend::ProcessEvents() diff --git a/src/window/sdl2/sdl2_display_backend.h b/src/window/sdl2/sdl2_display_backend.h index 2f97d78..41b00ca 100644 --- a/src/window/sdl2/sdl2_display_backend.h +++ b/src/window/sdl2/sdl2_display_backend.h @@ -7,7 +7,7 @@ class SDL2DisplayBackend : public DisplayBackend public: SDL2DisplayBackend(); - std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) override; + std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) override; void ProcessEvents() override; void RunLoop() override; void ExitLoop() override; diff --git a/src/window/sdl2/sdl2_display_window.cpp b/src/window/sdl2/sdl2_display_window.cpp index 14b1216..05bfabc 100644 --- a/src/window/sdl2/sdl2_display_window.cpp +++ b/src/window/sdl2/sdl2_display_window.cpp @@ -1,15 +1,19 @@ #include "sdl2_display_window.h" #include +#include #include #include +#include + +#define EVENT_NOTIFY_WINDOW SDL_USEREVENT + 100 Uint32 SDL2DisplayWindow::PaintEventNumber = 0xffffffff; bool SDL2DisplayWindow::ExitRunLoop; std::unordered_map SDL2DisplayWindow::WindowList; -SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale, bool resizable) : WindowHost(windowHost), UIScale(uiscale) +SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale, bool resizable, bool utility) : WindowHost(windowHost), UIScale(uiscale) { - unsigned int flags = resizable ? (SDL_WINDOW_HIDDEN | SDL_WINDOW_RESIZABLE) : SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/; + unsigned int flags = SDL_WINDOW_HIDDEN /*| SDL_WINDOW_ALLOW_HIGHDPI*/; if (renderAPI == RenderAPI::Vulkan) flags |= SDL_WINDOW_VULKAN; else if (renderAPI == RenderAPI::OpenGL) @@ -18,20 +22,34 @@ SDL2DisplayWindow::SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWi else if (renderAPI == RenderAPI::Metal) flags |= SDL_WINDOW_METAL; #endif + + if (resizable) + flags |= SDL_WINDOW_RESIZABLE; if (popupWindow) flags |= SDL_WINDOW_BORDERLESS; - - if (renderAPI == RenderAPI::Vulkan || renderAPI == RenderAPI::OpenGL || renderAPI == RenderAPI::Metal) + if (utility) { - Handle.window = SDL_CreateWindow("", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 320, 200, flags); - if (!Handle.window) - throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError()); + Owner = owner; + flags |= (SDL_WINDOW_UTILITY | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_SKIP_TASKBAR); } - else + + Handle.window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 320, 200, flags); + if (!Handle.window) + throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError()); + + switch (renderAPI) { - int result = SDL_CreateWindowAndRenderer(320, 200, flags, &Handle.window, &RendererHandle); - if (result != 0) - throw std::runtime_error(std::string("Unable to create SDL window:") + SDL_GetError()); + case RenderAPI::Vulkan: + case RenderAPI::OpenGL: + case RenderAPI::Metal: + break; + default: { + RendererHandle = SDL_CreateRenderer(Handle.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!RendererHandle) + RendererHandle = SDL_CreateRenderer(Handle.window, -1, SDL_RENDERER_SOFTWARE); + if (!RendererHandle) + throw std::runtime_error(std::string("Unable to create renderer: ") + SDL_GetError()); + } } WindowList[SDL_GetWindowID(Handle.window)] = this; @@ -78,6 +96,14 @@ VkSurfaceKHR SDL2DisplayWindow::CreateVulkanSurface(VkInstance instance) return surfaceHandle; } +void SDL2DisplayWindow::NotifyWindow() +{ + SDL_Event e; + SDL_zero(e); + e.type = EVENT_NOTIFY_WINDOW; + SDL_PushEvent(&e); +} + void SDL2DisplayWindow::SetWindowTitle(const std::string& text) { SDL_SetWindowTitle(Handle.window, text.c_str()); @@ -112,7 +138,21 @@ void SDL2DisplayWindow::SetClientFrame(const Rect& box) void SDL2DisplayWindow::Show() { + if (Owner) + { + SDL_SetWindowModalFor(Handle.window, Owner->Handle.window); + SDL_SetWindowAlwaysOnTop(Handle.window, SDL_TRUE); + } + + // this is a hack, but it seems to prevent unpainted windows on my pc SDL_ShowWindow(Handle.window); + SDL_RaiseWindow(Handle.window); + SDL_Delay(10); + WindowHost->OnWindowGeometryChanged(); + WindowHost->OnWindowPaint(); + SDL_Delay(10); + Update(); + ProcessEvents(); } void SDL2DisplayWindow::Restore() @@ -210,8 +250,14 @@ bool SDL2DisplayWindow::GetKeyState(InputKey key) const Uint8* state = SDL_GetKeyboardState(&numkeys); if (!state) return false; - SDL_Scancode index = InputKeyToScancode(key); - return (index < numkeys) ? state[index] != 0 : false; + auto test = [numkeys, state](InputKey key) { + SDL_Scancode index = InputKeyToScancode(key); + return (index < numkeys) ? state[index] != 0 : false; + }; + + if (key == InputKey::Ctrl) return test(key) || test(InputKey::LControl) || test(InputKey::RControl); + if (key == InputKey::Shift) return test(key) || test(InputKey::LShift) || test(InputKey::RShift); + return test(key); } Rect SDL2DisplayWindow::GetWindowFrame() const @@ -495,6 +541,9 @@ void SDL2DisplayWindow::OnWindowEvent(const SDL_WindowEvent& event) { switch (event.event) { + case EVENT_NOTIFY_WINDOW: + WindowHost->OnWindowNotified(); + break; case SDL_WINDOWEVENT_CLOSE: WindowHost->OnWindowClose(); break; diff --git a/src/window/sdl2/sdl2_display_window.h b/src/window/sdl2/sdl2_display_window.h index b79a005..49dc3c6 100644 --- a/src/window/sdl2/sdl2_display_window.h +++ b/src/window/sdl2/sdl2_display_window.h @@ -8,7 +8,7 @@ class SDL2DisplayWindow : public DisplayWindow { public: - SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale, bool resizable); + SDL2DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, SDL2DisplayWindow* owner, RenderAPI renderAPI, double uiscale, bool resizable, bool utility); ~SDL2DisplayWindow(); void SetWindowTitle(const std::string& text) override; @@ -55,6 +55,8 @@ class SDL2DisplayWindow : public DisplayWindow std::vector GetVulkanInstanceExtensions() override; VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + + virtual void NotifyWindow() override; static void DispatchEvent(const SDL_Event& event); static SDL2DisplayWindow* FindEventWindow(const SDL_Event& event); @@ -95,6 +97,7 @@ class SDL2DisplayWindow : public DisplayWindow static Uint32 ExecTimer(Uint32 interval, void* id); DisplayWindowHost* WindowHost = nullptr; + SDL2DisplayWindow* Owner = nullptr; SDL2NativeHandle Handle; SDL_Renderer* RendererHandle = nullptr; SDL_Texture* BackBufferTexture = nullptr; diff --git a/src/window/win32/win32_display_backend.cpp b/src/window/win32/win32_display_backend.cpp index c3e0f12..5b6fb5a 100644 --- a/src/window/win32/win32_display_backend.cpp +++ b/src/window/win32/win32_display_backend.cpp @@ -5,9 +5,9 @@ #include "win32_save_file_dialog.h" #include "win32_open_folder_dialog.h" -std::unique_ptr Win32DisplayBackend::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) +std::unique_ptr Win32DisplayBackend::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) { - return std::make_unique(windowHost, popupWindow, static_cast(owner), renderAPI, resizable); + return std::make_unique(windowHost, popupWindow, static_cast(owner), renderAPI, resizable, utility); } void Win32DisplayBackend::ProcessEvents() diff --git a/src/window/win32/win32_display_backend.h b/src/window/win32/win32_display_backend.h index 756e11e..15ecbca 100644 --- a/src/window/win32/win32_display_backend.h +++ b/src/window/win32/win32_display_backend.h @@ -5,7 +5,7 @@ class Win32DisplayBackend : public DisplayBackend { public: - std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) override; + std::unique_ptr Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) override; void ProcessEvents() override; void RunLoop() override; void ExitLoop() override; diff --git a/src/window/win32/win32_display_window.cpp b/src/window/win32/win32_display_window.cpp index 41cbedc..8b9d8fb 100644 --- a/src/window/win32/win32_display_window.cpp +++ b/src/window/win32/win32_display_window.cpp @@ -10,6 +10,8 @@ #pragma comment(lib, "dwmapi.lib") +#define MESSAGE_NOTIFY_WINDOW (WM_APP + 100) + #ifndef HID_USAGE_PAGE_GENERIC #define HID_USAGE_PAGE_GENERIC ((USHORT) 0x01) #endif @@ -78,7 +80,7 @@ static double DelayLoadGetDpiScale(HWND hwnd) } } -Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner, RenderAPI renderAPI, bool resizable) : WindowHost(windowHost), PopupWindow(popupWindow) +Win32DisplayWindow::Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) : WindowHost(windowHost), PopupWindow(popupWindow) { Windows.push_front(this); WindowsIterator = Windows.begin(); @@ -585,6 +587,10 @@ LRESULT Win32DisplayWindow::OnWindowMessage(UINT msg, WPARAM wparam, LPARAM lpar } return 0; } + else if (msg == MESSAGE_NOTIFY_WINDOW) + { + WindowHost->OnWindowNotified(); + } else if (msg == WM_ACTIVATE) { WindowHost->OnWindowActivated(); @@ -949,6 +955,11 @@ VkSurfaceKHR Win32DisplayWindow::CreateVulkanSurface(VkInstance instance) return surface; } +void Win32DisplayWindow::NotifyWindow() +{ + PostMessageA(WindowHandle.hwnd, MESSAGE_NOTIFY_WINDOW, 0, 0); +} + std::vector Win32DisplayWindow::GetVulkanInstanceExtensions() { return { "VK_KHR_surface", "VK_KHR_win32_surface" }; diff --git a/src/window/win32/win32_display_window.h b/src/window/win32/win32_display_window.h index 5c6fd1f..f6a9e1b 100644 --- a/src/window/win32/win32_display_window.h +++ b/src/window/win32/win32_display_window.h @@ -10,7 +10,7 @@ class Win32DisplayWindow : public DisplayWindow { public: - Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner, RenderAPI renderAPI, bool resizable); + Win32DisplayWindow(DisplayWindowHost* windowHost, bool popupWindow, Win32DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility); ~Win32DisplayWindow(); void SetWindowTitle(const std::string& text) override; @@ -62,6 +62,8 @@ class Win32DisplayWindow : public DisplayWindow std::vector GetVulkanInstanceExtensions() override; VkSurfaceKHR CreateVulkanSurface(VkInstance instance) override; + virtual void NotifyWindow() override; + static void ProcessEvents(); static void RunLoop(); static void ExitLoop(); diff --git a/src/window/window.cpp b/src/window/window.cpp index 021384b..40b767f 100644 --- a/src/window/window.cpp +++ b/src/window/window.cpp @@ -7,9 +7,9 @@ #include "core/widget.h" #include -std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable) +std::unique_ptr DisplayWindow::Create(DisplayWindowHost* windowHost, bool popupWindow, DisplayWindow* owner, RenderAPI renderAPI, bool resizable, bool utility) { - return DisplayBackend::Get()->Create(windowHost, popupWindow, owner, renderAPI, resizable); + return DisplayBackend::Get()->Create(windowHost, popupWindow, owner, renderAPI, resizable, utility); } void DisplayWindow::ProcessEvents()