From ea87825d58ab5b58dd360c3f080518c07a865db0 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 19 Apr 2019 23:20:09 +0800 Subject: ... --- include/cru/common/event.hpp | 5 +- include/cru/platform/native/ui_applicaition.hpp | 2 + include/cru/win/graph/d2d_painter.hpp | 48 ++++++++++++ include/cru/win/graph/win_painter.hpp | 48 ------------ include/cru/win/native/win_application.hpp | 6 +- src/ui/ui_manager.cpp | 8 +- src/win/graph/CMakeLists.txt | 2 +- src/win/graph/d2d_painter.cpp | 93 +++++++++++++++++++++++ src/win/graph/graph_manager.cpp | 6 +- src/win/graph/win_font.cpp | 2 +- src/win/graph/win_painter.cpp | 99 ------------------------- src/win/native/win_application.cpp | 33 ++++++--- src/win/native/win_native_window.cpp | 1 + src/win/native/window_manager.cpp | 5 ++ src/win/native/window_manager.hpp | 2 +- src/win/native/window_painter.cpp | 13 +++- src/win/native/window_painter.hpp | 6 +- 17 files changed, 207 insertions(+), 172 deletions(-) create mode 100644 include/cru/win/graph/d2d_painter.hpp delete mode 100644 include/cru/win/graph/win_painter.hpp create mode 100644 src/win/graph/d2d_painter.cpp delete mode 100644 src/win/graph/win_painter.cpp diff --git a/include/cru/common/event.hpp b/include/cru/common/event.hpp index 987bcdd6..741dcd99 100644 --- a/include/cru/common/event.hpp +++ b/include/cru/common/event.hpp @@ -102,8 +102,9 @@ class Event : public details::EventBase { template void Raise(Args&&... args) { - for (const auto& handler : handlers_) - (handler.second)(std::forward(args)...); + std::list handlers; + for (const auto& [key, handler] : handlers_) handlers.push_back(handler); + for (const auto& handler : handlers) handler(std::forward(args)...); } protected: diff --git a/include/cru/platform/native/ui_applicaition.hpp b/include/cru/platform/native/ui_applicaition.hpp index 8d42d813..17ff703d 100644 --- a/include/cru/platform/native/ui_applicaition.hpp +++ b/include/cru/platform/native/ui_applicaition.hpp @@ -18,6 +18,8 @@ struct UiApplication : public virtual Interface { virtual int Run() = 0; virtual void Quit(int quite_code) = 0; + virtual void AddOnQuitHandler(const std::function& handler) = 0; + virtual void InvokeLater(const std::function& action) = 0; virtual unsigned long SetTimeout(std::chrono::milliseconds milliseconds, const std::function& action) = 0; diff --git a/include/cru/win/graph/d2d_painter.hpp b/include/cru/win/graph/d2d_painter.hpp new file mode 100644 index 00000000..d33dced4 --- /dev/null +++ b/include/cru/win/graph/d2d_painter.hpp @@ -0,0 +1,48 @@ +#pragma once +#include "../win_pre_config.hpp" + +#include "cru/platform/graph/painter.hpp" + +namespace cru::win::graph { +class GraphManager; + +class D2DPainter : public Object, public virtual platform::graph::Painter { + public: + explicit D2DPainter(ID2D1RenderTarget* render_target); + D2DPainter(const D2DPainter& other) = delete; + D2DPainter(D2DPainter&& other) = delete; + D2DPainter& operator=(const D2DPainter& other) = delete; + D2DPainter& operator=(D2DPainter&& other) = delete; + ~D2DPainter() override = default; + + platform::Matrix GetTransform() override; + void SetTransform(const platform::Matrix& matrix) override; + void Clear(const ui::Color& color) override; + void StrokeRectangle(const ui::Rect& rectangle, platform::graph::Brush* brush, + float width) override; + void FillRectangle(const ui::Rect& rectangle, + platform::graph::Brush* brush) override; + void StrokeGeometry(platform::graph::Geometry* geometry, + platform::graph::Brush* brush, float width) override; + void FillGeometry(platform::graph::Geometry* geometry, + platform::graph::Brush* brush) override; + void DrawText(const ui::Point& offset, + platform::graph::TextLayout* text_layout, + platform::graph::Brush* brush) override; + void EndDraw() override final; + bool IsDisposed() override final { return is_disposed_; } + + void EndDrawAndDeleteThis() { + EndDraw(); + delete this; + } + + protected: + virtual void DoEndDraw() = 0; + + private: + ID2D1RenderTarget* render_target_; + + bool is_disposed_ = false; +}; +} // namespace cru::win::graph diff --git a/include/cru/win/graph/win_painter.hpp b/include/cru/win/graph/win_painter.hpp deleted file mode 100644 index 8351cb7b..00000000 --- a/include/cru/win/graph/win_painter.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -#include "../win_pre_config.hpp" - -#include "cru/platform/graph/painter.hpp" - -namespace cru::win::graph { -class GraphManager; - -class WinPainter : public Object, public virtual platform::graph::Painter { - public: - explicit WinPainter(ID2D1RenderTarget* render_target); - WinPainter(const WinPainter& other) = delete; - WinPainter(WinPainter&& other) = delete; - WinPainter& operator=(const WinPainter& other) = delete; - WinPainter& operator=(WinPainter&& other) = delete; - ~WinPainter() override; - - platform::Matrix GetTransform() override; - void SetTransform(const platform::Matrix& matrix) override; - void Clear(const ui::Color& color) override; - void StrokeRectangle(const ui::Rect& rectangle, platform::graph::Brush* brush, - float width) override; - void FillRectangle(const ui::Rect& rectangle, - platform::graph::Brush* brush) override; - void StrokeGeometry(platform::graph::Geometry* geometry, - platform::graph::Brush* brush, float width) override; - void FillGeometry(platform::graph::Geometry* geometry, - platform::graph::Brush* brush) override; - void DrawText(const ui::Point& offset, - platform::graph::TextLayout* text_layout, - platform::graph::Brush* brush) override; - void EndDraw() override; - bool IsDisposed() override { return is_disposed_; } - - void EndDrawAndDeleteThis() { - EndDraw(); - delete this; - } - - protected: - virtual void DoEndDraw(); - - private: - ID2D1RenderTarget* render_target_; - - bool is_disposed_ = false; -}; -} // namespace cru::win::graph diff --git a/include/cru/win/native/win_application.hpp b/include/cru/win/native/win_application.hpp index 458b10ae..5bdb753e 100644 --- a/include/cru/win/native/win_application.hpp +++ b/include/cru/win/native/win_application.hpp @@ -16,7 +16,7 @@ class WinApplication : public Object, static WinApplication* GetInstance(); private: - static WinApplication* instance_; + static WinApplication* instance; private: explicit WinApplication(HINSTANCE h_instance); @@ -32,6 +32,8 @@ class WinApplication : public Object, int Run() override; void Quit(int quit_code) override; + void AddOnQuitHandler(const std::function& handler) override; + void InvokeLater(const std::function& action) override; unsigned long SetTimeout(std::chrono::milliseconds milliseconds, const std::function& action) override; @@ -55,5 +57,7 @@ class WinApplication : public Object, std::shared_ptr god_window_; std::shared_ptr timer_manager_; std::shared_ptr window_manager_; + + std::vector> quit_handlers_; }; } // namespace cru::win::native diff --git a/src/ui/ui_manager.cpp b/src/ui/ui_manager.cpp index 2ac1c8e7..0c3a8f49 100644 --- a/src/ui/ui_manager.cpp +++ b/src/ui/ui_manager.cpp @@ -19,8 +19,12 @@ PredefineResources::PredefineResources() { } UiManager* UiManager::GetInstance() { - static UiManager instance; - return &instance; + static UiManager* instance = new UiManager(); + platform::native::UiApplication::GetInstance()->AddOnQuitHandler([] { + delete instance; + instance = nullptr; + }); + return instance; } UiManager::UiManager() : predefine_resources_(new PredefineResources()) {} diff --git a/src/win/graph/CMakeLists.txt b/src/win/graph/CMakeLists.txt index 7781e09a..61749a6a 100644 --- a/src/win/graph/CMakeLists.txt +++ b/src/win/graph/CMakeLists.txt @@ -1,9 +1,9 @@ add_library(cru_win_graph STATIC + d2d_painter.cpp graph_manager.cpp win_brush.cpp win_font.cpp win_geometry.cpp win_graph_factory.cpp - win_painter.cpp win_text_layout.cpp) target_link_libraries(cru_win_graph PUBLIC D3D11 D2d1 DWrite cru_win_base) diff --git a/src/win/graph/d2d_painter.cpp b/src/win/graph/d2d_painter.cpp new file mode 100644 index 00000000..26f6bef0 --- /dev/null +++ b/src/win/graph/d2d_painter.cpp @@ -0,0 +1,93 @@ +#include "cru/win/graph/d2d_painter.hpp" + +#include "cru/win/exception.hpp" +#include "cru/win/graph/d2d_util.hpp" +#include "cru/win/graph/graph_manager.hpp" +#include "cru/win/graph/win_brush.hpp" +#include "cru/win/graph/win_geometry.hpp" +#include "cru/win/graph/win_text_layout.hpp" + +#include + +namespace cru::win::graph { +D2DPainter::D2DPainter(ID2D1RenderTarget* render_target) { + assert(render_target); + render_target_ = render_target; +} + +platform::Matrix D2DPainter::GetTransform() { + assert(!IsDisposed()); + D2D1_MATRIX_3X2_F m; + render_target_->GetTransform(&m); + return util::Convert(m); +} + +void D2DPainter::SetTransform(const platform::Matrix& matrix) { + assert(!IsDisposed()); + render_target_->SetTransform(util::Convert(matrix)); +} + +void D2DPainter::Clear(const ui::Color& color) { + assert(!IsDisposed()); + render_target_->Clear(util::Convert(color)); +} + +void D2DPainter::StrokeRectangle(const ui::Rect& rectangle, + platform::graph::Brush* brush, float width) { + assert(!IsDisposed()); + const auto b = dynamic_cast(brush); + assert(b); + render_target_->DrawRectangle(util::Convert(rectangle), b->GetD2DBrush(), + width); +} + +void D2DPainter::FillRectangle(const ui::Rect& rectangle, + platform::graph::Brush* brush) { + assert(!IsDisposed()); + const auto b = dynamic_cast(brush); + assert(b); + render_target_->FillRectangle(util::Convert(rectangle), b->GetD2DBrush()); +} + +void D2DPainter::StrokeGeometry(platform::graph::Geometry* geometry, + platform::graph::Brush* brush, float width) { + assert(!IsDisposed()); + const auto g = dynamic_cast(geometry); + assert(g); + const auto b = dynamic_cast(brush); + assert(b); + + render_target_->DrawGeometry(g->GetNative(), b->GetD2DBrush(), width); +} + +void D2DPainter::FillGeometry(platform::graph::Geometry* geometry, + platform::graph::Brush* brush) { + assert(!IsDisposed()); + const auto g = dynamic_cast(geometry); + assert(g); + const auto b = dynamic_cast(brush); + assert(b); + + render_target_->FillGeometry(g->GetNative(), b->GetD2DBrush()); +} + +void D2DPainter::DrawText(const ui::Point& offset, + platform::graph::TextLayout* text_layout, + platform::graph::Brush* brush) { + assert(!IsDisposed()); + const auto t = dynamic_cast(text_layout); + assert(t); + const auto b = dynamic_cast(brush); + assert(b); + + render_target_->DrawTextLayout(util::Convert(offset), + t->GetDWriteTextLayout(), b->GetD2DBrush()); +} + +void D2DPainter::EndDraw() { + if (!is_disposed_) { + is_disposed_ = true; + DoEndDraw(); + } +} +} // namespace cru::win::graph diff --git a/src/win/graph/graph_manager.cpp b/src/win/graph/graph_manager.cpp index a4306b1b..30e1a14e 100644 --- a/src/win/graph/graph_manager.cpp +++ b/src/win/graph/graph_manager.cpp @@ -2,10 +2,12 @@ #include "cru/win/exception.hpp" +#include + namespace cru::win::graph { GraphManager* GraphManager::GetInstance() { - static GraphManager instance; - return &instance; + static GraphManager* instance = new GraphManager(); + return instance; } GraphManager::GraphManager() { diff --git a/src/win/graph/win_font.cpp b/src/win/graph/win_font.cpp index 0eb5e6b2..96983d3e 100644 --- a/src/win/graph/win_font.cpp +++ b/src/win/graph/win_font.cpp @@ -13,7 +13,7 @@ WinFontDescriptor::WinFontDescriptor(GraphManager* graph_manager, float font_size) { assert(graph_manager); std::array buffer; - if (!::GetUserDefaultLocaleName(buffer.data(), buffer.size())) + if (!::GetUserDefaultLocaleName(buffer.data(), static_cast(buffer.size()))) throw Win32Error(::GetLastError(), "Failed to get locale."); ThrowIfFailed(graph_manager->GetDWriteFactory()->CreateTextFormat( diff --git a/src/win/graph/win_painter.cpp b/src/win/graph/win_painter.cpp deleted file mode 100644 index 69ce1141..00000000 --- a/src/win/graph/win_painter.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "cru/win/graph/win_painter.hpp" - -#include "cru/win/exception.hpp" -#include "cru/win/graph/d2d_util.hpp" -#include "cru/win/graph/graph_manager.hpp" -#include "cru/win/graph/win_brush.hpp" -#include "cru/win/graph/win_geometry.hpp" -#include "cru/win/graph/win_text_layout.hpp" - -#include - -namespace cru::win::graph { -WinPainter::WinPainter(ID2D1RenderTarget* render_target) { - assert(render_target); - render_target_ = render_target; -} - -WinPainter::~WinPainter() { EndDraw(); } - -platform::Matrix WinPainter::GetTransform() { - assert(!IsDisposed()); - D2D1_MATRIX_3X2_F m; - render_target_->GetTransform(&m); - return util::Convert(m); -} - -void WinPainter::SetTransform(const platform::Matrix& matrix) { - assert(!IsDisposed()); - render_target_->SetTransform(util::Convert(matrix)); -} - -void WinPainter::Clear(const ui::Color& color) { - assert(!IsDisposed()); - render_target_->Clear(util::Convert(color)); -} - -void WinPainter::StrokeRectangle(const ui::Rect& rectangle, - platform::graph::Brush* brush, float width) { - assert(!IsDisposed()); - const auto b = dynamic_cast(brush); - assert(b); - render_target_->DrawRectangle(util::Convert(rectangle), b->GetD2DBrush(), - width); -} - -void WinPainter::FillRectangle(const ui::Rect& rectangle, - platform::graph::Brush* brush) { - assert(!IsDisposed()); - const auto b = dynamic_cast(brush); - assert(b); - render_target_->FillRectangle(util::Convert(rectangle), b->GetD2DBrush()); -} - -void WinPainter::StrokeGeometry(platform::graph::Geometry* geometry, - platform::graph::Brush* brush, float width) { - assert(!IsDisposed()); - const auto g = dynamic_cast(geometry); - assert(g); - const auto b = dynamic_cast(brush); - assert(b); - - render_target_->DrawGeometry(g->GetNative(), b->GetD2DBrush(), width); -} - -void WinPainter::FillGeometry(platform::graph::Geometry* geometry, - platform::graph::Brush* brush) { - assert(!IsDisposed()); - const auto g = dynamic_cast(geometry); - assert(g); - const auto b = dynamic_cast(brush); - assert(b); - - render_target_->FillGeometry(g->GetNative(), b->GetD2DBrush()); -} - -void WinPainter::DrawText(const ui::Point& offset, - platform::graph::TextLayout* text_layout, - platform::graph::Brush* brush) { - assert(!IsDisposed()); - const auto t = dynamic_cast(text_layout); - assert(t); - const auto b = dynamic_cast(brush); - assert(b); - - render_target_->DrawTextLayout(util::Convert(offset), - t->GetDWriteTextLayout(), b->GetD2DBrush()); -} - -void WinPainter::EndDraw() { - if (!IsDisposed()) { - DoEndDraw(); - } -} - -void WinPainter::DoEndDraw() { - ThrowIfFailed(render_target_->EndDraw()); - is_disposed_ = true; -} -} // namespace cru::win::graph diff --git a/src/win/native/win_application.cpp b/src/win/native/win_application.cpp index 72e12fa0..6c39453f 100644 --- a/src/win/native/win_application.cpp +++ b/src/win/native/win_application.cpp @@ -1,6 +1,7 @@ #include "cru/win/native/win_application.hpp" #include "cru/win/exception.hpp" +#include "cru/win/graph/graph_manager.hpp" #include "cru/win/native/god_window.hpp" #include "cru/win/native/win_native_window.hpp" #include "god_window_message.hpp" @@ -17,19 +18,22 @@ UiApplication* UiApplication::GetInstance() { } // namespace cru::platform::native namespace cru::win::native { -WinApplication* WinApplication::instance_ = nullptr; +WinApplication* WinApplication::instance = nullptr; + +namespace { +bool application_constructing = false; +} WinApplication* WinApplication::GetInstance() { - if (instance_ == nullptr) - instance_ = new WinApplication(::GetModuleHandleW(nullptr)); - return instance_; + if (instance == nullptr && !application_constructing) { + application_constructing = true; + instance = new WinApplication(::GetModuleHandleW(nullptr)); + } + return instance; } WinApplication::WinApplication(HINSTANCE h_instance) : h_instance_(h_instance) { - if (instance_) - throw std::runtime_error("A application instance already exists."); - - instance_ = this; + assert(instance == nullptr); if (!::IsWindows8OrGreater()) throw std::runtime_error("Must run on Windows 8 or later."); @@ -39,7 +43,8 @@ WinApplication::WinApplication(HINSTANCE h_instance) : h_instance_(h_instance) { window_manager_ = std::make_shared(this); } -WinApplication::~WinApplication() { instance_ = nullptr; } +WinApplication::~WinApplication() { + instance = nullptr; } int WinApplication::Run() { MSG msg; @@ -47,11 +52,21 @@ int WinApplication::Run() { TranslateMessage(&msg); DispatchMessageW(&msg); } + + for (const auto& handler : quit_handlers_) handler(); + + delete graph::GraphManager::GetInstance(); + delete this; + return static_cast(msg.wParam); } void WinApplication::Quit(const int quit_code) { ::PostQuitMessage(quit_code); } +void WinApplication::AddOnQuitHandler(const std::function& handler) { + quit_handlers_.push_back(handler); +} + void WinApplication::InvokeLater(const std::function& action) { // copy the action to a safe place auto p_action_copy = new std::function(action); diff --git a/src/win/native/win_native_window.cpp b/src/win/native/win_native_window.cpp index 0afad4e6..1d3b15ba 100644 --- a/src/win/native/win_native_window.cpp +++ b/src/win/native/win_native_window.cpp @@ -254,6 +254,7 @@ RECT WinNativeWindow::GetClientRectPixel() { void WinNativeWindow::OnDestroyInternal() { application_->GetWindowManager()->UnregisterWindow(hwnd_); hwnd_ = nullptr; + destroy_event_.Raise(); if (delete_this_on_destroy_) application_->InvokeLater([this] { delete this; }); } diff --git a/src/win/native/window_manager.cpp b/src/win/native/window_manager.cpp index a2fcdb54..5fea5a27 100644 --- a/src/win/native/window_manager.cpp +++ b/src/win/native/window_manager.cpp @@ -26,6 +26,11 @@ WindowManager::WindowManager(WinApplication* application) { L"CruUIWindowClass", GeneralWndProc, application->GetInstanceHandle()); } +WindowManager::~WindowManager() { + for (const auto [key, window] : window_map_) + delete window; +} + void WindowManager::RegisterWindow(HWND hwnd, WinNativeWindow* window) { assert(window_map_.count(hwnd) == 0); // The hwnd is already in the map. window_map_.emplace(hwnd, window); diff --git a/src/win/native/window_manager.hpp b/src/win/native/window_manager.hpp index fa5bbe9d..8fab9cfc 100644 --- a/src/win/native/window_manager.hpp +++ b/src/win/native/window_manager.hpp @@ -19,7 +19,7 @@ class WindowManager : public Object { WindowManager(WindowManager&& other) = delete; WindowManager& operator=(const WindowManager& other) = delete; WindowManager& operator=(WindowManager&& other) = delete; - ~WindowManager() override = default; + ~WindowManager() override; // Get the general window class for creating ordinary window. std::shared_ptr GetGeneralWindowClass() const { diff --git a/src/win/native/window_painter.cpp b/src/win/native/window_painter.cpp index 46364cdd..4e98a7fd 100644 --- a/src/win/native/window_painter.cpp +++ b/src/win/native/window_painter.cpp @@ -1,5 +1,6 @@ #include "window_painter.hpp" +#include "cru/win/exception.hpp" #include "cru/win/graph/graph_manager.hpp" #include "cru/win/native/window_render_target.hpp" @@ -7,7 +8,7 @@ namespace cru::win::native { WindowPainter::WindowPainter(WinNativeWindow* window) - : WinPainter(window->GetWindowRenderTarget() + : D2DPainter(window->GetWindowRenderTarget() ->GetGraphManager() ->GetD2D1DeviceContext()), window_(window) { @@ -18,7 +19,13 @@ WindowPainter::WindowPainter(WinNativeWindow* window) ->BeginDraw(); } +WindowPainter::~WindowPainter() { EndDraw(); } + void WindowPainter::DoEndDraw() { - WinPainter::DoEndDraw(); - window_->GetWindowRenderTarget()->Present(); } + ThrowIfFailed(window_->GetWindowRenderTarget() + ->GetGraphManager() + ->GetD2D1DeviceContext() + ->EndDraw()); + window_->GetWindowRenderTarget()->Present(); +} } // namespace cru::win::native diff --git a/src/win/native/window_painter.hpp b/src/win/native/window_painter.hpp index 0e6ab2cb..78c0717c 100644 --- a/src/win/native/window_painter.hpp +++ b/src/win/native/window_painter.hpp @@ -1,16 +1,16 @@ #pragma once -#include "cru/win/graph/win_painter.hpp" +#include "cru/win/graph/d2d_painter.hpp" #include "cru/win/native/win_native_window.hpp" namespace cru::win::native { -class WindowPainter : public graph::WinPainter { +class WindowPainter : public graph::D2DPainter { public: explicit WindowPainter(WinNativeWindow* window); WindowPainter(const WindowPainter& other) = delete; WindowPainter& operator=(const WindowPainter& other) = delete; WindowPainter(WindowPainter&& other) = delete; WindowPainter& operator=(WindowPainter&& other) = delete; - ~WindowPainter() override = default; + ~WindowPainter() override; protected: void DoEndDraw() override; -- cgit v1.2.3