From ea33fb1c7212a8a3b9633e0b9fd909aab186028c Mon Sep 17 00:00:00 2001 From: Matthew Kosarek Date: Sat, 3 Aug 2024 16:34:45 -0400 Subject: [PATCH] refactor: a Container is used as the active element instead of a miral::Window (#201) --- src/compositor_state.h | 6 +- src/container.cpp | 2 +- src/container.h | 3 +- src/floating_container.cpp | 35 ++++-- src/floating_container.h | 6 +- src/i3_command_executor.cpp | 16 +-- src/leaf_container.cpp | 37 +++--- src/leaf_container.h | 5 +- src/miracle_config.cpp | 4 +- src/miracle_config.h | 2 +- src/output.cpp | 34 +++--- src/output.h | 14 ++- src/parent_container.cpp | 12 +- src/parent_container.h | 3 + src/policy.cpp | 109 ++++++++---------- src/policy.h | 2 +- src/renderer.cpp | 2 +- src/shell_component_container.cpp | 5 + src/shell_component_container.h | 2 + src/tiling_window_tree.cpp | 31 +++-- src/tiling_window_tree.h | 3 + ...window_manager_tools_window_controller.cpp | 2 +- src/workspace.cpp | 94 ++++++++------- src/workspace.h | 12 +- tests/tiling_window_tree_test.cpp | 2 +- 25 files changed, 251 insertions(+), 192 deletions(-) diff --git a/src/compositor_state.h b/src/compositor_state.h index 0ec20bf..25d7c83 100644 --- a/src/compositor_state.h +++ b/src/compositor_state.h @@ -19,10 +19,12 @@ along with this program. If not, see . #define MIRACLE_WM_COMPOSITOR_STATE_H #include -#include +#include namespace miracle { +class Container; + enum class WindowManagerMode { normal = 0, @@ -37,7 +39,7 @@ struct CompositorState { mir::geometry::Point cursor_position; WindowManagerMode mode = WindowManagerMode::normal; - miral::Window active_window; + std::shared_ptr active; }; } diff --git a/src/container.cpp b/src/container.cpp index 14ea7fc..d4140d4 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -31,7 +31,7 @@ using namespace miracle; ContainerType miracle::container_type_from_string(std::string const& str) { if (str == "tiled") - return ContainerType::tiled; + return ContainerType::leaf; else if (str == "floating") return ContainerType::floating; else if (str == "shell") diff --git a/src/container.h b/src/container.h index 140a1bc..828aef4 100644 --- a/src/container.h +++ b/src/container.h @@ -43,7 +43,7 @@ class Output; enum class ContainerType { none, - tiled, + leaf, floating, shell, parent @@ -104,6 +104,7 @@ public: virtual uint32_t animation_handle() const = 0; virtual void animation_handle(uint32_t) = 0; virtual bool is_focused() const = 0; + virtual bool is_fullscreen() const = 0; virtual std::optional window() const = 0; virtual bool select_next(Direction) = 0; virtual bool pinned() const = 0; diff --git a/src/floating_container.cpp b/src/floating_container.cpp index 0b04bc8..4f9faab 100644 --- a/src/floating_container.cpp +++ b/src/floating_container.cpp @@ -30,7 +30,7 @@ using namespace miracle; FloatingContainer::FloatingContainer( miral::Window const& window, - miral::MinimalWindowManager& wm, + std::shared_ptr const& wm, WindowController& window_controller, Workspace* workspace, CompositorState const& state) : @@ -84,31 +84,31 @@ size_t FloatingContainer::get_min_width() const void FloatingContainer::handle_ready() { auto& info = window_controller.info_for(window_); - wm.handle_window_ready(info); + wm->handle_window_ready(info); } void FloatingContainer::handle_modify(miral::WindowSpecification const& modifications) { auto& info = window_controller.info_for(window_); - wm.handle_modify_window(info, modifications); + wm->handle_modify_window(info, modifications); } void FloatingContainer::handle_request_move(MirInputEvent const* input_event) { - wm.handle_request_move( + wm->handle_request_move( window_controller.info_for(window_), input_event); } void FloatingContainer::handle_request_resize( MirInputEvent const* input_event, MirResizeEdge edge) { - wm.handle_request_resize( + wm->handle_request_resize( window_controller.info_for(window_), input_event, edge); } void FloatingContainer::handle_raise() { - wm.handle_raise_window(window_controller.info_for(window_)); + wm->handle_raise_window(window_controller.info_for(window_)); } void FloatingContainer::on_open() @@ -118,23 +118,26 @@ void FloatingContainer::on_open() void FloatingContainer::on_focus_gained() { - wm.advise_focus_gained(window_controller.info_for(window_)); + if (get_output()->get_active_workspace()->get_workspace() != workspace_->get_workspace()) + return; + + wm->advise_focus_gained(window_controller.info_for(window_)); } void FloatingContainer::on_focus_lost() { - wm.advise_focus_lost(window_controller.info_for(window_)); + wm->advise_focus_lost(window_controller.info_for(window_)); } void FloatingContainer::on_move_to(geom::Point const& top_left) { - wm.advise_move_to(window_controller.info_for(window_), top_left); + wm->advise_move_to(window_controller.info_for(window_), top_left); } mir::geometry::Rectangle FloatingContainer::confirm_placement( MirWindowState state, mir::geometry::Rectangle const& placement) { - return wm.confirm_placement_on_display( + return wm->confirm_placement_on_display( window_controller.info_for(window_), state, placement); @@ -195,6 +198,11 @@ Workspace* FloatingContainer::get_workspace() const return workspace_; } +void FloatingContainer::set_workspace(Workspace* workspace) +{ + workspace_ = workspace; +} + Output* FloatingContainer::get_output() const { return workspace_->get_output(); @@ -222,7 +230,12 @@ void FloatingContainer::animation_handle(uint32_t handle) bool FloatingContainer::is_focused() const { - return state.active_window == window_; + return state.active.get() == this; +} + +bool FloatingContainer::is_fullscreen() const +{ + return window_controller.is_fullscreen(window_); } ContainerType FloatingContainer::get_type() const diff --git a/src/floating_container.h b/src/floating_container.h index fce1374..dad06df 100644 --- a/src/floating_container.h +++ b/src/floating_container.h @@ -33,7 +33,7 @@ class FloatingContainer : public Container public: FloatingContainer( miral::Window const&, - miral::MinimalWindowManager& wm, + std::shared_ptr const& wm, WindowController& window_controller, Workspace* workspace, CompositorState const& state); @@ -67,12 +67,14 @@ public: void restore_state(MirWindowState state) override; std::optional restore_state() override; Workspace* get_workspace() const override; + void set_workspace(Workspace*); Output* get_output() const override; glm::mat4 get_transform() const override; void set_transform(glm::mat4 transform) override; uint32_t animation_handle() const override; void animation_handle(uint32_t uint_32) override; bool is_focused() const override; + bool is_fullscreen() const override; ContainerType get_type() const override; glm::mat4 get_workspace_transform() const override; glm::mat4 get_output_transform() const override; @@ -85,7 +87,7 @@ public: private: miral::Window window_; - miral::MinimalWindowManager& wm; + std::shared_ptr wm; WindowController& window_controller; CompositorState const& state; diff --git a/src/i3_command_executor.cpp b/src/i3_command_executor.cpp index 54e77fe..9fff9c4 100644 --- a/src/i3_command_executor.cpp +++ b/src/i3_command_executor.cpp @@ -198,7 +198,7 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL if (!container) return; - if (container->get_type() != ContainerType::tiled) + if (container->get_type() != ContainerType::leaf) { mir::log_warning("Cannot focus prev when a tiling window is not selected"); return; @@ -224,7 +224,7 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL if (!container) return; - if (container->get_type() != ContainerType::tiled) + if (container->get_type() != ContainerType::leaf) { mir::log_warning("Cannot focus prev when a tiling window is not selected"); return; @@ -332,10 +332,10 @@ void I3CommandExecutor::process_move(I3Command const& command, I3ScopedCommandLi auto const& arg1 = command.arguments[index++]; if (arg1 == "center") { - auto active_window = policy.get_state().active_window; + auto active = policy.get_state().active; auto area = active_output->get_area(); - float x = (float)area.size.width.as_int() / 2.f - (float)active_window.size().width.as_int() / 2.f; - float y = (float)area.size.height.as_int() / 2.f - (float)active_window.size().height.as_int() / 2.f; + float x = (float)area.size.width.as_int() / 2.f - (float)active->get_visible_area().size.width.as_int() / 2.f; + float y = (float)area.size.height.as_int() / 2.f - (float)active->get_visible_area().size.height.as_int() / 2.f; policy.try_move_to((int)x, (int)y); } else if (arg1 == "mouse") @@ -392,9 +392,9 @@ void I3CommandExecutor::process_move(I3Command const& command, I3ScopedCommandLi y = end_y; } - auto active_window = policy.get_state().active_window; - float x_pos = x / 2.f - (float)active_window.size().width.as_int() / 2.f; - float y_pos = y / 2.f - (float)active_window.size().height.as_int() / 2.f; + auto active = policy.get_state().active; + float x_pos = x / 2.f - (float)active->get_visible_area().size.width.as_int() / 2.f; + float y_pos = y / 2.f - (float)active->get_visible_area().size.height.as_int() / 2.f; policy.try_move_to((int)x_pos, (int)y_pos); return; } diff --git a/src/leaf_container.cpp b/src/leaf_container.cpp index 9a5ce03..b17aba5 100644 --- a/src/leaf_container.cpp +++ b/src/leaf_container.cpp @@ -35,7 +35,7 @@ LeafContainer::LeafContainer( TilingWindowTree* tree, std::shared_ptr const& parent, CompositorState const& state) : - node_interface { node_interface }, + window_controller {node_interface }, logical_area { std::move(area) }, config { config }, tree { tree }, @@ -111,10 +111,10 @@ geom::Rectangle LeafContainer::get_visible_area() const void LeafContainer::constrain() { - if (node_interface.is_fullscreen(window_)) - node_interface.noclip(window_); + if (window_controller.is_fullscreen(window_)) + window_controller.noclip(window_); else - node_interface.clip(window_, get_visible_area()); + window_controller.clip(window_, get_visible_area()); } size_t LeafContainer::get_min_width() const @@ -135,7 +135,7 @@ void LeafContainer::handle_ready() void LeafContainer::handle_modify(miral::WindowSpecification const& modifications) { - auto const& info = node_interface.info_for(window_); + auto const& info = window_controller.info_for(window_); // TODO: Check if the current workspace is active. If not, return early. @@ -160,12 +160,12 @@ void LeafContainer::handle_modify(miral::WindowSpecification const& modification mods.size().consume(); } - node_interface.modify(window_, mods); + window_controller.modify(window_, mods); } void LeafContainer::handle_raise() { - node_interface.select_active_window(window_); + window_controller.select_active_window(window_); } bool LeafContainer::resize(miracle::Direction direction) @@ -181,13 +181,13 @@ void LeafContainer::show() void LeafContainer::hide() { - before_shown_state = node_interface.get_state(window_); + before_shown_state = window_controller.get_state(window_); next_state = mir_window_state_hidden; } bool LeafContainer::toggle_fullscreen() { - if (node_interface.is_fullscreen(window_)) + if (window_controller.is_fullscreen(window_)) next_state = mir_window_state_restored; else next_state = mir_window_state_fullscreen; @@ -206,7 +206,7 @@ mir::geometry::Rectangle LeafContainer::confirm_placement( void LeafContainer::on_open() { - node_interface.open(window_); + window_controller.open(window_); } void LeafContainer::on_focus_gained() @@ -224,14 +224,14 @@ void LeafContainer::on_move_to(geom::Point const&) bool LeafContainer::is_fullscreen() const { - return node_interface.is_fullscreen(window_); + return window_controller.is_fullscreen(window_); } void LeafContainer::commit_changes() { if (next_state) { - node_interface.change_state(window_, next_state.value()); + window_controller.change_state(window_, next_state.value()); constrain(); next_state.reset(); } @@ -241,9 +241,9 @@ void LeafContainer::commit_changes() auto previous = get_visible_area(); logical_area = next_logical_area.value(); next_logical_area.reset(); - if (!node_interface.is_fullscreen(window_)) + if (!window_controller.is_fullscreen(window_)) { - node_interface.set_rectangle(window_, previous, get_visible_area()); + window_controller.set_rectangle(window_, previous, get_visible_area()); constrain(); } } @@ -272,6 +272,11 @@ void LeafContainer::toggle_layout() tree->toggle_layout(*this); } +void LeafContainer::set_tree(TilingWindowTree* tree_) +{ + tree = tree_; +} + void LeafContainer::restore_state(MirWindowState state) { restore_state_ = state; @@ -316,12 +321,12 @@ void LeafContainer::animation_handle(uint32_t handle) bool LeafContainer::is_focused() const { - return state.active_window == window_; + return state.active.get() == this; } ContainerType LeafContainer::get_type() const { - return ContainerType::tiled; + return ContainerType::leaf; } bool LeafContainer::select_next(miracle::Direction direction) diff --git a/src/leaf_container.h b/src/leaf_container.h index b4555d0..f204e06 100644 --- a/src/leaf_container.h +++ b/src/leaf_container.h @@ -55,7 +55,7 @@ public: void set_state(MirWindowState state); void show(); void hide(); - bool is_fullscreen() const; + bool is_fullscreen() const override; void constrain() override; size_t get_min_width() const override; size_t get_min_height() const override; @@ -75,6 +75,7 @@ public: void request_horizontal_layout() override; void request_vertical_layout() override; void toggle_layout() override; + void set_tree(TilingWindowTree* tree); [[nodiscard]] TilingWindowTree* get_tree() const { return tree; } [[nodiscard]] std::optional window() const override { return window_; } @@ -97,7 +98,7 @@ public: bool move_to(int, int) override; private: - WindowController& node_interface; + WindowController& window_controller; geom::Rectangle logical_area; std::optional next_logical_area; std::shared_ptr config; diff --git a/src/miracle_config.cpp b/src/miracle_config.cpp index b5cc7ef..0f12929 100644 --- a/src/miracle_config.cpp +++ b/src/miracle_config.cpp @@ -811,7 +811,7 @@ void FilesystemConfiguration::_load() { auto num = workspace["number"].as(); auto type = container_type_from_string(workspace["layout"].as()); - if (type != ContainerType::tiled && type != ContainerType::floating) + if (type != ContainerType::leaf && type != ContainerType::floating) { mir::log_error("layout should be 'tiled' or 'floating': L%d:%d", workspace["layout"].Mark().line, workspace["layout"].Mark().column); continue; @@ -1155,5 +1155,5 @@ WorkspaceConfig FilesystemConfiguration::get_workspace_config(int key) const return config; } - return { key, ContainerType::tiled }; + return { key, ContainerType::leaf }; } \ No newline at end of file diff --git a/src/miracle_config.h b/src/miracle_config.h index 27edfc8..258b416 100644 --- a/src/miracle_config.h +++ b/src/miracle_config.h @@ -129,7 +129,7 @@ struct BorderConfig struct WorkspaceConfig { int num = -1; - ContainerType layout = ContainerType::tiled; + ContainerType layout = ContainerType::leaf; }; class MiracleConfig diff --git a/src/output.cpp b/src/output.cpp index fdc3c3c..a5b8602 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -42,7 +42,7 @@ Output::Output( WorkspaceManager& workspace_manager, geom::Rectangle const& area, miral::WindowManagerTools const& tools, - miral::MinimalWindowManager& floating_window_manager, + std::shared_ptr const& floating_window_manager, CompositorState& state, std::shared_ptr const& config, WindowController& node_interface, @@ -82,13 +82,13 @@ bool Output::handle_pointer_event(const MirPointerEvent* event) return true; auto const action = mir_pointer_event_action(event); - if (has_clicked_floating_window || get_active_workspace()->has_floating_window(state.active_window)) + if (has_clicked_floating_window || get_active_workspace()->has_floating_window(state.active)) { if (action == mir_pointer_action_button_down) has_clicked_floating_window = true; else if (action == mir_pointer_action_button_up) has_clicked_floating_window = false; - return floating_window_manager.handle_pointer_event(event); + return floating_window_manager->handle_pointer_event(event); } return false; @@ -106,16 +106,16 @@ ContainerType Output::allocate_position( return get_active_workspace()->allocate_position(app_info, requested_specification, ideal_type); } -std::shared_ptr Output::advise_new_window( +std::shared_ptr Output::create_container( miral::WindowInfo const& window_info, ContainerType type) const { - return get_active_workspace()->advise_new_window(window_info, type); + return get_active_workspace()->create_container(window_info, type); } -void Output::advise_delete_window(const std::shared_ptr& container) +void Output::delete_container(std::shared_ptr const &container) { auto workspace = container->get_workspace(); - workspace->advise_delete_window(container); + workspace->delete_container(container); } bool Output::select_window_from_point(int x, int y) const @@ -309,20 +309,13 @@ std::vector Output::collect_all_windows() const void Output::request_toggle_active_float() { - if (tools.active_window() == Window()) + if (!state.active) { - mir::log_warning("request_toggle_active_float: active window unset"); + mir::log_warning("request_toggle_active_float: active unset"); return; } - auto container = window_controller.get_container(state.active_window); - if (!container) - { - mir::log_error("request_toggle_active_float: container not found"); - return; - } - - container->get_workspace()->toggle_floating(container); + state.active->get_workspace()->toggle_floating(state.active); } void Output::add_immediately(miral::Window& window, ContainerType hint) @@ -336,10 +329,15 @@ void Output::add_immediately(miral::Window& window, ContainerType hint) ContainerType type = allocate_position(tools.info_for(window.application()), spec, hint); tools.modify_window(window, spec); - auto container = advise_new_window(window_controller.info_for(window), type); + auto container = create_container(window_controller.info_for(window), type); container->handle_ready(); } +void Output::graft(std::shared_ptr const& container) +{ + get_active_workspace()->graft(container); +} + geom::Rectangle Output::get_workspace_rectangle(int workspace) const { // TODO: Support vertical workspaces one day in the future diff --git a/src/output.h b/src/output.h index 13ed2b9..b89c68d 100644 --- a/src/output.h +++ b/src/output.h @@ -44,7 +44,7 @@ public: WorkspaceManager& workspace_manager, geom::Rectangle const& area, miral::WindowManagerTools const& tools, - miral::MinimalWindowManager& floating_window_manager, + std::shared_ptr const& floating_window_manager, CompositorState& state, std::shared_ptr const& options, WindowController&, @@ -53,8 +53,8 @@ public: bool handle_pointer_event(MirPointerEvent const* event); ContainerType allocate_position(miral::ApplicationInfo const& app_info, miral::WindowSpecification& requested_specification, ContainerType hint = ContainerType::none); - [[nodiscard]] std::shared_ptr advise_new_window(miral::WindowInfo const& window_info, ContainerType type) const; - void advise_delete_window(std::shared_ptr const& container); + [[nodiscard]] std::shared_ptr create_container(miral::WindowInfo const& window_info, ContainerType type) const; + void delete_container(std::shared_ptr const &container); [[nodiscard]] bool select_window_from_point(int x, int y) const; void advise_new_workspace(int workspace); void advise_workspace_deleted(int workspace); @@ -70,8 +70,12 @@ public: /// Immediately requests that the provided window be added to the output /// with the provided type. This is a deviation away from the typical /// window-adding flow where you first call 'place_new_window' followed - /// by 'advise_new_window'. + /// by 'create_container'. void add_immediately(miral::Window& window, ContainerType hint = ContainerType::none); + + /// Takes an existing [Container] object and places it in an appropriate position + /// on the active [Workspace]. + void graft(std::shared_ptr const& container); void set_is_active(bool new_is_active) { is_active_ = new_is_active; } void set_transform(glm::mat4 const& in); void set_position(glm::vec2 const&); @@ -95,7 +99,7 @@ private: miral::Output output; WorkspaceManager& workspace_manager; miral::WindowManagerTools tools; - miral::MinimalWindowManager& floating_window_manager; + std::shared_ptr floating_window_manager; CompositorState& state; geom::Rectangle area; std::shared_ptr config; diff --git a/src/parent_container.cpp b/src/parent_container.cpp index f6d3ffb..773580a 100644 --- a/src/parent_container.cpp +++ b/src/parent_container.cpp @@ -584,6 +584,11 @@ void ParentContainer::toggle_layout() { } +void ParentContainer::set_tree(TilingWindowTree* tree_) +{ + tree = tree_; +} + void ParentContainer::on_focus_gained() { } @@ -599,7 +604,7 @@ void ParentContainer::on_move_to(mir::geometry::Point const& top_left) mir::geometry::Rectangle ParentContainer::confirm_placement(MirWindowState state, mir::geometry::Rectangle const& rectangle) { - return mir::geometry::Rectangle(); + return rectangle; } ContainerType ParentContainer::get_type() const @@ -697,3 +702,8 @@ bool ParentContainer::move_to(int x, int y) { return false; } + +bool ParentContainer::is_fullscreen() const +{ + return false; +} diff --git a/src/parent_container.h b/src/parent_container.h index baba736..318b23d 100644 --- a/src/parent_container.h +++ b/src/parent_container.h @@ -78,6 +78,7 @@ public: void request_horizontal_layout() override; void request_vertical_layout() override; void toggle_layout() override; + void set_tree(TilingWindowTree*); void on_focus_gained() override; void on_focus_lost() override; void on_move_to(mir::geometry::Point const& top_left) override; @@ -104,6 +105,8 @@ public: bool move_by(Direction direction, int pixels) override; bool move_to(int x, int y) override; + bool is_fullscreen() const override; + private: WindowController& node_interface; geom::Rectangle logical_area; diff --git a/src/policy.cpp b/src/policy.cpp index c2e6256..8419ef6 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -50,7 +50,7 @@ Policy::Policy( SurfaceTracker& surface_tracker, mir::Server const& server) : window_manager_tools { tools }, - floating_window_manager(tools, config->get_input_event_modifier()), + floating_window_manager(std::make_shared(tools, config->get_input_event_modifier())), external_client_launcher { external_client_launcher }, runner { runner }, config { config }, @@ -243,7 +243,7 @@ void Policy::advise_new_window(miral::WindowInfo const& window_info) auto shared_output = pending_output.lock(); if (!shared_output) { - mir::log_warning("advise_new_window: output unavailable"); + mir::log_warning("create_container: output unavailable"); auto window = window_info.window(); if (!output_list.empty()) { @@ -262,7 +262,7 @@ void Policy::advise_new_window(miral::WindowInfo const& window_info) return; } - auto container = shared_output->advise_new_window(window_info, pending_type); + auto container = shared_output->create_container(window_info, pending_type); container->animation_handle(animator.register_animateable()); container->on_open(); @@ -287,7 +287,6 @@ void Policy::handle_window_ready(miral::WindowInfo& window_info) void Policy::advise_focus_gained(const miral::WindowInfo& window_info) { - state.active_window = window_info.window(); auto container = window_controller.get_container(window_info.window()); if (!container) { @@ -295,12 +294,12 @@ void Policy::advise_focus_gained(const miral::WindowInfo& window_info) return; } + state.active = container; container->on_focus_gained(); } void Policy::advise_focus_lost(const miral::WindowInfo& window_info) { - state.active_window = Window(); auto container = window_controller.get_container(window_info.window()); if (!container) { @@ -308,6 +307,8 @@ void Policy::advise_focus_lost(const miral::WindowInfo& window_info) return; } + if (container == state.active) + state.active = nullptr; container->on_focus_lost(); } @@ -326,17 +327,17 @@ void Policy::advise_delete_window(const miral::WindowInfo& window_info) auto container = window_controller.get_container(window_info.window()); if (!container) { - mir::log_error("advise_delete_window: container is not provided"); + mir::log_error("delete_container: container is not provided"); return; } if (container->get_output()) - container->get_output()->advise_delete_window(container); + container->get_output()->delete_container(container); surface_tracker.remove(window_info.window()); - if (state.active_window == window_info.window()) - state.active_window = Window(); + if (state.active == container) + state.active = nullptr; } void Policy::advise_move_to(miral::WindowInfo const& window_info, geom::Point top_left) @@ -547,21 +548,14 @@ void Policy::try_toggle_resize_mode() return; } - auto const& window = state.active_window; - if (!window) - { - state.mode = WindowManagerMode::normal; - return; - } - - auto container = window_controller.get_container(window); + auto container = state.active; if (!container) { state.mode = WindowManagerMode::normal; return; } - if (container->get_type() != ContainerType::tiled) + if (container->get_type() != ContainerType::leaf) { state.mode = WindowManagerMode::normal; return; @@ -580,11 +574,10 @@ bool Policy::try_request_vertical() if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - container->request_vertical_layout(); + state.active->request_vertical_layout(); return true; } @@ -593,11 +586,10 @@ bool Policy::try_toggle_layout() if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - container->toggle_layout(); + state.active->toggle_layout(); return true; } @@ -606,11 +598,10 @@ bool Policy::try_request_horizontal() if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - container->request_horizontal_layout(); + state.active->request_horizontal_layout(); return true; } @@ -619,11 +610,10 @@ bool Policy::try_resize(miracle::Direction direction) if (state.mode != WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->resize(direction); + return state.active->resize(direction); } bool Policy::try_move(miracle::Direction direction) @@ -631,11 +621,10 @@ bool Policy::try_move(miracle::Direction direction) if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->move(direction); + return state.active->move(direction); } bool Policy::try_move_by(miracle::Direction direction, int pixels) @@ -643,11 +632,10 @@ bool Policy::try_move_by(miracle::Direction direction, int pixels) if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->move_by(direction, pixels); + return state.active->move_by(direction, pixels); } bool Policy::try_move_to(int x, int y) @@ -655,11 +643,10 @@ bool Policy::try_move_to(int x, int y) if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->move_to(x, y); + return state.active->move_to(x, y); } bool Policy::try_select(miracle::Direction direction) @@ -667,11 +654,10 @@ bool Policy::try_select(miracle::Direction direction) if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->select_next(direction); + return state.active->select_next(direction); } bool Policy::try_close_window() @@ -679,7 +665,14 @@ bool Policy::try_close_window() if (!active_output) return false; - window_controller.close(state.active_window); + if (!state.active) + return false; + + auto window = state.active->window(); + if (!window) + return false; + + window_controller.close(window.value()); return true; } @@ -694,11 +687,10 @@ bool Policy::try_toggle_fullscreen() if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->toggle_fullscreen(); + return state.active->toggle_fullscreen(); } bool Policy::select_workspace(int number) @@ -718,21 +710,18 @@ bool Policy::move_active_to_workspace(int number) if (state.mode == WindowManagerMode::resizing) return false; - if (!active_output || !state.active_window) + if (!active_output || !state.active) return false; - auto& info = window_controller.info_for(state.active_window); - if (window_helpers::is_window_fullscreen(info.state())) + if (state.active->is_fullscreen()) return false; - auto container = window_controller.get_container(state.active_window); - auto window_to_move = state.active_window; - active_output->advise_delete_window(container); - state.active_window = Window(); + auto to_move = state.active; + active_output->delete_container(state.active); + state.active = nullptr; auto screen_to_move_to = workspace_manager.request_workspace(active_output, number); - screen_to_move_to->add_immediately(window_to_move, ContainerType::tiled); - + screen_to_move_to->graft(to_move); return true; } @@ -753,11 +742,10 @@ bool Policy::toggle_pinned_to_workspace() if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->pinned(!container->pinned()); + return state.active->pinned(!state.active->pinned()); } bool Policy::set_is_pinned(bool pinned) @@ -765,9 +753,8 @@ bool Policy::set_is_pinned(bool pinned) if (state.mode == WindowManagerMode::resizing) return false; - if (!state.active_window) + if (!state.active) return false; - auto container = window_controller.get_container(state.active_window); - return container->pinned(pinned); + return state.active->pinned(pinned); } \ No newline at end of file diff --git a/src/policy.h b/src/policy.h index 3622e53..6b2c7f9 100644 --- a/src/policy.h +++ b/src/policy.h @@ -130,7 +130,7 @@ private: ContainerType pending_type; std::vector orphaned_window_list; miral::WindowManagerTools window_manager_tools; - miral::MinimalWindowManager floating_window_manager; + std::shared_ptr floating_window_manager; AutoRestartingLauncher& external_client_launcher; miral::MirRunner& runner; std::shared_ptr config; diff --git a/src/renderer.cpp b/src/renderer.cpp index e1688fe..66f1738 100644 --- a/src/renderer.cpp +++ b/src/renderer.cpp @@ -225,7 +225,7 @@ Renderer::DrawData Renderer::get_draw_data(mir::graphics::Renderable const& rend auto tools = WindowToolsAccessor::get_instance().get_tools(); auto& info = tools.info_for(window); auto userdata = static_pointer_cast(info.userdata()); - data.needs_outline = (userdata->get_type() == ContainerType::tiled || userdata->get_type() == ContainerType::floating) + data.needs_outline = (userdata->get_type() == ContainerType::leaf || userdata->get_type() == ContainerType::floating) && !info.parent(); data.workspace_transform = userdata->get_output_transform() * userdata->get_workspace_transform(); data.is_focused = userdata->is_focused(); diff --git a/src/shell_component_container.cpp b/src/shell_component_container.cpp index 62544b9..be33d0c 100644 --- a/src/shell_component_container.cpp +++ b/src/shell_component_container.cpp @@ -230,4 +230,9 @@ bool ShellComponentContainer::move_to(int x, int y) return false; } +bool ShellComponentContainer::is_fullscreen() const +{ + return false; +} + } // miracle \ No newline at end of file diff --git a/src/shell_component_container.h b/src/shell_component_container.h index 4ac1931..fd66ddc 100644 --- a/src/shell_component_container.h +++ b/src/shell_component_container.h @@ -77,6 +77,8 @@ public: bool move_by(Direction direction, int pixels) override; bool move_to(int x, int y) override; + bool is_fullscreen() const override; + private: miral::Window window_; WindowController& window_controller; diff --git a/src/tiling_window_tree.cpp b/src/tiling_window_tree.cpp index e84e804..6108dfa 100644 --- a/src/tiling_window_tree.cpp +++ b/src/tiling_window_tree.cpp @@ -93,6 +93,20 @@ std::shared_ptr TilingWindowTree::confirm_window( return parent->confirm_window(window_info.window()); } +void TilingWindowTree::graft(std::shared_ptr const& parent) +{ + parent->set_tree(this); + root_lane->graft_existing(parent, root_lane->num_nodes()); + root_lane->commit_changes(); +} + +void TilingWindowTree::graft(std::shared_ptr const& leaf) +{ + leaf->set_tree(this); + root_lane->graft_existing(leaf, root_lane->num_nodes()); + root_lane->commit_changes(); +} + bool TilingWindowTree::resize_container(miracle::Direction direction, Container& container) { if (is_active_window_fullscreen) @@ -363,8 +377,8 @@ std::shared_ptr TilingWindowTree::handle_select( // 4. If none match, we return nullptr bool is_vertical = is_vertical_direction(direction); bool is_negative = is_negative_direction(direction); - auto& current_node = from; - auto parent = Container::as_parent(current_node.get_parent().lock()); + auto current_node = from.shared_from_this(); + auto parent = Container::as_parent(current_node->get_parent().lock()); if (!parent) { mir::log_warning("Cannot handle_select the root node"); @@ -390,7 +404,7 @@ std::shared_ptr TilingWindowTree::handle_select( } } - current_node = *parent; + current_node = parent; parent = Container::as_parent(parent->get_parent().lock()); } while (parent != nullptr); @@ -609,7 +623,7 @@ bool TilingWindowTree::advise_fullscreen_container(LeafContainer& container) bool TilingWindowTree::advise_restored_container(LeafContainer& container) { auto active = active_container(); - if (active->window() == container.window().value() && is_active_window_fullscreen) + if (active && active->window() == container.window().value() && is_active_window_fullscreen) { is_active_window_fullscreen = false; container.set_logical_area(container.get_logical_area()); @@ -756,12 +770,5 @@ Workspace* TilingWindowTree::get_workspace() const std::shared_ptr TilingWindowTree::active_container() const { - if (!state.active_window) - return nullptr; - - auto container = window_controller.get_container(state.active_window); - if (!container) - return nullptr; - - return Container::as_leaf(container); + return Container::as_leaf(state.active); } \ No newline at end of file diff --git a/src/tiling_window_tree.h b/src/tiling_window_tree.h index c76a037..70a8906 100644 --- a/src/tiling_window_tree.h +++ b/src/tiling_window_tree.h @@ -68,6 +68,9 @@ public: miral::WindowInfo const&, std::shared_ptr const& container); + void graft(std::shared_ptr const&); + void graft(std::shared_ptr const&); + /// Try to resize the current active window in the provided direction bool resize_container(Direction direction, Container&); diff --git a/src/window_manager_tools_window_controller.cpp b/src/window_manager_tools_window_controller.cpp index 565e0f3..ee9ddac 100644 --- a/src/window_manager_tools_window_controller.cpp +++ b/src/window_manager_tools_window_controller.cpp @@ -194,7 +194,7 @@ void WindowManagerToolsWindowController::on_animation( { spec.top_left().value().x.as_int(), spec.top_left().value().y.as_int() }, { scale.x, scale.y }); - if (container->get_type() == ContainerType::tiled) + if (container->get_type() == ContainerType::leaf) clip(window, new_rectangle); else noclip(window); diff --git a/src/workspace.cpp b/src/workspace.cpp index 9961251..be1cc6e 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -24,6 +24,7 @@ along with this program. If not, see . #include "output.h" #include "tiling_window_tree.h" #include "window_helpers.h" +#include "parent_container.h" #include "floating_container.h" #include "shell_component_container.h" @@ -73,7 +74,7 @@ Workspace::Workspace( std::shared_ptr const& config, WindowController& window_controller, CompositorState const& state, - miral::MinimalWindowManager& floating_window_manager) : + std::shared_ptr const& floating_window_manager) : output { output }, tools { tools }, workspace { workspace }, @@ -113,14 +114,14 @@ ContainerType Workspace::allocate_position( : hint; switch (layout) { - case ContainerType::tiled: + case ContainerType::leaf: { requested_specification = tree->place_new_window(requested_specification, get_layout_container()); - return ContainerType::tiled; + return ContainerType::leaf; } case ContainerType::floating: { - requested_specification = floating_window_manager.place_new_window(app_info, requested_specification); + requested_specification = floating_window_manager->place_new_window(app_info, requested_specification); requested_specification.server_side_decorated() = false; return ContainerType::floating; } @@ -129,20 +130,20 @@ ContainerType Workspace::allocate_position( } } -std::shared_ptr Workspace::advise_new_window( +std::shared_ptr Workspace::create_container( miral::WindowInfo const& window_info, ContainerType type) { std::shared_ptr container = nullptr; switch (type) { - case ContainerType::tiled: + case ContainerType::leaf: { container = tree->confirm_window(window_info, get_layout_container()); break; } case ContainerType::floating: { - floating_window_manager.advise_new_window(window_info); + floating_window_manager->advise_new_window(window_info); container = add_floating_window(window_info.window()); break; } @@ -167,7 +168,7 @@ std::shared_ptr Workspace::advise_new_window( // TODO: hack // Warning: We need to advise fullscreen only after we've associated the userdata() appropriately - if (type == ContainerType::tiled && window_helpers::is_window_fullscreen(window_info.state())) + if (type == ContainerType::leaf && window_helpers::is_window_fullscreen(window_info.state())) { tree->advise_fullscreen_container(*Container::as_leaf(container)); } @@ -183,23 +184,24 @@ void Workspace::handle_ready_hack(LeafContainer& container) window_controller.raise(window->window().value()); if (tree->has_fullscreen_window()) - window_controller.raise(state.active_window); + window_controller.raise(state.active->window().value()); } -void Workspace::advise_delete_window(std::shared_ptr const& container) +void Workspace::delete_container(std::shared_ptr const &container) { switch (container->get_type()) { - case ContainerType::tiled: + case ContainerType::leaf: { tree->advise_delete_window(container); break; } case ContainerType::floating: { - auto window = Container::as_floating(container)->window().value(); - floating_window_manager.advise_delete_window(window_controller.info_for(window)); - remove_floating_window(window); + auto floating = Container::as_floating(container); + floating_window_manager->advise_delete_window(window_controller.info_for(floating->window().value())); + floating_windows.erase( + std::remove(floating_windows.begin(), floating_windows.end(), floating), floating_windows.end()); break; } default: @@ -273,7 +275,7 @@ bool Workspace::select_window_from_point(int x, int y) { auto window = floating->window().value(); geom::Rectangle window_area(window.top_left(), window.size()); - if (window == state.active_window && window_area.contains(geom::Point(x, y))) + if (floating == state.active && window_area.contains(geom::Point(x, y))) return false; else if (window_area.contains(geom::Point(x, y))) { @@ -283,7 +285,7 @@ bool Workspace::select_window_from_point(int x, int y) } auto node = tree->select_window_from_point(x, y); - if (node && node->window().value() != state.active_window) + if (node && node != state.active) { window_controller.select_active_window(node->window().value()); return true; @@ -301,7 +303,7 @@ void Workspace::toggle_floating(std::shared_ptr const& container) switch (container->get_type()) { - case ContainerType::tiled: + case ContainerType::leaf: { if (tree->has_fullscreen_window()) { @@ -310,14 +312,14 @@ void Workspace::toggle_floating(std::shared_ptr const& container) } // First, remove the window from the tiling window tree - advise_delete_window(window_controller.get_container(*window)); + delete_container(window_controller.get_container(*window)); // Next, ask the floating window manager to place the new window auto& prev_info = window_controller.info_for(*window); auto spec = window_helpers::copy_from(prev_info); spec.top_left() = geom::Point { window->top_left().x.as_int() + 20, window->top_left().y.as_int() + 20 }; window_controller.noclip(*window); - auto new_spec = floating_window_manager.place_new_window( + auto new_spec = floating_window_manager->place_new_window( tools.info_for(window->application()), spec); tools.modify_window(*window, new_spec); @@ -328,7 +330,7 @@ void Workspace::toggle_floating(std::shared_ptr const& container) case ContainerType::floating: { // First, remove the floating window - advise_delete_window(window_controller.get_container(*window)); + delete_container(window_controller.get_container(*window)); // Next, ask the tiling tree to place the new window auto& prev_info = window_controller.info_for(*window); @@ -336,7 +338,7 @@ void Workspace::toggle_floating(std::shared_ptr const& container) auto new_spec = tree->place_new_window(spec, nullptr); tools.modify_window(*window, new_spec); - new_type = ContainerType::tiled; + new_type = ContainerType::leaf; break; } default: @@ -346,9 +348,9 @@ void Workspace::toggle_floating(std::shared_ptr const& container) // In all cases, advise a new window and pretend like it is ready again auto& info = window_controller.info_for(*window); - auto new_container = advise_new_window(info, new_type); + auto new_container = create_container(info, new_type); new_container->handle_ready(); - window_controller.select_active_window(state.active_window); + window_controller.select_active_window(state.active->window().value()); } void Workspace::hide() @@ -396,11 +398,11 @@ void Workspace::transfer_pinned_windows_to(std::shared_ptr const& oth } } -bool Workspace::has_floating_window(miral::Window const& window) +bool Workspace::has_floating_window(std::shared_ptr const& container) { for (auto const& other : floating_windows) { - if (other->window() == window) + if (other == container) return true; } @@ -415,14 +417,6 @@ std::shared_ptr Workspace::add_floating_window(miral::Window return floating; } -void Workspace::remove_floating_window(miral::Window const& window) -{ - floating_windows.erase(std::remove_if(floating_windows.begin(), floating_windows.end(), [&window](std::shared_ptr const& floating) - { - return floating->window() == window; - })); -} - Output* Workspace::get_output() { return output; @@ -448,6 +442,29 @@ bool Workspace::is_empty() const return tree->is_empty() && floating_windows.empty(); } +void Workspace::graft(std::shared_ptr const& container) +{ + switch (container->get_type()) + { + case ContainerType::floating: + { + auto floating = Container::as_floating(container); + floating->set_workspace(this); + floating_windows.push_back(floating); + break; + } + case ContainerType::parent: + tree->graft(Container::as_parent(container)); + break; + case ContainerType::leaf: + tree->graft(Container::as_leaf(container)); + break; + default: + mir::log_error("Workspace::graft: ungraftable container type: %d", (int)container->get_type()); + break; + } +} + int Workspace::workspace_to_number(int workspace) { if (workspace == 0) @@ -458,16 +475,15 @@ int Workspace::workspace_to_number(int workspace) std::shared_ptr Workspace::get_layout_container() { - if (!state.active_window) + if (!state.active) return nullptr; - auto container = window_controller.get_container(state.active_window); - if (!container) - return nullptr; - - auto parent = container->get_parent().lock(); + auto parent = state.active->get_parent().lock(); if (!parent) return nullptr; + if (parent->get_workspace() != this) + return nullptr; + return parent; } \ No newline at end of file diff --git a/src/workspace.h b/src/workspace.h index fd6787d..65253b9 100644 --- a/src/workspace.h +++ b/src/workspace.h @@ -47,7 +47,7 @@ public: std::shared_ptr const& config, WindowController& window_controller, CompositorState const& state, - miral::MinimalWindowManager& floating_window_manager); + std::shared_ptr const& floating_window_manager); [[nodiscard]] int get_workspace() const; void set_area(mir::geometry::Rectangle const&); @@ -57,22 +57,22 @@ public: miral::ApplicationInfo const& app_info, miral::WindowSpecification& requested_specification, ContainerType hint); - std::shared_ptr advise_new_window( + std::shared_ptr create_container( miral::WindowInfo const& window_info, ContainerType type); void handle_ready_hack(LeafContainer& container); - void advise_delete_window(const std::shared_ptr& container); + void delete_container(std::shared_ptr const &container); void show(); void hide(); void transfer_pinned_windows_to(std::shared_ptr const& other); void for_each_window(std::function)> const&); bool select_window_from_point(int x, int y); void toggle_floating(std::shared_ptr const&); - bool has_floating_window(miral::Window const&); + bool has_floating_window(std::shared_ptr const&); std::shared_ptr add_floating_window(miral::Window const&); - void remove_floating_window(miral::Window const&); Output* get_output(); void trigger_rerender(); [[nodiscard]] bool is_empty() const; + void graft(std::shared_ptr const&); static int workspace_to_number(int workspace); private: @@ -84,7 +84,7 @@ private: WindowController& window_controller; CompositorState const& state; std::shared_ptr config; - miral::MinimalWindowManager& floating_window_manager; + std::shared_ptr floating_window_manager; /// Retrieves the container that is currently being used for layout std::shared_ptr get_layout_container(); diff --git a/tests/tiling_window_tree_test.cpp b/tests/tiling_window_tree_test.cpp index 4a822bd..fb1a2df 100644 --- a/tests/tiling_window_tree_test.cpp +++ b/tests/tiling_window_tree_test.cpp @@ -125,7 +125,7 @@ public: auto leaf = tree.confirm_window(info, nullptr); pairs.push_back({ window, leaf }); - state.active_window = window; + state.active = leaf; tree.advise_focus_gained(*leaf); return leaf; }