From f2aa96fba0b72eeeadf5160ea5df2c8143ec8aa0 Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 12 Dec 2019 23:26:04 +0800 Subject: ... --- include/cru/common/logger.hpp | 5 + include/cru/platform/native/cursor.hpp | 6 +- include/cru/platform/native/event.hpp | 15 + include/cru/platform/native/native_event.hpp | 16 - include/cru/platform/native/native_window.hpp | 75 ---- include/cru/platform/native/ui_application.hpp | 21 +- include/cru/platform/native/window.hpp | 74 ++++ include/cru/win/graph/direct/factory.hpp | 3 +- include/cru/win/native/cursor.hpp | 26 +- include/cru/win/native/god_window.hpp | 12 +- include/cru/win/native/native_window.hpp | 146 ------- include/cru/win/native/resource.hpp | 23 ++ include/cru/win/native/ui_application.hpp | 55 +-- include/cru/win/native/window.hpp | 146 +++++++ include/cru/win/native/window_class.hpp | 13 +- .../native/window_native_message_event_args.hpp | 11 +- include/cru/win/native/window_render_target.hpp | 17 +- src/platform/native/CMakeLists.txt | 4 +- src/win/debug_logger.hpp | 4 +- src/win/graph/direct/factory.cpp | 3 + src/win/native/CMakeLists.txt | 5 +- src/win/native/cursor.cpp | 20 +- src/win/native/dpi_util.hpp | 1 - src/win/native/god_window.cpp | 10 +- src/win/native/native_window.cpp | 422 -------------------- src/win/native/timer.hpp | 10 +- src/win/native/ui_application.cpp | 72 ++-- src/win/native/window.cpp | 434 +++++++++++++++++++++ src/win/native/window_class.cpp | 6 +- src/win/native/window_d2d_painter.cpp | 8 +- src/win/native/window_d2d_painter.hpp | 10 +- src/win/native/window_manager.cpp | 6 +- src/win/native/window_manager.hpp | 17 +- src/win/native/window_render_target.cpp | 11 +- 34 files changed, 862 insertions(+), 845 deletions(-) create mode 100644 include/cru/platform/native/event.hpp delete mode 100644 include/cru/platform/native/native_event.hpp delete mode 100644 include/cru/platform/native/native_window.hpp create mode 100644 include/cru/platform/native/window.hpp delete mode 100644 include/cru/win/native/native_window.hpp create mode 100644 include/cru/win/native/resource.hpp create mode 100644 include/cru/win/native/window.hpp delete mode 100644 src/win/native/native_window.cpp create mode 100644 src/win/native/window.cpp diff --git a/include/cru/common/logger.hpp b/include/cru/common/logger.hpp index 08765499..61d97422 100644 --- a/include/cru/common/logger.hpp +++ b/include/cru/common/logger.hpp @@ -28,6 +28,11 @@ class StdioLogSource : public virtual ILogSource { ~StdioLogSource() override = default; void Write(LogLevel level, const std::string_view& s) override { + // TODO: Emmm... Since it is buggy to use narrow char in UTF-8 on Windows. I + // think this implementation might be broken. (However, I didn't test it.) + // Maybe, I should detect Windows and use wide char (And I didn't test this + // either) or other more complicated implementation. Currently, I settled + // with this. if (level == LogLevel::Error) { std::cerr << s; } else { diff --git a/include/cru/platform/native/cursor.hpp b/include/cru/platform/native/cursor.hpp index 961dff34..cb8b7ed2 100644 --- a/include/cru/platform/native/cursor.hpp +++ b/include/cru/platform/native/cursor.hpp @@ -1,18 +1,18 @@ #pragma once -#include "../native_resource.hpp" +#include "../resource.hpp" #include namespace cru::platform::native { -struct ICursor : public virtual INativeResource {}; +struct ICursor : virtual INativeResource {}; enum class SystemCursorType { Arrow, Hand, }; -struct ICursorManager : public virtual INativeResource { +struct ICursorManager : virtual INativeResource { virtual std::shared_ptr GetSystemCursor(SystemCursorType type) = 0; // TODO: Add method to create cursor. diff --git a/include/cru/platform/native/event.hpp b/include/cru/platform/native/event.hpp new file mode 100644 index 00000000..48e9cfca --- /dev/null +++ b/include/cru/platform/native/event.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include "../graph_base.hpp" +#include "basic_types.hpp" + +namespace cru::platform::native { +struct NativeMouseButtonEventArgs { + MouseButton button; + Point point; +}; + +enum class FocusChangeType { Gain, Lost }; + +enum class MouseEnterLeaveType { Enter, Leave }; +} // namespace cru::platform::native diff --git a/include/cru/platform/native/native_event.hpp b/include/cru/platform/native/native_event.hpp deleted file mode 100644 index dcd7a336..00000000 --- a/include/cru/platform/native/native_event.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include "../graphic_base.hpp" -#include "basic_types.hpp" - -namespace cru::platform::native { -struct NativeMouseButtonEventArgs { - MouseButton button; - Point point; -}; - -enum class FocusChangeType { Gain, Lost }; - -enum class MouseEnterLeaveType { Enter, Leave }; - -} // namespace cru::platform::native diff --git a/include/cru/platform/native/native_window.hpp b/include/cru/platform/native/native_window.hpp deleted file mode 100644 index cd2459e0..00000000 --- a/include/cru/platform/native/native_window.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once -#include "../native_resource.hpp" - -#include "cru/common/event.hpp" - -#include "../graphic_base.hpp" -#include "basic_types.hpp" -#include "cursor.hpp" -#include "native_event.hpp" - -namespace cru::platform::graph { -struct IPainter; -} - -namespace cru::platform::native { -// 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. -struct INativeWindow : public 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 void Close() = 0; - - virtual INativeWindow* GetParent() = 0; - - virtual bool IsVisible() = 0; - virtual void SetVisible(bool is_visible) = 0; - - virtual Size GetClientSize() = 0; - virtual void SetClientSize(const Size& size) = 0; - - // Get the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - virtual Rect GetWindowRect() = 0; - - // Set the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - virtual void SetWindowRect(const Rect& rect) = 0; - - // Relative to client lefttop. - virtual Point GetMousePosition() = 0; - - virtual bool CaptureMouse() = 0; - virtual bool ReleaseMouse() = 0; - - virtual void SetCursor(std::shared_ptr cursor) = 0; - - virtual void RequestRepaint() = 0; - - // Remember to call EndDraw on return value and destroy it. - virtual std::unique_ptr BeginPaint() = 0; - - virtual IEvent* DestroyEvent() = 0; - virtual IEvent* PaintEvent() = 0; - virtual IEvent* ResizeEvent() = 0; - virtual IEvent* FocusEvent() = 0; - virtual IEvent* MouseEnterLeaveEvent() = 0; - virtual IEvent* MouseMoveEvent() = 0; - virtual IEvent* MouseDownEvent() = 0; - virtual IEvent* MouseUpEvent() = 0; - virtual IEvent* KeyDownEvent() = 0; - virtual IEvent* KeyUpEvent() = 0; -}; -} // namespace cru::platform::native diff --git a/include/cru/platform/native/ui_application.hpp b/include/cru/platform/native/ui_application.hpp index 6d2ab659..c1f10d15 100644 --- a/include/cru/platform/native/ui_application.hpp +++ b/include/cru/platform/native/ui_application.hpp @@ -1,29 +1,20 @@ #pragma once -#include "../native_resource.hpp" +#include "../resource.hpp" #include #include #include +namespace cru::platform::graph { +struct IGraphFactory; +} + namespace cru::platform::native { struct INativeWindow; struct ICursorManager; // The entry point of a ui application. -// It will call IGraphFactory::CreateInstance during its creation -// and set graph factory to be auto deleted. If you want to keep -// the graph factory then you should manually set it to false after -// creating the ui application. struct IUiApplication : public virtual INativeResource { - public: - // Create a platform-specific instance and save it as the global instance. - // Do not create the instance twice. Implements should assert for that. - // After creating, get the instance by GetInstance. - static IUiApplication* CreateInstance(); - - // Get the global instance. If it is not created, then return nullptr. - static IUiApplication* GetInstance(); - public: // Block current thread and run the message loop. Return the exit code when // message loop gets a quit message (possibly posted by method RequestQuit). @@ -44,6 +35,8 @@ struct IUiApplication : public virtual INativeResource { virtual std::vector GetAllWindow() = 0; virtual INativeWindow* CreateWindow(INativeWindow* parent) = 0; + virtual cru::platform::graph::IGraphFactory* GetGraphFactory() = 0; + virtual ICursorManager* GetCursorManager() = 0; }; } // namespace cru::platform::native diff --git a/include/cru/platform/native/window.hpp b/include/cru/platform/native/window.hpp new file mode 100644 index 00000000..bfaf170b --- /dev/null +++ b/include/cru/platform/native/window.hpp @@ -0,0 +1,74 @@ +#pragma once +#include "../resource.hpp" + +#include "../graph_base.hpp" +#include "basic_types.hpp" +#include "cru/common/event.hpp" +#include "cursor.hpp" +#include "event.hpp" + +namespace cru::platform::graph { +struct IPainter; +} + +namespace cru::platform::native { +// 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. +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 void Close() = 0; + + virtual INativeWindow* GetParent() = 0; + + virtual bool IsVisible() = 0; + virtual void SetVisible(bool is_visible) = 0; + + virtual Size GetClientSize() = 0; + virtual void SetClientSize(const Size& size) = 0; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual Rect GetWindowRect() = 0; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + virtual void SetWindowRect(const Rect& rect) = 0; + + // Relative to client lefttop. + virtual Point GetMousePosition() = 0; + + virtual bool CaptureMouse() = 0; + virtual bool ReleaseMouse() = 0; + + virtual void SetCursor(std::shared_ptr cursor) = 0; + + virtual void RequestRepaint() = 0; + + // Remember to call EndDraw on return value and destroy it. + virtual std::unique_ptr BeginPaint() = 0; + + virtual IEvent* DestroyEvent() = 0; + virtual IEvent* PaintEvent() = 0; + virtual IEvent* ResizeEvent() = 0; + virtual IEvent* FocusEvent() = 0; + virtual IEvent* MouseEnterLeaveEvent() = 0; + virtual IEvent* MouseMoveEvent() = 0; + virtual IEvent* MouseDownEvent() = 0; + virtual IEvent* MouseUpEvent() = 0; + virtual IEvent* KeyDownEvent() = 0; + virtual IEvent* KeyUpEvent() = 0; +}; +} // namespace cru::platform::native diff --git a/include/cru/win/graph/direct/factory.hpp b/include/cru/win/graph/direct/factory.hpp index ae4eeb3a..4c106f54 100644 --- a/include/cru/win/graph/direct/factory.hpp +++ b/include/cru/win/graph/direct/factory.hpp @@ -5,10 +5,9 @@ namespace cru::platform::graph::win::direct { class DirectGraphFactory : public DirectResource, public virtual IGraphFactory { - private: + public: DirectGraphFactory(); - public: CRU_DELETE_COPY(DirectGraphFactory) CRU_DELETE_MOVE(DirectGraphFactory) diff --git a/include/cru/win/native/cursor.hpp b/include/cru/win/native/cursor.hpp index 3ef480ea..e5728b1c 100644 --- a/include/cru/win/native/cursor.hpp +++ b/include/cru/win/native/cursor.hpp @@ -1,32 +1,30 @@ #pragma once -#include -#include "../win_pre_config.hpp" +#include "resource.hpp" -#include "cru/common/base.hpp" #include "cru/platform/native/cursor.hpp" -#include "cru/win/native/platform_id.hpp" + +#include namespace cru::platform::native::win { -class WinCursor : public Cursor { +class WinCursor : public WinNativeResource, public virtual ICursor { public: - WinCursor(HCURSOR handle, bool auto_delete); + WinCursor(HCURSOR handle, bool auto_destroy); CRU_DELETE_COPY(WinCursor) CRU_DELETE_MOVE(WinCursor) ~WinCursor() override; - CRU_PLATFORMID_IMPLEMENT_WIN - public: HCURSOR GetHandle() const { return handle_; } private: HCURSOR handle_; - bool auto_delete_; + bool auto_destroy_; }; -class WinCursorManager : public CursorManager { +class WinCursorManager : public WinNativeResource, + public virtual ICursorManager { public: WinCursorManager(); @@ -35,13 +33,11 @@ class WinCursorManager : public CursorManager { ~WinCursorManager() override = default; - CRU_PLATFORMID_IMPLEMENT_WIN - public: - std::shared_ptr GetSystemWinCursor(SystemCursor type); + std::shared_ptr GetSystemWinCursor(SystemCursorType type); - std::shared_ptr GetSystemCursor(SystemCursor type) override { - return std::static_pointer_cast(GetSystemWinCursor(type)); + std::shared_ptr GetSystemCursor(SystemCursorType type) override { + return std::static_pointer_cast(GetSystemWinCursor(type)); } private: diff --git a/include/cru/win/native/god_window.hpp b/include/cru/win/native/god_window.hpp index 9fd20caa..3cf97e0b 100644 --- a/include/cru/win/native/god_window.hpp +++ b/include/cru/win/native/god_window.hpp @@ -12,10 +12,10 @@ class WindowClass; class GodWindow : public Object { public: explicit GodWindow(WinUiApplication* application); - GodWindow(const GodWindow& other) = delete; - GodWindow(GodWindow&& other) = delete; - GodWindow& operator=(const GodWindow& other) = delete; - GodWindow& operator=(GodWindow&& other) = delete; + + CRU_DELETE_COPY(GodWindow) + CRU_DELETE_MOVE(GodWindow) + ~GodWindow() override; HWND GetHandle() const { return hwnd_; } @@ -26,7 +26,7 @@ class GodWindow : public Object { private: WinUiApplication* application_; - std::shared_ptr god_window_class_; + std::unique_ptr god_window_class_; HWND hwnd_; }; -} // namespace cru::win::native \ No newline at end of file +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/native_window.hpp b/include/cru/win/native/native_window.hpp deleted file mode 100644 index 16b14dbf..00000000 --- a/include/cru/win/native/native_window.hpp +++ /dev/null @@ -1,146 +0,0 @@ -#pragma once -#include "../win_pre_config.hpp" - -#include "cru/platform/native/native_window.hpp" -#include "platform_id.hpp" -#include "window_native_message_event_args.hpp" - -#include - -namespace cru::platform::native::win { -class WinUiApplication; -class WindowClass; -class WindowManager; -class WindowRenderTarget; - -class WinNativeWindow : public INativeWindow { - public: - WinNativeWindow(WinUiApplication* application, - std::shared_ptr window_class, DWORD window_style, - WinNativeWindow* parent); - WinNativeWindow(const WinNativeWindow& other) = delete; - WinNativeWindow(WinNativeWindow&& other) = delete; - WinNativeWindow& operator=(const WinNativeWindow& other) = delete; - WinNativeWindow& operator=(WinNativeWindow&& other) = delete; - ~WinNativeWindow() override; - - CRU_PLATFORMID_IMPLEMENT_WIN - - public: - bool IsValid() override; - void SetDeleteThisOnDestroy(bool value) override; - - void Close() override; - - WinNativeWindow* GetParent() override { return parent_window_; } - - bool IsVisible() override; - void SetVisible(bool is_visible) override; - - Size GetClientSize() override; - void SetClientSize(const Size& size) override; - - // Get the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - Rect GetWindowRect() override; - - // Set the rect of the window containing frame. - // The lefttop of the rect is relative to screen lefttop. - void SetWindowRect(const Rect& rect) override; - - Point GetMousePosition() override; - - bool CaptureMouse() override; - bool ReleaseMouse() override; - - void Repaint() override; - graph::Painter* BeginPaint() override; - - void SetCursor(std::shared_ptr cursor) override; - - IEvent* DestroyEvent() override { return &destroy_event_; } - IEvent* PaintEvent() override { return &paint_event_; } - IEvent* ResizeEvent() override { return &resize_event_; } - IEvent* FocusEvent() override { return &focus_event_; } - IEvent* MouseEnterLeaveEvent() override { - return &mouse_enter_leave_event_; - } - IEvent* MouseMoveEvent() override { return &mouse_move_event_; } - IEvent* MouseDownEvent() - override { - return &mouse_down_event_; - } - IEvent* MouseUpEvent() - override { - return &mouse_up_event_; - } - IEvent* KeyDownEvent() override { return &key_down_event_; } - IEvent* KeyUpEvent() override { return &key_up_event_; } - - IEvent* NativeMessageEvent() { - return &native_message_event_; - } - - // Get the handle of the window. Return null if window is invalid. - HWND GetWindowHandle() const { return hwnd_; } - - bool HandleNativeWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, - LPARAM l_param, LRESULT* result); - - WindowRenderTarget* GetWindowRenderTarget() const { - return window_render_target_.get(); - } - - private: - // Get the client rect in pixel. - RECT GetClientRectPixel(); - - //*************** region: native messages *************** - - void OnDestroyInternal(); - void OnPaintInternal(); - void OnResizeInternal(int new_width, int new_height); - - void OnSetFocusInternal(); - void OnKillFocusInternal(); - - void OnMouseMoveInternal(POINT point); - void OnMouseLeaveInternal(); - void OnMouseDownInternal(platform::native::MouseButton button, POINT point); - void OnMouseUpInternal(platform::native::MouseButton button, POINT point); - - void OnMouseWheelInternal(short delta, POINT point); - void OnKeyDownInternal(int virtual_code); - void OnKeyUpInternal(int virtual_code); - void OnCharInternal(wchar_t c); - - void OnActivatedInternal(); - void OnDeactivatedInternal(); - - private: - WinUiApplication* application_; - - bool delete_this_on_destroy_ = true; - - HWND hwnd_; - WinNativeWindow* parent_window_; - - bool has_focus_ = false; - bool is_mouse_in_ = false; - - std::shared_ptr window_render_target_; - - Event destroy_event_; - Event paint_event_; - Event resize_event_; - Event focus_event_; - Event mouse_enter_leave_event_; - Event mouse_move_event_; - Event mouse_down_event_; - Event mouse_up_event_; - Event key_down_event_; - Event key_up_event_; - - Event native_message_event_; -}; -} // namespace cru::platform::native::win diff --git a/include/cru/win/native/resource.hpp b/include/cru/win/native/resource.hpp new file mode 100644 index 00000000..2c76fe6b --- /dev/null +++ b/include/cru/win/native/resource.hpp @@ -0,0 +1,23 @@ +#pragma once +#include "../win_pre_config.hpp" + +#include "cru/platform/resource.hpp" + +namespace cru::platform::native::win { +class WinNativeResource : public Object, public virtual INativeResource { + public: + static constexpr std::string_view k_platform_id = "Windows"; + + protected: + WinNativeResource() = default; + + public: + CRU_DELETE_COPY(WinNativeResource) + CRU_DELETE_MOVE(WinNativeResource) + + ~WinNativeResource() override = default; + + public: + std::string_view GetPlatformId() const final { return k_platform_id; } +}; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/ui_application.hpp b/include/cru/win/native/ui_application.hpp index 94c4b1eb..65bdc9e4 100644 --- a/include/cru/win/native/ui_application.hpp +++ b/include/cru/win/native/ui_application.hpp @@ -1,39 +1,40 @@ #pragma once -#include "../win_pre_config.hpp" +#include "resource.hpp" #include "cru/platform/native/ui_application.hpp" -#include "platform_id.hpp" -#include "cursor.hpp" - #include +namespace cru::platform::graph::win::direct { +class DirectGraphFactory; +} + namespace cru::platform::native::win { class GodWindow; class TimerManager; class WindowManager; +class WinCursorManager; -class WinUiApplication : public UiApplication { - friend UiApplication* UiApplication::CreateInstance(); - +class WinUiApplication : public WinNativeResource, + public virtual IUiApplication { public: - static WinUiApplication* GetInstance(); + static WinUiApplication* GetInstance() { return instance; } + + private: + static WinUiApplication* instance; private: - explicit WinUiApplication(HINSTANCE h_instance); + WinUiApplication(); public: - WinUiApplication(const WinUiApplication&) = delete; - WinUiApplication(WinUiApplication&&) = delete; - WinUiApplication& operator=(const WinUiApplication&) = delete; - WinUiApplication& operator=(WinUiApplication&&) = delete; - ~WinUiApplication() override; + CRU_DELETE_COPY(WinUiApplication) + CRU_DELETE_MOVE(WinUiApplication) - CRU_PLATFORMID_IMPLEMENT_WIN + ~WinUiApplication() override; public: int Run() override; - void Quit(int quit_code) override; + void RequestQuit(int quit_code) override; void AddOnQuitHandler(const std::function& handler) override; @@ -47,25 +48,29 @@ class WinUiApplication : public UiApplication { std::vector GetAllWindow() override; INativeWindow* CreateWindow(INativeWindow* parent) override; - WinCursorManager* GetCursorManager() override; + cru::platform::graph::IGraphFactory* GetGraphFactory() override; + + cru::platform::graph::win::direct::DirectGraphFactory* GetDirectFactory() { + return graph_factory_.get(); + } - bool IsAutoDelete() const { return auto_delete_; } - void SetAutoDelete(bool value) { auto_delete_ = value; } + ICursorManager* GetCursorManager() override; - HINSTANCE GetInstanceHandle() const { return h_instance_; } + HINSTANCE GetInstanceHandle() const { return instance_handle_; } GodWindow* GetGodWindow() const { return god_window_.get(); } TimerManager* GetTimerManager() const { return timer_manager_.get(); } WindowManager* GetWindowManager() const { return window_manager_.get(); } private: - bool auto_delete_ = false; + HINSTANCE instance_handle_; - HINSTANCE h_instance_; + std::unique_ptr + graph_factory_; - std::shared_ptr god_window_; - std::shared_ptr timer_manager_; - std::shared_ptr window_manager_; + std::unique_ptr god_window_; + std::unique_ptr timer_manager_; + std::unique_ptr window_manager_; std::unique_ptr cursor_manager_; diff --git a/include/cru/win/native/window.hpp b/include/cru/win/native/window.hpp new file mode 100644 index 00000000..9752682f --- /dev/null +++ b/include/cru/win/native/window.hpp @@ -0,0 +1,146 @@ +#pragma once +#include "resource.hpp" + +#include "cru/platform/native/window.hpp" +#include "window_native_message_event_args.hpp" + +#include + +namespace cru::platform::native::win { +class WinUiApplication; +class WinCursor; +class WindowClass; +class WindowManager; +class WindowRenderTarget; + +class WinNativeWindow : public WinNativeResource, public virtual INativeWindow { + public: + WinNativeWindow(WinUiApplication* application, + WindowClass* window_class, DWORD window_style, + WinNativeWindow* parent); + + CRU_DELETE_COPY(WinNativeWindow) + CRU_DELETE_MOVE(WinNativeWindow) + + ~WinNativeWindow() override; + + public: + bool IsValid() override; + void SetDeleteThisOnDestroy(bool value) override; + + void Close() override; + + WinNativeWindow* GetParent() override { return parent_window_; } + + bool IsVisible() override; + void SetVisible(bool is_visible) override; + + Size GetClientSize() override; + void SetClientSize(const Size& size) override; + + // Get the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + Rect GetWindowRect() override; + + // Set the rect of the window containing frame. + // The lefttop of the rect is relative to screen lefttop. + void SetWindowRect(const Rect& rect) override; + + Point GetMousePosition() override; + + bool CaptureMouse() override; + bool ReleaseMouse() override; + + void RequestRepaint() override; + std::unique_ptr BeginPaint() override; + + void SetCursor(std::shared_ptr cursor) override; + + IEvent* DestroyEvent() override { return &destroy_event_; } + IEvent* PaintEvent() override { return &paint_event_; } + IEvent* ResizeEvent() override { return &resize_event_; } + IEvent* FocusEvent() override { return &focus_event_; } + IEvent* MouseEnterLeaveEvent() override { + return &mouse_enter_leave_event_; + } + IEvent* MouseMoveEvent() override { return &mouse_move_event_; } + IEvent* MouseDownEvent() + override { + return &mouse_down_event_; + } + IEvent* MouseUpEvent() + override { + return &mouse_up_event_; + } + IEvent* KeyDownEvent() override { return &key_down_event_; } + IEvent* KeyUpEvent() override { return &key_up_event_; } + + IEvent* NativeMessageEvent() { + return &native_message_event_; + } + + // Get the handle of the window. Return null if window is invalid. + HWND GetWindowHandle() const { return hwnd_; } + + bool HandleNativeWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, + LPARAM l_param, LRESULT* result); + + WindowRenderTarget* GetWindowRenderTarget() const { + return window_render_target_.get(); + } + + private: + // Get the client rect in pixel. + RECT GetClientRectPixel(); + + //*************** region: native messages *************** + + void OnDestroyInternal(); + void OnPaintInternal(); + void OnResizeInternal(int new_width, int new_height); + + void OnSetFocusInternal(); + void OnKillFocusInternal(); + + void OnMouseMoveInternal(POINT point); + void OnMouseLeaveInternal(); + void OnMouseDownInternal(platform::native::MouseButton button, POINT point); + void OnMouseUpInternal(platform::native::MouseButton button, POINT point); + + void OnMouseWheelInternal(short delta, POINT point); + void OnKeyDownInternal(int virtual_code); + void OnKeyUpInternal(int virtual_code); + void OnCharInternal(wchar_t c); + + void OnActivatedInternal(); + void OnDeactivatedInternal(); + + private: + WinUiApplication* application_; + + bool delete_this_on_destroy_ = true; + + HWND hwnd_; + WinNativeWindow* parent_window_; + + bool has_focus_ = false; + bool is_mouse_in_ = false; + + std::unique_ptr window_render_target_; + + std::shared_ptr cursor_; + + Event destroy_event_; + Event paint_event_; + Event resize_event_; + Event focus_event_; + Event mouse_enter_leave_event_; + Event mouse_move_event_; + Event mouse_down_event_; + Event mouse_up_event_; + Event key_down_event_; + Event key_up_event_; + + Event native_message_event_; +}; +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/window_class.hpp b/include/cru/win/native/window_class.hpp index fec3b32e..fd5102a5 100644 --- a/include/cru/win/native/window_class.hpp +++ b/include/cru/win/native/window_class.hpp @@ -8,12 +8,11 @@ namespace cru::platform::native::win { class WindowClass : public Object { public: - WindowClass(const std::wstring& name, WNDPROC window_proc, - HINSTANCE h_instance); - WindowClass(const WindowClass& other) = delete; - WindowClass(WindowClass&& other) = delete; - WindowClass& operator=(const WindowClass& other) = delete; - WindowClass& operator=(WindowClass&& other) = delete; + WindowClass(std::wstring name, WNDPROC window_proc, HINSTANCE h_instance); + + CRU_DELETE_COPY(WindowClass) + CRU_DELETE_MOVE(WindowClass) + ~WindowClass() override = default; const wchar_t* GetName() const { return name_.c_str(); } @@ -24,4 +23,4 @@ class WindowClass : public Object { std::wstring name_; ATOM atom_; }; -} // namespace cru::win::native +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/window_native_message_event_args.hpp b/include/cru/win/native/window_native_message_event_args.hpp index 4cf744f2..18de1f46 100644 --- a/include/cru/win/native/window_native_message_event_args.hpp +++ b/include/cru/win/native/window_native_message_event_args.hpp @@ -15,13 +15,8 @@ class WindowNativeMessageEventArgs : public Object { public: WindowNativeMessageEventArgs(const WindowNativeMessage& message) : message_(message) {} - WindowNativeMessageEventArgs(const WindowNativeMessageEventArgs& other) = - default; - WindowNativeMessageEventArgs(WindowNativeMessageEventArgs&& other) = default; - WindowNativeMessageEventArgs& operator=( - const WindowNativeMessageEventArgs& other) = default; - WindowNativeMessageEventArgs& operator=( - WindowNativeMessageEventArgs&& other) = default; + CRU_DEFAULT_COPY(WindowNativeMessageEventArgs) + CRU_DEFAULT_MOVE(WindowNativeMessageEventArgs) ~WindowNativeMessageEventArgs() override = default; WindowNativeMessage GetWindowMessage() const { return message_; } @@ -42,4 +37,4 @@ class WindowNativeMessageEventArgs : public Object { LRESULT result_; bool handled_ = false; }; -} // namespace cru::win::native +} // namespace cru::platform::native::win diff --git a/include/cru/win/native/window_render_target.hpp b/include/cru/win/native/window_render_target.hpp index bde47f4f..248bfc25 100644 --- a/include/cru/win/native/window_render_target.hpp +++ b/include/cru/win/native/window_render_target.hpp @@ -4,22 +4,23 @@ #include "cru/common/base.hpp" namespace cru::platform::graph::win::direct { -struct IDirectFactory; +class DirectGraphFactory; } namespace cru::platform::native::win { // Represents a window render target. class WindowRenderTarget : public Object { public: - WindowRenderTarget(graph::win::direct::IDirectFactory* factory, HWND hwnd); - WindowRenderTarget(const WindowRenderTarget& other) = delete; - WindowRenderTarget(WindowRenderTarget&& other) = delete; - WindowRenderTarget& operator=(const WindowRenderTarget& other) = delete; - WindowRenderTarget& operator=(WindowRenderTarget&& other) = delete; + WindowRenderTarget(graph::win::direct::DirectGraphFactory* factory, + HWND hwnd); + + CRU_DELETE_COPY(WindowRenderTarget) + CRU_DELETE_MOVE(WindowRenderTarget) + ~WindowRenderTarget() override = default; public: - graph::win::direct::IDirectFactory* GetWinNativeFactory() const { + graph::win::direct::DirectGraphFactory* GetDirectFactory() const { return factory_; } @@ -39,7 +40,7 @@ class WindowRenderTarget : public Object { void CreateTargetBitmap(); private: - graph::win::direct::IDirectFactory* factory_; + graph::win::direct::DirectGraphFactory* factory_; Microsoft::WRL::ComPtr dxgi_swap_chain_; Microsoft::WRL::ComPtr target_bitmap_; }; diff --git a/src/platform/native/CMakeLists.txt b/src/platform/native/CMakeLists.txt index bc7c4a63..be3e73a5 100644 --- a/src/platform/native/CMakeLists.txt +++ b/src/platform/native/CMakeLists.txt @@ -3,8 +3,8 @@ add_library(cru_platform_native INTERFACE) target_sources(cru_platform_native INTERFACE ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/basic_types.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/cursor.hpp - ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/native_event.hpp - ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/native_window.hpp + ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/event.hpp + ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/window.hpp ${CRU_PLATFORM_NATIVE_INCLUDE_DIR}/ui_application.hpp ) target_link_libraries(cru_platform_native INTERFACE cru_platform_graph) diff --git a/src/win/debug_logger.hpp b/src/win/debug_logger.hpp index 53c4859b..c5321828 100644 --- a/src/win/debug_logger.hpp +++ b/src/win/debug_logger.hpp @@ -1,6 +1,7 @@ #include "cru/win/win_pre_config.hpp" #include "cru/common/logger.hpp" +#include "cru/win/string.hpp" namespace cru::platform::win { @@ -14,7 +15,8 @@ class WinDebugLoggerSource : public ::cru::log::ILogSource { ~WinDebugLoggerSource() = default; void Write(::cru::log::LogLevel level, const std::string_view& s) override { - ::OutputDebugStringA(s.data()); + const std::wstring&& ws = ToUtf16String(s); + ::OutputDebugStringW(ws.data()); } }; } // namespace cru::platform::win diff --git a/src/win/graph/direct/factory.cpp b/src/win/graph/direct/factory.cpp index 7882c3ee..1fff9fa9 100644 --- a/src/win/graph/direct/factory.cpp +++ b/src/win/graph/direct/factory.cpp @@ -12,6 +12,9 @@ namespace cru::platform::graph::win::direct { DirectGraphFactory::DirectGraphFactory() { + // TODO! Detect repeated creation. Because I don't think we can create two d2d + // and dwrite factory so we need to prevent the "probably dangerous" behavior. + UINT creation_flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #ifdef CRU_DEBUG diff --git a/src/win/native/CMakeLists.txt b/src/win/native/CMakeLists.txt index 0e7e5b4e..979b54df 100644 --- a/src/win/native/CMakeLists.txt +++ b/src/win/native/CMakeLists.txt @@ -9,9 +9,9 @@ add_library(cru_win_native STATIC cursor.cpp god_window.cpp - native_window.cpp timer.cpp ui_application.cpp + window.cpp window_class.cpp window_d2d_painter.cpp window_manager.cpp @@ -21,8 +21,9 @@ target_sources(cru_win_native PUBLIC ${CRU_WIN_NATIVE_INCLUDE_DIR}/cursor.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/exception.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/god_window.hpp - ${CRU_WIN_NATIVE_INCLUDE_DIR}/native_window.hpp + ${CRU_WIN_NATIVE_INCLUDE_DIR}/resource.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/ui_application.hpp + ${CRU_WIN_NATIVE_INCLUDE_DIR}/window.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/window_class.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/window_native_message_event_args.hpp ${CRU_WIN_NATIVE_INCLUDE_DIR}/window_render_target.hpp diff --git a/src/win/native/cursor.cpp b/src/win/native/cursor.cpp index a0f9dd6c..096f3fdf 100644 --- a/src/win/native/cursor.cpp +++ b/src/win/native/cursor.cpp @@ -1,22 +1,22 @@ #include "cru/win/native/cursor.hpp" -#include "cru/common/format.hpp" #include "cru/common/logger.hpp" #include "cru/win/native/exception.hpp" #include namespace cru::platform::native::win { -WinCursor::WinCursor(HCURSOR handle, bool auto_delete) { +WinCursor::WinCursor(HCURSOR handle, bool auto_destroy) { handle_ = handle; - auto_delete_ = auto_delete; + auto_destroy_ = auto_destroy; } WinCursor::~WinCursor() { - if (auto_delete_) { + if (auto_destroy_) { if (!::DestroyCursor(handle_)) { - // This is not a fetal error but might still need notice. - log::Warn(L"Failed to destroy a cursor. Last error code: {}", + // This is not a fetal error but might still need notice because it may + // cause leak. + log::Warn("Failed to destroy a cursor. Last error code: {}", ::GetLastError()); } } @@ -27,7 +27,7 @@ WinCursor* LoadWinCursor(const wchar_t* name) { const auto handle = static_cast(::LoadImageW( NULL, name, IMAGE_CURSOR, SM_CYCURSOR, SM_CYCURSOR, LR_SHARED)); if (handle == NULL) { - throw Win32Error(::GetLastError(), "Failed to get system cursor."); + throw Win32Error(::GetLastError(), "Failed to load system cursor."); } return new WinCursor(handle, false); } @@ -38,11 +38,11 @@ WinCursorManager::WinCursorManager() sys_hand_(LoadWinCursor(IDC_HAND)) {} std::shared_ptr WinCursorManager::GetSystemWinCursor( - SystemCursor type) { + SystemCursorType type) { switch (type) { - case SystemCursor::Arrow: + case SystemCursorType::Arrow: return sys_arrow_; - case SystemCursor::Hand: + case SystemCursorType::Hand: return sys_hand_; default: throw std::runtime_error("Unknown system cursor value."); diff --git a/src/win/native/dpi_util.hpp b/src/win/native/dpi_util.hpp index a642fd79..0ebcd7e2 100644 --- a/src/win/native/dpi_util.hpp +++ b/src/win/native/dpi_util.hpp @@ -1,5 +1,4 @@ #pragma once - #include "cru/platform/native/basic_types.hpp" // The dpi awareness needs to be implemented in the future. Currently we use 96 diff --git a/src/win/native/god_window.cpp b/src/win/native/god_window.cpp index 5f1d7b53..be54f698 100644 --- a/src/win/native/god_window.cpp +++ b/src/win/native/god_window.cpp @@ -1,5 +1,6 @@ #include "cru/win/native/god_window.hpp" +#include "cru/common/logger.hpp" #include "cru/win/native/exception.hpp" #include "cru/win/native/ui_application.hpp" #include "cru/win/native/window_class.hpp" @@ -30,7 +31,7 @@ GodWindow::GodWindow(WinUiApplication* application) { const auto h_instance = application->GetInstanceHandle(); - god_window_class_ = std::make_shared(god_window_class_name, + god_window_class_ = std::make_unique(god_window_class_name, GodWndProc, h_instance); hwnd_ = CreateWindowEx(0, god_window_class_name, L"", 0, CW_USEDEFAULT, @@ -41,7 +42,12 @@ GodWindow::GodWindow(WinUiApplication* application) { throw Win32Error(::GetLastError(), "Failed to create god window."); } -GodWindow::~GodWindow() { ::DestroyWindow(hwnd_); } +GodWindow::~GodWindow() { + if (!::DestroyWindow(hwnd_)) { + // Although this could be "safely" ignore. + log::Warn("Failed to destroy god window."); + } +} bool GodWindow::HandleGodWindowMessage(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param, LRESULT* result) { diff --git a/src/win/native/native_window.cpp b/src/win/native/native_window.cpp deleted file mode 100644 index 684511b9..00000000 --- a/src/win/native/native_window.cpp +++ /dev/null @@ -1,422 +0,0 @@ -#include "cru/win/native/native_window.hpp" - -#include "cru/common/format.hpp" -#include "cru/common/logger.hpp" -#include "cru/win/graph/direct/graph_factory.hpp" -#include "cru/win/native/cursor.hpp" -#include "cru/win/native/exception.hpp" -#include "cru/win/native/ui_application.hpp" -#include "cru/win/native/window_class.hpp" -#include "cru/win/native/window_render_target.hpp" -#include "dpi_util.hpp" -#include "window_d2d_painter.hpp" -#include "window_manager.hpp" - -#include -#include - -namespace cru::platform::native::win { -inline Point PiToDip(const POINT& pi_point) { - return Point(PixelToDipX(pi_point.x), PixelToDipY(pi_point.y)); -} - -WinNativeWindow::WinNativeWindow(WinUiApplication* application, - std::shared_ptr window_class, - DWORD window_style, WinNativeWindow* parent) { - assert(application); // application can't be null. - assert(parent == nullptr || - parent->IsValid()); // Parent window is not valid. - - application_ = application; - parent_window_ = parent; - - const auto window_manager = application->GetWindowManager(); - - hwnd_ = CreateWindowExW( - 0, window_manager->GetGeneralWindowClass()->GetName(), L"", window_style, - CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, - parent == nullptr ? nullptr : parent->GetWindowHandle(), nullptr, - application->GetInstanceHandle(), nullptr); - - if (hwnd_ == nullptr) - throw Win32Error(::GetLastError(), "Failed to create window."); - - window_manager->RegisterWindow(hwnd_, this); - - window_render_target_.reset(new WindowRenderTarget( - graph::win::direct::DirectGraphFactory::GetInstance(), hwnd_)); -} - -WinNativeWindow::~WinNativeWindow() { - if (IsValid()) { - SetDeleteThisOnDestroy(false); // avoid double delete. - Close(); - } -} - -bool WinNativeWindow::IsValid() { return hwnd_ != nullptr; } - -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; -} - -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(GetWindowLongPtr(hwnd_, GWL_STYLE)); - const auto window_ex_style = - static_cast(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."); - - return Rect::FromVertices(PixelToDipX(rect.left), PixelToDipY(rect.top), - PixelToDipX(rect.right), PixelToDipY(rect.bottom)); -} - -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."); - } -} - -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{}; -} - -bool WinNativeWindow::CaptureMouse() { - if (IsValid()) { - ::SetCapture(hwnd_); - return true; - } - return false; -} - -bool WinNativeWindow::ReleaseMouse() { - if (IsValid()) { - const auto result = ::ReleaseCapture(); - return result != 0; - } - return false; -} - -void WinNativeWindow::Repaint() { - if (IsValid()) { - if (!::InvalidateRect(hwnd_, nullptr, FALSE)) - throw Win32Error(::GetLastError(), "Failed to invalidate window."); - if (!::UpdateWindow(hwnd_)) - throw Win32Error(::GetLastError(), "Failed to update window."); - } -} - -graph::Painter* WinNativeWindow::BeginPaint() { - return new WindowD2DPainter(this); -} - -void WinNativeWindow::SetCursor(std::shared_ptr cursor) { - if (!IsValid()) return; - assert(cursor); - WinCursor* c = static_cast(cursor.get()); - - auto outputError = [] { - log::Debug(L"Failed to set cursor. Last error code: {}.", ::GetLastError()); - }; - - if (!::SetClassLongPtrW(hwnd_, GCLP_HCURSOR, - reinterpret_cast(c->GetHandle()))) { - outputError(); - return; - } - - ::POINT point; - if (!::GetCursorPos(&point)) { - outputError(); - return; - } - - ::RECT rect; - if (!::GetClientRect(hwnd_, &rect)) { - outputError(); - return; - } - - ::POINT lefttop{rect.left, rect.top}; - ::POINT rightbottom{rect.right, rect.bottom}; - if (!::ClientToScreen(hwnd_, &lefttop)) { - outputError(); - return; - } - - if (!::ClientToScreen(hwnd_, &rightbottom)) { - outputError(); - return; - } - - if (point.x >= lefttop.x && point.y >= lefttop.y && - point.x <= rightbottom.x && point.y <= rightbottom.y) { - ::SetCursor(c->GetHandle()); - } -} - -bool WinNativeWindow::HandleNativeWindowMessage(HWND hwnd, UINT msg, - WPARAM w_param, LPARAM l_param, - LRESULT* result) { - WindowNativeMessageEventArgs args{ - WindowNativeMessage{hwnd, msg, w_param, l_param}}; - native_message_event_.Raise(args); - if (args.IsHandled()) { - *result = args.GetResult(); - return true; - } - - switch (msg) { - case WM_PAINT: - OnPaintInternal(); - *result = 0; - return true; - case WM_ERASEBKGND: - *result = 1; - return true; - case WM_SETFOCUS: - OnSetFocusInternal(); - *result = 0; - return true; - case WM_KILLFOCUS: - OnKillFocusInternal(); - *result = 0; - return true; - case WM_MOUSEMOVE: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseMoveInternal(point); - *result = 0; - return true; - } - case WM_LBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(platform::native::MouseButton::Left, point); - *result = 0; - return true; - } - case WM_LBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(platform::native::MouseButton::Left, point); - *result = 0; - return true; - } - case WM_RBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(platform::native::MouseButton::Right, point); - *result = 0; - return true; - } - case WM_RBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(platform::native::MouseButton::Right, point); - *result = 0; - return true; - } - case WM_MBUTTONDOWN: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseDownInternal(platform::native::MouseButton::Middle, point); - *result = 0; - return true; - } - case WM_MBUTTONUP: { - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - OnMouseUpInternal(platform::native::MouseButton::Middle, point); - *result = 0; - return true; - } - case WM_MOUSEWHEEL: - POINT point; - point.x = GET_X_LPARAM(l_param); - point.y = GET_Y_LPARAM(l_param); - ScreenToClient(hwnd, &point); - OnMouseWheelInternal(GET_WHEEL_DELTA_WPARAM(w_param), point); - *result = 0; - return true; - case WM_KEYDOWN: - OnKeyDownInternal(static_cast(w_param)); - *result = 0; - return true; - case WM_KEYUP: - OnKeyUpInternal(static_cast(w_param)); - *result = 0; - return true; - case WM_CHAR: - OnCharInternal(static_cast(w_param)); - *result = 0; - return true; - case WM_SIZE: - OnResizeInternal(LOWORD(l_param), HIWORD(l_param)); - *result = 0; - return true; - case WM_ACTIVATE: - if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE) - OnActivatedInternal(); - else if (w_param == WA_INACTIVE) - OnDeactivatedInternal(); - *result = 0; - return true; - case WM_DESTROY: - OnDestroyInternal(); - *result = 0; - return true; - default: - return false; - } -} - -RECT WinNativeWindow::GetClientRectPixel() { - RECT rect; - if (!GetClientRect(hwnd_, &rect)) - throw Win32Error(::GetLastError(), "Failed to invoke GetClientRect."); - return rect; -} - -void WinNativeWindow::OnDestroyInternal() { - application_->GetWindowManager()->UnregisterWindow(hwnd_); - hwnd_ = nullptr; - destroy_event_.Raise(nullptr); - if (delete_this_on_destroy_) - application_->InvokeLater([this] { delete this; }); -} - -void WinNativeWindow::OnPaintInternal() { - paint_event_.Raise(nullptr); - ValidateRect(hwnd_, nullptr); -} - -void WinNativeWindow::OnResizeInternal(const int new_width, - const int new_height) { - if (!(new_width == 0 && new_height == 0)) { - window_render_target_->ResizeBuffer(new_width, new_height); - resize_event_.Raise(Size{PixelToDipX(new_width), PixelToDipY(new_height)}); - } -} - -void WinNativeWindow::OnSetFocusInternal() { - has_focus_ = true; - focus_event_.Raise(true); -} - -void WinNativeWindow::OnKillFocusInternal() { - has_focus_ = false; - focus_event_.Raise(false); -} - -void WinNativeWindow::OnMouseMoveInternal(const POINT point) { - // when mouse was previous outside the window - if (!is_mouse_in_) { - // invoke TrackMouseEvent to have WM_MOUSELEAVE sent. - TRACKMOUSEEVENT tme; - tme.cbSize = sizeof tme; - tme.dwFlags = TME_LEAVE; - tme.hwndTrack = hwnd_; - - TrackMouseEvent(&tme); - - is_mouse_in_ = true; - mouse_enter_leave_event_.Raise(true); - } - - mouse_move_event_.Raise(PiToDip(point)); -} - -void WinNativeWindow::OnMouseLeaveInternal() { - is_mouse_in_ = false; - mouse_enter_leave_event_.Raise(false); -} - -void WinNativeWindow::OnMouseDownInternal(platform::native::MouseButton button, - POINT point) { - const auto dip_point = PiToDip(point); - mouse_down_event_.Raise({button, dip_point}); -} - -void WinNativeWindow::OnMouseUpInternal(platform::native::MouseButton button, - POINT point) { - const auto dip_point = PiToDip(point); - mouse_up_event_.Raise({button, dip_point}); -} - -void WinNativeWindow::OnMouseWheelInternal(short delta, POINT point) {} - -void WinNativeWindow::OnKeyDownInternal(int virtual_code) { - key_down_event_.Raise(virtual_code); -} - -void WinNativeWindow::OnKeyUpInternal(int virtual_code) { - key_up_event_.Raise(virtual_code); -} - -void WinNativeWindow::OnCharInternal(wchar_t c) {} - -void WinNativeWindow::OnActivatedInternal() {} - -void WinNativeWindow::OnDeactivatedInternal() {} -} // namespace cru::platform::native::win diff --git a/src/win/native/timer.hpp b/src/win/native/timer.hpp index 08749768..10658cf1 100644 --- a/src/win/native/timer.hpp +++ b/src/win/native/timer.hpp @@ -15,10 +15,10 @@ using TimerAction = std::function; class TimerManager : public Object { public: TimerManager(GodWindow* god_window); - TimerManager(const TimerManager& other) = delete; - TimerManager(TimerManager&& other) = delete; - TimerManager& operator=(const TimerManager& other) = delete; - TimerManager& operator=(TimerManager&& other) = delete; + + CRU_DELETE_COPY(TimerManager) + CRU_DELETE_MOVE(TimerManager) + ~TimerManager() override = default; UINT_PTR CreateTimer(UINT milliseconds, bool loop, const TimerAction& action); @@ -31,4 +31,4 @@ class TimerManager : public Object { std::map> map_{}; UINT_PTR current_count_ = 0; }; -} // namespace cru::win::native +} // namespace cru::platform::native::win diff --git a/src/win/native/ui_application.cpp b/src/win/native/ui_application.cpp index 0bbe9c03..f3a7f1dc 100644 --- a/src/win/native/ui_application.cpp +++ b/src/win/native/ui_application.cpp @@ -2,58 +2,39 @@ #include "../debug_logger.hpp" #include "cru/common/logger.hpp" -#include "cru/win/graph/direct/graph_factory.hpp" +#include "cru/platform/check.hpp" +#include "cru/win/graph/direct/factory.hpp" +#include "cru/win/native/cursor.hpp" #include "cru/win/native/exception.hpp" #include "cru/win/native/god_window.hpp" -#include "cru/win/native/native_window.hpp" +#include "cru/win/native/window.hpp" #include "god_window_message.hpp" #include "timer.hpp" #include "window_manager.hpp" -#include #include namespace cru::platform::native::win { -namespace { -WinUiApplication* instance = nullptr; -} -} // namespace cru::platform::native::win - -namespace cru::platform::native { -UiApplication* UiApplication::CreateInstance() { - auto& i = - ::cru::platform::native::win::instance; // avoid long namespace prefix - assert(i == nullptr); - i = new win::WinUiApplication(::GetModuleHandleW(nullptr)); - return i; -} +WinUiApplication* WinUiApplication::instance = nullptr; -UiApplication* UiApplication::GetInstance() { - return ::cru::platform::native::win::instance; -} -} // namespace cru::platform::native - -namespace cru::platform::native::win { -WinUiApplication* WinUiApplication::GetInstance() { return instance; } +WinUiApplication::WinUiApplication() { + if (instance) { + throw new std::runtime_error( + "Already created an instance of WinUiApplication"); + } -WinUiApplication::WinUiApplication(HINSTANCE h_instance) - : h_instance_(h_instance) { - assert(instance == nullptr); + instance = this; log::Logger::GetInstance()->AddSource( - new ::cru::platform::win::WinDebugLoggerSource()); - - if (!::IsWindows8OrGreater()) - throw std::runtime_error("Must run on Windows 8 or later."); - - const auto graph_factory = graph::GraphFactory::CreateInstance(); - graph_factory->SetAutoDelete(true); + std::make_unique<::cru::platform::win::WinDebugLoggerSource>()); - god_window_ = std::make_shared(this); - timer_manager_ = std::make_shared(god_window_.get()); - window_manager_ = std::make_shared(this); + graph_factory_ = + std::make_unique(); - cursor_manager_.reset(new WinCursorManager()); + god_window_ = std::make_unique(this); + timer_manager_ = std::make_unique(god_window_.get()); + window_manager_ = std::make_unique(this); + cursor_manager_ = std::make_unique(); } WinUiApplication::~WinUiApplication() { instance = nullptr; } @@ -67,12 +48,10 @@ int WinUiApplication::Run() { for (const auto& handler : quit_handlers_) handler(); - if (auto_delete_) delete this; - return static_cast(msg.wParam); } -void WinUiApplication::Quit(const int quit_code) { +void WinUiApplication::RequestQuit(const int quit_code) { ::PostQuitMessage(quit_code); } @@ -84,8 +63,8 @@ void WinUiApplication::InvokeLater(const std::function& action) { // copy the action to a safe place auto p_action_copy = new std::function(action); - if (PostMessageW(GetGodWindow()->GetHandle(), invoke_later_message_id, - reinterpret_cast(p_action_copy), 0) == 0) + if (::PostMessageW(GetGodWindow()->GetHandle(), invoke_later_message_id, + reinterpret_cast(p_action_copy), 0) == 0) throw Win32Error(::GetLastError(), "InvokeLater failed to post message."); } @@ -119,14 +98,17 @@ std::vector WinUiApplication::GetAllWindow() { INativeWindow* WinUiApplication::CreateWindow(INativeWindow* parent) { WinNativeWindow* p = nullptr; if (parent != nullptr) { - p = dynamic_cast(parent); - assert(p); + p = CheckPlatform(parent, GetPlatformId()); } return new WinNativeWindow(this, window_manager_->GetGeneralWindowClass(), WS_OVERLAPPEDWINDOW, p); } -WinCursorManager* WinUiApplication::GetCursorManager() { +cru::platform::graph::IGraphFactory* WinUiApplication::GetGraphFactory() { + return graph_factory_.get(); +} + +ICursorManager* WinUiApplication::GetCursorManager() { return cursor_manager_.get(); } } // namespace cru::platform::native::win diff --git a/src/win/native/window.cpp b/src/win/native/window.cpp new file mode 100644 index 00000000..517426ff --- /dev/null +++ b/src/win/native/window.cpp @@ -0,0 +1,434 @@ +#include "cru/win/native/window.hpp" + +#include "cru/common/format.hpp" +#include "cru/common/logger.hpp" +#include "cru/platform/check.hpp" +#include "cru/win/native/cursor.hpp" +#include "cru/win/native/exception.hpp" +#include "cru/win/native/ui_application.hpp" +#include "cru/win/native/window_class.hpp" +#include "cru/win/native/window_render_target.hpp" +#include "dpi_util.hpp" +#include "window_d2d_painter.hpp" +#include "window_manager.hpp" + +#include +#include + +namespace cru::platform::native::win { +inline Point PiToDip(const POINT& pi_point) { + return Point(PixelToDipX(pi_point.x), PixelToDipY(pi_point.y)); +} + +WinNativeWindow::WinNativeWindow(WinUiApplication* application, + WindowClass* window_class, DWORD window_style, + WinNativeWindow* parent) + : application_(application), parent_window_(parent) { + assert(application); // application can't be null. + + if (parent != nullptr && !parent->IsValid()) { + throw new std::runtime_error("Can't use a invalid window as parent."); + } + + const auto window_manager = application->GetWindowManager(); + + hwnd_ = CreateWindowExW( + 0, window_manager->GetGeneralWindowClass()->GetName(), L"", window_style, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + parent == nullptr ? nullptr : parent->GetWindowHandle(), nullptr, + application->GetInstanceHandle(), nullptr); + + if (hwnd_ == nullptr) + throw Win32Error(::GetLastError(), "Failed to create window."); + + window_manager->RegisterWindow(hwnd_, this); + + window_render_target_ = std::make_unique( + application->GetDirectFactory(), hwnd_); +} + +WinNativeWindow::~WinNativeWindow() { + if (IsValid()) { + SetDeleteThisOnDestroy(false); // avoid double delete. + Close(); + } +} + +bool WinNativeWindow::IsValid() { return hwnd_ != nullptr; } + +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; +} + +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(GetWindowLongPtr(hwnd_, GWL_STYLE)); + const auto window_ex_style = + static_cast(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."); + + return Rect::FromVertices(PixelToDipX(rect.left), PixelToDipY(rect.top), + PixelToDipX(rect.right), PixelToDipY(rect.bottom)); +} + +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."); + } +} + +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{}; +} + +bool WinNativeWindow::CaptureMouse() { + if (IsValid()) { + ::SetCapture(hwnd_); + return true; + } + return false; +} + +bool WinNativeWindow::ReleaseMouse() { + if (IsValid()) { + const auto result = ::ReleaseCapture(); + return result != 0; + } + return false; +} + +void WinNativeWindow::RequestRepaint() { + if (IsValid()) { + 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 WinNativeWindow::BeginPaint() { + return std::make_unique(this); +} + +void WinNativeWindow::SetCursor(std::shared_ptr cursor) { + if (cursor == nullptr) { + throw std::runtime_error("Can't use a nullptr as cursor."); + } + + if (!IsValid()) return; + + cursor_ = CheckPlatform(cursor, GetPlatformId()); + + if (!::SetClassLongPtrW(hwnd_, GCLP_HCURSOR, + reinterpret_cast(cursor_->GetHandle()))) { + log::Warn( + "Failed to set cursor because failed to set class long. Last error " + "code: {}.", + ::GetLastError()); + return; + } + + if (!IsVisible()) return; + + auto lg = [](const std::string_view& reason) { + log::Warn( + "Failed to set cursor because {} when window is visible. (We need " + "to update cursor if it is inside the window.) Last error code: {}.", + reason, ::GetLastError()); + }; + + ::POINT point; + if (!::GetCursorPos(&point)) { + lg("failed to get cursor pos"); + return; + } + + ::RECT rect; + if (!::GetClientRect(hwnd_, &rect)) { + lg("failed to get window's client rect"); + return; + } + + ::POINT lefttop{rect.left, rect.top}; + ::POINT rightbottom{rect.right, rect.bottom}; + if (!::ClientToScreen(hwnd_, &lefttop)) { + lg("failed to call ClientToScreen on lefttop"); + return; + } + + if (!::ClientToScreen(hwnd_, &rightbottom)) { + lg("failed to call ClientToScreen on rightbottom"); + return; + } + + if (point.x >= lefttop.x && point.y >= lefttop.y && + point.x <= rightbottom.x && point.y <= rightbottom.y) { + ::SetCursor(cursor_->GetHandle()); + } +} + +bool WinNativeWindow::HandleNativeWindowMessage(HWND hwnd, UINT msg, + WPARAM w_param, LPARAM l_param, + LRESULT* result) { + WindowNativeMessageEventArgs args{ + WindowNativeMessage{hwnd, msg, w_param, l_param}}; + native_message_event_.Raise(args); + if (args.IsHandled()) { + *result = args.GetResult(); + return true; + } + + switch (msg) { + case WM_PAINT: + OnPaintInternal(); + *result = 0; + return true; + case WM_ERASEBKGND: + *result = 1; + return true; + case WM_SETFOCUS: + OnSetFocusInternal(); + *result = 0; + return true; + case WM_KILLFOCUS: + OnKillFocusInternal(); + *result = 0; + return true; + case WM_MOUSEMOVE: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseMoveInternal(point); + *result = 0; + return true; + } + case WM_LBUTTONDOWN: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseDownInternal(platform::native::MouseButton::Left, point); + *result = 0; + return true; + } + case WM_LBUTTONUP: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseUpInternal(platform::native::MouseButton::Left, point); + *result = 0; + return true; + } + case WM_RBUTTONDOWN: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseDownInternal(platform::native::MouseButton::Right, point); + *result = 0; + return true; + } + case WM_RBUTTONUP: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseUpInternal(platform::native::MouseButton::Right, point); + *result = 0; + return true; + } + case WM_MBUTTONDOWN: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseDownInternal(platform::native::MouseButton::Middle, point); + *result = 0; + return true; + } + case WM_MBUTTONUP: { + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + OnMouseUpInternal(platform::native::MouseButton::Middle, point); + *result = 0; + return true; + } + case WM_MOUSEWHEEL: + POINT point; + point.x = GET_X_LPARAM(l_param); + point.y = GET_Y_LPARAM(l_param); + ScreenToClient(hwnd, &point); + OnMouseWheelInternal(GET_WHEEL_DELTA_WPARAM(w_param), point); + *result = 0; + return true; + case WM_KEYDOWN: + OnKeyDownInternal(static_cast(w_param)); + *result = 0; + return true; + case WM_KEYUP: + OnKeyUpInternal(static_cast(w_param)); + *result = 0; + return true; + case WM_CHAR: + OnCharInternal(static_cast(w_param)); + *result = 0; + return true; + case WM_SIZE: + OnResizeInternal(LOWORD(l_param), HIWORD(l_param)); + *result = 0; + return true; + case WM_ACTIVATE: + if (w_param == WA_ACTIVE || w_param == WA_CLICKACTIVE) + OnActivatedInternal(); + else if (w_param == WA_INACTIVE) + OnDeactivatedInternal(); + *result = 0; + return true; + case WM_DESTROY: + OnDestroyInternal(); + *result = 0; + return true; + default: + return false; + } +} + +RECT WinNativeWindow::GetClientRectPixel() { + RECT rect; + if (!GetClientRect(hwnd_, &rect)) + throw Win32Error(::GetLastError(), "Failed to invoke GetClientRect."); + return rect; +} + +void WinNativeWindow::OnDestroyInternal() { + application_->GetWindowManager()->UnregisterWindow(hwnd_); + hwnd_ = nullptr; + destroy_event_.Raise(nullptr); + if (delete_this_on_destroy_) + application_->InvokeLater([this] { delete this; }); +} + +void WinNativeWindow::OnPaintInternal() { + paint_event_.Raise(nullptr); + ValidateRect(hwnd_, nullptr); +} + +void WinNativeWindow::OnResizeInternal(const int new_width, + const int new_height) { + if (!(new_width == 0 && new_height == 0)) { + window_render_target_->ResizeBuffer(new_width, new_height); + resize_event_.Raise(Size{PixelToDipX(new_width), PixelToDipY(new_height)}); + } +} + +void WinNativeWindow::OnSetFocusInternal() { + has_focus_ = true; + focus_event_.Raise(FocusChangeType::Gain); +} + +void WinNativeWindow::OnKillFocusInternal() { + has_focus_ = false; + focus_event_.Raise(FocusChangeType::Lost); +} + +void WinNativeWindow::OnMouseMoveInternal(const POINT point) { + // when mouse was previous outside the window + if (!is_mouse_in_) { + // invoke TrackMouseEvent to have WM_MOUSELEAVE sent. + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof tme; + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hwnd_; + + TrackMouseEvent(&tme); + + is_mouse_in_ = true; + mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Enter); + } + + mouse_move_event_.Raise(PiToDip(point)); +} + +void WinNativeWindow::OnMouseLeaveInternal() { + is_mouse_in_ = false; + mouse_enter_leave_event_.Raise(MouseEnterLeaveType::Leave); +} + +void WinNativeWindow::OnMouseDownInternal(platform::native::MouseButton button, + POINT point) { + const auto dip_point = PiToDip(point); + mouse_down_event_.Raise({button, dip_point}); +} + +void WinNativeWindow::OnMouseUpInternal(platform::native::MouseButton button, + POINT point) { + const auto dip_point = PiToDip(point); + mouse_up_event_.Raise({button, dip_point}); +} + +void WinNativeWindow::OnMouseWheelInternal(short delta, POINT point) {} + +void WinNativeWindow::OnKeyDownInternal(int virtual_code) { + key_down_event_.Raise(virtual_code); +} + +void WinNativeWindow::OnKeyUpInternal(int virtual_code) { + key_up_event_.Raise(virtual_code); +} + +void WinNativeWindow::OnCharInternal(wchar_t c) {} + +void WinNativeWindow::OnActivatedInternal() {} + +void WinNativeWindow::OnDeactivatedInternal() {} +} // namespace cru::platform::native::win diff --git a/src/win/native/window_class.cpp b/src/win/native/window_class.cpp index d69160ab..11dc86aa 100644 --- a/src/win/native/window_class.cpp +++ b/src/win/native/window_class.cpp @@ -3,9 +3,9 @@ #include "cru/win/native/exception.hpp" namespace cru::platform::native::win { -WindowClass::WindowClass(const std::wstring& name, WNDPROC window_proc, +WindowClass::WindowClass(std::wstring name, WNDPROC window_proc, HINSTANCE h_instance) - : name_(name) { + : name_(std::move(name)) { WNDCLASSEXW window_class; window_class.cbSize = sizeof(WNDCLASSEXW); @@ -18,7 +18,7 @@ WindowClass::WindowClass(const std::wstring& name, WNDPROC window_proc, window_class.hCursor = LoadCursor(NULL, IDC_ARROW); window_class.hbrBackground = GetSysColorBrush(COLOR_BTNFACE); window_class.lpszMenuName = NULL; - window_class.lpszClassName = name.c_str(); + window_class.lpszClassName = name_.c_str(); window_class.hIconSm = NULL; atom_ = ::RegisterClassExW(&window_class); diff --git a/src/win/native/window_d2d_painter.cpp b/src/win/native/window_d2d_painter.cpp index 16d276ef..ab74a964 100644 --- a/src/win/native/window_d2d_painter.cpp +++ b/src/win/native/window_d2d_painter.cpp @@ -1,7 +1,7 @@ #include "window_d2d_painter.hpp" -#include "cru/win/graph/direct/direct_factory.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" #include "cru/win/native/window_render_target.hpp" #include @@ -11,12 +11,12 @@ using namespace cru::platform::graph::win::direct; WindowD2DPainter::WindowD2DPainter(WinNativeWindow* window) : D2DPainter(window->GetWindowRenderTarget() - ->GetWinNativeFactory() + ->GetDirectFactory() ->GetD2D1DeviceContext()), window_(window) { window->GetWindowRenderTarget()->SetAsTarget(); window->GetWindowRenderTarget() - ->GetWinNativeFactory() + ->GetDirectFactory() ->GetD2D1DeviceContext() ->BeginDraw(); } @@ -25,7 +25,7 @@ WindowD2DPainter::~WindowD2DPainter() { EndDraw(); } void WindowD2DPainter::DoEndDraw() { ThrowIfFailed(window_->GetWindowRenderTarget() - ->GetWinNativeFactory() + ->GetDirectFactory() ->GetD2D1DeviceContext() ->EndDraw()); window_->GetWindowRenderTarget()->Present(); diff --git a/src/win/native/window_d2d_painter.hpp b/src/win/native/window_d2d_painter.hpp index 1c90e8ab..6877babd 100644 --- a/src/win/native/window_d2d_painter.hpp +++ b/src/win/native/window_d2d_painter.hpp @@ -1,15 +1,13 @@ #pragma once #include "cru/win/graph/direct/painter.hpp" -#include "cru/win/native/native_window.hpp" +#include "cru/win/native/window.hpp" namespace cru::platform::native::win { class WindowD2DPainter : public graph::win::direct::D2DPainter { public: explicit WindowD2DPainter(WinNativeWindow* window); - WindowD2DPainter(const WindowD2DPainter& other) = delete; - WindowD2DPainter& operator=(const WindowD2DPainter& other) = delete; - WindowD2DPainter(WindowD2DPainter&& other) = delete; - WindowD2DPainter& operator=(WindowD2DPainter&& other) = delete; + CRU_DELETE_COPY(WindowD2DPainter) + CRU_DELETE_MOVE(WindowD2DPainter) ~WindowD2DPainter() override; protected: @@ -18,4 +16,4 @@ class WindowD2DPainter : public graph::win::direct::D2DPainter { private: WinNativeWindow* window_; }; -} // namespace cru::win::native +} // namespace cru::platform::native::win diff --git a/src/win/native/window_manager.cpp b/src/win/native/window_manager.cpp index 5699b38a..0bf7656a 100644 --- a/src/win/native/window_manager.cpp +++ b/src/win/native/window_manager.cpp @@ -1,7 +1,7 @@ #include "window_manager.hpp" #include "cru/win/native/ui_application.hpp" -#include "cru/win/native/native_window.hpp" +#include "cru/win/native/window.hpp" #include "cru/win/native/window_class.hpp" #include @@ -22,7 +22,7 @@ LRESULT __stdcall GeneralWndProc(HWND hWnd, UINT Msg, WPARAM wParam, WindowManager::WindowManager(WinUiApplication* application) { application_ = application; - general_window_class_ = std::make_shared( + general_window_class_ = std::make_unique( L"CruUIWindowClass", GeneralWndProc, application->GetInstanceHandle()); } @@ -39,7 +39,7 @@ void WindowManager::UnregisterWindow(HWND hwnd) { const auto find_result = window_map_.find(hwnd); assert(find_result != window_map_.end()); // The hwnd is not in the map. window_map_.erase(find_result); - if (window_map_.empty()) application_->Quit(0); + if (window_map_.empty()) application_->RequestQuit(0); } WinNativeWindow* WindowManager::FromHandle(HWND hwnd) { diff --git a/src/win/native/window_manager.hpp b/src/win/native/window_manager.hpp index a0661556..677719aa 100644 --- a/src/win/native/window_manager.hpp +++ b/src/win/native/window_manager.hpp @@ -15,15 +15,15 @@ class WindowClass; class WindowManager : public Object { public: WindowManager(WinUiApplication* application); - WindowManager(const WindowManager& other) = delete; - WindowManager(WindowManager&& other) = delete; - WindowManager& operator=(const WindowManager& other) = delete; - WindowManager& operator=(WindowManager&& other) = delete; + + CRU_DELETE_COPY(WindowManager) + CRU_DELETE_MOVE(WindowManager) + ~WindowManager() override; // Get the general window class for creating ordinary window. - std::shared_ptr GetGeneralWindowClass() const { - return general_window_class_; + WindowClass* GetGeneralWindowClass() const { + return general_window_class_.get(); } // Register a window newly created. @@ -45,8 +45,7 @@ class WindowManager : public Object { private: WinUiApplication* application_; - std::shared_ptr general_window_class_; + std::unique_ptr general_window_class_; std::map window_map_; }; - -} // namespace cru::win::native +} // namespace cru::platform::native::win diff --git a/src/win/native/window_render_target.cpp b/src/win/native/window_render_target.cpp index 426afdf6..f501b4dd 100644 --- a/src/win/native/window_render_target.cpp +++ b/src/win/native/window_render_target.cpp @@ -1,21 +1,22 @@ #include "cru/win/native/window_render_target.hpp" -#include "cru/win/graph/direct/direct_factory.hpp" #include "cru/win/graph/direct/exception.hpp" +#include "cru/win/graph/direct/factory.hpp" #include "dpi_util.hpp" #include namespace cru::platform::native::win { using namespace cru::platform::graph::win::direct; -WindowRenderTarget::WindowRenderTarget(IDirectFactory* factory, HWND hwnd) { - this->factory_ = factory; +WindowRenderTarget::WindowRenderTarget(DirectGraphFactory* factory, HWND hwnd) + : factory_(factory) { + assert(factory); const auto d3d11_device = factory->GetD3D11Device(); const auto dxgi_factory = factory->GetDxgiFactory(); // Allocate a descriptor. - DXGI_SWAP_CHAIN_DESC1 swap_chain_desc = {0}; + DXGI_SWAP_CHAIN_DESC1 swap_chain_desc; swap_chain_desc.Width = 0; // use automatic sizing swap_chain_desc.Height = 0; swap_chain_desc.Format = @@ -74,7 +75,7 @@ void WindowRenderTarget::CreateTargetBitmap() { ThrowIfFailed( dxgi_swap_chain_->GetBuffer(0, IID_PPV_ARGS(&dxgi_back_buffer))); - const auto dpi = GetDpi(); + const auto dpi = GetDpi(); // TODO! DPI awareness. auto bitmap_properties = D2D1::BitmapProperties1( D2D1_BITMAP_OPTIONS_TARGET | D2D1_BITMAP_OPTIONS_CANNOT_DRAW, -- cgit v1.2.3