diff --git a/docs/MULTI_WINDOW_DESIGN.md b/docs/MULTI_WINDOW_DESIGN.md index 81ade02..17fe8ac 100644 --- a/docs/MULTI_WINDOW_DESIGN.md +++ b/docs/MULTI_WINDOW_DESIGN.md @@ -1,37 +1,464 @@ + # 多窗口渲染支持设计文档 ## 1. 概述 -本文档描述了 Mirage 渲染引擎的多窗口渲染支持方案。目标是让渲染管线能够同时支持多个独立窗口的渲染,每个窗口拥有独立的 swapchain 和相关资源,同时共享底层渲染器和资源管理器。 +本文档描述了 Mirage 渲染引擎的多窗口渲染支持方案。该方案包含两个主要部分: -## 2. 现有架构分析 +1. **统一窗口管理框架** - 负责窗口实例的创建、注册、父子关系管理和事件分发 +2. **多窗口渲染管线** - 负责每个窗口的独立渲染上下文管理和渲染执行 -### 2.1 当前问题 +目标是让渲染管线能够同时支持多个独立窗口的渲染,每个窗口拥有独立的 swapchain 和相关资源,同时共享底层渲染器和资源管理器。 -1. **render_pipeline 直接持有 swapchain& 引用**:无法支持多窗口 -2. **frame_scheduler 与单一 swapchain 绑定**:同步对象和帧缓冲与单个 swapchain 关联 -3. **缺少窗口到资源的映射**:没有机制管理多个窗口的独立资源 -4. **共享资源与独立资源未分离**:所有资源混合在 render_pipeline 中 +## 2. 整体架构 -### 2.2 当前依赖关系 +### 2.1 架构层次图 ``` +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ Application Layer │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────────────┐ │ +│ │ unified_window_manager │ │ +│ │ 统一窗口管理入口,协调各组件 │ │ +│ └──────────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌──────────────────────────┼──────────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ window_factory │ │ window_registry │ │ window_id_ │ │ +│ │ 窗口创建工厂 │ │ 窗口注册表 │ │ generator │ │ +│ └─────────────────┘ └─────────────────┘ │ ID生成器 │ │ +│ └─────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────────┘ + │ + │ 协作 + ▼ +┌─────────────────────────────────────────────────────────────────────────────────┐ +│ Render Layer │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────────────┐ │ +│ │ render_pipeline │ │ +│ │ 多窗口渲染管线核心 │ │ +│ └──────────────────────────────────────────────────────────────────────────┘ │ +│ │ │ +│ ┌──────────────────────────┼──────────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ +│ │ window_render_ │ │ shared_render_ │ │ 各种 Renderer │ │ +│ │ context │ │ resources │ │ geometry/image │ │ +│ │ 每窗口渲染上下文 │ │ 共享渲染资源 │ │ /text/effects │ │ +│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────────┘ +``` + +### 2.2 核心组件关系 + +``` +unified_window_manager +├── window_id_generator // 生成唯一窗口ID +├── window_registry // 存储窗口实例和元数据 +│ └── windows_: unordered_map +│ └── window_entry +│ ├── id: window_id +│ ├── type: window_type +│ ├── state: window_state +│ ├── parent_id: window_id +│ ├── children: unordered_set +│ └── instance: window_ptr +├── window_factory // 创建各类窗口 +│ └── create_*_window() -> window_id +└── event_callback_ // 事件回调,携带 source_window + render_pipeline -├── swapchain& (单一引用,需要改为多窗口) -├── frame_scheduler (包含 swapchain 相关资源) -│ ├── acquire_semaphores -│ ├── present_semaphores -│ ├── swapchain_pass_clear/load -│ └── swapchain_framebuffers -├── offscreen_target (需要每窗口独立) -├── blit_descriptor_sets (绑定到单一 offscreen) -├── swapchain_image_initialized/consistent (每窗口状态) -└── 各种 Renderer (可共享) +├── window_contexts_: unordered_map +│ └── window_render_context // 每窗口独立渲染资源 +│ ├── swapchain +│ ├── offscreen_target +│ ├── framebuffers +│ └── sync_objects +└── shared_resources_: shared_render_resources // 共享渲染资源 + ├── renderers (geometry/image/text/effects) + ├── command_pool/buffers + └── blit_pipeline ``` -## 3. 资源分类 +### 2.3 窗口ID类型 -### 3.1 每窗口独立的资源 +**统一使用 `uint64_t` 类型**(定义于 [`src/common/window_id.h`](../src/common/window_id.h)): + +```cpp +/// 窗口唯一标识符类型 +using window_id = uint64_t; + +/// 无效窗口ID常量 +constexpr window_id INVALID_WINDOW_ID = 0; + +/// 检查窗口ID是否有效 +[[nodiscard]] constexpr auto is_valid_window_id(window_id id) noexcept -> bool; +``` + +### 2.4 窗口类型系统 + +```cpp +/// 窗口类型枚举 +enum class window_type : uint8_t { + MAIN_WINDOW = 0, ///< 主窗口 - 应用程序的主要窗口 + CHILD_WINDOW, ///< 子窗口 - 嵌入在父窗口中的窗口 + POPUP, ///< 弹出窗口 - 临时性的浮动窗口 + DIALOG, ///< 对话框 - 模态或非模态对话框 + TOOLTIP, ///< 提示窗口 - 简单的提示信息窗口 + TOOL_WINDOW, ///< 工具窗口 - 辅助工具面板 +}; + +/// 窗口状态枚举 +enum class window_state : uint8_t { + NORMAL = 0, ///< 正常状态 + MINIMIZED, ///< 最小化 + MAXIMIZED, ///< 最大化 + FULLSCREEN, ///< 全屏 + HIDDEN, ///< 隐藏 +}; +``` + +## 3. 窗口管理组件 + +### 3.1 window_id_generator - ID生成器 + +**职责**:线程安全地生成唯一的窗口ID + +**定义位置**:[`src/common/window_id.h`](../src/common/window_id.h) + +```cpp +class window_id_generator { +public: + /// 生成下一个唯一的窗口ID + [[nodiscard]] auto generate() noexcept -> window_id; + + /// 查看下一个将要生成的ID(不消耗) + [[nodiscard]] auto peek_next() const noexcept -> window_id; + + /// 获取当前已生成的最大ID + [[nodiscard]] auto current() const noexcept -> window_id; + +private: + std::atomic next_id_{0}; +}; +``` + +### 3.2 window_registry - 窗口注册表 + +**职责**: +- 窗口实例存储与查询 +- 窗口父子关系管理 +- 窗口状态追踪 +- 焦点和主窗口管理 + +**定义位置**:[`src/window/window_registry.h`](../src/window/window_registry.h) + +**核心数据结构**: + +```cpp +/// 窗口元数据条目 +struct window_entry { + window_id id{INVALID_WINDOW_ID}; ///< 窗口唯一标识符 + window_type type{window_type::MAIN_WINDOW}; ///< 窗口类型 + window_state state{window_state::NORMAL}; ///< 窗口当前状态 + window_id parent_id{INVALID_WINDOW_ID}; ///< 父窗口ID + std::unordered_set children; ///< 子窗口ID集合 + window_ptr instance; ///< 实际窗口实例 +}; +``` + +**主要接口**: + +| 方法 | 说明 | +|------|------| +| `register_window()` | 注册窗口 | +| `unregister_window()` | 注销窗口 | +| `get_window()` | 获取窗口实例 | +| `get_parent()` | 获取父窗口ID | +| `get_children()` | 获取子窗口列表 | +| `get_all_descendants()` | 获取所有后代窗口(递归) | +| `set_parent()` | 设置父窗口 | +| `is_ancestor_of()` | 检查祖先关系 | +| `set_state()` / `get_state()` | 状态管理 | +| `get_focused_window()` / `set_focused_window()` | 焦点管理 | +| `get_main_window()` / `set_main_window()` | 主窗口管理 | + +### 3.3 window_factory - 窗口工厂 + +**职责**:创建各类窗口并注册到注册表 + +**定义位置**:[`src/window/window_factory.h`](../src/window/window_factory.h) + +**创建方法**: + +```cpp +/// 创建主窗口 +[[nodiscard]] auto create_main_window(const window_create_info& info) + -> std::expected; + +/// 创建子窗口 +[[nodiscard]] auto create_child_window(window_id parent, const child_window_create_info& info) + -> std::expected; + +/// 创建弹出窗口 +[[nodiscard]] auto create_popup(window_id owner, const popup_create_info& info) + -> std::expected; + +/// 创建对话框 +[[nodiscard]] auto create_dialog(window_id owner, const dialog_create_info& info) + -> std::expected; +``` + +**特定窗口类型的创建信息**: + +```cpp +/// 弹出窗口创建信息 +struct popup_create_info { + std::string title; + uint32_t width = 200; + uint32_t height = 150; + int32_t x = 0; ///< 相对于owner的x偏移 + int32_t y = 0; ///< 相对于owner的y偏移 + bool auto_close = true; ///< 失去焦点时自动关闭 +}; + +/// 对话框创建信息 +struct dialog_create_info { + std::string title; + uint32_t width = 400; + uint32_t height = 300; + bool modal = true; ///< 是否模态 + bool resizable = false; ///< 是否可调整大小 +}; + +/// 子窗口创建信息 +struct child_window_create_info { + std::string title; + uint32_t width = 640; + uint32_t height = 480; + int32_t x = 0; ///< 相对于父窗口的x偏移 + int32_t y = 0; ///< 相对于父窗口的y偏移 + bool resizable = true; +}; +``` + +### 3.4 unified_window_manager - 统一窗口管理器 + +**职责**:窗口管理框架的统一入口,整合所有窗口管理功能 + +**定义位置**:[`src/window/unified_window_manager.h`](../src/window/unified_window_manager.h) + +**核心功能**: + +1. **窗口创建**:通过 window_factory 创建各类窗口 +2. **窗口销毁**:安全销毁窗口及其子窗口 +3. **窗口查询**:通过 window_registry 查询窗口 +4. **事件处理**:轮询事件并分发到回调函数 +5. **状态管理**:显示/隐藏/焦点控制 + +**使用示例**: + +```cpp +unified_window_manager manager; + +// 创建主窗口 +auto result = manager.create_main_window({ + .title = "My App", + .width = 1280, + .height = 720 +}); + +if (result) { + auto main_id = result.value(); + + // 设置事件回调(事件携带 source_window) + manager.set_event_callback([](window_id id, const event& e) { + // id 即为事件来源窗口 + if (e.type == event_type::WINDOW_CLOSE) { + // 处理窗口关闭 + } + }); + + // 创建子窗口 + auto child_result = manager.create_child_window(main_id, { + .title = "Child Window", + .width = 400, + .height = 300 + }); + + // 主循环 + while (manager.has_windows()) { + manager.poll_events(); + // 渲染... + } +} +``` + +**主要接口**: + +| 类别 | 方法 | +|------|------| +| 窗口创建 | `create_main_window()`, `create_child_window()`, `create_popup()`, `create_dialog()` | +| 窗口销毁 | `destroy_window()`, `destroy_all_children()` | +| 窗口查询 | `get_window()`, `contains()`, `get_window_type()`, `get_window_state()` | +| 窗口关系 | `get_parent()`, `get_children()`, `get_main_window()`, `get_focused_window()` | +| 窗口状态 | `set_window_state()`, `show_window()`, `hide_window()`, `focus_window()` | +| 事件处理 | `poll_events()`, `set_event_callback()` | +| 批量查询 | `get_all_windows()`, `get_windows_by_type()`, `get_visible_windows()` | +| 统计 | `window_count()`, `has_windows()` | + +## 4. 窗口关系管理 + +### 4.1 父子窗口关系 + +窗口注册表维护完整的父子关系树: + +``` +Main Window (id=1) +├── Child Window A (id=2, parent=1) +│ └── Popup (id=4, parent=2) +└── Child Window B (id=3, parent=1) + └── Dialog (id=5, parent=3) +``` + +**关系操作**: + +```cpp +// 获取父窗口 +window_id parent = manager.get_parent(child_id); + +// 获取直接子窗口 +std::vector children = manager.get_children(parent_id); + +// 获取所有后代窗口(递归) +std::vector descendants = manager.registry().get_all_descendants(parent_id); + +// 检查祖先关系 +bool is_ancestor = manager.registry().is_ancestor_of(ancestor_id, descendant_id); + +// 修改父窗口 +manager.registry().set_parent(child_id, new_parent_id); +``` + +### 4.2 窗口层次遍历 + +```cpp +// 深度优先遍历窗口树 +void traverse_window_tree(unified_window_manager& manager, window_id root) { + auto* window = manager.get_window(root); + if (!window) return; + + // 处理当前窗口 + process_window(root, window); + + // 递归处理子窗口 + for (window_id child : manager.get_children(root)) { + traverse_window_tree(manager, child); + } +} +``` + +### 4.3 销毁策略 + +销毁窗口时自动处理子窗口: + +```cpp +// 只销毁指定窗口(子窗口变为孤儿) +manager.destroy_window(window_id); + +// 销毁所有子窗口 +size_t count = manager.destroy_all_children(parent_id); +``` + +## 5. 事件系统 + +### 5.1 事件回调机制 + +事件回调签名: + +```cpp +/// 窗口事件回调类型 +/// @param id 事件来源窗口ID +/// @param e 事件对象 +using window_event_callback = std::function; +``` + +**设置回调**: + +```cpp +manager.set_event_callback([](window_id source, const event& e) { + switch (e.type) { + case event_type::WINDOW_CLOSE: + // source 是被关闭的窗口 + break; + case event_type::WINDOW_RESIZE: + // 处理窗口大小变化 + break; + case event_type::KEY_PRESSED: + // 处理按键事件 + break; + // ... + } +}); +``` + +### 5.2 事件源窗口 + +每个事件都携带 `source_window` 信息: + +```cpp +// event 结构体(event_types.h) +struct event { + event_type type{event_type::NONE}; + window_id source_window{INVALID_WINDOW_ID}; // 事件来源窗口ID + + union { + window_event_data window; + key_event_data key; + mouse_button_event_data mouse_button; + // ... + }; +}; +``` + +### 5.3 事件轮询 + +`poll_events()` 方法执行以下操作: + +1. 遍历所有注册的窗口 +2. 调用每个窗口的 `poll_events()` 方法 +3. 检查窗口关闭状态 +4. 将事件分发到回调函数(填充 source_window) +5. 处理待销毁的窗口(延迟销毁) + +```cpp +void unified_window_manager::poll_events() { + // 处理上一轮待销毁的窗口 + process_pending_destroys(); + + // 遍历所有窗口 + for (auto id : registry_->get_all_windows()) { + auto* window = registry_->get_window(id); + if (window) { + window->poll_events(); + + // 检查窗口关闭 + if (window->should_close()) { + handle_window_close(id); + } + } + } +} +``` + +## 6. 渲染资源分类 + +### 6.1 每窗口独立的资源 | 资源类型 | 说明 | 生命周期 | |---------|------|---------| @@ -46,7 +473,7 @@ render_pipeline | blit_descriptor_sets | 绑定该窗口离屏目标的描述符 | 窗口创建/resize | | offscreen_target | 离屏渲染目标 | 窗口创建/resize/销毁 | -### 3.2 可共享的资源 +### 6.2 可共享的资源 | 资源类型 | 说明 | 共享方式 | |---------|------|---------| @@ -66,9 +493,9 @@ render_pipeline | texture_manager | 纹理管理 | 全局共享 | | glyph_cache | 字形缓存 | 全局共享 | -## 4. 类设计 +## 7. 渲染层类设计 -### 4.1 类图结构 +### 7.1 类图结构 ``` ┌──────────────────────────────────────────────────────────────────────────────┐ @@ -134,13 +561,10 @@ render_pipeline └──────────────────────────────────────────────────────────────────────────────┘ ``` -### 4.2 window_render_context 完整接口设计 +### 7.2 window_render_context 完整接口设计 ```cpp namespace mirage { - /// 窗口标识符类型 - using window_id = uint64_t; - /// 窗口渲染上下文 - 封装每窗口独立的 Vulkan 资源 class window_render_context { public: @@ -210,8 +634,6 @@ namespace mirage { // ===================================================================== /// 处理窗口大小变化 - /// @param width 新宽度 - /// @param height 新高度 void on_resize(uint32_t width, uint32_t height); /// 执行 resize(在帧开始时调用) @@ -221,101 +643,33 @@ namespace mirage { // 状态查询 // ===================================================================== - [[nodiscard]] auto get_id() const -> window_id { return id_; } + [[nodiscard]] auto get_id() const -> window_id; [[nodiscard]] auto get_extent() const -> vk::Extent2D; - [[nodiscard]] auto get_offscreen() -> offscreen_target* { return offscreen_.get(); } - [[nodiscard]] auto get_offscreen() const -> const offscreen_target* { return offscreen_.get(); } + [[nodiscard]] auto get_offscreen() -> offscreen_target*; [[nodiscard]] auto get_swapchain_pass(bool clear) const -> vk::RenderPass; [[nodiscard]] auto get_framebuffer(uint32_t index) const -> vk::Framebuffer; [[nodiscard]] auto get_blit_descriptor(uint32_t frame_index) const -> vk::DescriptorSet; - [[nodiscard]] auto current_frame() const -> uint32_t { return current_frame_; } - [[nodiscard]] auto current_image_index() const -> uint32_t { return current_image_index_; } - [[nodiscard]] auto image_count() const -> size_t; // ===================================================================== // 增量渲染状态管理 // ===================================================================== - /// 检查是否需要全量渲染 - [[nodiscard]] auto needs_full_render() const -> bool { return need_full_render_; } - - /// 标记需要全量渲染 - void mark_full_render_needed() { need_full_render_ = true; } - - /// 清除全量渲染标记 - void clear_full_render_flag() { need_full_render_ = false; } - - /// 检查指定图像是否已初始化 + [[nodiscard]] auto needs_full_render() const -> bool; + void mark_full_render_needed(); + void clear_full_render_flag(); [[nodiscard]] auto is_image_initialized(uint32_t index) const -> bool; - - /// 标记图像已初始化 void mark_image_initialized(uint32_t index); - - /// 检查图像一致性 [[nodiscard]] auto is_image_consistent(uint32_t index) const -> bool; - - /// 标记所有图像不一致(脏区域变化时调用) void mark_all_inconsistent(); - - /// 标记指定图像一致 void mark_image_consistent(uint32_t index); /// 清理资源 void cleanup(); - - private: - window_id id_; - logical_device& device_; - resource_manager& res_mgr_; - vk::SurfaceKHR surface_; - config config_; - - // Swapchain 和相关资源 - std::unique_ptr swapchain_; - std::unique_ptr offscreen_; - - // RenderPass(与 swapchain 格式绑定) - vk::RenderPass swapchain_pass_clear_ = nullptr; - vk::RenderPass swapchain_pass_load_ = nullptr; - - // Framebuffer(每个 swapchain image 一个) - std::vector framebuffers_; - - // 同步对象 - std::vector acquire_semaphores_; - std::vector present_semaphores_; - - // Blit 描述符集(每帧一个,绑定到此窗口的 offscreen) - std::vector blit_descriptor_sets_; - - // 状态追踪 - std::vector image_initialized_; - std::vector image_consistent_; - bool need_full_render_ = true; - - // 帧状态 - uint32_t current_frame_ = 0; - uint32_t current_image_index_ = 0; - - // Resize 防抖 - bool resize_pending_ = false; - uint32_t pending_width_ = 0; - uint32_t pending_height_ = 0; - - // 内部方法 - void create_swapchain(uint32_t width, uint32_t height); - void create_renderpass(); - void create_framebuffers(); - void create_sync_objects(); - void create_offscreen(); - void allocate_blit_descriptors(const shared_render_resources& shared); - void update_blit_descriptors(const shared_render_resources& shared); - void cleanup_swapchain_resources(); }; } ``` -### 4.3 window_frame_context 结构 +### 7.3 window_frame_context 结构 ```cpp namespace mirage { @@ -329,14 +683,12 @@ namespace mirage { vk::Extent2D extent; ///< 当前渲染尺寸 /// 转换为 pass_state::frame_resources - [[nodiscard]] auto to_frame_resources() -> pass_state::frame_resources { - return pass_state::frame_resources(cmd, frame_index, offscreen); - } + [[nodiscard]] auto to_frame_resources() -> pass_state::frame_resources; }; } ``` -### 4.4 shared_render_resources 设计 +### 7.4 shared_render_resources 设计 ```cpp namespace mirage { @@ -349,393 +701,339 @@ namespace mirage { uint32_t initial_index_capacity = 8192; }; - shared_render_resources( - logical_device& device, - resource_manager& res_mgr, - texture_manager& tex_mgr, - render::text::text_shaper& text_shaper, - render::text::glyph_cache& glyph_cache, - render::text::async_mtsdf_generator* async_gen, - const config& cfg = {} - ); - - ~shared_render_resources(); - - // 禁止拷贝 - shared_render_resources(const shared_render_resources&) = delete; - auto operator=(const shared_render_resources&) -> shared_render_resources& = delete; - - /// 初始化共享资源 - /// @param sample_format swapchain 格式(用于创建兼容的 pipeline) - void initialize(vk::Format sample_format); - // ===================================================================== // 命令和同步资源访问 // ===================================================================== [[nodiscard]] auto get_command_buffer(uint32_t frame_index) -> vk::CommandBuffer; [[nodiscard]] auto get_frame_fence(uint32_t frame_index) -> vk::Fence; - [[nodiscard]] auto get_command_pool() const -> vk::CommandPool { return command_pool_; } + [[nodiscard]] auto get_command_pool() const -> vk::CommandPool; // ===================================================================== // Blit 资源访问 // ===================================================================== - [[nodiscard]] auto get_blit_pipeline() const -> vk::Pipeline { return blit_pipeline_; } - [[nodiscard]] auto get_blit_layout() const -> vk::PipelineLayout { return blit_layout_; } - [[nodiscard]] auto get_blit_desc_layout() const -> vk::DescriptorSetLayout { return blit_desc_layout_; } - [[nodiscard]] auto get_blit_desc_pool() const -> vk::DescriptorPool { return blit_desc_pool_; } - [[nodiscard]] auto get_blit_sampler() const -> vk::Sampler { return blit_sampler_; } + [[nodiscard]] auto get_blit_pipeline() const -> vk::Pipeline; + [[nodiscard]] auto get_blit_layout() const -> vk::PipelineLayout; + [[nodiscard]] auto get_blit_desc_layout() const -> vk::DescriptorSetLayout; + [[nodiscard]] auto get_blit_sampler() const -> vk::Sampler; // ===================================================================== // 渲染器访问 // ===================================================================== - [[nodiscard]] auto geometry() -> geometry_renderer* { return geometry_.get(); } - [[nodiscard]] auto imager() -> image_renderer* { return imager_.get(); } - [[nodiscard]] auto mask() -> mask_renderer* { return mask_.get(); } - [[nodiscard]] auto text() -> render::text_renderer* { return text_.get(); } - [[nodiscard]] auto effects() -> post_effect_applicator* { return effects_.get(); } - [[nodiscard]] auto target_pool() -> render::unified_target_pool* { return target_pool_.get(); } - [[nodiscard]] auto tree_builder() -> render::render_tree_builder* { return tree_builder_.get(); } - [[nodiscard]] auto tree_executor() -> render::render_tree_executor* { return tree_executor_.get(); } + [[nodiscard]] auto geometry() -> geometry_renderer*; + [[nodiscard]] auto imager() -> image_renderer*; + [[nodiscard]] auto mask() -> mask_renderer*; + [[nodiscard]] auto text() -> text_renderer*; + [[nodiscard]] auto effects() -> post_effect_applicator*; + [[nodiscard]] auto target_pool() -> unified_target_pool*; // ===================================================================== // 帧管理 // ===================================================================== - /// 等待指定帧完成 void wait_frame_fence(uint32_t frame_index); - - /// 重置指定帧栅栏 void reset_frame_fence(uint32_t frame_index); + void wait_idle(); + void cleanup(); + }; +} +``` + +## 8. 窗口创建流程 + +### 8.1 通过 unified_window_manager 创建窗口 + +``` +用户代码 unified_window_manager window_factory window_registry + │ │ │ │ + │ create_main_window(info) │ │ │ + ├───────────────────────────>│ │ │ + │ │ create_main_window(info) │ │ + │ ├───────────────────────────>│ │ + │ │ │ id_generator_.generate() + │ │ │ (生成唯一ID) │ + │ │ │ │ + │ │ │ 调用平台窗口创建 │ + │ │ │ (创建 window_ptr) │ + │ │ │ │ + │ │ │ register_window() │ + │ │ ├───────────────────────>│ + │ │ │ │ 存储 window_entry + │ │ │<───────────────────────┤ success + │ │<───────────────────────────┤ window_id │ + │ │ │ │ + │ │ setup_window_callbacks(id) │ │ + │ │ (设置事件回调) │ │ + │ │ │ │ + │<───────────────────────────┤ expected │ │ +``` + +### 8.2 完整窗口创建示例 + +```cpp +// 创建窗口管理器 +unified_window_manager window_manager; + +// 创建主窗口 +auto main_result = window_manager.create_main_window({ + .title = "Main Application", + .width = 1280, + .height = 720, + .mode = window_mode::WINDOWED, + .flags = window_flag::VISIBLE | window_flag::RESIZABLE +}); + +if (!main_result) { + std::cerr << "Failed to create main window: " << main_result.error() << std::endl; + return; +} + +window_id main_id = main_result.value(); + +// 创建子窗口 +auto child_result = window_manager.create_child_window(main_id, { + .title = "Tool Panel", + .width = 300, + .height = 400, + .x = 50, + .y = 50, + .resizable = true +}); + +// 创建弹出窗口 +auto popup_result = window_manager.create_popup(main_id, { + .title = "Context Menu", + .width = 200, + .height = 150, + .x = 100, + .y = 100, + .auto_close = true +}); + +// 创建对话框 +auto dialog_result = window_manager.create_dialog(main_id, { + .title = "Settings", + .width = 500, + .height = 400, + .modal = true, + .resizable = false +}); +``` + +## 9. 与渲染系统的集成 + +### 9.1 架构关系 + +`unified_window_manager` 和 `render_pipeline` 是独立但协作的组件: + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ Application │ +│ │ +│ ┌────────────────────────┐ ┌────────────────────────┐ │ +│ │ unified_window_manager │ │ render_pipeline │ │ +│ │ - 窗口实例管理 │ │ - 渲染上下文管理 │ │ +│ │ - 父子关系 │ │ - swapchain │ │ +│ │ - 事件分发 │ │ - 帧同步 │ │ +│ │ - 窗口状态 │ │ - 渲染执行 │ │ +│ └───────────┬────────────┘ └───────────┬────────────┘ │ +│ │ │ │ +│ │ window_id (共享标识符) │ │ +│ └───────────────┬───────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌───────────────────────┐ │ +│ │ 通过相同的 window_id │ │ +│ │ 关联窗口与渲染上下文 │ │ +│ └───────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 9.2 窗口与渲染上下文的关联 + +```cpp +// 创建窗口后,在 render_pipeline 中注册渲染上下文 +unified_window_manager window_manager; +render_pipeline pipeline(/* ... */); + +// 1. 创建窗口 +auto result = window_manager.create_main_window({ + .title = "My App", + .width = 1280, + .height = 720 +}); + +if (result) { + window_id id = result.value(); + auto* window = window_manager.get_window(id); + + // 2. 创建 Vulkan surface + VkSurfaceKHR surface = window->create_vulkan_surface(vk_instance); + + // 3. 在渲染管线注册窗口 + pipeline.register_window(id, surface, 1280, 720); +} + +// 主循环 +while (window_manager.has_windows()) { + window_manager.poll_events(); + + // 渲染每个窗口 + for (auto id : window_manager.get_visible_windows()) { + // 获取该窗口的渲染树 + auto& tree = get_render_tree_for_window(id); - /// 等待所有帧完成 - void wait_idle(); + // 渲染 + pipeline.render_frame(id, tree, current_time); + } +} - /// 清理资源 - void cleanup(); - - [[nodiscard]] auto frames_in_flight() const -> uint32_t { return config_.frames_in_flight; } - - private: - logical_device& device_; - resource_manager& res_mgr_; - texture_manager& tex_mgr_; - render::text::text_shaper& text_shaper_; - render::text::glyph_cache& glyph_cache_; - render::text::async_mtsdf_generator* async_gen_; - config config_; - - // 命令资源 - vk::CommandPool command_pool_; - std::vector command_buffers_; - - // 帧同步(按帧索引,所有窗口共享) - std::vector frame_fences_; - - // Blit 资源(所有窗口共享) - vk::Pipeline blit_pipeline_; - vk::PipelineLayout blit_layout_; - vk::DescriptorSetLayout blit_desc_layout_; - vk::DescriptorPool blit_desc_pool_; - vk::Sampler blit_sampler_; - - // 渲染器(所有窗口共享) - std::unique_ptr tree_builder_; - std::unique_ptr tree_executor_; - std::unique_ptr target_pool_; - std::unique_ptr geometry_; - std::unique_ptr imager_; - std::unique_ptr mask_; - std::unique_ptr text_; - std::unique_ptr effects_; - std::unique_ptr upload_scheduler_; - - // 内部方法 - void create_command_resources(); - void create_sync_objects(); - void create_blit_pipeline(vk::Format format); - void create_blit_resources(); - void create_renderers(vk::RenderPass offscreen_pass); - }; +// 清理 +for (auto id : window_manager.get_all_windows()) { + pipeline.unregister_window(id); } ``` -## 5. render_pipeline 修改方案 - -### 5.1 新的 render_pipeline 接口 +### 9.3 render_pipeline 多窗口接口 ```cpp -namespace mirage { - /// 多窗口渲染管线 - class render_pipeline { - public: - struct config { - uint32_t frames_in_flight = 3; - bool adaptive_sync = false; - }; +class render_pipeline { +public: + // ===================================================================== + // 窗口管理 + // ===================================================================== - render_pipeline( - logical_device& device, - resource_manager& res_mgr, - texture_manager& tex_mgr, - render::text::text_shaper& text_shaper, - render::text::glyph_cache& glyph_cache, - render::text::async_mtsdf_generator* async_gen, - const config& cfg = {} - ); + /// 注册新窗口 + [[nodiscard]] auto register_window( + window_id id, + vk::SurfaceKHR surface, + uint32_t width, + uint32_t height + ) -> bool; - ~render_pipeline(); + /// 注销窗口 + void unregister_window(window_id id); - // 禁止拷贝 - render_pipeline(const render_pipeline&) = delete; - auto operator=(const render_pipeline&) -> render_pipeline& = delete; + /// 检查窗口是否已注册 + [[nodiscard]] auto has_window(window_id id) const -> bool; - // ===================================================================== - // 初始化 - // ===================================================================== + /// 获取窗口渲染上下文 + [[nodiscard]] auto get_window_context(window_id id) -> window_render_context*; - /// 初始化管线(必须在注册第一个窗口之前调用) - /// @param sample_format 示例 swapchain 格式(用于创建 pipeline) - void initialize(vk::Format sample_format); + // ===================================================================== + // 渲染接口 + // ===================================================================== - // ===================================================================== - // 窗口管理 - // ===================================================================== + /// 渲染指定窗口的一帧 + [[nodiscard]] auto render_frame( + window_id id, + const render_tree& tree, + float time, + const std::optional& dirty_rect = std::nullopt + ) -> bool; - /// 注册新窗口 - /// @param id 窗口唯一标识 - /// @param surface 窗口表面(所有权转移) - /// @param width 初始宽度 - /// @param height 初始高度 - /// @param window_cfg 窗口配置 - /// @return 是否成功注册 - [[nodiscard]] auto register_window( - window_id id, - vk::SurfaceKHR surface, - uint32_t width, - uint32_t height, - const window_render_context::config& window_cfg = {} - ) -> bool; + // ===================================================================== + // 窗口事件 + // ===================================================================== - /// 注销窗口 - /// @param id 窗口标识 - void unregister_window(window_id id); - - /// 检查窗口是否已注册 - [[nodiscard]] auto has_window(window_id id) const -> bool; - - /// 获取窗口上下文(用于高级操作) - [[nodiscard]] auto get_window(window_id id) -> window_render_context*; - [[nodiscard]] auto get_window(window_id id) const -> const window_render_context*; - - // ===================================================================== - // 渲染接口 - // ===================================================================== - - /// 渲染指定窗口的一帧 - /// @param id 窗口标识 - /// @param commands 渲染命令列表 - /// @param time 当前时间 - /// @return 是否成功渲染 - [[nodiscard]] auto render_frame( - window_id id, - const std::vector& commands, - float time - ) -> bool; - - /// 渲染指定窗口的一帧(使用预构建渲染树) - /// @param id 窗口标识 - /// @param tree 渲染树 - /// @param time 当前时间 - /// @param dirty_rect 脏区域(可选) - /// @return 是否成功渲染 - [[nodiscard]] auto render_frame( - window_id id, - const render::render_tree& tree, - float time, - const std::optional& dirty_rect = std::nullopt - ) -> bool; - - // ===================================================================== - // 窗口事件 - // ===================================================================== - - /// 处理窗口大小变化 - void on_resize(window_id id, uint32_t width, uint32_t height); - - // ===================================================================== - // 资源管理 - // ===================================================================== - - /// 等待所有渲染完成 - void wait_idle(); - - /// 清理所有资源 - void cleanup(); - - /// 注册自定义后效 - [[nodiscard]] auto register_custom_effect( - uint32_t id, - std::span spirv - ) -> bool; - - // ===================================================================== - // 内部访问(供高级用途) - // ===================================================================== - - [[nodiscard]] auto shared_resources() -> shared_render_resources* { - return shared_.get(); - } - - private: - logical_device& device_; - resource_manager& res_mgr_; - texture_manager& tex_mgr_; - render::text::text_shaper& text_shaper_; - render::text::glyph_cache& glyph_cache_; - render::text::async_mtsdf_generator* async_gen_; - config config_; - - std::unique_ptr shared_; - std::unordered_map> windows_; - - bool initialized_ = false; - - // 内部方法 - auto render_frame_impl( - window_render_context& window, - const render::render_tree& tree, - float time, - const std::optional& dirty_rect - ) -> bool; - }; -} + /// 处理窗口大小变化 + void on_resize(window_id id, uint32_t width, uint32_t height); +}; ``` -### 5.2 render_frame 实现流程 +### 9.4 渲染帧实现流程 ```cpp -auto render_pipeline::render_frame_impl( - window_render_context& window, - const render::render_tree& tree, +auto render_pipeline::render_frame( + window_id id, + const render_tree& tree, float time, const std::optional& dirty_rect ) -> bool { - // 1. 处理 resize(如果有待处理的) - window.perform_resize_if_pending(); + // 1. 获取窗口上下文 + auto* window = get_window_context(id); + if (!window) return false; - // 2. 判断是否需要渲染 - if (!window.needs_full_render() && !dirty_rect.has_value()) { + // 2. 处理 resize(如果有待处理的) + window->perform_resize_if_pending(); + + // 3. 判断是否需要渲染 + if (!window->needs_full_render() && !dirty_rect.has_value()) { return true; // 跳过渲染 } - // 3. 获取帧索引 - uint32_t frame_index = window.current_frame(); + // 4. 获取帧索引 + uint32_t frame_index = window->current_frame(); - // 4. 等待并重置帧栅栏 + // 5. 等待并重置帧栅栏 shared_->wait_frame_fence(frame_index); shared_->reset_frame_fence(frame_index); - // 5. 开始窗口帧 + // 6. 开始窗口帧 auto cmd = shared_->get_command_buffer(frame_index); auto fence = shared_->get_frame_fence(frame_index); - auto maybe_ctx = window.begin_frame(fence, cmd); + auto maybe_ctx = window->begin_frame(fence, cmd); if (!maybe_ctx) { return false; // 需要重建 swapchain } auto win_ctx = std::move(*maybe_ctx); - // 6. 执行渲染(使用共享渲染器) - // ... (与原有逻辑类似,但使用 window 的 offscreen 和 extent) + // 7. 执行渲染 + // ... 使用共享渲染器渲染到 window 的 offscreen - // 7. 结束帧 + // 8. Blit 到 swapchain + // ... + + // 9. 结束帧 auto resources = win_ctx.to_frame_resources(); - return window.end_frame(std::move(resources), win_ctx.image_index); + return window->end_frame(std::move(resources), win_ctx.image_index); } ``` -## 6. frame_scheduler 修改方案 +## 10. 资源生命周期管理 -### 6.1 移除 frame_scheduler - -由于 `frame_scheduler` 的大部分职责已被拆分: - -- **命令和栅栏资源** → `shared_render_resources` -- **swapchain 相关资源** → `window_render_context` -- **帧同步逻辑** → 分布在 `render_pipeline` 和 `window_render_context` - -因此,`frame_scheduler` 类可以被**移除**,其功能分散到上述两个新类中。 - -### 6.2 功能迁移对照表 - -| frame_scheduler 功能 | 迁移目标 | -|---------------------|---------| -| create_sync_objects | window_render_context::create_sync_objects + shared_render_resources::create_sync_objects | -| create_command_resources | shared_render_resources::create_command_resources | -| create_swapchain_renderpass | window_render_context::create_renderpass | -| create_swapchain_framebuffers | window_render_context::create_framebuffers | -| begin_frame | window_render_context::begin_frame | -| end_frame | window_render_context::end_frame | -| on_resize | window_render_context::on_resize | -| wait_idle | shared_render_resources::wait_idle | - -## 7. 资源生命周期管理策略 - -### 7.1 窗口创建流程 +### 10.1 窗口创建流程 ``` -Application render_pipeline window_render_context shared_render_resources - │ │ │ │ - │ register_window(id,surface) │ │ │ - ├──────────────────────────────>│ │ │ - │ │ create(id, surface, w, h) │ │ - │ ├──────────────────────────────>│ │ - │ │ │ create_swapchain() │ - │ │ ├──────────────────────────────>│ - │ │ │ create_renderpass() │ - │ │ ├──────────────────────────────>│ - │ │ │ create_framebuffers() │ - │ │ ├──────────────────────────────>│ - │ │ │ create_sync_objects() │ - │ │ ├──────────────────────────────>│ - │ │ │ create_offscreen() │ - │ │ ├──────────────────────────────>│ - │ │ │ allocate_blit_descriptors() │ - │ │ ├──────────────────────────────>│ - │ │ │ update_blit_descriptors() │ - │ │ ├──────────────────────────────>│ - │ │<──────────────────────────────┤ window ready │ - │<──────────────────────────────┤ success │ │ +Application render_pipeline window_render_context + │ │ │ + │ register_window(id,surface) │ │ + ├──────────────────────────────>│ │ + │ │ create window_render_context │ + │ ├──────────────────────────────>│ + │ │ │ create_swapchain() + │ │ │ create_renderpass() + │ │ │ create_framebuffers() + │ │ │ create_sync_objects() + │ │ │ create_offscreen() + │ │ │ allocate_blit_descriptors() + │ │<──────────────────────────────┤ window ready + │<──────────────────────────────┤ success │ ``` -### 7.2 窗口销毁流程 +### 10.2 窗口销毁流程 ``` -Application render_pipeline window_render_context shared_render_resources - │ │ │ │ - │ unregister_window(id) │ │ │ - ├──────────────────────────────>│ │ │ - │ │ wait_idle() │ │ - │ ├──────────────────────────────────────────────────────────────>│ - │ │ cleanup() │ │ - │ ├──────────────────────────────>│ │ - │ │ │ cleanup_swapchain_resources │ - │ │ ├──────────────────────────────>│ - │ │ │ destroy sync objects │ - │ │ ├──────────────────────────────>│ - │ │ │ destroy offscreen │ - │ │ ├──────────────────────────────>│ - │ │ │ free blit_descriptors │ - │ │ ├──────────────────────────────>│ - │ │ │ destroy surface │ - │ │ ├──────────────────────────────>│ - │ │ remove from windows_ │ │ - │<──────────────────────────────┤ done │ │ +Application render_pipeline window_render_context + │ │ │ + │ unregister_window(id) │ │ + ├──────────────────────────────>│ │ + │ │ wait_idle() │ + │ │ cleanup() │ + │ ├──────────────────────────────>│ + │ │ │ cleanup_swapchain_resources + │ │ │ destroy sync objects + │ │ │ destroy offscreen + │ │ │ free blit_descriptors + │ │ │ destroy surface + │ │<──────────────────────────────┤ + │ │ remove from windows_ │ + │<──────────────────────────────┤ done │ ``` -### 7.3 Resize 流程 +### 10.3 Resize 流程 ``` Application render_pipeline window_render_context @@ -744,35 +1042,25 @@ Application render_pipeline window_render_conte ├──────────────────────────────>│ │ │ │ on_resize(w, h) │ │ ├──────────────────────────────>│ - │ │ │ set resize_pending_ = true + │ │ │ set resize_pending_ = true │ │ │ │ ... 下一帧渲染时 ... │ │ │ │ │ │ │ perform_resize_if_pending() │ │ ├──────────────────────────────>│ - │ │ │ wait for operations - │ │ │ cleanup_swapchain_resources - │ │ │ recreate swapchain - │ │ │ recreate renderpass - │ │ │ recreate framebuffers - │ │ │ resize offscreen - │ │ │ update_blit_descriptors - │ │ │ reset image states + │ │ │ wait for operations + │ │ │ cleanup_swapchain_resources + │ │ │ recreate swapchain + │ │ │ recreate renderpass + │ │ │ recreate framebuffers + │ │ │ resize offscreen + │ │ │ update_blit_descriptors + │ │ │ reset image states ``` -### 7.4 资源所有权规则 +## 11. 多窗口渲染时序 -1. **Surface**: 由 `window_render_context` 拥有,创建时传入,销毁时释放 -2. **Swapchain**: 由 `window_render_context` 独占拥有 -3. **Offscreen Target**: 由 `window_render_context` 独占拥有 -4. **Blit Descriptors**: 从 `shared_render_resources` 的 pool 分配,由 `window_render_context` 持有 -5. **Command Buffer**: 由 `shared_render_resources` 拥有,按帧索引借用给窗口 -6. **Fence**: 由 `shared_render_resources` 拥有,所有窗口共享同一帧索引的 fence -7. **Renderers**: 由 `shared_render_resources` 独占拥有,渲染时临时借用 - -## 8. 多窗口渲染流程图 - -### 8.1 单帧渲染流程 +### 11.1 单帧渲染流程 ``` ┌─────────────────────┐ @@ -796,10 +1084,6 @@ Application render_pipeline window_render_conte ┌────────▼────────┐ │ ┌───────▼────────┐ │ 返回 true │ │ │ 等待帧栅栏 │ └─────────────────┘ │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 重置帧栅栏 │ - │ └───────┬────────┘ │ │ │ ┌───────▼────────┐ │ │ 开始窗口帧 │ @@ -812,31 +1096,7 @@ Application render_pipeline window_render_conte └───────────────────┘ │ └───────┬────────┘ │ │ │ ┌───────▼────────┐ - │ │ 重置后效池 │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 开始渲染器帧 │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 上传纹理 │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 开始离屏 Pass │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 执行渲染树 │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 结束离屏 Pass │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ - │ │ 开始 swapchain │ + │ │ 渲染到离屏 │ │ └───────┬────────┘ │ │ │ ┌───────▼────────┐ @@ -844,77 +1104,53 @@ Application render_pipeline window_render_conte │ └───────┬────────┘ │ │ │ ┌───────▼────────┐ - │ │ 结束 swapchain │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ │ │ 提交并呈现 │ │ └───────┬────────┘ │ │ │ ┌───────▼────────┐ - │ │ 更新帧索引 │ - │ └───────┬────────┘ - │ │ - │ ┌───────▼────────┐ │ │ 返回 true │ │ └───────────────┘ ``` -### 8.2 多窗口并发渲染时序 +### 11.2 多窗口并发渲染时序 ``` -Application render_pipeline Window 1 Window 2 shared_resources - │ │ │ │ │ - │ │ 帧 N 开始 │ │ - │ render_frame(w1) │ │ │ │ - ├────────────────────>│ │ │ │ - │ │ wait_fence(idx) │ │ │ - │ ├──────────────────────────────────────────────────────────────>│ - │ │<──────────────────────────────────────────────────────────────┤ - │ │ reset_fence(idx) │ │ │ - │ ├──────────────────────────────────────────────────────────────>│ - │ │ begin_frame() │ │ │ - │ ├───────────────────>│ │ │ - │ │<───────────────────┤ │ │ - │ │ geometry.begin() │ │ │ - │ ├──────────────────────────────────────────────────────────────>│ - │ │ execute render │ │ │ - │ ├───────────────────>│ │ │ - │ │ end_frame() │ │ │ - │ ├───────────────────>│ │ │ - │ │<───────────────────┤ │ │ - │<────────────────────┤ │ │ │ - │ │ │ │ │ - │ render_frame(w2) │ │ │ │ - ├────────────────────>│ │ │ │ - │ │ 注:同一帧索引,栅栏已重置 │ │ - │ │ begin_frame() │ │ │ - │ ├────────────────────────────────────────>│ │ - │ │<────────────────────────────────────────┤ │ - │ │ geometry.begin() │ │ │ - │ ├──────────────────────────────────────────────────────────────>│ - │ │ execute render │ │ │ - │ ├────────────────────────────────────────>│ │ - │ │ end_frame() │ │ │ - │ ├────────────────────────────────────────>│ │ - │ │<────────────────────────────────────────┤ │ - │<────────────────────┤ │ │ │ +Application render_pipeline Window 1 Window 2 + │ │ │ │ + │ │ 帧 N 开始 │ + │ render_frame(w1) │ │ │ + ├────────────────────>│ │ │ + │ │ begin_frame() │ │ + │ ├───────────────────>│ │ + │ │<───────────────────┤ │ + │ │ execute render │ │ + │ ├───────────────────>│ │ + │ │ end_frame() │ │ + │ ├───────────────────>│ │ + │ │<───────────────────┤ │ + │<────────────────────┤ │ │ + │ │ │ │ + │ render_frame(w2) │ │ │ + ├────────────────────>│ │ │ + │ │ begin_frame() │ │ + │ ├────────────────────────────────────────>│ + │ │<────────────────────────────────────────┤ + │ │ execute render │ │ + │ ├────────────────────────────────────────>│ + │ │ end_frame() │ │ + │ ├────────────────────────────────────────>│ + │ │<────────────────────────────────────────┤ + │<────────────────────┤ │ │ ``` -## 9. 关键实现细节 +## 12. 关键实现细节 -### 9.1 帧索引管理 +### 12.1 帧索引管理 -**问题**: 多窗口共享 `frames_in_flight` 时,如何管理帧索引? - -**解决方案**: -- 每个窗口维护独立的 `current_frame_` 计数器 -- 所有窗口共享同一组 Fence(按帧索引) -- 当渲染某窗口时,使用该窗口的 `current_frame_` 作为帧索引 +每个窗口维护独立的 `current_frame_` 计数器,所有窗口共享同一组 Fence(按帧索引)。 ```cpp -// 在 window_render_context 中 -auto begin_frame(vk::Fence fence, vk::CommandBuffer cmd) { +auto window_render_context::begin_frame(vk::Fence fence, vk::CommandBuffer cmd) { // 使用自己的帧索引 auto& acquire_sem = acquire_semaphores_[current_frame_]; @@ -923,11 +1159,10 @@ auto begin_frame(vk::Fence fence, vk::CommandBuffer cmd) { if (!result) return std::nullopt; current_image_index_ = result.value(); - - // ... 返回上下文 + // ... } -auto end_frame(...) { +auto window_render_context::end_frame(...) { // ... 提交和呈现 // 更新帧索引 @@ -936,29 +1171,16 @@ auto end_frame(...) { } ``` -### 9.2 Blit 描述符池策略 +### 12.2 Blit 描述符池策略 -**问题**: 原设计的 `blit_desc_pool_` 只为单窗口分配描述符。按最大窗口数预分配会造成内存浪费。 - -**解决方案**: 采用**每窗口独立描述符池**策略,避免预分配浪费。 - -#### 方案对比 - -| 方案 | 优点 | 缺点 | -|------|------|------| -| 预分配最大数量 | 实现简单 | 内存浪费,不灵活 | -| 共享池+动态分配 | 内存效率较高 | 需要 FREE_DESCRIPTOR_SET 标志,碎片化风险 | -| **每窗口独立池** | 内存效率高,生命周期清晰 | 稍多的池对象 | - -#### 推荐方案:每窗口独立描述符池 +采用**每窗口独立描述符池**策略: ```cpp -// 在 window_render_context 中 class window_render_context { private: // 每窗口拥有自己的小型描述符池 - vk::DescriptorPool blit_desc_pool_; // 仅为此窗口的描述符 - std::vector blit_descriptor_sets_; // frames_in_flight 个 + vk::DescriptorPool blit_desc_pool_; + std::vector blit_descriptor_sets_; void create_blit_descriptors(const shared_render_resources& shared) { // 池大小仅为此窗口所需:frames_in_flight 个描述符 @@ -970,221 +1192,72 @@ private: pool_info.maxSets = config_.frames_in_flight; pool_info.poolSizeCount = 1; pool_info.pPoolSizes = &pool_size; - // 不需要 FREE_DESCRIPTOR_SET 标志,窗口销毁时整个池一起销毁 - auto [result, pool] = device_.get_handle().createDescriptorPool(pool_info); - blit_desc_pool_ = pool; - - // 分配描述符集 - std::vector layouts( - config_.frames_in_flight, - shared.get_blit_desc_layout() // 使用共享的布局 - ); - - vk::DescriptorSetAllocateInfo alloc_info{}; - alloc_info.descriptorPool = blit_desc_pool_; - alloc_info.descriptorSetCount = config_.frames_in_flight; - alloc_info.pSetLayouts = layouts.data(); - - auto [alloc_result, sets] = device_.get_handle().allocateDescriptorSets(alloc_info); - blit_descriptor_sets_ = sets; - } - - void cleanup_blit_descriptors() { - // 销毁整个池,自动释放所有描述符集 - if (blit_desc_pool_) { - device_.get_handle().destroyDescriptorPool(blit_desc_pool_); - blit_desc_pool_ = nullptr; - } - blit_descriptor_sets_.clear(); + // 创建池并分配描述符集 + // ... } }; ``` -#### shared_render_resources 只保留布局 +### 12.3 资源所有权规则 -```cpp -class shared_render_resources { -private: - // 只保留布局(所有窗口共用),不再持有池 - vk::DescriptorSetLayout blit_desc_layout_; - vk::Sampler blit_sampler_; - vk::Pipeline blit_pipeline_; - vk::PipelineLayout blit_layout_; - - // 移除: vk::DescriptorPool blit_desc_pool_; - -public: - // 提供布局供窗口使用 - [[nodiscard]] auto get_blit_desc_layout() const -> vk::DescriptorSetLayout { - return blit_desc_layout_; - } -}; -``` +| 资源 | 所有者 | 说明 | +|------|--------|------| +| Surface | window_render_context | 创建时传入,销毁时释放 | +| Swapchain | window_render_context | 独占拥有 | +| Offscreen Target | window_render_context | 独占拥有 | +| Blit Descriptors | window_render_context | 从自己的 pool 分配 | +| Command Buffer | shared_render_resources | 按帧索引借用 | +| Fence | shared_render_resources | 所有窗口共享 | +| Renderers | shared_render_resources | 渲染时临时借用 | -#### 内存占用分析 - -假设 `frames_in_flight = 3`: - -| 窗口数量 | 描述符集总数 | 描述符池数量 | -|---------|-------------|-------------| -| 1 窗口 | 3 | 1 | -| 2 窗口 | 6 | 2 | -| N 窗口 | 3N | N | - -**按需分配优势**: -- 资源随窗口创建/销毁动态管理 -- 无需预设最大窗口数限制 -- 每个窗口的描述符池生命周期独立、清晰 -- 窗口销毁时整个池一起销毁,无碎片化问题 - -### 9.3 渲染器状态切换 - -**问题**: 共享渲染器在不同窗口间切换时,需要更新视口等状态。 - -**解决方案**: 在每个窗口帧开始时重新设置渲染器参数 - -```cpp -void render_pipeline::render_frame_impl(window_render_context& window, ...) { - auto extent = window.get_extent(); - vec2f_t viewport_size{ - static_cast(extent.width), - static_cast(extent.height) - }; - - // 每个窗口帧开始时设置渲染器视口 - shared_->geometry()->begin_frame(frame_index, viewport_size); - shared_->imager()->begin_frame(frame_index, viewport_size); - shared_->mask()->begin_frame(frame_index, viewport_size); - shared_->text()->begin_frame(frame_index, viewport_size); - - // ... 执行渲染 -} -``` - -### 9.4 Surface 销毁顺序 - -**关键**: Surface 必须在 Swapchain 销毁后才能销毁 - -```cpp -window_render_context::~window_render_context() { - cleanup(); -} - -void window_render_context::cleanup() { - // 1. 等待设备空闲 - device_.get_handle().waitIdle(); - - // 2. 先销毁 swapchain 相关资源 - cleanup_swapchain_resources(); - - // 3. 销毁 swapchain 本身 - swapchain_.reset(); - - // 4. 销毁同步对象 - for (auto& sem : acquire_semaphores_) { /* destroy */ } - for (auto& sem : present_semaphores_) { /* destroy */ } - - // 5. 销毁 offscreen - offscreen_.reset(); - - // 6. 最后销毁 surface - if (surface_) { - // 需要 VkInstance 来销毁 surface - // 通常通过 device_ 获取或外部传入 - vkDestroySurfaceKHR(instance, surface_, nullptr); - surface_ = nullptr; - } -} -``` - -### 9.5 线程安全考虑 - -**当前设计假设**: 单线程渲染(所有 `render_frame` 调用在同一线程) - -**如果需要多线程**: -1. 为每个窗口分配独立的命令池和命令缓冲 -2. 使用互斥锁保护共享渲染器状态 -3. 考虑使用并行命令缓冲录制 - -## 10. 迁移计划 - -### 10.1 分阶段实施 - -**阶段 1: 创建新类(不破坏现有功能)** -1. 创建 `window_render_context` 类框架 -2. 创建 `shared_render_resources` 类框架 -3. 编写单元测试 - -**阶段 2: 迁移共享资源** -1. 将 blit 资源迁移到 `shared_render_resources` -2. 将渲染器迁移到 `shared_render_resources` -3. 将命令和栅栏资源迁移 -4. 验证现有功能不受影响 - -**阶段 3: 迁移窗口资源** -1. 将 swapchain 相关资源迁移到 `window_render_context` -2. 将 offscreen 迁移 -3. 实现 begin_frame/end_frame -4. 验证单窗口渲染 - -**阶段 4: 重构 render_pipeline** -1. 修改为多窗口接口 -2. 移除 frame_scheduler -3. 提供向后兼容的简化接口(可选) - -**阶段 5: 测试和优化** -1. 多窗口场景测试 -2. 性能基准测试 -3. 边界条件测试(resize、窗口销毁等) - -### 10.2 向后兼容建议 - -为保持向后兼容,可提供简化的单窗口接口: - -```cpp -class render_pipeline { -public: - // 新的多窗口接口 - auto register_window(...) -> bool; - auto render_frame(window_id, ...) -> bool; - - // 向后兼容的单窗口接口(使用默认窗口 ID) - static constexpr window_id DEFAULT_WINDOW = 0; - - auto render_frame(const render_tree& tree, float time, ...) -> bool { - return render_frame(DEFAULT_WINDOW, tree, time, ...); - } -}; -``` - -## 11. 文件结构建议 +## 13. 文件结构 ``` +src/common/ +├── window_id.h # 统一窗口ID类型定义 + +src/window/ +├── window_id.h # 窗口ID生成器(引用 common/window_id.h) +├── window_type.h # 窗口类型枚举定义 +├── window_registry.h # 窗口注册表 +├── window_registry.cpp +├── window_factory.h # 窗口工厂 +├── window_factory.cpp +├── unified_window_manager.h # 统一窗口管理器 +├── unified_window_manager.cpp +└── ... + src/render/pipeline/ -├── window_render_context.h # 窗口渲染上下文 +├── window_render_context.h # 窗口渲染上下文 ├── window_render_context.cpp -├── shared_render_resources.h # 共享渲染资源 +├── shared_render_resources.h # 共享渲染资源 ├── shared_render_resources.cpp -├── render_pipeline.h # 修改后的渲染管线 +├── render_pipeline.h # 多窗口渲染管线 ├── render_pipeline.cpp -├── frame_context.h # 保持不变 -├── pass_state_tags.h # 保持不变 -└── ... (其他现有文件) +└── ... ``` -## 12. 总结 +## 14. 总结 本设计方案通过以下方式实现多窗口渲染支持: -1. **资源分离**: 将每窗口独立资源封装到 `window_render_context`,共享资源封装到 `shared_render_resources` -2. **清晰的所有权**: 每个类明确拥有和管理其资源的生命周期 -3. **最小化改动**: 复用现有的 `frame_context` 和 pass state 机制 -4. **向后兼容**: 可选的简化接口保持旧代码可用 -5. **可扩展性**: 设计支持未来扩展(如多线程渲染) +| 方面 | 解决方案 | +|------|----------| +| 窗口ID统一 | 使用 `uint64_t` 类型的 `window_id`,定义于 `common/window_id.h` | +| 窗口实例管理 | `window_registry` 存储窗口实例和元数据 | +| 窗口创建 | `window_factory` 提供各类窗口的创建方法 | +| 父子关系 | `window_registry` 维护父子关系树 | +| 事件分发 | `unified_window_manager` 统一轮询和分发事件 | +| 渲染资源隔离 | `window_render_context` 封装每窗口独立资源 | +| 渲染资源共享 | `shared_render_resources` 管理共享渲染器 | +| 协调机制 | 通过相同的 `window_id` 关联窗口与渲染上下文 | 关键优势: -- 窗口间资源隔离,互不影响 -- 共享渲染器减少内存占用 -- 统一的帧同步机制 -- 灵活的 resize 处理 \ No newline at end of file + +- **类型安全**:统一的 `window_id` 类型避免类型不一致 +- **清晰的职责分离**:窗口管理与渲染管理独立但协作 +- **完整的层次管理**:支持父子窗口关系和层次遍历 +- **灵活的事件系统**:事件携带 `source_window` 信息 +- **高效的资源管理**:共享渲染器、独立渲染上下文 +- **线程安全**:`window_registry` 使用读写锁 \ No newline at end of file diff --git a/docs/WINDOW_MANAGEMENT_REFACTOR.md b/docs/WINDOW_MANAGEMENT_REFACTOR.md new file mode 100644 index 0000000..0d77233 --- /dev/null +++ b/docs/WINDOW_MANAGEMENT_REFACTOR.md @@ -0,0 +1,1270 @@ +# 统一窗口管理框架架构方案 + +## 1. 概述 + +本文档描述了 Mirage 引擎窗口管理框架的重构方案,旨在解决现有架构中的不一致性和不完善问题,建立统一、可扩展的多窗口管理系统。 + +## 2. 现有问题分析 + +### 2.1 问题清单 + +| 问题 | 位置 | 描述 | +|------|------|------| +| 窗口ID类型不一致 | `window_manager.h:19` vs `window_render_context.h:16` | `window_manager` 使用 `uint32_t`,`window_render_context` 使用 `uint64_t` | +| 单窗口持有 | `application.h:325` | `application` 持有单个 `window_` 指针,多窗口支持不完善 | +| 事件缺少源窗口 | `event_types.h:206` | `event` 结构体无 `source_window` 字段 | +| 缺少窗口类型 | `window_types.h` | 只有 `window_mode`,缺少窗口类型枚举 | +| 缺少父子关系 | 整体架构 | 无窗口层级管理机制 | +| 组件解耦不完整 | `window_manager` + `render_pipeline` | 两者需手动同步 | + +### 2.2 现有架构依赖 + +``` +application +├── window_manager (管理窗口实例) +│ └── windows_: std::unordered_map +├── render_pipeline (管理渲染上下文) +│ └── window_contexts_: std::unordered_map +└── window_ (单个窗口指针,冗余) +``` + +## 3. 新架构设计 + +### 3.1 架构类图 + +``` +┌──────────────────────────────────────────────────────────────────────────────────────┐ +│ unified_window_manager │ +├──────────────────────────────────────────────────────────────────────────────────────┤ +│ - registry_: window_registry │ +│ - factory_: window_factory │ +│ - render_pipeline_: render_pipeline* │ +│ - event_dispatcher_: window_event_dispatcher │ +├──────────────────────────────────────────────────────────────────────────────────────┤ +│ + create_main_window(create_info) -> expected │ +│ + create_child_window(parent, create_info) -> expected │ +│ + create_popup(owner, popup_info) -> expected │ +│ + create_dialog(owner, dialog_info) -> expected │ +│ + destroy_window(id) -> bool │ +│ + get_window(id) -> window_interface* │ +│ + get_render_context(id) -> window_render_context* │ +│ + poll_events() -> void │ +│ + dispatch_event(event) -> void │ +└──────────────────────────────────────────────────────────────────────────────────────┘ + │ + ┌────────────────────┼────────────────────┬──────────────────────┐ + │ │ │ │ + ▼ ▼ ▼ ▼ +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────────┐ +│ window_factory │ │ window_registry │ │ render_pipeline │ │window_event_dispatcher│ +├──────────────────┤ ├──────────────────┤ ├──────────────────┤ ├──────────────────────┤ +│ create_window() │ │ windows_ │ │ window_contexts_ │ │ event_handlers_ │ +│ create_surface() │ │ parent_child_ │ │ shared_resources │ │ dispatch() │ +│ get_create_info()│ │ window_states_ │ │ render_window() │ │ register_handler() │ +└──────────────────┘ └──────────────────┘ └──────────────────┘ └──────────────────────┘ +``` + +### 3.2 核心类型定义 + +#### 3.2.1 统一窗口ID类型 - window_id.h + +```cpp +#pragma once + +#include +#include +#include + +namespace mirage { + /// 统一窗口标识符类型 + /// 使用 uint64_t 以支持: + /// - 高32位:窗口类型和标志 + /// - 低32位:窗口序号 + using window_id = uint64_t; + + /// 无效窗口ID常量 + constexpr window_id INVALID_WINDOW_ID = 0; + + /// 主窗口ID常量(首个创建的主窗口) + constexpr window_id MAIN_WINDOW_ID = 1; + + /// 窗口ID生成器 + class window_id_generator { + public: + /// 生成下一个窗口ID + /// @param type 窗口类型 + /// @return 新的窗口ID + [[nodiscard]] static auto generate(uint32_t type_flags) -> window_id; + + /// 从ID提取窗口类型标志 + [[nodiscard]] static auto get_type_flags(window_id id) -> uint32_t; + + /// 从ID提取序号 + [[nodiscard]] static auto get_sequence(window_id id) -> uint32_t; + + private: + static inline std::atomic sequence_counter_{1}; + }; + + /// 窗口ID哈希函数(用于 unordered_map) + struct window_id_hash { + auto operator()(window_id id) const noexcept -> std::size_t { + return std::hash{}(id); + } + }; +} // namespace mirage +``` + +#### 3.2.2 窗口类型枚举 - window_type.h + +```cpp +#pragma once + +#include +#include + +namespace mirage { + /// 窗口类型枚举 + enum class window_type : uint8_t { + MAIN_WINDOW = 0, ///< 主窗口 - 应用程序的主要窗口 + CHILD_WINDOW, ///< 子窗口 - 嵌入在父窗口中的窗口 + POPUP, ///< 弹出窗口 - 临时性的浮动窗口 + DIALOG, ///< 对话框 - 模态或非模态对话框 + TOOLTIP, ///< 提示窗口 - 简单的提示信息窗口 + TOOL_WINDOW, ///< 工具窗口 - 辅助工具面板 + SPLASH, ///< 启动画面 - 应用启动时的闪屏窗口 + }; + + /// 窗口类型转字符串 + [[nodiscard]] constexpr auto window_type_to_string(window_type type) -> std::string_view { + switch (type) { + case window_type::MAIN_WINDOW: return "MAIN_WINDOW"; + case window_type::CHILD_WINDOW: return "CHILD_WINDOW"; + case window_type::POPUP: return "POPUP"; + case window_type::DIALOG: return "DIALOG"; + case window_type::TOOLTIP: return "TOOLTIP"; + case window_type::TOOL_WINDOW: return "TOOL_WINDOW"; + case window_type::SPLASH: return "SPLASH"; + default: return "UNKNOWN"; + } + } + + /// 窗口关系类型 + enum class window_relationship : uint8_t { + NONE = 0, ///< 无关系 + PARENT_CHILD, ///< 父子关系(子窗口随父窗口移动/关闭) + OWNER_OWNED, ///< 所有者关系(owned窗口在owner之上,但独立移动) + }; + + /// 对话框类型 + enum class dialog_type : uint8_t { + MODAL = 0, ///< 模态对话框 - 阻止与其他窗口交互 + MODELESS, ///< 非模态对话框 - 允许与其他窗口交互 + SYSTEM_MODAL, ///< 系统模态 - 阻止与所有应用窗口交互 + }; + + /// 窗口状态 + enum class window_state : uint8_t { + NORMAL = 0, ///< 正常状态 + MINIMIZED, ///< 最小化 + MAXIMIZED, ///< 最大化 + FULLSCREEN, ///< 全屏 + HIDDEN, ///< 隐藏 + }; +} // namespace mirage +``` + +#### 3.2.3 增强事件结构 - enhanced_event.h + +```cpp +#pragma once + +#include "window_id.h" +#include "event/event_types.h" + +namespace mirage { + /// 增强事件基类 - 携带源窗口信息 + struct window_event_base { + /// 源窗口ID + window_id source_window{INVALID_WINDOW_ID}; + + /// 事件时间戳(毫秒) + uint64_t timestamp{0}; + + /// 事件是否已被处理 + bool handled{false}; + }; + + /// 增强通用事件结构 + struct enhanced_event : window_event_base { + /// 事件类型 + event_type type{event_type::NONE}; + + union { + window_event_data window; + key_event_data key; + char_input_event_data char_input; + mouse_button_event_data mouse_button; + mouse_move_event_data mouse_move; + mouse_scroll_event_data mouse_scroll; + }; + + enhanced_event() : type(event_type::NONE), window{} {} + + explicit enhanced_event(event_type t, window_id src = INVALID_WINDOW_ID) + : type(t), window{} { + source_window = src; + } + + /// 从旧事件结构转换 + static auto from_legacy(const event& e, window_id src) -> enhanced_event { + enhanced_event result; + result.type = e.type; + result.source_window = src; + + // 复制事件数据 + switch (e.type) { + case event_type::WINDOW_CLOSE: + case event_type::WINDOW_RESIZE: + case event_type::WINDOW_FOCUS: + case event_type::WINDOW_LOST_FOCUS: + case event_type::WINDOW_MOVED: + case event_type::WINDOW_MINIMIZED: + case event_type::WINDOW_MAXIMIZED: + case event_type::WINDOW_RESTORED: + result.window = e.window; + break; + case event_type::KEY_PRESSED: + case event_type::KEY_RELEASED: + case event_type::KEY_REPEAT: + result.key = e.key; + break; + case event_type::CHAR_INPUT: + result.char_input = e.char_input; + break; + case event_type::MOUSE_BUTTON_PRESSED: + case event_type::MOUSE_BUTTON_RELEASED: + result.mouse_button = e.mouse_button; + break; + case event_type::MOUSE_MOVED: + case event_type::MOUSE_ENTERED: + case event_type::MOUSE_LEFT: + result.mouse_move = e.mouse_move; + break; + case event_type::MOUSE_SCROLLED: + result.mouse_scroll = e.mouse_scroll; + break; + default: + break; + } + return result; + } + }; + + /// 窗口创建事件 + struct window_created_event : window_event_base { + window_type type{window_type::MAIN_WINDOW}; + window_id parent_id{INVALID_WINDOW_ID}; + }; + + /// 窗口销毁事件 + struct window_destroyed_event : window_event_base { + // 窗口已被销毁,source_window 是被销毁的窗口ID + }; + + /// 窗口焦点变化事件 + struct window_focus_event : window_event_base { + bool focused{false}; + window_id previous_focus{INVALID_WINDOW_ID}; + }; + + /// 窗口父子关系变化事件 + struct window_hierarchy_event : window_event_base { + window_id old_parent{INVALID_WINDOW_ID}; + window_id new_parent{INVALID_WINDOW_ID}; + }; +} // namespace mirage +``` + +### 3.3 窗口创建信息扩展 + +```cpp +#pragma once + +#include "window_types.h" +#include "window_type.h" +#include "window_id.h" + +namespace mirage { + /// 扩展窗口创建信息 + struct extended_window_create_info : window_create_info { + /// 窗口类型 + window_type type{window_type::MAIN_WINDOW}; + + /// 父窗口ID(仅对 CHILD_WINDOW 有效) + window_id parent{INVALID_WINDOW_ID}; + + /// 所有者窗口ID(仅对 POPUP、DIALOG 有效) + window_id owner{INVALID_WINDOW_ID}; + + /// 初始状态 + window_state initial_state{window_state::NORMAL}; + + /// 是否创建对应的渲染上下文 + bool create_render_context{true}; + + /// 构造函数 - 从基础创建信息转换 + extended_window_create_info() = default; + + explicit extended_window_create_info(const window_create_info& base) + : window_create_info(base) {} + }; + + /// 弹出窗口创建信息 + struct popup_create_info { + /// 基础窗口信息 + extended_window_create_info base; + + /// 相对于所有者的位置(屏幕坐标) + int32_t relative_x{0}; + int32_t relative_y{0}; + + /// 是否自动关闭(点击外部时) + bool auto_close{true}; + + /// 是否显示阴影 + bool show_shadow{true}; + + popup_create_info() { + base.type = window_type::POPUP; + base.flags = window_flag::VISIBLE; // 无边框 + } + }; + + /// 对话框创建信息 + struct dialog_create_info { + /// 基础窗口信息 + extended_window_create_info base; + + /// 对话框类型 + dialog_type dialog_type{dialog_type::MODAL}; + + /// 是否居中显示 + bool center_on_owner{true}; + + /// 是否可拖动 + bool draggable{true}; + + /// 是否显示关闭按钮 + bool show_close_button{true}; + + dialog_create_info() { + base.type = window_type::DIALOG; + base.flags = window_flag::VISIBLE | window_flag::DECORATED; + } + }; + + /// tooltip创建信息 + struct tooltip_create_info { + /// 基础窗口信息 + extended_window_create_info base; + + /// 显示延迟(毫秒) + uint32_t show_delay_ms{500}; + + /// 自动隐藏延迟(毫秒,0表示不自动隐藏) + uint32_t hide_delay_ms{5000}; + + /// 跟随鼠标 + bool follow_cursor{false}; + + tooltip_create_info() { + base.type = window_type::TOOLTIP; + base.flags = window_flag::VISIBLE; + base.create_render_context = true; + } + }; +} // namespace mirage +``` + +### 3.4 窗口注册表 - window_registry + +```cpp +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_common.h" + +#include +#include +#include +#include + +namespace mirage { + /// 窗口注册信息 + struct window_registration_info { + window_id id{INVALID_WINDOW_ID}; + window_type type{window_type::MAIN_WINDOW}; + window_state state{window_state::NORMAL}; + window_id parent{INVALID_WINDOW_ID}; + window_id owner{INVALID_WINDOW_ID}; + window_relationship relationship{window_relationship::NONE}; + window_ptr window; // 拥有窗口实例 + }; + + /// 窗口注册表 - 管理窗口实例存储与查询 + class window_registry { + public: + window_registry() = default; + ~window_registry() = default; + + // 禁止拷贝 + window_registry(const window_registry&) = delete; + auto operator=(const window_registry&) -> window_registry& = delete; + + // ===================================================================== + // 窗口注册/注销 + // ===================================================================== + + /// 注册窗口 + /// @param info 窗口注册信息(所有权转移) + /// @return 是否成功 + [[nodiscard]] auto register_window(window_registration_info info) -> bool; + + /// 注销窗口 + /// @param id 窗口ID + /// @return 被注销的窗口指针(所有权转移给调用者) + [[nodiscard]] auto unregister_window(window_id id) -> window_ptr; + + /// 检查窗口是否已注册 + [[nodiscard]] auto is_registered(window_id id) const -> bool; + + // ===================================================================== + // 窗口查询 + // ===================================================================== + + /// 获取窗口实例 + [[nodiscard]] auto get_window(window_id id) -> window_interface*; + [[nodiscard]] auto get_window(window_id id) const -> const window_interface*; + + /// 获取窗口类型 + [[nodiscard]] auto get_window_type(window_id id) const -> std::optional; + + /// 获取窗口状态 + [[nodiscard]] auto get_window_state(window_id id) const -> std::optional; + + /// 设置窗口状态 + auto set_window_state(window_id id, window_state state) -> bool; + + /// 获取所有窗口ID + [[nodiscard]] auto get_all_window_ids() const -> std::vector; + + /// 获取指定类型的所有窗口ID + [[nodiscard]] auto get_windows_by_type(window_type type) const -> std::vector; + + /// 获取窗口数量 + [[nodiscard]] auto get_window_count() const -> size_t; + + // ===================================================================== + // 父子关系管理 + // ===================================================================== + + /// 获取父窗口ID + [[nodiscard]] auto get_parent(window_id id) const -> window_id; + + /// 获取所有者窗口ID + [[nodiscard]] auto get_owner(window_id id) const -> window_id; + + /// 获取子窗口列表 + [[nodiscard]] auto get_children(window_id parent) const -> std::vector; + + /// 获取owned窗口列表 + [[nodiscard]] auto get_owned_windows(window_id owner) const -> std::vector; + + /// 设置父窗口 + auto set_parent(window_id child, window_id parent) -> bool; + + /// 检查是否为祖先窗口 + [[nodiscard]] auto is_ancestor_of(window_id ancestor, window_id descendant) const -> bool; + + // ===================================================================== + // 焦点管理 + // ===================================================================== + + /// 获取当前焦点窗口 + [[nodiscard]] auto get_focused_window() const -> window_id; + + /// 设置焦点窗口 + auto set_focused_window(window_id id) -> void; + + // ===================================================================== + // 主窗口管理 + // ===================================================================== + + /// 获取主窗口ID + [[nodiscard]] auto get_main_window() const -> window_id; + + /// 设置主窗口ID + auto set_main_window(window_id id) -> void; + + private: + /// 窗口存储 + std::unordered_map windows_; + + /// 父子关系映射(parent -> children) + std::unordered_map, window_id_hash> children_map_; + + /// 所有者关系映射(owner -> owned) + std::unordered_map, window_id_hash> owned_map_; + + /// 主窗口ID + window_id main_window_{INVALID_WINDOW_ID}; + + /// 当前焦点窗口 + window_id focused_window_{INVALID_WINDOW_ID}; + + /// 读写锁(线程安全) + mutable std::shared_mutex mutex_; + + // 内部辅助方法 + auto remove_from_children_map(window_id parent, window_id child) -> void; + auto remove_from_owned_map(window_id owner, window_id owned) -> void; + }; +} // namespace mirage +``` + +### 3.5 窗口工厂 - window_factory + +```cpp +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_common.h" +#include "extended_window_create_info.h" + +#include + +namespace mirage { + // 前向声明 + class window_registry; + class render_pipeline; + class logical_device; + + /// 窗口工厂 - 负责创建各类窗口 + class window_factory { + public: + /// 构造函数 + /// @param registry 窗口注册表引用 + /// @param render_pipeline 渲染管线引用(可选,用于创建渲染上下文) + window_factory( + window_registry& registry, + render_pipeline* render_pipeline = nullptr + ); + + ~window_factory() = default; + + /// 设置渲染管线(延迟设置) + auto set_render_pipeline(render_pipeline* pipeline) -> void; + + // ===================================================================== + // 窗口创建接口 + // ===================================================================== + + /// 创建主窗口 + /// @param info 创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_main_window( + const window_create_info& info + ) -> std::expected; + + /// 创建子窗口 + /// @param parent 父窗口ID + /// @param info 创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_child_window( + window_id parent, + const window_create_info& info + ) -> std::expected; + + /// 创建弹出窗口 + /// @param owner 所有者窗口ID + /// @param info 弹出窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_popup( + window_id owner, + const popup_create_info& info + ) -> std::expected; + + /// 创建对话框 + /// @param owner 所有者窗口ID + /// @param info 对话框创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_dialog( + window_id owner, + const dialog_create_info& info + ) -> std::expected; + + /// 创建tooltip窗口 + /// @param owner 所有者窗口ID + /// @param info tooltip创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_tooltip( + window_id owner, + const tooltip_create_info& info + ) -> std::expected; + + /// 通用窗口创建 + /// @param info 扩展创建信息 + /// @return 成功返回窗口ID,失败返回错误 + [[nodiscard]] auto create_window( + const extended_window_create_info& info + ) -> std::expected; + + private: + window_registry& registry_; + render_pipeline* render_pipeline_; + + /// 创建窗口实现 + [[nodiscard]] auto create_window_impl( + const extended_window_create_info& info + ) -> std::expected; + + /// 为窗口创建渲染上下文 + [[nodiscard]] auto create_render_context_for_window( + window_id id, + window_interface* window + ) -> bool; + }; +} // namespace mirage +``` + +### 3.6 统一窗口管理器 - unified_window_manager + +```cpp +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_registry.h" +#include "window_factory.h" +#include "enhanced_event.h" + +#include +#include + +namespace mirage { + // 前向声明 + class render_pipeline; + class window_render_context; + + /// 窗口事件处理器类型 + using window_event_handler = std::function; + + /// 统一窗口管理器 - 整合窗口管理的所有功能 + class unified_window_manager { + public: + /// 构造函数 + unified_window_manager(); + ~unified_window_manager(); + + // 禁止拷贝和移动 + unified_window_manager(const unified_window_manager&) = delete; + unified_window_manager& operator=(const unified_window_manager&) = delete; + unified_window_manager(unified_window_manager&&) = delete; + unified_window_manager& operator=(unified_window_manager&&) = delete; + + // ===================================================================== + // 初始化 + // ===================================================================== + + /// 初始化窗口管理器 + /// @param render_pipeline 渲染管线指针(可选) + auto initialize(render_pipeline* pipeline = nullptr) -> void; + + /// 设置渲染管线 + auto set_render_pipeline(render_pipeline* pipeline) -> void; + + // ===================================================================== + // 窗口创建接口 + // ===================================================================== + + /// 创建主窗口 + [[nodiscard]] auto create_main_window( + const window_create_info& info + ) -> std::expected; + + /// 创建子窗口 + [[nodiscard]] auto create_child_window( + window_id parent, + const window_create_info& info + ) -> std::expected; + + /// 创建弹出窗口 + [[nodiscard]] auto create_popup( + window_id owner, + const popup_create_info& info + ) -> std::expected; + + /// 创建对话框 + [[nodiscard]] auto create_dialog( + window_id owner, + const dialog_create_info& info + ) -> std::expected; + + /// 创建tooltip + [[nodiscard]] auto create_tooltip( + window_id owner, + const tooltip_create_info& info + ) -> std::expected; + + // ===================================================================== + // 窗口销毁 + // ===================================================================== + + /// 销毁窗口 + /// @param id 窗口ID + /// @return 是否成功 + [[nodiscard]] auto destroy_window(window_id id) -> bool; + + /// 销毁窗口及其所有子窗口 + [[nodiscard]] auto destroy_window_tree(window_id id) -> bool; + + // ===================================================================== + // 窗口查询 + // ===================================================================== + + /// 获取窗口实例 + [[nodiscard]] auto get_window(window_id id) -> window_interface*; + [[nodiscard]] auto get_window(window_id id) const -> const window_interface*; + + /// 获取窗口渲染上下文 + [[nodiscard]] auto get_render_context(window_id id) -> window_render_context*; + [[nodiscard]] auto get_render_context(window_id id) const -> const window_render_context*; + + /// 获取所有窗口ID + [[nodiscard]] auto get_all_window_ids() const -> std::vector; + + /// 获取窗口数量 + [[nodiscard]] auto get_window_count() const -> size_t; + + /// 获取主窗口 + [[nodiscard]] auto get_main_window() const -> window_id; + + /// 获取焦点窗口 + [[nodiscard]] auto get_focused_window() const -> window_id; + + // ===================================================================== + // 窗口关系 + // ===================================================================== + + /// 获取父窗口 + [[nodiscard]] auto get_parent(window_id id) const -> window_id; + + /// 获取子窗口列表 + [[nodiscard]] auto get_children(window_id id) const -> std::vector; + + /// 获取所有者窗口 + [[nodiscard]] auto get_owner(window_id id) const -> window_id; + + /// 获取owned窗口列表 + [[nodiscard]] auto get_owned_windows(window_id id) const -> std::vector; + + // ===================================================================== + // 事件处理 + // ===================================================================== + + /// 轮询所有窗口事件 + auto poll_events() -> void; + + /// 分发事件到处理器 + auto dispatch_event(const enhanced_event& event) -> void; + + /// 注册全局事件处理器 + auto register_global_handler(window_event_handler handler) -> size_t; + + /// 注册窗口事件处理器 + auto register_window_handler(window_id id, window_event_handler handler) -> size_t; + + /// 移除事件处理器 + auto unregister_handler(size_t handler_id) -> void; + + // ===================================================================== + // 状态管理 + // ===================================================================== + + /// 检查是否所有窗口都已关闭 + [[nodiscard]] auto all_windows_closed() const -> bool; + + /// 获取窗口状态 + [[nodiscard]] auto get_window_state(window_id id) const -> std::optional; + + /// 设置窗口状态 + auto set_window_state(window_id id, window_state state) -> bool; + + private: + /// 窗口注册表 + std::unique_ptr registry_; + + /// 窗口工厂 + std::unique_ptr factory_; + + /// 渲染管线引用 + render_pipeline* render_pipeline_{nullptr}; + + /// 全局事件处理器 + std::vector> global_handlers_; + + /// 窗口事件处理器映射 + std::unordered_map>, window_id_hash> window_handlers_; + + /// 处理器ID计数器 + size_t next_handler_id_{1}; + + /// 处理窗口原生事件 + auto handle_native_event(window_id id, const event& e) -> void; + }; +} // namespace mirage +``` + +## 4. 数据流图 + +### 4.1 窗口创建流程 + +``` +用户调用 unified_window_manager window_factory window_registry render_pipeline + │ │ │ │ │ + │ create_main_window(info) │ │ │ │ + ├─────────────────────────────>│ │ │ │ + │ │ create_main_window(info) │ │ │ + │ ├───────────────────────────>│ │ │ + │ │ │ create_window_impl() │ │ + │ │ │ (调用平台窗口创建) │ │ + │ │ │ │ │ + │ │ │ generate_window_id() │ │ + │ │ ├───────────────────────────>│ │ + │ │ │<───────────────────────────┤ window_id │ + │ │ │ │ │ + │ │ │ register_window() │ │ + │ │ ├───────────────────────────>│ │ + │ │ │ │ store window_ptr │ + │ │ │ │ │ + │ │ │ create_render_context() │ │ + │ │ ├───────────────────────────────────────────────────────>│ + │ │ │ │ │ create surface + │ │ │ │ │ register_window() + │ │ │<──────────────────────────────────────────────────────┤ success + │ │<───────────────────────────┤ window_id │ │ + │<─────────────────────────────┤ expected │ │ │ +``` + +### 4.2 事件处理流程 + +``` +平台事件 window_interface unified_window_manager 事件处理器 + │ │ │ │ + │ 原生事件 │ │ │ + ├───────────────────────>│ │ │ + │ │ event callback │ │ + │ ├───────────────────────────>│ │ + │ │ │ 创建 enhanced_event │ + │ │ │ (添加 source_window) │ + │ │ │ │ + │ │ │ dispatch_event() │ + │ │ ├───────────────────────>│ global_handlers + │ │ ├───────────────────────>│ window_handlers[id] + │ │ │ │ + │ │ │ 特殊事件处理 │ + │ │ │ (WINDOW_CLOSE等) │ + │ │ │ │ +``` + +### 4.3 渲染流程 + +``` +用户调用 unified_window_manager render_pipeline window_render_context + │ │ │ │ + │ 获取 window_id │ │ │ + │<───────────────────────────┤ │ │ + │ │ │ │ + │ render_pipeline-> │ │ │ + │ render_window(id, ...) │ │ │ + ├─────────────────────────────────────────────────────────>│ │ + │ │ │ get_window_context(id) │ + │ │ ├───────────────────────>│ + │ │ │<───────────────────────┤ context* + │ │ │ │ + │ │ │ begin_frame() │ + │ │ ├───────────────────────>│ + │ │ │ │ acquire_next_image + │ │ │<───────────────────────┤ frame_context + │ │ │ │ + │ │ │ execute_render_tree() │ + │ │ │ blit_to_swapchain() │ + │ │ │ │ + │ │ │ end_frame() │ + │ │ ├───────────────────────>│ + │ │ │ │ present() + │<────────────────────────────────────────────────────────┤ success │ +``` + +## 5. 组件职责说明 + +### 5.1 职责分配表 + +| 组件 | 职责 | 依赖 | +|------|------|------| +| `unified_window_manager` | 统一管理入口,协调各组件 | `window_registry`, `window_factory`, `render_pipeline` | +| `window_registry` | 窗口实例存储、父子关系管理、状态追踪 | 无 | +| `window_factory` | 窗口创建、渲染上下文创建 | `window_registry`, `render_pipeline` | +| `render_pipeline` | 渲染上下文管理、渲染执行 | `window_render_context`, `shared_render_resources` | +| `window_render_context` | 单窗口渲染资源管理 | `swapchain`, `offscreen_target` | + +### 5.2 新旧职责对比 + +| 功能 | 旧实现 | 新实现 | +|------|--------|--------| +| 窗口创建 | `window_manager::create_window()` | `unified_window_manager::create_*_window()` | +| 窗口存储 | `window_manager::windows_` | `window_registry::windows_` | +| 渲染上下文创建 | `render_pipeline::register_window()` | `window_factory::create_render_context_for_window()` | +| 渲染上下文存储 | `render_pipeline::window_contexts_` | `render_pipeline::window_contexts_` (不变) | +| ID生成 | `window_manager::next_window_id_++` | `window_id_generator::generate()` | +| 父子关系 | 无 | `window_registry::children_map_` | +| 事件分发 | `window_interface::poll_events()` | `unified_window_manager::poll_events()` + `dispatch_event()` | + +## 6. 需要修改的文件清单 + +### 6.1 新增文件 + +| 文件路径 | 描述 | +|----------|------| +| `src/window/window_id.h` | 统一窗口ID类型定义 | +| `src/window/window_type.h` | 窗口类型枚举定义 | +| `src/window/enhanced_event.h` | 增强事件结构定义 | +| `src/window/extended_window_create_info.h` | 扩展窗口创建信息 | +| `src/window/window_registry.h` | 窗口注册表头文件 | +| `src/window/window_registry.cpp` | 窗口注册表实现 | +| `src/window/window_factory.h` | 窗口工厂头文件 | +| `src/window/window_factory.cpp` | 窗口工厂实现 | +| `src/window/unified_window_manager.h` | 统一窗口管理器头文件 | +| `src/window/unified_window_manager.cpp` | 统一窗口管理器实现 | + +### 6.2 需要修改的现有文件 + +| 文件路径 | 修改概要 | +|----------|----------| +| `src/window/window_common.h` | 包含 `window_id.h`,移除旧的 `window_ptr` 定义 | +| `src/window/window_manager.h` | 标记为废弃,或重构为 `unified_window_manager` 的简化包装 | +| `src/window/window_manager.cpp` | 同上 | +| `src/window/event/event_types.h` | 添加 `source_window` 字段到 `event` 结构 | +| `src/render/pipeline/window_render_context.h` | 使用统一的 `window_id` 类型 | +| `src/render/pipeline/window_render_context.cpp` | 同上 | +| `src/render/pipeline/render_pipeline.h` | 使用统一的 `window_id` 类型 | +| `src/render/pipeline/render_pipeline.cpp` | 同上 | +| `src/app/application.h` | 使用 `unified_window_manager`,移除 `window_` 指针 | +| `src/app/application.cpp` | 适配新的窗口管理器API | +| `src/widget/window/main_window_widget.h` | 存储 `window_id` 而非指针 | +| `src/widget/window/main_window_widget.cpp` | 同上 | + +### 6.3 各文件修改详情 + +#### 6.3.1 `src/window/window_common.h` 修改 + +```cpp +// 修改前 +#pragma once +#include +#include +#include +#include +#include "window_types.h" +#include "event/event_types.h" + +namespace mirage { + class window_interface; + template + using expected = std::expected; + using window_ptr = std::unique_ptr; + using event_callback_fn = std::function; + using native_window_handle = void*; + using monitor_list = std::vector; +} + +// 修改后 +#pragma once +#include +#include +#include +#include +#include "window_id.h" // 新增 +#include "window_type.h" // 新增 +#include "window_types.h" +#include "event/event_types.h" + +namespace mirage { + class window_interface; + template + using expected = std::expected; + using window_ptr = std::unique_ptr; + using event_callback_fn = std::function; + using native_window_handle = void*; + using monitor_list = std::vector; +} +``` + +#### 6.3.2 `src/window/event/event_types.h` 修改 + +```cpp +// 在 event 结构体中添加 source_window 字段 + +/// 通用事件结构 +struct event { + event_type type{event_type::NONE}; + window_id source_window{INVALID_WINDOW_ID}; // 新增:源窗口ID + + union { + window_event_data window; + key_event_data key; + char_input_event_data char_input; + mouse_button_event_data mouse_button; + mouse_move_event_data mouse_move; + mouse_scroll_event_data mouse_scroll; + }; + + event() : type(event_type::NONE), source_window(INVALID_WINDOW_ID), window{} {} + + explicit event(event_type t, window_id src = INVALID_WINDOW_ID) + : type(t), source_window(src), window{} {} +}; +``` + +#### 6.3.3 `src/window/window_manager.h` 修改 + +```cpp +// 标记为废弃,建议使用 unified_window_manager +#pragma once + +#include "window_common.h" +#include "window_interface.h" + +#include +#include +#include + +namespace mirage { + /// @deprecated 请使用 unified_window_manager + /// 窗口管理器类 - 为向后兼容保留 + class [[deprecated("Use unified_window_manager instead")]] window_manager { + public: + // ... 保持现有接口,内部可委托给 unified_window_manager + }; +} // namespace mirage +``` + +#### 6.3.4 `src/render/pipeline/window_render_context.h` 修改 + +```cpp +// 移除本地 window_id 定义,使用全局定义 +#pragma once + +#include "window/window_id.h" // 改为使用统一的 window_id +// ... 其余不变 +``` + +#### 6.3.5 `src/app/application.h` 修改 + +```cpp +// 修改前 +class application { +private: + std::unique_ptr window_manager_; + window_interface* window_ = nullptr; + // ... +}; + +// 修改后 +class application { +private: + std::unique_ptr window_manager_; // 替换 + window_id main_window_id_{INVALID_WINDOW_ID}; // 替换 window_* + // ... + +public: + // 新增便捷方法 + [[nodiscard]] auto get_main_window() const -> window_interface* { + return window_manager_->get_window(main_window_id_); + } + + [[nodiscard]] auto get_main_window_id() const -> window_id { + return main_window_id_; + } +}; +``` + +## 7. 实施顺序建议 + +### 7.1 分阶段实施计划 + +```mermaid +gantt + title 窗口管理重构实施计划 + dateFormat YYYY-MM-DD + section 阶段1-基础类型 + window_id.h :a1, 2024-01-01, 1d + window_type.h :a2, after a1, 1d + enhanced_event.h :a3, after a2, 1d + section 阶段2-核心组件 + window_registry :b1, after a3, 2d + window_factory :b2, after b1, 2d + section 阶段3-整合 + unified_window_manager:c1, after b2, 3d + section 阶段4-迁移 + 修改现有文件 :d1, after c1, 3d + application适配 :d2, after d1, 2d + section 阶段5-测试 + 单元测试 :e1, after d2, 2d + 集成测试 :e2, after e1, 2d +``` + +### 7.2 详细步骤 + +#### 阶段 1:基础类型定义(无破坏性更改) + +1. **创建 `src/window/window_id.h`** + - 定义 `window_id` 类型为 `uint64_t` + - 定义 `INVALID_WINDOW_ID` 常量 + - 定义 `window_id_generator` 类 + - 定义 `window_id_hash` 结构 + +2. **创建 `src/window/window_type.h`** + - 定义 `window_type` 枚举 + - 定义 `window_relationship` 枚举 + - 定义 `dialog_type` 枚举 + - 定义 `window_state` 枚举 + +3. **创建 `src/window/enhanced_event.h`** + - 定义 `window_event_base` 结构 + - 定义 `enhanced_event` 结构 + - 提供 `from_legacy()` 转换方法 + +4. **创建 `src/window/extended_window_create_info.h`** + - 定义 `extended_window_create_info` + - 定义 `popup_create_info` + - 定义 `dialog_create_info` + - 定义 `tooltip_create_info` + +#### 阶段 2:核心组件实现(新增类,不修改现有) + +5. **实现 `window_registry`** + - 实现窗口注册/注销 + - 实现父子关系管理 + - 实现窗口查询接口 + - 添加线程安全支持 + +6. **实现 `window_factory`** + - 实现各类窗口创建方法 + - 集成渲染上下文创建 + - 实现ID生成逻辑 + +#### 阶段 3:统一管理器(新增类) + +7. **实现 `unified_window_manager`** + - 整合 `window_registry` 和 `window_factory` + - 实现事件处理和分发 + - 提供统一API + +#### 阶段 4:渐进式迁移(修改现有代码) + +8. **修改 `window_common.h`** + - 包含新的类型定义头文件 + +9. **修改 `event_types.h`** + - 为 `event` 结构添加 `source_window` 字段 + - 保持向后兼容(默认值为 `INVALID_WINDOW_ID`) + +10. **修改 `window_render_context.h/cpp`** + - 移除本地 `window_id` 定义 + - 使用 `window/window_id.h` 中的定义 + +11. **修改 `render_pipeline.h/cpp`** + - 使用统一的 `window_id` 类型 + - 确保类型一致 + +12. **修改 `application.h/cpp`** + - 替换 `window_manager_` 为 `unified_window_manager` + - 替换 `window_` 指针为 `main_window_id_` + - 更新相关方法 + +13. **标记 `window_manager` 为废弃** + - 添加 `[[deprecated]]` 属性 + - 可选:内部委托给 `unified_window_manager` + +#### 阶段 5:测试与验证 + +14. **单元测试** + - `window_id_generator` 测试 + - `window_registry` 测试 + - `window_factory` 测试 + - `unified_window_manager` 测试 + +15. **集成测试** + - 多窗口创建/销毁 + - 父子窗口关系 + - 事件分发 + - 渲染集成 + +### 7.3 向后兼容策略 + +1. **保留旧API**:`window_manager` 类标记为废弃但仍可用 +2. **渐进式迁移**:新代码使用 `unified_window_manager`,旧代码逐步迁移 +3. **默认值**:`source_window` 默认为 `INVALID_WINDOW_ID`,不影响现有事件处理 +4. **类型兼容**:`window_id` 使用 `uint64_t`,现有 `uint32_t` 可隐式转换 + +### 7.4 回滚计划 + +如果迁移过程中出现问题: + +1. **阶段1-2**:直接删除新增文件,无影响 +2. **阶段3**:删除 `unified_window_manager`,无影响 +3. **阶段4**:需要逐个文件回滚修改 + - 使用 Git 版本控制 + - 每个文件独立提交 + - 保留修改前的备份 + +## 8. 性能考虑 + +### 8.1 内存开销 + +| 组件 | 内存占用 | 说明 | +|------|----------|------| +| `window_id` | 8字节 vs 4字节 | 比原来多4字节,可接受 | +| `window_registry` | ~100字节/窗口 | 包含哈希表开销 | +| `enhanced_event` | +16字节 | 添加 source_window 和 timestamp | + +### 8.2 性能优化建议 + +1. **使用 `std::unordered_map` 配合 `window_id_hash`**:O(1) 查找 +2. **读写锁**:`window_registry` 使用 `std::shared_mutex` 支持并发读 +3. **事件池**:可考虑使用事件对象池减少分配 +4. **延迟初始化**:渲染上下文按需创建 + +## 9. 总结 + +本重构方案通过以下方式解决现有问题: + +| 问题 | 解决方案 | +|------|----------| +| 窗口ID类型不一致 | 统一使用 `uint64_t` 类型的 `window_id` | +| 单窗口持有 | `application` 使用 `window_id` 而非指针 | +| 事件缺少源窗口 | 添加 `source_window` 字段 | +| 缺少窗口类型 | 新增 `window_type` 枚举 | +| 缺少父子关系 | `window_registry` 管理层级关系 | +| 组件解耦不完整 | `unified_window_manager` 协调各组件 | + +关键优势: +- **类型安全**:统一的 `window_id` 类型 +- **可扩展**:支持多种窗口类型 +- **解耦**:窗口管理与渲染分离 +- **向后兼容**:渐进式迁移策略 +- **线程安全**:读写锁支持并发访问 \ No newline at end of file diff --git a/src/app/application.cpp b/src/app/application.cpp index c118b47..826686f 100644 --- a/src/app/application.cpp +++ b/src/app/application.cpp @@ -1,6 +1,5 @@ #include "application.h" -#include "window_manager.h" #include "window_interface.h" #include "window_common.h" #include "event/event_types.h" @@ -52,7 +51,7 @@ namespace mirage::app { // 1. 创建窗口管理器和窗口 // ======================================================================== - window_manager_ = std::make_unique(); + window_manager_ = std::make_unique(); window_create_info window_info{ .title = config.title, @@ -67,13 +66,14 @@ namespace mirage::app { window_info.flags = window_flag::VISIBLE | window_flag::DECORATED | window_flag::FOCUSED; } - auto window_result = window_manager_->create_window(window_info); + auto window_result = window_manager_->create_main_window(window_info); if (!window_result.has_value()) { std::cerr << "[application] Failed to create window: " << window_result.error() << std::endl; return false; } - window_ = window_manager_->get_window(window_result.value()); + main_window_id_ = window_result.value(); + window_ = window_manager_->get_window(main_window_id_); if (!window_) { std::cerr << "[application] Failed to get window pointer" << std::endl; return false; @@ -508,7 +508,7 @@ namespace mirage::app { void application::process_events() { if (window_manager_) { - window_manager_->poll_all_events(); + window_manager_->poll_events(); } } diff --git a/src/app/application.h b/src/app/application.h index d30cbe0..42ca8d3 100644 --- a/src/app/application.h +++ b/src/app/application.h @@ -16,6 +16,7 @@ #include "vulkan/vulkan_common.h" #include "widget_context.h" #include "window/main_window_widget.h" +#include "unified_window_manager.h" #include "widget_event/widget_event_router.h" @@ -36,7 +37,6 @@ namespace mirage { // 前向声明 namespace mirage { class window_interface; - class window_manager; class render_pipeline; class widget_base; class render_context; @@ -318,10 +318,13 @@ private: // 核心组件 // ======================================================================== - /// @brief 窗口管理器 - std::unique_ptr window_manager_; + /// @brief 统一窗口管理器 + std::unique_ptr window_manager_; - /// @brief 窗口指针(由窗口管理器管理) + /// @brief 主窗口ID + window_id main_window_id_{INVALID_WINDOW_ID}; + + /// @brief 窗口指针(由窗口管理器管理,兼容层) window_interface* window_ = nullptr; /// @brief GLFW 窗口指针(用于创建 Vulkan Surface) diff --git a/src/common/window_id.h b/src/common/window_id.h new file mode 100644 index 0000000..b9b6dcc --- /dev/null +++ b/src/common/window_id.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +namespace mirage { + +/// 窗口唯一标识符类型 +/// 定义在 common 模块,供 render 和 window 模块共同使用 +using window_id = uint64_t; + +/// 无效窗口ID常量 +constexpr window_id INVALID_WINDOW_ID = 0; + +/// 检查窗口ID是否有效 +/// @param id 要检查的窗口ID +/// @return 如果ID有效返回true,否则返回false +[[nodiscard]] constexpr auto is_valid_window_id(window_id id) noexcept -> bool { + return id != INVALID_WINDOW_ID; +} + +/// 线程安全的窗口ID生成器 +/// 使用原子操作确保多线程环境下ID的唯一性 +class window_id_generator { +public: + /// 生成下一个唯一的窗口ID + /// @return 新生成的窗口ID + [[nodiscard]] auto generate() noexcept -> window_id { + return ++next_id_; + } + + /// 查看下一个将要生成的ID(不消耗) + /// @return 下一个将要生成的窗口ID + [[nodiscard]] auto peek_next() const noexcept -> window_id { + return next_id_.load(std::memory_order_relaxed) + 1; + } + + /// 获取当前已生成的最大ID + /// @return 当前最大的窗口ID + [[nodiscard]] auto current() const noexcept -> window_id { + return next_id_.load(std::memory_order_relaxed); + } + +private: + std::atomic next_id_{0}; +}; + +} // namespace mirage \ No newline at end of file diff --git a/src/render/pipeline/window_render_context.h b/src/render/pipeline/window_render_context.h index 94f39ea..2e3f660 100644 --- a/src/render/pipeline/window_render_context.h +++ b/src/render/pipeline/window_render_context.h @@ -5,6 +5,7 @@ #include "vulkan/logical_device.h" #include "vulkan/resource_manager.h" #include "vulkan/swapchain.h" +#include "window_id.h" #include #include @@ -12,8 +13,7 @@ #include namespace mirage { - /// 窗口标识符类型 - using window_id = uint64_t; + // window_id 类型已在 common/window_id.h 中定义于 mirage 命名空间 /// 窗口渲染上下文 - 封装每窗口独立的 Vulkan 资源 /// diff --git a/src/window/event/event_types.h b/src/window/event/event_types.h index 2c905e5..769de87 100644 --- a/src/window/event/event_types.h +++ b/src/window/event/event_types.h @@ -4,6 +4,8 @@ #include #include +#include "window_id.h" + #ifdef DELETE #undef DELETE #endif @@ -205,6 +207,7 @@ namespace mirage { /// 通用事件结构 struct event { event_type type{event_type::NONE}; + window_id source_window{INVALID_WINDOW_ID}; ///< 事件来源窗口ID union { window_event_data window; @@ -215,10 +218,14 @@ namespace mirage { mouse_scroll_event_data mouse_scroll; }; - event() : type(event_type::NONE), window{} { + event() : type(event_type::NONE), source_window(INVALID_WINDOW_ID), window{} { } - explicit event(event_type t) : type(t), window{} { + explicit event(event_type t) : type(t), source_window(INVALID_WINDOW_ID), window{} { + } + + event(event_type t, window_id src_window) + : type(t), source_window(src_window), window{} { } }; diff --git a/src/window/integration/vulkan_surface.cpp b/src/window/integration/vulkan_surface.cpp index 73ec489..1785f66 100644 --- a/src/window/integration/vulkan_surface.cpp +++ b/src/window/integration/vulkan_surface.cpp @@ -84,10 +84,10 @@ namespace mirage { } auto vulkan_surface_manager::collect_required_extensions( - const window_manager& manager + const unified_window_manager& manager ) -> std::vector { // 获取所有窗口ID - auto window_ids = manager.get_all_window_ids(); + auto window_ids = manager.get_all_windows(); // 构建窗口指针列表 std::vector windows; diff --git a/src/window/integration/vulkan_surface.h b/src/window/integration/vulkan_surface.h index 8788249..2326d77 100644 --- a/src/window/integration/vulkan_surface.h +++ b/src/window/integration/vulkan_surface.h @@ -2,8 +2,8 @@ #include "window_common.h" #include "window_interface.h" -#include "window_manager.h" #include "vulkan/vulkan_common.h" +#include "unified_window_manager.h" #include #include @@ -50,7 +50,7 @@ namespace mirage { /// @param manager 窗口管理器引用 /// @return 扩展名称列表(已去重) [[nodiscard]] static auto collect_required_extensions( - const window_manager& manager + const unified_window_manager& manager ) -> std::vector; /// 销毁 Vulkan Surface diff --git a/src/window/unified_window_manager.cpp b/src/window/unified_window_manager.cpp new file mode 100644 index 0000000..6896122 --- /dev/null +++ b/src/window/unified_window_manager.cpp @@ -0,0 +1,409 @@ +#include "unified_window_manager.h" +#include "window_interface.h" + +#include +#include + +namespace mirage { + // ============================================================================= + // 构造函数与析构函数 + // ============================================================================= + + unified_window_manager::unified_window_manager() : id_generator_{} + , registry_{std::make_unique()} + , factory_{ + std::make_unique(*registry_, id_generator_) + } + , event_callback_{} + , pending_destroy_{} { + } + + unified_window_manager::~unified_window_manager() { + // 清理所有窗口 + // 窗口实例由 registry_ 管理,registry_ 析构时会自动清理 + } + + // ============================================================================= + // 窗口创建 + // ============================================================================= + + auto unified_window_manager::create_main_window(const mirage::window_create_info& info) + -> std::expected { + auto result = factory_->create_main_window(info); + if (!result) { + return std::unexpected(result.error()); + } + + auto id = result.value(); + + // 设置窗口事件回调 + setup_window_callbacks(id); + + // 如果是第一个主窗口,自动设置为主窗口 + if (!is_valid_window_id(registry_->get_main_window())) { + registry_->set_main_window(id); + } + + return id; + } + + auto unified_window_manager::create_child_window(window_id parent, + const child_window_create_info& info) + -> std::expected { + auto result = factory_->create_child_window(parent, info); + if (!result) { + return std::unexpected(result.error()); + } + + auto id = result.value(); + + // 设置窗口事件回调 + setup_window_callbacks(id); + + return id; + } + + auto unified_window_manager::create_popup(window_id owner, const popup_create_info& info) + -> std::expected { + auto result = factory_->create_popup(owner, info); + if (!result) { + return std::unexpected(result.error()); + } + + auto id = result.value(); + + // 设置窗口事件回调 + setup_window_callbacks(id); + + return id; + } + + auto unified_window_manager::create_dialog(window_id owner, const dialog_create_info& info) + -> std::expected { + auto result = factory_->create_dialog(owner, info); + if (!result) { + return std::unexpected(result.error()); + } + + auto id = result.value(); + + // 设置窗口事件回调 + setup_window_callbacks(id); + + return id; + } + + // ============================================================================= + // 窗口销毁 + // ============================================================================= + + auto unified_window_manager::destroy_window(window_id id) -> bool { + if (!registry_->contains(id)) { + return false; + } + + // 先递归销毁所有子窗口 + destroy_all_children(id); + + // 注销窗口 + return registry_->unregister_window(id); + } + + auto unified_window_manager::destroy_all_children(window_id parent) -> size_t { + auto children = registry_->get_children(parent); + size_t count = 0; + + for (auto child_id : children) { + // 递归销毁子窗口的子窗口 + count += destroy_all_children(child_id); + + // 销毁子窗口本身 + if (registry_->unregister_window(child_id)) { + ++count; + } + } + + return count; + } + + // ============================================================================= + // 窗口查询 + // ============================================================================= + + auto unified_window_manager::get_window(window_id id) -> mirage::window_interface* { + return registry_->get_window(id); + } + + auto unified_window_manager::get_window(window_id id) const -> const mirage::window_interface* { + return registry_->get_window(id); + } + + auto unified_window_manager::contains(window_id id) const -> bool { + return registry_->contains(id); + } + + auto unified_window_manager::get_window_type(window_id id) const -> window_type { + auto type = registry_->get_type(id); + return type.value_or(window_type::MAIN_WINDOW); + } + + auto unified_window_manager::get_window_state(window_id id) const -> window_state { + return registry_->get_state(id); + } + + // ============================================================================= + // 窗口关系 + // ============================================================================= + + auto unified_window_manager::get_parent(window_id id) const -> window_id { + return registry_->get_parent(id); + } + + auto unified_window_manager::get_children(window_id id) const -> std::vector { + return registry_->get_children(id); + } + + auto unified_window_manager::get_main_window() const -> window_id { + return registry_->get_main_window(); + } + + auto unified_window_manager::get_focused_window() const -> window_id { + return registry_->get_focused_window(); + } + + // ============================================================================= + // 窗口状态 + // ============================================================================= + + auto unified_window_manager::set_window_state(window_id id, window_state state) -> bool { + auto* window = registry_->get_window(id); + if (!window) { + return false; + } + + // 更新注册表中的状态 + if (!registry_->set_state(id, state)) { + return false; + } + + // 同步窗口实际状态 + switch (state) { + case window_state::NORMAL: + window->restore(); + break; + case window_state::MINIMIZED: + window->minimize(); + break; + case window_state::MAXIMIZED: + window->maximize(); + break; + case window_state::HIDDEN: + window->hide(); + break; + case window_state::FULLSCREEN: + window->set_mode(mirage::window_mode::FULLSCREEN); + break; + } + + return true; + } + + auto unified_window_manager::show_window(window_id id) -> bool { + auto* window = registry_->get_window(id); + if (!window) { + return false; + } + + window->show(); + registry_->set_state(id, window_state::NORMAL); + return true; + } + + auto unified_window_manager::hide_window(window_id id) -> bool { + auto* window = registry_->get_window(id); + if (!window) { + return false; + } + + window->hide(); + registry_->set_state(id, window_state::HIDDEN); + return true; + } + + auto unified_window_manager::focus_window(window_id id) -> bool { + auto* window = registry_->get_window(id); + if (!window) { + return false; + } + + window->focus(); + registry_->set_focused_window(id); + return true; + } + + // ============================================================================= + // 事件处理 + // ============================================================================= + + void unified_window_manager::poll_events() { + // 处理之前累积的待销毁窗口 + process_pending_destroys(); + + // 获取所有窗口ID + auto all_windows = registry_->get_all_windows(); + + // 遍历所有窗口调用 poll_events() + for (auto id : all_windows) { + auto* window = registry_->get_window(id); + if (window) { + window->poll_events(); + + // 检查窗口关闭状态 + if (window->should_close()) { + handle_window_close(id); + } + } + } + + // 处理本次轮询产生的待销毁窗口 + process_pending_destroys(); + } + + void unified_window_manager::set_event_callback(window_event_callback callback) { + event_callback_ = std::move(callback); + + // 为所有已存在的窗口重新设置回调 + auto all_windows = registry_->get_all_windows(); + for (auto id : all_windows) { + setup_window_callbacks(id); + } + } + + // ============================================================================= + // 批量查询 + // ============================================================================= + + auto unified_window_manager::get_all_windows() const -> std::vector { + return registry_->get_all_windows(); + } + + auto unified_window_manager::get_windows_by_type(window_type type) const + -> std::vector { + return registry_->get_windows_by_type(type); + } + + auto unified_window_manager::get_visible_windows() const -> std::vector { + auto all_windows = registry_->get_all_windows(); + std::vector visible; + visible.reserve(all_windows.size()); + + // 使用 ranges 过滤可见窗口 + auto is_visible = [this](window_id id) { + auto state = registry_->get_state(id); + return state != window_state::HIDDEN; + }; + + std::ranges::copy_if(all_windows, std::back_inserter(visible), is_visible); + + return visible; + } + + // ============================================================================= + // 统计 + // ============================================================================= + + auto unified_window_manager::window_count() const -> size_t { + return registry_->count(); + } + + auto unified_window_manager::has_windows() const -> bool { + return !registry_->empty(); + } + + // ============================================================================= + // 组件访问 + // ============================================================================= + + auto unified_window_manager::registry() -> window_registry& { + return *registry_; + } + + auto unified_window_manager::registry() const -> const window_registry& { + return *registry_; + } + + // ============================================================================= + // 内部方法 + // ============================================================================= + + void unified_window_manager::setup_window_callbacks(window_id id) { + auto* window = registry_->get_window(id); + if (!window) { + return; + } + + // 为窗口设置事件回调 + // 事件中填充 source_window 字段,转发到 event_callback_ + window->set_event_callback([this, id](const mirage::event& e) { + // 创建带有源窗口信息的事件副本 + mirage::event enhanced_event = e; + enhanced_event.source_window = id; + + // 处理特殊事件 + switch (e.type) { + case mirage::event_type::WINDOW_FOCUS: + registry_->set_focused_window(id); + break; + case mirage::event_type::WINDOW_LOST_FOCUS: + if (registry_->get_focused_window() == id) { + registry_->set_focused_window(INVALID_WINDOW_ID); + } + break; + case mirage::event_type::WINDOW_MINIMIZED: + registry_->set_state(id, window_state::MINIMIZED); + break; + case mirage::event_type::WINDOW_MAXIMIZED: + registry_->set_state(id, window_state::MAXIMIZED); + break; + case mirage::event_type::WINDOW_RESTORED: + registry_->set_state(id, window_state::NORMAL); + break; + default: + break; + } + + // 转发到用户回调 + if (event_callback_) { + event_callback_(id, enhanced_event); + } + }); + } + + void unified_window_manager::handle_window_close(window_id id) { + // 如果是主窗口关闭,可能需要特殊处理 + auto main_window = registry_->get_main_window(); + + // 触发关闭事件 + if (event_callback_) { + mirage::event close_event{mirage::event_type::WINDOW_CLOSE, id}; + event_callback_(id, close_event); + } + + // 将窗口添加到待销毁列表(延迟销毁,避免在遍历过程中修改容器) + pending_destroy_.push_back(id); + } + + void unified_window_manager::process_pending_destroys() { + if (pending_destroy_.empty()) { + return; + } + + // 复制列表以避免在销毁过程中产生新的待销毁窗口导致的问题 + auto to_destroy = std::move(pending_destroy_); + pending_destroy_.clear(); + + for (auto id : to_destroy) { + destroy_window(id); + } + } +} // namespace mirage diff --git a/src/window/unified_window_manager.h b/src/window/unified_window_manager.h new file mode 100644 index 0000000..d007e8d --- /dev/null +++ b/src/window/unified_window_manager.h @@ -0,0 +1,275 @@ +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_types.h" +#include "window_common.h" +#include "window_registry.h" +#include "window_factory.h" + +#include +#include +#include +#include +#include + +namespace mirage { + /// 窗口事件回调类型 + /// @param id 事件来源窗口ID + /// @param e 事件对象 + using window_event_callback = std::function; + + /// 统一窗口管理器 + /// + /// 窗口管理框架的统一入口,整合: + /// - window_registry - 窗口注册表 + /// - window_factory - 窗口工厂 + /// - window_id_generator - ID生成器 + /// - 事件轮询与分发 + /// + /// 使用示例: + /// @code + /// unified_window_manager manager; + /// + /// // 创建主窗口 + /// auto result = manager.create_main_window({.title = "My App", .width = 1280, .height = 720}); + /// if (result) { + /// auto main_id = result.value(); + /// + /// // 设置事件回调 + /// manager.set_event_callback([](window_id id, const event& e) { + /// // 处理事件 + /// }); + /// + /// // 主循环 + /// while (manager.has_windows()) { + /// manager.poll_events(); + /// // 渲染... + /// } + /// } + /// @endcode + class unified_window_manager { + public: + /// 构造函数 + /// 初始化 id_generator_, registry_, factory_ + unified_window_manager(); + + /// 析构函数 + ~unified_window_manager(); + + // 禁止拷贝 + unified_window_manager(const unified_window_manager&) = delete; + auto operator=(const unified_window_manager&) -> unified_window_manager& = delete; + + // 允许移动 + unified_window_manager(unified_window_manager&&) noexcept = default; + auto operator=(unified_window_manager&&) noexcept -> unified_window_manager& = default; + + // ========================================================================= + // 窗口创建 + // ========================================================================= + + /// 创建主窗口 + /// @param info 窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_main_window(const mirage::window_create_info& info) + -> std::expected; + + /// 创建子窗口 + /// @param parent 父窗口ID + /// @param info 子窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_child_window(window_id parent, + const child_window_create_info& info) + -> std::expected; + + /// 创建弹出窗口 + /// @param owner 所有者窗口ID + /// @param info 弹出窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_popup(window_id owner, const popup_create_info& info) + -> std::expected; + + /// 创建对话框 + /// @param owner 所有者窗口ID + /// @param info 对话框创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_dialog(window_id owner, const dialog_create_info& info) + -> std::expected; + + // ========================================================================= + // 窗口销毁 + // ========================================================================= + + /// 销毁窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false + auto destroy_window(window_id id) -> bool; + + /// 销毁指定窗口的所有子窗口 + /// @param parent 父窗口ID + /// @return 被销毁的子窗口数量 + auto destroy_all_children(window_id parent) -> size_t; + + // ========================================================================= + // 窗口查询 + // ========================================================================= + + /// 获取窗口实例 + /// @param id 窗口ID + /// @return 窗口实例指针,如不存在返回nullptr + [[nodiscard]] auto get_window(window_id id) -> mirage::window_interface*; + + /// 获取窗口实例(const版本) + /// @param id 窗口ID + /// @return 窗口实例指针,如不存在返回nullptr + [[nodiscard]] auto get_window(window_id id) const -> const mirage::window_interface*; + + /// 检查窗口是否存在 + /// @param id 窗口ID + /// @return 如果存在返回true,否则返回false + [[nodiscard]] auto contains(window_id id) const -> bool; + + /// 获取窗口类型 + /// @param id 窗口ID + /// @return 窗口类型,如窗口不存在返回 MAIN_WINDOW 作为默认值 + [[nodiscard]] auto get_window_type(window_id id) const -> window_type; + + /// 获取窗口状态 + /// @param id 窗口ID + /// @return 窗口状态,如窗口不存在返回 HIDDEN + [[nodiscard]] auto get_window_state(window_id id) const -> window_state; + + // ========================================================================= + // 窗口关系 + // ========================================================================= + + /// 获取父窗口ID + /// @param id 窗口ID + /// @return 父窗口ID,如无父窗口或窗口不存在返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_parent(window_id id) const -> window_id; + + /// 获取直接子窗口列表 + /// @param id 窗口ID + /// @return 子窗口ID列表,如窗口不存在返回空列表 + [[nodiscard]] auto get_children(window_id id) const -> std::vector; + + /// 获取主窗口ID + /// @return 主窗口ID,如无主窗口返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_main_window() const -> window_id; + + /// 获取当前焦点窗口ID + /// @return 焦点窗口ID,如无焦点窗口返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_focused_window() const -> window_id; + + // ========================================================================= + // 窗口状态 + // ========================================================================= + + /// 设置窗口状态 + /// @param id 窗口ID + /// @param state 新状态 + /// @return 成功返回true,失败返回false + auto set_window_state(window_id id, window_state state) -> bool; + + /// 显示窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false + auto show_window(window_id id) -> bool; + + /// 隐藏窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false + auto hide_window(window_id id) -> bool; + + /// 使窗口获取焦点 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false + auto focus_window(window_id id) -> bool; + + // ========================================================================= + // 事件处理 + // ========================================================================= + + /// 轮询所有窗口的事件 + /// 遍历所有窗口调用 poll_events(),检查窗口关闭状态,触发事件回调 + void poll_events(); + + /// 设置事件回调函数 + /// @param callback 事件回调函数 + void set_event_callback(window_event_callback callback); + + // ========================================================================= + // 批量查询 + // ========================================================================= + + /// 获取所有已注册的窗口ID + /// @return 所有窗口ID列表 + [[nodiscard]] auto get_all_windows() const -> std::vector; + + /// 按类型获取所有窗口ID + /// @param type 窗口类型 + /// @return 该类型的所有窗口ID列表 + [[nodiscard]] auto get_windows_by_type(window_type type) const -> std::vector; + + /// 获取所有可见窗口ID + /// @return 所有可见窗口ID列表 + [[nodiscard]] auto get_visible_windows() const -> std::vector; + + // ========================================================================= + // 统计 + // ========================================================================= + + /// 获取已注册窗口总数 + /// @return 窗口数量 + [[nodiscard]] auto window_count() const -> size_t; + + /// 检查是否有任何窗口 + /// @return 如果有窗口返回true,否则返回false + [[nodiscard]] auto has_windows() const -> bool; + + // ========================================================================= + // 组件访问 + // ========================================================================= + + /// 获取窗口注册表引用 + /// @return 窗口注册表引用 + [[nodiscard]] auto registry() -> window_registry&; + + /// 获取窗口注册表引用(const版本) + /// @return 窗口注册表常量引用 + [[nodiscard]] auto registry() const -> const window_registry&; + + private: + /// 窗口ID生成器 + window_id_generator id_generator_; + + /// 窗口注册表 + std::unique_ptr registry_; + + /// 窗口工厂 + std::unique_ptr factory_; + + /// 事件回调函数 + window_event_callback event_callback_; + + /// 待销毁窗口列表(用于延迟销毁) + std::vector pending_destroy_; + + // ========================================================================= + // 内部方法 + // ========================================================================= + + /// 为窗口设置事件回调 + /// 事件中填充 source_window 字段,转发到 event_callback_ + /// @param id 窗口ID + void setup_window_callbacks(window_id id); + + /// 处理窗口关闭事件 + /// @param id 窗口ID + void handle_window_close(window_id id); + + /// 处理待销毁的窗口 + void process_pending_destroys(); + }; +} // namespace mirage diff --git a/src/window/window_factory.cpp b/src/window/window_factory.cpp new file mode 100644 index 0000000..0e2563c --- /dev/null +++ b/src/window/window_factory.cpp @@ -0,0 +1,319 @@ +#include "window_factory.h" +#include "window_registry.h" +#include "window_interface.h" + +namespace mirage { + // ============================================================================= + // 构造函数 + // ============================================================================= + + window_factory::window_factory(window_registry& registry, window_id_generator& id_gen) : registry_(registry) + , id_generator_(id_gen) { + } + + // ============================================================================= + // 主窗口创建 + // ============================================================================= + + auto window_factory::create_main_window(const mirage::window_create_info& info) + -> std::expected { + // 准备创建信息 + auto prepared_info = prepare_create_info(info, window_type::MAIN_WINDOW); + + // 调用平台窗口创建函数 + auto window_result = mirage::create_window(prepared_info); + if (!window_result) { + return std::unexpected("Failed to create main window: platform error " + + std::string(mirage::window_error_to_string(window_result.error()))); + } + + // 生成窗口ID + auto id = id_generator_.generate(); + + // 注册窗口到注册表 + if (!registry_.register_window(id, window_type::MAIN_WINDOW, + std::move(window_result.value()), INVALID_WINDOW_ID)) { + return std::unexpected("Failed to register main window"); + } + + return id; + } + + // ============================================================================= + // 子窗口创建 + // ============================================================================= + + auto window_factory::create_child_window(window_id parent, const child_window_create_info& info) + -> std::expected { + // 验证父窗口存在 + if (!registry_.contains(parent)) { + return std::unexpected("Parent window does not exist"); + } + + // 获取父窗口位置以计算子窗口的绝对位置 + auto parent_pos_result = get_owner_position(parent); + if (!parent_pos_result) { + return std::unexpected(parent_pos_result.error()); + } + auto [parent_x, parent_y] = parent_pos_result.value(); + + // 构建创建信息 + mirage::window_create_info create_info; + create_info.title = info.title; + create_info.width = static_cast(info.width); + create_info.height = static_cast(info.height); + create_info.mode = mirage::window_mode::WINDOWED; + + // 设置窗口标志 + create_info.flags = mirage::window_flag::VISIBLE | + mirage::window_flag::DECORATED | + mirage::window_flag::FOCUSED; + if (info.resizable) { + create_info.flags = create_info.flags | mirage::window_flag::RESIZABLE; + } + + // 准备创建信息 + auto prepared_info = prepare_create_info(create_info, window_type::CHILD_WINDOW); + + // 调用平台窗口创建函数 + auto window_result = mirage::create_window(prepared_info); + if (!window_result) { + return std::unexpected("Failed to create child window: platform error " + + std::string(mirage::window_error_to_string(window_result.error()))); + } + + // 设置子窗口位置(相对于父窗口) + auto& window_ptr = window_result.value(); + window_ptr->set_position(parent_x + info.x, parent_y + info.y); + + // 生成窗口ID + auto id = id_generator_.generate(); + + // 注册窗口到注册表(带父窗口) + if (!registry_.register_window(id, window_type::CHILD_WINDOW, + std::move(window_ptr), parent)) { + return std::unexpected("Failed to register child window"); + } + + return id; + } + + // ============================================================================= + // 弹出窗口创建 + // ============================================================================= + + auto window_factory::create_popup(window_id owner, const popup_create_info& info) + -> std::expected { + // 验证所有者窗口存在 + if (!registry_.contains(owner)) { + return std::unexpected("Owner window does not exist"); + } + + // 获取所有者窗口位置 + auto owner_pos_result = get_owner_position(owner); + if (!owner_pos_result) { + return std::unexpected(owner_pos_result.error()); + } + auto [owner_x, owner_y] = owner_pos_result.value(); + + // 构建创建信息 - 弹出窗口通常无边框 + mirage::window_create_info create_info; + create_info.title = info.title; + create_info.width = static_cast(info.width); + create_info.height = static_cast(info.height); + create_info.mode = mirage::window_mode::WINDOWED; + + // 弹出窗口标志:无边框、浮动 + create_info.flags = mirage::window_flag::VISIBLE | + mirage::window_flag::FLOATING; + + // 准备创建信息 + auto prepared_info = prepare_create_info(create_info, window_type::POPUP); + + // 调用平台窗口创建函数 + auto window_result = mirage::create_window(prepared_info); + if (!window_result) { + return std::unexpected("Failed to create popup window: platform error " + + std::string(mirage::window_error_to_string(window_result.error()))); + } + + // 设置弹出窗口位置(相对于所有者) + auto& window_ptr = window_result.value(); + window_ptr->set_position(owner_x + info.x, owner_y + info.y); + + // 生成窗口ID + auto id = id_generator_.generate(); + + // 注册窗口到注册表(带所有者作为父窗口) + if (!registry_.register_window(id, window_type::POPUP, + std::move(window_ptr), owner)) { + return std::unexpected("Failed to register popup window"); + } + + return id; + } + + // ============================================================================= + // 对话框创建 + // ============================================================================= + + auto window_factory::create_dialog(window_id owner, const dialog_create_info& info) + -> std::expected { + // 验证所有者窗口存在 + if (!registry_.contains(owner)) { + return std::unexpected("Owner window does not exist"); + } + + // 获取所有者窗口信息用于居中 + auto* owner_window = registry_.get_window(owner); + if (!owner_window) { + return std::unexpected("Failed to get owner window"); + } + + auto [owner_width, owner_height] = owner_window->get_size(); + auto [owner_x, owner_y] = owner_window->get_position(); + + // 构建创建信息 + mirage::window_create_info create_info; + create_info.title = info.title; + create_info.width = static_cast(info.width); + create_info.height = static_cast(info.height); + create_info.mode = mirage::window_mode::WINDOWED; + + // 对话框标志:有边框、浮动、获取焦点 + create_info.flags = mirage::window_flag::VISIBLE | + mirage::window_flag::DECORATED | + mirage::window_flag::FLOATING | + mirage::window_flag::FOCUSED; + + if (info.resizable) { + create_info.flags = create_info.flags | mirage::window_flag::RESIZABLE; + } + + // 准备创建信息 + auto prepared_info = prepare_create_info(create_info, window_type::DIALOG); + + // 调用平台窗口创建函数 + auto window_result = mirage::create_window(prepared_info); + if (!window_result) { + return std::unexpected("Failed to create dialog window: platform error " + + std::string(mirage::window_error_to_string(window_result.error()))); + } + + auto& window_ptr = window_result.value(); + + // 计算居中位置 + int32_t dialog_x = owner_x + (owner_width - static_cast(info.width)) / 2; + int32_t dialog_y = owner_y + (owner_height - static_cast(info.height)) / 2; + window_ptr->set_position(dialog_x, dialog_y); + + // 生成窗口ID + auto id = id_generator_.generate(); + + // 注册窗口到注册表(带所有者作为父窗口) + if (!registry_.register_window(id, window_type::DIALOG, + std::move(window_ptr), owner)) { + return std::unexpected("Failed to register dialog window"); + } + + return id; + } + + // ============================================================================= + // 通用窗口创建 + // ============================================================================= + + auto window_factory::create_window(window_type type, + const mirage::window_create_info& info, + window_id parent) + -> std::expected { + // 如果指定了父窗口,验证其存在 + if (is_valid_window_id(parent) && !registry_.contains(parent)) { + return std::unexpected("Parent window does not exist"); + } + + // 准备创建信息 + auto prepared_info = prepare_create_info(info, type); + + // 调用平台窗口创建函数 + auto window_result = mirage::create_window(prepared_info); + if (!window_result) { + return std::unexpected("Failed to create window: platform error " + + std::string(mirage::window_error_to_string(window_result.error()))); + } + + // 生成窗口ID + auto id = id_generator_.generate(); + + // 注册窗口到注册表 + if (!registry_.register_window(id, type, std::move(window_result.value()), parent)) { + return std::unexpected("Failed to register window"); + } + + return id; + } + + // ============================================================================= + // 内部辅助方法 + // ============================================================================= + + auto window_factory::prepare_create_info(const mirage::window_create_info& info, + window_type type) const + -> mirage::window_create_info { + mirage::window_create_info result = info; + + // 根据窗口类型调整默认设置 + switch (type) { + case window_type::MAIN_WINDOW: + // 主窗口保持原始设置 + break; + + case window_type::CHILD_WINDOW: + // 子窗口:确保有装饰 + result.flags = result.flags | mirage::window_flag::DECORATED; + break; + + case window_type::POPUP: + // 弹出窗口:无边框、浮动 + // 移除装饰标志 + result.flags = static_cast( + static_cast(result.flags) & + ~static_cast(mirage::window_flag::DECORATED) + ); + result.flags = result.flags | mirage::window_flag::FLOATING; + break; + + case window_type::DIALOG: + // 对话框:有装饰、浮动 + result.flags = result.flags | + mirage::window_flag::DECORATED | + mirage::window_flag::FLOATING; + break; + + case window_type::TOOLTIP: + // 提示窗口:无边框、浮动、不获取焦点 + result.flags = static_cast( + static_cast(result.flags) & + ~static_cast(mirage::window_flag::DECORATED) & + ~static_cast(mirage::window_flag::FOCUSED) + ); + result.flags = result.flags | mirage::window_flag::FLOATING; + break; + + default: + break; + } + + return result; + } + + auto window_factory::get_owner_position(window_id owner_id) const + -> std::expected, std::string> { + auto* owner_window = registry_.get_window(owner_id); + if (!owner_window) { + return std::unexpected("Owner window not found"); + } + + return owner_window->get_position(); + } +} // namespace mirage diff --git a/src/window/window_factory.h b/src/window/window_factory.h new file mode 100644 index 0000000..a53e0fe --- /dev/null +++ b/src/window/window_factory.h @@ -0,0 +1,165 @@ +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_types.h" +#include "window_common.h" + +#include +#include +#include + +namespace mirage { + // 前向声明 + class window_registry; + + /// 弹出窗口创建信息 + struct popup_create_info { + /// 窗口标题 + std::string title; + + /// 窗口宽度 + uint32_t width = 200; + + /// 窗口高度 + uint32_t height = 150; + + /// 相对于owner的x偏移 + int32_t x = 0; + + /// 相对于owner的y偏移 + int32_t y = 0; + + /// 失去焦点时自动关闭 + bool auto_close = true; + }; + + /// 对话框创建信息 + struct dialog_create_info { + /// 窗口标题 + std::string title; + + /// 窗口宽度 + uint32_t width = 400; + + /// 窗口高度 + uint32_t height = 300; + + /// 是否模态 + bool modal = true; + + /// 是否可调整大小 + bool resizable = false; + }; + + /// 子窗口创建信息 + struct child_window_create_info { + /// 窗口标题 + std::string title; + + /// 窗口宽度 + uint32_t width = 640; + + /// 窗口高度 + uint32_t height = 480; + + /// 相对于父窗口的x偏移 + int32_t x = 0; + + /// 相对于父窗口的y偏移 + int32_t y = 0; + + /// 是否可调整大小 + bool resizable = true; + }; + + /// 窗口工厂 + /// 负责创建各类窗口并将其注册到窗口注册表 + class window_factory { + public: + /// 构造函数 + /// @param registry 窗口注册表引用 + /// @param id_gen 窗口ID生成器引用 + explicit window_factory(window_registry& registry, window_id_generator& id_gen); + + ~window_factory() = default; + + // 禁止拷贝 + window_factory(const window_factory&) = delete; + auto operator=(const window_factory&) -> window_factory& = delete; + + // 禁止移动 + window_factory(window_factory&&) = delete; + auto operator=(window_factory&&) -> window_factory& = delete; + + // ========================================================================= + // 窗口创建接口 + // ========================================================================= + + /// 创建主窗口 + /// @param info 窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_main_window(const mirage::window_create_info& info) + -> std::expected; + + /// 创建子窗口 + /// @param parent 父窗口ID + /// @param info 子窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_child_window(window_id parent, const child_window_create_info& info) + -> std::expected; + + /// 创建弹出窗口 + /// @param owner 所有者窗口ID + /// @param info 弹出窗口创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_popup(window_id owner, const popup_create_info& info) + -> std::expected; + + /// 创建对话框 + /// @param owner 所有者窗口ID + /// @param info 对话框创建信息 + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_dialog(window_id owner, const dialog_create_info& info) + -> std::expected; + + // ========================================================================= + // 通用创建接口 + // ========================================================================= + + /// 通用窗口创建方法 + /// @param type 窗口类型 + /// @param info 窗口创建信息 + /// @param parent 父窗口ID(可选) + /// @return 成功返回窗口ID,失败返回错误消息 + [[nodiscard]] auto create_window(window_type type, + const mirage::window_create_info& info, + window_id parent = INVALID_WINDOW_ID) + -> std::expected; + + private: + /// 窗口注册表引用 + window_registry& registry_; + + /// 窗口ID生成器引用 + window_id_generator& id_generator_; + + // ========================================================================= + // 内部辅助方法 + // ========================================================================= + + /// 将 window_create_info 转换为适合特定窗口类型的配置 + /// @param info 基础创建信息 + /// @param type 窗口类型 + /// @return 调整后的创建信息 + [[nodiscard]] auto prepare_create_info(const mirage::window_create_info& info, + window_type type) const + -> mirage::window_create_info; + + /// 获取所有者窗口的位置(用于计算弹出窗口的绝对位置) + /// @param owner_id 所有者窗口ID + /// @return 成功返回位置{x, y},失败返回错误消息 + [[nodiscard]] auto get_owner_position(window_id owner_id) const + -> std::expected, std::string>; + }; +} // namespace mirage diff --git a/src/window/window_manager.cpp b/src/window/window_manager.cpp deleted file mode 100644 index 98cdce1..0000000 --- a/src/window/window_manager.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include "window_manager.h" - -namespace mirage { - // ========== 窗口管理 ========== - - auto window_manager::create_window(const window_create_info& info) - -> std::expected { - // 使用全局工厂函数创建窗口 - auto result = mirage::create_window(info); - - if (!result.has_value()) { - // 将window_error转换为字符串 - return std::unexpected(std::string(window_error_to_string(result.error()))); - } - - // 生成新的窗口ID - window_id id = next_window_id_++; - - // 存储窗口 - windows_[id] = std::move(result.value()); - - return id; - } - - auto window_manager::destroy_window(window_id id) -> bool { - auto it = windows_.find(id); - if (it == windows_.end()) { - return false; - } - - // 销毁窗口 - windows_.erase(it); - return true; - } - - auto window_manager::get_window(window_id id) -> window_interface* { - auto it = windows_.find(id); - if (it == windows_.end()) { - return nullptr; - } - return it->second.get(); - } - - auto window_manager::get_window(window_id id) const -> const window_interface* { - auto it = windows_.find(id); - if (it == windows_.end()) { - return nullptr; - } - return it->second.get(); - } - - auto window_manager::get_all_window_ids() const -> std::vector { - std::vector ids; - ids.reserve(windows_.size()); - - for (const auto& [id, window] : windows_) { - ids.push_back(id); - } - - return ids; - } - - auto window_manager::get_window_count() const -> size_t { - return windows_.size(); - } - - // ========== 事件处理 ========== - - auto window_manager::poll_all_events() -> void { - // 遍历所有窗口并轮询事件 - for (auto& [id, window] : windows_) { - if (window) { - window->poll_events(); - } - } - } - - auto window_manager::all_windows_closed() const -> bool { - // 如果没有窗口,认为所有窗口都已关闭 - if (windows_.empty()) { - return true; - } - - // 检查所有窗口是否都应该关闭 - for (const auto& [id, window] : windows_) { - if (window && !window->should_close()) { - return false; - } - } - - return true; - } - - // ========== Vulkan设备管理 ========== - - auto window_manager::set_shared_device(std::shared_ptr device) -> void { - shared_device_ = std::move(device); - } - - auto window_manager::get_shared_device() const -> std::shared_ptr { - return shared_device_; - } -} // namespace mirage diff --git a/src/window/window_manager.h b/src/window/window_manager.h deleted file mode 100644 index 77d6bb9..0000000 --- a/src/window/window_manager.h +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once - -#include "window_common.h" -#include "window_interface.h" -#include "vulkan/logical_device.h" - -#include -#include -#include - -namespace mirage { - /// 窗口管理器类 - /// - /// 用于管理多个窗口实例,支持桌面平台的多窗口应用。 - /// 提供窗口的创建、销毁、查询和统一事件轮询功能。 - class window_manager { - public: - /// 窗口ID类型 - using window_id = uint32_t; - - /// 窗口智能指针类型 - using window_ptr = std::unique_ptr; - - /// 默认构造函数 - window_manager() = default; - - /// 析构函数 - ~window_manager() = default; - - // 禁止拷贝 - window_manager(const window_manager&) = delete; - window_manager& operator=(const window_manager&) = delete; - - // 允许移动 - window_manager(window_manager&&) noexcept = default; - window_manager& operator=(window_manager&&) noexcept = default; - - // ========== 窗口管理 ========== - - /// 创建窗口 - /// - /// 根据提供的创建信息创建一个新窗口实例,并返回窗口ID。 - /// - /// @param info 窗口创建信息 - /// @return 成功返回窗口ID,失败返回错误消息 - [[nodiscard]] auto create_window(const window_create_info& info) - -> std::expected; - - /// 销毁窗口 - /// - /// 根据窗口ID销毁对应的窗口实例。 - /// - /// @param id 窗口ID - /// @return 成功返回true,失败返回false - auto destroy_window(window_id id) -> bool; - - /// 获取窗口 - /// - /// 根据窗口ID获取对应的窗口实例指针。 - /// - /// @param id 窗口ID - /// @return 成功返回窗口指针,失败返回nullptr - [[nodiscard]] auto get_window(window_id id) -> window_interface*; - - /// 获取窗口(常量版本) - /// - /// 根据窗口ID获取对应的窗口实例指针。 - /// - /// @param id 窗口ID - /// @return 成功返回窗口指针,失败返回nullptr - [[nodiscard]] auto get_window(window_id id) const -> const window_interface*; - - /// 获取所有窗口ID - /// - /// 返回当前管理的所有窗口的ID列表。 - /// - /// @return 窗口ID列表 - [[nodiscard]] auto get_all_window_ids() const -> std::vector; - - /// 获取窗口数量 - /// - /// 返回当前管理的窗口总数。 - /// - /// @return 窗口数量 - [[nodiscard]] auto get_window_count() const -> size_t; - - // ========== 事件处理 ========== - - /// 轮询所有窗口的事件 - /// - /// 遍历所有窗口并调用它们的poll_events()方法, - /// 处理所有待处理的窗口事件。 - auto poll_all_events() -> void; - - /// 检查是否所有窗口都已关闭 - /// - /// 检查所有窗口的should_close()状态。 - /// - /// @return 如果所有窗口都应该关闭返回true,否则返回false - [[nodiscard]] auto all_windows_closed() const -> bool; - - // ========== Vulkan设备管理 ========== - - /// 设置共享的Vulkan逻辑设备 - /// - /// 为多窗口共享Vulkan资源设置共享的逻辑设备。 - /// - /// @param device 共享的逻辑设备智能指针 - auto set_shared_device(std::shared_ptr device) -> void; - - /// 获取共享的Vulkan逻辑设备 - /// - /// 返回当前设置的共享逻辑设备。 - /// - /// @return 共享的逻辑设备智能指针 - [[nodiscard]] auto get_shared_device() const -> std::shared_ptr; - - private: - /// 窗口存储映射表 - std::unordered_map windows_; - - /// 下一个窗口ID(自动递增) - window_id next_window_id_ = 1; - - /// 共享的Vulkan逻辑设备 - std::shared_ptr shared_device_; - }; -} // namespace mirage diff --git a/src/window/window_registry.cpp b/src/window/window_registry.cpp new file mode 100644 index 0000000..36b6740 --- /dev/null +++ b/src/window/window_registry.cpp @@ -0,0 +1,432 @@ +#include "window_registry.h" + +#include +#include "window_interface.h" + +namespace mirage { + +// ============================================================================= +// 窗口注册/注销 +// ============================================================================= + +auto window_registry::register_window(window_id id, window_type type, + window_ptr instance, + window_id parent) -> bool { + std::unique_lock lock(mutex_); + + // 检查ID是否已存在 + if (windows_.find(id) != windows_.end()) { + return false; + } + + // 如果指定了父窗口,检查父窗口是否存在 + if (is_valid_window_id(parent) && windows_.find(parent) == windows_.end()) { + return false; + } + + // 创建窗口条目 + window_entry entry; + entry.id = id; + entry.type = type; + entry.state = window_state::NORMAL; + entry.parent_id = parent; + entry.children = {}; + entry.instance = std::move(instance); + + // 插入窗口条目 + windows_.emplace(id, std::move(entry)); + + // 如果有父窗口,添加到父窗口的子窗口集合 + if (is_valid_window_id(parent)) { + add_to_parent_impl(id, parent); + } + + // 如果是第一个主窗口,自动设置为主窗口 + if (type == window_type::MAIN_WINDOW && !is_valid_window_id(main_window_)) { + main_window_ = id; + } + + return true; +} + +auto window_registry::unregister_window(window_id id) -> bool { + std::unique_lock lock(mutex_); + + auto it = windows_.find(id); + if (it == windows_.end()) { + return false; + } + + auto& entry = it->second; + + // 先递归注销所有子窗口 + // 注意:需要复制子窗口集合,因为递归过程中会修改它 + auto children_copy = entry.children; + for (auto child_id : children_copy) { + // 递归调用需要先释放锁,这里使用非递归方式处理 + // 将子窗口的父窗口设为无效,然后删除 + if (auto child_it = windows_.find(child_id); child_it != windows_.end()) { + child_it->second.parent_id = INVALID_WINDOW_ID; + } + } + + // 从父窗口的子窗口集合中移除 + if (is_valid_window_id(entry.parent_id)) { + remove_from_parent_impl(id, entry.parent_id); + } + + // 如果是焦点窗口,清除焦点 + if (focused_window_ == id) { + focused_window_ = INVALID_WINDOW_ID; + } + + // 如果是主窗口,清除主窗口标记 + if (main_window_ == id) { + main_window_ = INVALID_WINDOW_ID; + } + + // 移除窗口条目 + windows_.erase(it); + + return true; +} + +auto window_registry::contains(window_id id) const -> bool { + std::shared_lock lock(mutex_); + return windows_.find(id) != windows_.end(); +} + +// ============================================================================= +// 窗口查询 +// ============================================================================= + +auto window_registry::get_window(window_id id) -> mirage::window_interface* { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + return it->second.instance.get(); + } + return nullptr; +} + +auto window_registry::get_window(window_id id) const -> const mirage::window_interface* { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + return it->second.instance.get(); + } + return nullptr; +} + +auto window_registry::get_entry(window_id id) const -> std::optional { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + // 创建条目副本(不包含instance,因为unique_ptr不可复制) + window_entry copy; + copy.id = it->second.id; + copy.type = it->second.type; + copy.state = it->second.state; + copy.parent_id = it->second.parent_id; + copy.children = it->second.children; + copy.instance = nullptr; // 不复制实例 + return copy; + } + return std::nullopt; +} + +auto window_registry::get_type(window_id id) const -> std::optional { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + return it->second.type; + } + return std::nullopt; +} + +// ============================================================================= +// 窗口关系管理 +// ============================================================================= + +auto window_registry::get_parent(window_id id) const -> window_id { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + return it->second.parent_id; + } + return INVALID_WINDOW_ID; +} + +auto window_registry::get_children(window_id id) const -> std::vector { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + const auto& children = it->second.children; + return std::vector(children.begin(), children.end()); + } + return {}; +} + +auto window_registry::get_all_descendants(window_id id) const -> std::vector { + std::shared_lock lock(mutex_); + std::vector result; + collect_descendants_impl(id, result); + return result; +} + +auto window_registry::set_parent(window_id id, window_id new_parent) -> bool { + std::unique_lock lock(mutex_); + + auto it = windows_.find(id); + if (it == windows_.end()) { + return false; + } + + // 如果新父窗口有效,检查其是否存在 + if (is_valid_window_id(new_parent) && windows_.find(new_parent) == windows_.end()) { + return false; + } + + // 防止循环引用:检查new_parent是否是id的后代 + if (is_valid_window_id(new_parent)) { + std::vector descendants; + collect_descendants_impl(id, descendants); + auto found = std::find(descendants.begin(), descendants.end(), new_parent); + if (found != descendants.end()) { + return false; // 会形成循环 + } + } + + auto old_parent = it->second.parent_id; + + // 从旧父窗口移除 + if (is_valid_window_id(old_parent)) { + remove_from_parent_impl(id, old_parent); + } + + // 添加到新父窗口 + if (is_valid_window_id(new_parent)) { + add_to_parent_impl(id, new_parent); + } + + it->second.parent_id = new_parent; + return true; +} + +auto window_registry::is_ancestor_of(window_id ancestor, window_id descendant) const -> bool { + std::shared_lock lock(mutex_); + + if (!is_valid_window_id(ancestor) || !is_valid_window_id(descendant)) { + return false; + } + + // 从descendant向上遍历父窗口链 + auto current = descendant; + while (is_valid_window_id(current)) { + auto it = windows_.find(current); + if (it == windows_.end()) { + return false; + } + auto parent = it->second.parent_id; + if (parent == ancestor) { + return true; + } + current = parent; + } + + return false; +} + +// ============================================================================= +// 窗口状态管理 +// ============================================================================= + +auto window_registry::set_state(window_id id, window_state state) -> bool { + std::unique_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + it->second.state = state; + return true; + } + return false; +} + +auto window_registry::get_state(window_id id) const -> window_state { + std::shared_lock lock(mutex_); + auto it = windows_.find(id); + if (it != windows_.end()) { + return it->second.state; + } + return window_state::HIDDEN; +} + +// ============================================================================= +// 批量查询 +// ============================================================================= + +auto window_registry::get_windows_by_type(window_type type) const -> std::vector { + std::shared_lock lock(mutex_); + + std::vector result; + result.reserve(windows_.size()); + + for (const auto& [id, entry] : windows_) { + if (entry.type == type) { + result.push_back(id); + } + } + + return result; +} + +auto window_registry::get_all_windows() const -> std::vector { + std::shared_lock lock(mutex_); + + std::vector result; + result.reserve(windows_.size()); + + for (const auto& [id, entry] : windows_) { + result.push_back(id); + } + + return result; +} + +auto window_registry::get_windows_by_state(window_state state) const -> std::vector { + std::shared_lock lock(mutex_); + + std::vector result; + result.reserve(windows_.size()); + + for (const auto& [id, entry] : windows_) { + if (entry.state == state) { + result.push_back(id); + } + } + + return result; +} + +// ============================================================================= +// 统计信息 +// ============================================================================= + +auto window_registry::count() const -> size_t { + std::shared_lock lock(mutex_); + return windows_.size(); +} + +auto window_registry::count_by_type(window_type type) const -> size_t { + std::shared_lock lock(mutex_); + size_t count = 0; + for (const auto& [id, entry] : windows_) { + if (entry.type == type) { + ++count; + } + } + return count; +} + +auto window_registry::count_by_state(window_state state) const -> size_t { + std::shared_lock lock(mutex_); + size_t count = 0; + for (const auto& [id, entry] : windows_) { + if (entry.state == state) { + ++count; + } + } + return count; +} + +auto window_registry::empty() const -> bool { + std::shared_lock lock(mutex_); + return windows_.empty(); +} + +// ============================================================================= +// 焦点和主窗口管理 +// ============================================================================= + +auto window_registry::get_focused_window() const -> window_id { + std::shared_lock lock(mutex_); + return focused_window_; +} + +auto window_registry::set_focused_window(window_id id) -> bool { + std::unique_lock lock(mutex_); + + // 允许设置为无效ID(清除焦点) + if (!is_valid_window_id(id)) { + focused_window_ = INVALID_WINDOW_ID; + return true; + } + + // 检查窗口是否存在 + if (windows_.find(id) == windows_.end()) { + return false; + } + + focused_window_ = id; + return true; +} + +auto window_registry::get_main_window() const -> window_id { + std::shared_lock lock(mutex_); + return main_window_; +} + +auto window_registry::set_main_window(window_id id) -> bool { + std::unique_lock lock(mutex_); + + // 允许设置为无效ID(清除主窗口) + if (!is_valid_window_id(id)) { + main_window_ = INVALID_WINDOW_ID; + return true; + } + + // 检查窗口是否存在 + auto it = windows_.find(id); + if (it == windows_.end()) { + return false; + } + + // 只有主窗口类型才能设置为主窗口 + if (it->second.type != window_type::MAIN_WINDOW) { + return false; + } + + main_window_ = id; + return true; +} + +// ============================================================================= +// 内部辅助方法 +// ============================================================================= + +auto window_registry::remove_from_parent_impl(window_id child_id, window_id parent_id) -> void { + auto parent_it = windows_.find(parent_id); + if (parent_it != windows_.end()) { + parent_it->second.children.erase(child_id); + } +} + +auto window_registry::add_to_parent_impl(window_id child_id, window_id parent_id) -> void { + auto parent_it = windows_.find(parent_id); + if (parent_it != windows_.end()) { + parent_it->second.children.insert(child_id); + } +} + +auto window_registry::collect_descendants_impl(window_id id, std::vector& result) const -> void { + auto it = windows_.find(id); + if (it == windows_.end()) { + return; + } + + for (auto child_id : it->second.children) { + result.push_back(child_id); + collect_descendants_impl(child_id, result); + } +} + +} // namespace mirage \ No newline at end of file diff --git a/src/window/window_registry.h b/src/window/window_registry.h new file mode 100644 index 0000000..2379b7f --- /dev/null +++ b/src/window/window_registry.h @@ -0,0 +1,236 @@ +#pragma once + +#include "window_id.h" +#include "window_type.h" +#include "window_common.h" + +#include +#include +#include +#include +#include + +namespace mirage { + +/// 窗口元数据条目 +/// 存储单个窗口的所有相关信息 +struct window_entry { + /// 窗口唯一标识符 + window_id id{INVALID_WINDOW_ID}; + + /// 窗口类型 + window_type type{window_type::MAIN_WINDOW}; + + /// 窗口当前状态 + window_state state{window_state::NORMAL}; + + /// 父窗口ID,主窗口为 INVALID_WINDOW_ID + window_id parent_id{INVALID_WINDOW_ID}; + + /// 子窗口ID集合 + std::unordered_set children; + + /// 实际窗口实例(通过 mirage::window_ptr) + mirage::window_ptr instance; +}; + +/// 窗口注册表 +/// 负责窗口实例存储与查询、窗口父子关系管理、窗口状态追踪 +/// 线程安全,使用 std::shared_mutex 实现读写锁 +class window_registry { +public: + window_registry() = default; + ~window_registry() = default; + + // 禁止拷贝 + window_registry(const window_registry&) = delete; + auto operator=(const window_registry&) -> window_registry& = delete; + + // 禁止移动(因为有互斥锁成员) + window_registry(window_registry&&) = delete; + auto operator=(window_registry&&) -> window_registry& = delete; + + // ========================================================================= + // 窗口注册/注销 + // ========================================================================= + + /// 注册窗口 + /// @param id 窗口ID + /// @param type 窗口类型 + /// @param instance 窗口实例(所有权转移) + /// @param parent 父窗口ID,默认为 INVALID_WINDOW_ID + /// @return 成功返回true,失败返回false(如ID已存在) + [[nodiscard]] auto register_window(window_id id, window_type type, + mirage::window_ptr instance, + window_id parent = INVALID_WINDOW_ID) -> bool; + + /// 注销窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false(如ID不存在) + [[nodiscard]] auto unregister_window(window_id id) -> bool; + + /// 检查窗口是否已注册 + /// @param id 窗口ID + /// @return 如果已注册返回true,否则返回false + [[nodiscard]] auto contains(window_id id) const -> bool; + + // ========================================================================= + // 窗口查询 + // ========================================================================= + + /// 获取窗口实例 + /// @param id 窗口ID + /// @return 窗口实例指针,如不存在返回nullptr + [[nodiscard]] auto get_window(window_id id) -> mirage::window_interface*; + + /// 获取窗口实例(const版本) + /// @param id 窗口ID + /// @return 窗口实例指针,如不存在返回nullptr + [[nodiscard]] auto get_window(window_id id) const -> const mirage::window_interface*; + + /// 获取窗口条目的完整信息 + /// @param id 窗口ID + /// @return 窗口条目副本,如不存在返回nullopt + [[nodiscard]] auto get_entry(window_id id) const -> std::optional; + + /// 获取窗口类型 + /// @param id 窗口ID + /// @return 窗口类型,如不存在返回nullopt + [[nodiscard]] auto get_type(window_id id) const -> std::optional; + + // ========================================================================= + // 窗口关系管理 + // ========================================================================= + + /// 获取父窗口ID + /// @param id 窗口ID + /// @return 父窗口ID,如无父窗口或窗口不存在返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_parent(window_id id) const -> window_id; + + /// 获取直接子窗口列表 + /// @param id 窗口ID + /// @return 子窗口ID列表,如窗口不存在返回空列表 + [[nodiscard]] auto get_children(window_id id) const -> std::vector; + + /// 获取所有后代窗口(递归获取所有子窗口) + /// @param id 窗口ID + /// @return 所有后代窗口ID列表,如窗口不存在返回空列表 + [[nodiscard]] auto get_all_descendants(window_id id) const -> std::vector; + + /// 设置窗口的父窗口 + /// @param id 窗口ID + /// @param new_parent 新的父窗口ID + /// @return 成功返回true,失败返回false + [[nodiscard]] auto set_parent(window_id id, window_id new_parent) -> bool; + + /// 检查是否为祖先窗口 + /// @param ancestor 可能的祖先窗口ID + /// @param descendant 可能的后代窗口ID + /// @return 如果ancestor是descendant的祖先返回true + [[nodiscard]] auto is_ancestor_of(window_id ancestor, window_id descendant) const -> bool; + + // ========================================================================= + // 窗口状态管理 + // ========================================================================= + + /// 设置窗口状态 + /// @param id 窗口ID + /// @param state 新状态 + /// @return 成功返回true,失败返回false(如窗口不存在) + [[nodiscard]] auto set_state(window_id id, window_state state) -> bool; + + /// 获取窗口状态 + /// @param id 窗口ID + /// @return 窗口状态,如窗口不存在返回 HIDDEN + [[nodiscard]] auto get_state(window_id id) const -> window_state; + + // ========================================================================= + // 批量查询 + // ========================================================================= + + /// 按类型获取所有窗口ID + /// @param type 窗口类型 + /// @return 该类型的所有窗口ID列表 + [[nodiscard]] auto get_windows_by_type(window_type type) const -> std::vector; + + /// 获取所有已注册的窗口ID + /// @return 所有窗口ID列表 + [[nodiscard]] auto get_all_windows() const -> std::vector; + + /// 按状态获取所有窗口ID + /// @param state 窗口状态 + /// @return 该状态的所有窗口ID列表 + [[nodiscard]] auto get_windows_by_state(window_state state) const -> std::vector; + + // ========================================================================= + // 统计信息 + // ========================================================================= + + /// 获取已注册窗口总数 + /// @return 窗口数量 + [[nodiscard]] auto count() const -> size_t; + + /// 获取指定类型的窗口数量 + /// @param type 窗口类型 + /// @return 该类型的窗口数量 + [[nodiscard]] auto count_by_type(window_type type) const -> size_t; + + /// 获取指定状态的窗口数量 + /// @param state 窗口状态 + /// @return 该状态的窗口数量 + [[nodiscard]] auto count_by_state(window_state state) const -> size_t; + + /// 检查注册表是否为空 + /// @return 如果没有注册任何窗口返回true + [[nodiscard]] auto empty() const -> bool; + + // ========================================================================= + // 焦点和主窗口管理 + // ========================================================================= + + /// 获取当前焦点窗口ID + /// @return 焦点窗口ID,如无焦点窗口返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_focused_window() const -> window_id; + + /// 设置焦点窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false(如窗口不存在) + [[nodiscard]] auto set_focused_window(window_id id) -> bool; + + /// 获取主窗口ID + /// @return 主窗口ID,如无主窗口返回 INVALID_WINDOW_ID + [[nodiscard]] auto get_main_window() const -> window_id; + + /// 设置主窗口 + /// @param id 窗口ID + /// @return 成功返回true,失败返回false(如窗口不存在) + [[nodiscard]] auto set_main_window(window_id id) -> bool; + +private: + /// 读写互斥锁 + mutable std::shared_mutex mutex_; + + /// 窗口存储映射表 (id -> entry) + std::unordered_map windows_; + + /// 当前焦点窗口ID + window_id focused_window_{INVALID_WINDOW_ID}; + + /// 主窗口ID + window_id main_window_{INVALID_WINDOW_ID}; + + // ========================================================================= + // 内部辅助方法 + // ========================================================================= + + /// 从父窗口的子窗口集合中移除指定窗口(不加锁) + auto remove_from_parent_impl(window_id child_id, window_id parent_id) -> void; + + /// 添加到父窗口的子窗口集合(不加锁) + auto add_to_parent_impl(window_id child_id, window_id parent_id) -> void; + + /// 递归收集所有后代窗口(不加锁) + auto collect_descendants_impl(window_id id, std::vector& result) const -> void; +}; + +} // namespace mirage \ No newline at end of file diff --git a/src/window/window_type.h b/src/window/window_type.h new file mode 100644 index 0000000..0e008cd --- /dev/null +++ b/src/window/window_type.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include + +namespace mirage { + +/// 窗口类型枚举 +enum class window_type : uint8_t { + MAIN_WINDOW, ///< 主窗口 + CHILD_WINDOW, ///< 子窗口 + POPUP, ///< 弹出窗口 + DIALOG, ///< 对话框 + TOOLTIP ///< 提示窗口 +}; + +/// 窗口状态枚举 +enum class window_state : uint8_t { + NORMAL, ///< 正常状态 + MINIMIZED, ///< 最小化 + MAXIMIZED, ///< 最大化 + FULLSCREEN, ///< 全屏 + HIDDEN ///< 隐藏 +}; + +/// 将窗口类型转换为字符串表示 +/// @param type 窗口类型 +/// @return 窗口类型的字符串表示 +[[nodiscard]] constexpr auto to_string(window_type type) noexcept -> std::string_view { + switch (type) { + case window_type::MAIN_WINDOW: + return "MAIN_WINDOW"; + case window_type::CHILD_WINDOW: + return "CHILD_WINDOW"; + case window_type::POPUP: + return "POPUP"; + case window_type::DIALOG: + return "DIALOG"; + case window_type::TOOLTIP: + return "TOOLTIP"; + default: + return "UNKNOWN"; + } +} + +/// 将窗口状态转换为字符串表示 +/// @param state 窗口状态 +/// @return 窗口状态的字符串表示 +[[nodiscard]] constexpr auto to_string(window_state state) noexcept -> std::string_view { + switch (state) { + case window_state::NORMAL: + return "NORMAL"; + case window_state::MINIMIZED: + return "MINIMIZED"; + case window_state::MAXIMIZED: + return "MAXIMIZED"; + case window_state::FULLSCREEN: + return "FULLSCREEN"; + case window_state::HIDDEN: + return "HIDDEN"; + default: + return "UNKNOWN"; + } +} + +} // namespace mirage \ No newline at end of file