aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2020-04-12 20:30:49 +0800
committercrupest <crupest@outlook.com>2020-04-12 20:30:49 +0800
commitdb663ebb463dc00416038d068e538ab410558503 (patch)
tree5c20cac738e2a7111ba61754479a774c2e9e0c0a
parent23ef59b6aa14874e3b68c8716c137eb65583cd63 (diff)
downloadcru-db663ebb463dc00416038d068e538ab410558503.tar.gz
cru-db663ebb463dc00416038d068e538ab410558503.tar.bz2
cru-db663ebb463dc00416038d068e538ab410558503.zip
...
-rw-r--r--include/cru/ui/ui_host.hpp43
-rw-r--r--include/cru/ui/window.hpp5
-rw-r--r--src/main.cpp3
-rw-r--r--src/ui/control.cpp4
-rw-r--r--src/ui/ui_host.cpp12
-rw-r--r--src/ui/window.cpp1
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{});
}