diff options
author | crupest <crupest@outlook.com> | 2020-04-12 20:30:49 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2020-04-12 20:30:49 +0800 |
commit | db663ebb463dc00416038d068e538ab410558503 (patch) | |
tree | 5c20cac738e2a7111ba61754479a774c2e9e0c0a | |
parent | 23ef59b6aa14874e3b68c8716c137eb65583cd63 (diff) | |
download | cru-db663ebb463dc00416038d068e538ab410558503.tar.gz cru-db663ebb463dc00416038d068e538ab410558503.tar.bz2 cru-db663ebb463dc00416038d068e538ab410558503.zip |
...
-rw-r--r-- | include/cru/ui/ui_host.hpp | 43 | ||||
-rw-r--r-- | include/cru/ui/window.hpp | 5 | ||||
-rw-r--r-- | src/main.cpp | 3 | ||||
-rw-r--r-- | src/ui/control.cpp | 4 | ||||
-rw-r--r-- | src/ui/ui_host.cpp | 12 | ||||
-rw-r--r-- | src/ui/window.cpp | 1 |
6 files changed, 57 insertions, 11 deletions
diff --git a/include/cru/ui/ui_host.hpp b/include/cru/ui/ui_host.hpp index 96026675..ca2b70a4 100644 --- a/include/cru/ui/ui_host.hpp +++ b/include/cru/ui/ui_host.hpp @@ -8,6 +8,29 @@ namespace cru::ui { struct AfterLayoutEventArgs {}; +// The host of all controls and render objects. +// +// 3 situations on destroy: +// 1. Native window destroyed, IsRetainAfterDestroy: false: +// OnNativeDestroy(set native_window_destroyed_ to true, call ~Window due to +// deleting_ is false and IsRetainAfterDestroy is false) -> ~Window -> +// ~UiHost(not destroy native window repeatedly due to native_window_destroyed_ +// is true) +// 2. Native window destroyed, IsRetainAfterDestroy: true: +// OnNativeDestroy(set native_window_destroyed_ to true, not call ~Window +// because deleting_ is false and IsRetainAfterDestroy is true) +// then, ~Window -> ~UiHost(not destroy native window repeatedly due to +// native_window_destroyed_ is true) +// 3. Native window not destroyed, ~Window is called: +// ~Window -> ~UiHost(set deleting_ to true, destroy native window +// due to native_window_destroyed is false) -> OnNativeDestroy(not call ~Window +// due to deleting_ is true and IsRetainAfterDestroy is whatever) +// In conclusion: +// 1. Set native_window_destroyed_ to true at the beginning of OnNativeDestroy. +// 2. Set deleting_ to true at the beginning of ~UiHost. +// 3. Destroy native window when native_window_destroy_ is false in ~Window. +// 4. Delete Window when deleting_ is false and IsRetainAfterDestroy is false in +// OnNativeDestroy. class UiHost : public Object, public SelfResolvable<UiHost> { public: // This will create root window render object and attach it to window. @@ -71,6 +94,15 @@ class UiHost : public Object, public SelfResolvable<UiHost> { void UpdateCursor(); + std::shared_ptr<platform::native::INativeWindowResolver> + GetNativeWindowResolver() { + return native_window_resolver_; + } + + bool IsRetainAfterDestroy() { return retain_after_destroy_; } + + void SetRetainAfterDestroy(bool destroy) { retain_after_destroy_ = destroy; } + private: //*************** region: native messages *************** void OnNativeDestroy(platform::native::INativeWindow* window, std::nullptr_t); @@ -113,6 +145,17 @@ class UiHost : public Object, public SelfResolvable<UiHost> { std::shared_ptr<platform::native::INativeWindowResolver> native_window_resolver_; + // See remarks of UiHost. + bool retain_after_destroy_ = false; + // See remarks of UiHost. + bool deleting_ = false; + + // We need this because calling Resolve on resolver in handler of destroy + // event is bad and will always get the dying window. But we need to label the + // window as destroyed so the destructor will not destroy native window + // repeatedly. See remarks of UiHost. + bool native_window_destroyed_ = false; + std::vector<EventRevokerGuard> event_revoker_guards_; Window* window_control_; diff --git a/include/cru/ui/window.hpp b/include/cru/ui/window.hpp index f15e605b..2f5df4da 100644 --- a/include/cru/ui/window.hpp +++ b/include/cru/ui/window.hpp @@ -28,9 +28,6 @@ class Window final : public ContentControl { render::RenderObject* GetRenderObject() const override; - bool IsRetainAfterDestroy() { return retain_after_destroy_; } - void SetRetainAfterDestroy(bool destroy) { retain_after_destroy_ = destroy; } - protected: void OnChildChanged(Control* old_child, Control* new_child) override; @@ -39,7 +36,5 @@ class Window final : public ContentControl { // UiHost is responsible to take care of lifetime of this. render::WindowRenderObject* render_object_; - - bool retain_after_destroy_ = false; }; } // namespace cru::ui diff --git a/src/main.cpp b/src/main.cpp index fb2222d4..0172838e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include "cru/ui/controls/flex_layout.hpp" #include "cru/ui/controls/stack_layout.hpp" #include "cru/ui/controls/text_block.hpp" +#include "cru/ui/ui_host.hpp" #include "cru/ui/window.hpp" #include "cru/win/native/ui_application.hpp" @@ -51,7 +52,7 @@ int main() { text_block4->SetText("Hello World!!!"); flex_layout->AddChild(text_block4, 2); - window->ResolveNativeWindow()->SetVisible(true); + window->GetUiHost()->GetNativeWindowResolver()->Resolve()->SetVisible(true); return application->Run(); } diff --git a/src/ui/control.cpp b/src/ui/control.cpp index 7691dac2..5417f4ce 100644 --- a/src/ui/control.cpp +++ b/src/ui/control.cpp @@ -33,12 +33,12 @@ void Control::_SetParent(Control* parent) { } void Control::_SetDescendantUiHost(UiHost* host) { + if (host == nullptr && ui_host_ == nullptr) return; + // You can only attach or detach window. Expects((host != nullptr && ui_host_ == nullptr) || (host == nullptr && ui_host_ != nullptr)); - if (host == nullptr && ui_host_ == nullptr) return; - if (host == nullptr) { const auto old = ui_host_; TraverseDescendants([old](Control* control) { diff --git a/src/ui/ui_host.cpp b/src/ui/ui_host.cpp index c82709dd..8b85ad30 100644 --- a/src/ui/ui_host.cpp +++ b/src/ui/ui_host.cpp @@ -101,7 +101,7 @@ UiHost::UiHost(Window* window) IUiApplication::GetInstance()->CreateWindow(nullptr); const auto native_window = native_window_resolver_->Resolve(); - window->_SetDescendantUiHost(this); + window->ui_host_ = this; root_render_object_ = std::make_unique<render::WindowRenderObject>(this); root_render_object_->SetAttachedControl(window); @@ -130,8 +130,15 @@ UiHost::UiHost(Window* window) } UiHost::~UiHost() { + deleting_ = true; window_control_->TraverseDescendants( [this](Control* control) { control->OnDetachFromHost(this); }); + if (!native_window_destroyed_) { + const auto native_window = native_window_resolver_->Resolve(); + if (native_window) { + native_window->Close(); + } + } } void UiHost::InvalidatePaint() { @@ -216,7 +223,8 @@ Control* UiHost::GetMouseCaptureControl() { return mouse_captured_control_; } void UiHost::OnNativeDestroy(INativeWindow* window, std::nullptr_t) { CRU_UNUSED(window) - delete this; // TODO: Develop this. + native_window_destroyed_ = true; + if (!deleting_ && !retain_after_destroy_) delete window_control_; } void UiHost::OnNativePaint(INativeWindow* window, std::nullptr_t) { diff --git a/src/ui/window.cpp b/src/ui/window.cpp index 4f414385..7c0683af 100644 --- a/src/ui/window.cpp +++ b/src/ui/window.cpp @@ -4,7 +4,6 @@ #include "cru/ui/ui_host.hpp" namespace cru::ui { - Window* Window::CreateOverlapped() { return new Window(tag_overlapped_constructor{}); } |