diff options
-rw-r--r-- | include/cru/platform/native/ui_application.hpp | 5 | ||||
-rw-r--r-- | include/cru/platform/native/window.hpp | 24 | ||||
-rw-r--r-- | include/cru/ui/window.hpp | 34 | ||||
-rw-r--r-- | include/cru/win/native/ui_application.hpp | 2 | ||||
-rw-r--r-- | include/cru/win/native/window.hpp | 42 | ||||
-rw-r--r-- | src/ui/window.cpp | 90 | ||||
-rw-r--r-- | src/win/native/ui_application.cpp | 8 | ||||
-rw-r--r-- | src/win/native/window.cpp | 130 |
8 files changed, 193 insertions, 142 deletions
diff --git a/include/cru/platform/native/ui_application.hpp b/include/cru/platform/native/ui_application.hpp index b69b1f52..edbcc578 100644 --- a/include/cru/platform/native/ui_application.hpp +++ b/include/cru/platform/native/ui_application.hpp @@ -3,6 +3,7 @@ #include <chrono> #include <functional> +#include <memory> #include <vector> namespace cru::platform::graph { @@ -11,6 +12,7 @@ struct IGraphFactory; namespace cru::platform::native { struct INativeWindow; +struct INativeWindowResolver; struct ICursorManager; // The entry point of a ui application. @@ -39,7 +41,8 @@ struct IUiApplication : public virtual INativeResource { virtual void CancelTimer(unsigned long id) = 0; virtual std::vector<INativeWindow*> GetAllWindow() = 0; - virtual INativeWindow* CreateWindow(INativeWindow* parent) = 0; + virtual std::shared_ptr<INativeWindowResolver> CreateWindow( + INativeWindow* parent) = 0; virtual cru::platform::graph::IGraphFactory* GetGraphFactory() = 0; diff --git a/include/cru/platform/native/window.hpp b/include/cru/platform/native/window.hpp index bfaf170b..84193a13 100644 --- a/include/cru/platform/native/window.hpp +++ b/include/cru/platform/native/window.hpp @@ -12,22 +12,17 @@ struct IPainter; } namespace cru::platform::native { +struct INativeWindowResolver; + // Represents a native window, which exposes some low-level events and // operations. // -// Although you can always retain an instance of this class, the real window -// associated with it might be have already been destroyed by explicitly calling -// Close or closed by the user, which leads to an invalid instance. You can -// check the validity by IsValid. When you call perform native operations on the -// invalid instance, there is no effect. +// Usually you save an INativeWindowResolver after creating a window. Because +// window may be destroyed when user do certain actions like click the close +// button. Then the INativeWindow instance is destroyed and +// INativeWindowResolver::Resolve return nullptr to indicate the fact. struct INativeWindow : virtual INativeResource { - // Return if the window is still valid, that is, hasn't been closed or - // destroyed. - virtual bool IsValid() = 0; - - // Set if the instance is deleted automatically when the window is destroyed - // by other ways. Default is true. - virtual void SetDeleteThisOnDestroy(bool value) = 0; + virtual std::shared_ptr<INativeWindowResolver> GetResolver() = 0; virtual void Close() = 0; @@ -71,4 +66,9 @@ struct INativeWindow : virtual INativeResource { virtual IEvent<int>* KeyDownEvent() = 0; virtual IEvent<int>* KeyUpEvent() = 0; }; + +// See INativeWindow for more info. +struct INativeWindowResolver : virtual INativeResource { + virtual INativeWindow* Resolve() = 0; +}; } // namespace cru::platform::native diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp index 35d6772e..105063d9 100644 --- a/include/cru/ui/window.hpp +++ b/include/cru/ui/window.hpp @@ -9,7 +9,8 @@ namespace cru::platform::native { struct INativeWindow; -} +struct INativeWindowResolver; +} // namespace cru::platform::native namespace cru::ui { namespace render { @@ -38,13 +39,11 @@ class Window final : public ContentControl, public SelfResolvable<Window> { ~Window() override; public: - std::string_view GetControlType() const override final; + std::string_view GetControlType() const final; render::RenderObject* GetRenderObject() const override; - platform::native::INativeWindow* GetNativeWindow() const { - return native_window_; - } + platform::native::INativeWindow* GetNativeWindow(); // Get current control that mouse hovers on. This ignores the mouse-capture // control. Even when mouse is captured by another control, this function @@ -85,22 +84,29 @@ class Window final : public ContentControl, public SelfResolvable<Window> { //*************** region: native messages *************** - void OnNativeDestroy(std::nullptr_t); - void OnNativePaint(std::nullptr_t); - void OnNativeResize(const Size& size); + void OnNativeDestroy(platform::native::INativeWindow* window, std::nullptr_t); + void OnNativePaint(platform::native::INativeWindow* window, std::nullptr_t); + void OnNativeResize(platform::native::INativeWindow* window, + const Size& size); - void OnNativeFocus(cru::platform::native::FocusChangeType focus); + void OnNativeFocus(platform::native::INativeWindow* window, + cru::platform::native::FocusChangeType focus); void OnNativeMouseEnterLeave( + platform::native::INativeWindow* window, cru::platform::native::MouseEnterLeaveType enter); - void OnNativeMouseMove(const Point& point); + void OnNativeMouseMove(platform::native::INativeWindow* window, + const Point& point); void OnNativeMouseDown( + platform::native::INativeWindow* window, const platform::native::NativeMouseButtonEventArgs& args); void OnNativeMouseUp( + platform::native::INativeWindow* window, const platform::native::NativeMouseButtonEventArgs& args); - void OnNativeKeyDown(int virtual_code); - void OnNativeKeyUp(int virtual_code); + void OnNativeKeyDown(platform::native::INativeWindow* window, + int virtual_code); + void OnNativeKeyUp(platform::native::INativeWindow* window, int virtual_code); //*************** region: event dispatcher helper *************** @@ -112,7 +118,9 @@ class Window final : public ContentControl, public SelfResolvable<Window> { void UpdateCursor(); private: - platform::native::INativeWindow* native_window_; + std::shared_ptr<platform::native::INativeWindowResolver> + native_window_resolver_; + std::vector<EventRevokerGuard> event_revoker_guards_; std::unique_ptr<render::WindowRenderObject> render_object_; diff --git a/include/cru/win/native/ui_application.hpp b/include/cru/win/native/ui_application.hpp index 80e358e4..73f67abe 100644 --- a/include/cru/win/native/ui_application.hpp +++ b/include/cru/win/native/ui_application.hpp @@ -45,7 +45,7 @@ class WinUiApplication : public WinNativeResource, void CancelTimer(unsigned long id) override; std::vector<INativeWindow*> GetAllWindow() override; - INativeWindow* CreateWindow(INativeWindow* parent) override; + std::shared_ptr<INativeWindowResolver> CreateWindow(INativeWindow* parent) override; cru::platform::graph::IGraphFactory* GetGraphFactory() override; diff --git a/include/cru/win/native/window.hpp b/include/cru/win/native/window.hpp index 9752682f..3c883338 100644 --- a/include/cru/win/native/window.hpp +++ b/include/cru/win/native/window.hpp @@ -12,12 +12,12 @@ class WinCursor; class WindowClass; class WindowManager; class WindowRenderTarget; +class WinNativeWindowResolver; class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { public: - WinNativeWindow(WinUiApplication* application, - WindowClass* window_class, DWORD window_style, - WinNativeWindow* parent); + WinNativeWindow(WinUiApplication* application, WindowClass* window_class, + DWORD window_style, WinNativeWindow* parent); CRU_DELETE_COPY(WinNativeWindow) CRU_DELETE_MOVE(WinNativeWindow) @@ -25,8 +25,9 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { ~WinNativeWindow() override; public: - bool IsValid() override; - void SetDeleteThisOnDestroy(bool value) override; + std::shared_ptr<INativeWindowResolver> GetResolver() override { + return std::static_pointer_cast<INativeWindowResolver>(resolver_); + } void Close() override; @@ -118,7 +119,14 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { private: WinUiApplication* application_; - bool delete_this_on_destroy_ = true; + // when delete is called first, it set this to true to indicate + // destroy message handler not to double delete this instance; + // when destroy handler is called first (by user action or method + // Close), it set this to true to indicate delete not call Close + // again. + bool sync_flag_ = false; + + std::shared_ptr<WinNativeWindowResolver> resolver_; HWND hwnd_; WinNativeWindow* parent_window_; @@ -143,4 +151,26 @@ class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { Event<WindowNativeMessageEventArgs&> native_message_event_; }; + +class WinNativeWindowResolver : public WinNativeResource, + public virtual INativeWindowResolver { + friend WinNativeWindow::~WinNativeWindow(); + + public: + WinNativeWindowResolver(WinNativeWindow* window) : window_(window) {} + + CRU_DELETE_COPY(WinNativeWindowResolver) + CRU_DELETE_MOVE(WinNativeWindowResolver) + + ~WinNativeWindowResolver() override = default; + + public: + INativeWindow* Resolve() override { return window_; } + + private: + void Reset(); + + private: + WinNativeWindow* window_; +}; } // namespace cru::platform::native::win diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 6ff44b4b..35463778 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -11,6 +11,8 @@ namespace cru::ui { using cru::platform::native::FocusChangeType; +using cru::platform::native::INativeWindow; +using cru::platform::native::INativeWindowResolver; using cru::platform::native::IUiApplication; using cru::platform::native::MouseEnterLeaveType; @@ -88,11 +90,12 @@ Window* Window::CreateOverlapped() { namespace { template <typename T> -void BindNativeEvent(Window* window, IEvent<T>* event, - void (Window::*handler)(typename IEvent<T>::EventArgs), - std::vector<EventRevokerGuard>& guard_pool) { - guard_pool.push_back(EventRevokerGuard( - event->AddHandler(std::bind(handler, window, std::placeholders::_1)))); +inline void BindNativeEvent( + Window* window, INativeWindow* native_window, IEvent<T>* event, + void (Window::*handler)(INativeWindow*, typename IEvent<T>::EventArgs), + std::vector<EventRevokerGuard>& guard_pool) { + guard_pool.push_back(EventRevokerGuard(event->AddHandler( + std::bind(handler, window, native_window, std::placeholders::_1)))); } } // namespace @@ -101,30 +104,34 @@ Window::Window(tag_overlapped_constructor) focus_control_(this), mouse_captured_control_(nullptr) { window_ = this; - native_window_ = IUiApplication::GetInstance()->CreateWindow(nullptr); + native_window_resolver_ = + IUiApplication::GetInstance()->CreateWindow(nullptr); + + const auto native_window = native_window_resolver_->Resolve(); + render_object_.reset(new render::WindowRenderObject(this)); render_object_->SetAttachedControl(this); - BindNativeEvent(this, native_window_->DestroyEvent(), + BindNativeEvent(this, native_window, native_window->DestroyEvent(), &Window::OnNativeDestroy, event_revoker_guards_); - BindNativeEvent(this, native_window_->PaintEvent(), &Window::OnNativePaint, - event_revoker_guards_); - BindNativeEvent(this, native_window_->ResizeEvent(), &Window::OnNativeResize, - event_revoker_guards_); - BindNativeEvent(this, native_window_->FocusEvent(), &Window::OnNativeFocus, - event_revoker_guards_); - BindNativeEvent(this, native_window_->MouseEnterLeaveEvent(), + BindNativeEvent(this, native_window, native_window->PaintEvent(), + &Window::OnNativePaint, event_revoker_guards_); + BindNativeEvent(this, native_window, native_window->ResizeEvent(), + &Window::OnNativeResize, event_revoker_guards_); + BindNativeEvent(this, native_window, native_window->FocusEvent(), + &Window::OnNativeFocus, event_revoker_guards_); + BindNativeEvent(this, native_window, native_window->MouseEnterLeaveEvent(), &Window::OnNativeMouseEnterLeave, event_revoker_guards_); - BindNativeEvent(this, native_window_->MouseMoveEvent(), + BindNativeEvent(this, native_window, native_window->MouseMoveEvent(), &Window::OnNativeMouseMove, event_revoker_guards_); - BindNativeEvent(this, native_window_->MouseDownEvent(), + BindNativeEvent(this, native_window, native_window->MouseDownEvent(), &Window::OnNativeMouseDown, event_revoker_guards_); - BindNativeEvent(this, native_window_->MouseUpEvent(), + BindNativeEvent(this, native_window, native_window->MouseUpEvent(), &Window::OnNativeMouseUp, event_revoker_guards_); - BindNativeEvent(this, native_window_->KeyDownEvent(), + BindNativeEvent(this, native_window, native_window->KeyDownEvent(), &Window::OnNativeKeyDown, event_revoker_guards_); - BindNativeEvent(this, native_window_->KeyUpEvent(), &Window::OnNativeKeyUp, - event_revoker_guards_); + BindNativeEvent(this, native_window, native_window->KeyUpEvent(), + &Window::OnNativeKeyUp, event_revoker_guards_); } Window::~Window() { @@ -138,6 +145,10 @@ render::RenderObject* Window::GetRenderObject() const { return render_object_.get(); } +platform::native::INativeWindow* Window::GetNativeWindow() { + return native_window_resolver_->Resolve(); +} + bool Window::RequestFocusFor(Control* control) { assert(control != nullptr); // The control to request focus can't be null. // You can set it as the window. @@ -194,21 +205,27 @@ Control* Window::HitTest(const Point& point) { return render_object_->HitTest(point)->GetAttachedControl(); } -void Window::OnNativeDestroy(std::nullptr_t) { delete this; } +void Window::OnNativeDestroy(INativeWindow* window, std::nullptr_t) { + CRU_UNUSED(window) + delete this; +} -void Window::OnNativePaint(std::nullptr_t) { - auto painter = native_window_->BeginPaint(); +void Window::OnNativePaint(INativeWindow* window, std::nullptr_t) { + auto painter = window->BeginPaint(); render_object_->Draw(painter.get()); painter->EndDraw(); } -void Window::OnNativeResize(const Size& size) { +void Window::OnNativeResize(INativeWindow* window, const Size& size) { + CRU_UNUSED(window) CRU_UNUSED(size) render_object_->GetRenderHost()->InvalidateLayout(); } -void Window::OnNativeFocus(FocusChangeType focus) { +void Window::OnNativeFocus(INativeWindow* window, FocusChangeType focus) { + CRU_UNUSED(window) + focus == FocusChangeType::Gain ? DispatchEvent(event_names::GainFocus, focus_control_, &Control::GainFocusEvent, nullptr, true) @@ -216,7 +233,10 @@ void Window::OnNativeFocus(FocusChangeType focus) { &Control::LoseFocusEvent, nullptr, true); } -void Window::OnNativeMouseEnterLeave(MouseEnterLeaveType type) { +void Window::OnNativeMouseEnterLeave(INativeWindow* window, + MouseEnterLeaveType type) { + CRU_UNUSED(window) + if (type == MouseEnterLeaveType::Leave) { DispatchEvent(event_names::MouseLeave, mouse_hover_control_, &Control::MouseLeaveEvent, nullptr); @@ -224,7 +244,9 @@ void Window::OnNativeMouseEnterLeave(MouseEnterLeaveType type) { } } -void Window::OnNativeMouseMove(const Point& point) { +void Window::OnNativeMouseMove(INativeWindow* window, const Point& point) { + CRU_UNUSED(window) + // Find the first control that hit test succeed. const auto new_mouse_hover_control = HitTest(point); const auto old_mouse_hover_control = mouse_hover_control_; @@ -256,7 +278,10 @@ void Window::OnNativeMouseMove(const Point& point) { } void Window::OnNativeMouseDown( + INativeWindow* window, const platform::native::NativeMouseButtonEventArgs& args) { + CRU_UNUSED(window) + Control* control = mouse_captured_control_ ? mouse_captured_control_ : HitTest(args.point); DispatchEvent(event_names::MouseDown, control, &Control::MouseDownEvent, @@ -264,19 +289,26 @@ void Window::OnNativeMouseDown( } void Window::OnNativeMouseUp( + INativeWindow* window, const platform::native::NativeMouseButtonEventArgs& args) { + CRU_UNUSED(window) + Control* control = mouse_captured_control_ ? mouse_captured_control_ : HitTest(args.point); DispatchEvent(event_names::MouseUp, control, &Control::MouseUpEvent, nullptr, args.point, args.button); } -void Window::OnNativeKeyDown(int virtual_code) { +void Window::OnNativeKeyDown(INativeWindow* window, int virtual_code) { + CRU_UNUSED(window) + DispatchEvent(event_names::KeyDown, focus_control_, &Control::KeyDownEvent, nullptr, virtual_code); } -void Window::OnNativeKeyUp(int virtual_code) { +void Window::OnNativeKeyUp(INativeWindow* window, int virtual_code) { + CRU_UNUSED(window) + DispatchEvent(event_names::KeyUp, focus_control_, &Control::KeyUpEvent, nullptr, virtual_code); } diff --git a/src/win/native/ui_application.cpp b/src/win/native/ui_application.cpp index 75fce6ce..9ab61551 100644 --- a/src/win/native/ui_application.cpp +++ b/src/win/native/ui_application.cpp @@ -103,13 +103,15 @@ std::vector<INativeWindow*> WinUiApplication::GetAllWindow() { return result; } -INativeWindow* WinUiApplication::CreateWindow(INativeWindow* parent) { +std::shared_ptr<INativeWindowResolver> WinUiApplication::CreateWindow( + INativeWindow* parent) { WinNativeWindow* p = nullptr; if (parent != nullptr) { p = CheckPlatform<WinNativeWindow>(parent, GetPlatformId()); } - return new WinNativeWindow(this, window_manager_->GetGeneralWindowClass(), - WS_OVERLAPPEDWINDOW, p); + return (new WinNativeWindow(this, window_manager_->GetGeneralWindowClass(), + WS_OVERLAPPEDWINDOW, p)) + ->GetResolver(); } cru::platform::graph::IGraphFactory* WinUiApplication::GetGraphFactory() { diff --git a/src/win/native/window.cpp b/src/win/native/window.cpp index a8016676..2e99a5cb 100644 --- a/src/win/native/window.cpp +++ b/src/win/native/window.cpp @@ -23,10 +23,12 @@ inline Point PiToDip(const POINT& pi_point) { WinNativeWindow::WinNativeWindow(WinUiApplication* application, WindowClass* window_class, DWORD window_style, WinNativeWindow* parent) - : application_(application), parent_window_(parent) { + : application_(application), + resolver_(std::make_shared<WinNativeWindowResolver>(this)), + parent_window_(parent) { assert(application); // application can't be null. - if (parent != nullptr && !parent->IsValid()) { + if (parent != nullptr) { throw new std::runtime_error("Can't use a invalid window as parent."); } @@ -51,63 +53,45 @@ WinNativeWindow::WinNativeWindow(WinUiApplication* application, } WinNativeWindow::~WinNativeWindow() { - if (IsValid()) { - SetDeleteThisOnDestroy(false); // avoid double delete. + if (!sync_flag_) { + sync_flag_ = true; Close(); } + resolver_->Reset(); } -bool WinNativeWindow::IsValid() { return hwnd_ != nullptr; } +void WinNativeWindow::Close() { ::DestroyWindow(hwnd_); } -void WinNativeWindow::SetDeleteThisOnDestroy(bool value) { - delete_this_on_destroy_ = value; -} - -void WinNativeWindow::Close() { - if (IsValid()) DestroyWindow(hwnd_); -} - -bool WinNativeWindow::IsVisible() { - if (IsValid()) return ::IsWindowVisible(hwnd_); - return false; -} +bool WinNativeWindow::IsVisible() { return ::IsWindowVisible(hwnd_); } void WinNativeWindow::SetVisible(bool is_visible) { - if (!IsValid()) return; is_visible ? ShowWindow(hwnd_, SW_SHOWNORMAL) : ShowWindow(hwnd_, SW_HIDE); } Size WinNativeWindow::GetClientSize() { - if (!IsValid()) return Size{}; - const auto pixel_rect = GetClientRectPixel(); return Size(PixelToDipX(pixel_rect.right), PixelToDipY(pixel_rect.bottom)); } void WinNativeWindow::SetClientSize(const Size& size) { - if (IsValid()) { - const auto window_style = - static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_STYLE)); - const auto window_ex_style = - static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_EXSTYLE)); - - RECT rect; - rect.left = 0; - rect.top = 0; - rect.right = DipToPixelX(size.width); - rect.bottom = DipToPixelY(size.height); - if (!AdjustWindowRectEx(&rect, window_style, FALSE, window_ex_style)) - throw Win32Error(::GetLastError(), - "Failed to invoke AdjustWindowRectEx."); - - if (!SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left, - rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE)) - throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); - } + const auto window_style = + static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_STYLE)); + const auto window_ex_style = + static_cast<DWORD>(GetWindowLongPtr(hwnd_, GWL_EXSTYLE)); + + RECT rect; + rect.left = 0; + rect.top = 0; + rect.right = DipToPixelX(size.width); + rect.bottom = DipToPixelY(size.height); + if (!AdjustWindowRectEx(&rect, window_style, FALSE, window_ex_style)) + throw Win32Error(::GetLastError(), "Failed to invoke AdjustWindowRectEx."); + + if (!SetWindowPos(hwnd_, nullptr, 0, 0, rect.right - rect.left, + rect.bottom - rect.top, SWP_NOZORDER | SWP_NOMOVE)) + throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); } Rect WinNativeWindow::GetWindowRect() { - if (!IsValid()) return Rect{}; - RECT rect; if (!::GetWindowRect(hwnd_, &rect)) throw Win32Error(::GetLastError(), "Failed to invoke GetWindowRect."); @@ -117,50 +101,37 @@ Rect WinNativeWindow::GetWindowRect() { } void WinNativeWindow::SetWindowRect(const Rect& rect) { - if (IsValid()) { - if (!SetWindowPos(hwnd_, nullptr, DipToPixelX(rect.left), - DipToPixelY(rect.top), DipToPixelX(rect.GetRight()), - DipToPixelY(rect.GetBottom()), SWP_NOZORDER)) - throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); - } + if (!SetWindowPos(hwnd_, nullptr, DipToPixelX(rect.left), + DipToPixelY(rect.top), DipToPixelX(rect.GetRight()), + DipToPixelY(rect.GetBottom()), SWP_NOZORDER)) + throw Win32Error(::GetLastError(), "Failed to invoke SetWindowPos."); } Point WinNativeWindow::GetMousePosition() { - if (IsValid()) { - POINT p; - if (!::GetCursorPos(&p)) - throw Win32Error(::GetLastError(), "Failed to get cursor position."); - if (!::ScreenToClient(hwnd_, &p)) - throw Win32Error(::GetLastError(), "Failed to call ScreenToClient."); - return PiToDip(p); - } - return Point{}; + POINT p; + if (!::GetCursorPos(&p)) + throw Win32Error(::GetLastError(), "Failed to get cursor position."); + if (!::ScreenToClient(hwnd_, &p)) + throw Win32Error(::GetLastError(), "Failed to call ScreenToClient."); + return PiToDip(p); } bool WinNativeWindow::CaptureMouse() { - if (IsValid()) { - ::SetCapture(hwnd_); - return true; - } - return false; + ::SetCapture(hwnd_); + return true; } bool WinNativeWindow::ReleaseMouse() { - if (IsValid()) { - const auto result = ::ReleaseCapture(); - return result != 0; - } - return false; + const auto result = ::ReleaseCapture(); + return result != 0; } void WinNativeWindow::RequestRepaint() { - if (IsValid()) { - log::Debug("A repaint is requested."); - if (!::InvalidateRect(hwnd_, nullptr, FALSE)) - throw Win32Error(::GetLastError(), "Failed to invalidate window."); - if (!::UpdateWindow(hwnd_)) - throw Win32Error(::GetLastError(), "Failed to update window."); - } + log::Debug("A repaint is requested."); + if (!::InvalidateRect(hwnd_, nullptr, FALSE)) + throw Win32Error(::GetLastError(), "Failed to invalidate window."); + if (!::UpdateWindow(hwnd_)) + throw Win32Error(::GetLastError(), "Failed to update window."); } std::unique_ptr<graph::IPainter> WinNativeWindow::BeginPaint() { @@ -172,8 +143,6 @@ void WinNativeWindow::SetCursor(std::shared_ptr<ICursor> cursor) { throw std::runtime_error("Can't use a nullptr as cursor."); } - if (!IsValid()) return; - cursor_ = CheckPlatform<WinCursor>(cursor, GetPlatformId()); if (!::SetClassLongPtrW(hwnd_, GCLP_HCURSOR, @@ -358,8 +327,10 @@ void WinNativeWindow::OnDestroyInternal() { application_->GetWindowManager()->UnregisterWindow(hwnd_); hwnd_ = nullptr; destroy_event_.Raise(nullptr); - if (delete_this_on_destroy_) - application_->InvokeLater([this] { delete this; }); + if (!sync_flag_) { + sync_flag_ = true; + delete this; + } } void WinNativeWindow::OnPaintInternal() { @@ -438,4 +409,9 @@ void WinNativeWindow::OnCharInternal(wchar_t c) { CRU_UNUSED(c) } void WinNativeWindow::OnActivatedInternal() {} void WinNativeWindow::OnDeactivatedInternal() {} + +void WinNativeWindowResolver::Reset() { + assert(window_); // already reset, can't reset again + window_ = nullptr; +} } // namespace cru::platform::native::win |