refactor: a Container is used as the active element instead of a miral::Window (#201)

This commit is contained in:
Matthew Kosarek 2024-08-03 16:34:45 -04:00 committed by GitHub
parent 16047a0f03
commit ea33fb1c72
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 251 additions and 192 deletions

View File

@ -19,10 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define MIRACLE_WM_COMPOSITOR_STATE_H
#include <mir/geometry/point.h>
#include <miral/window.h>
#include <memory>
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<Container> active;
};
}

View File

@ -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")

View File

@ -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<miral::Window> window() const = 0;
virtual bool select_next(Direction) = 0;
virtual bool pinned() const = 0;

View File

@ -30,7 +30,7 @@ using namespace miracle;
FloatingContainer::FloatingContainer(
miral::Window const& window,
miral::MinimalWindowManager& wm,
std::shared_ptr<miral::MinimalWindowManager> 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

View File

@ -33,7 +33,7 @@ class FloatingContainer : public Container
public:
FloatingContainer(
miral::Window const&,
miral::MinimalWindowManager& wm,
std::shared_ptr<miral::MinimalWindowManager> const& wm,
WindowController& window_controller,
Workspace* workspace,
CompositorState const& state);
@ -67,12 +67,14 @@ public:
void restore_state(MirWindowState state) override;
std::optional<MirWindowState> 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<miral::MinimalWindowManager> wm;
WindowController& window_controller;
CompositorState const& state;

View File

@ -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;
}

View File

@ -35,7 +35,7 @@ LeafContainer::LeafContainer(
TilingWindowTree* tree,
std::shared_ptr<ParentContainer> 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)

View File

@ -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<miral::Window> 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<geom::Rectangle> next_logical_area;
std::shared_ptr<MiracleConfig> config;

View File

@ -811,7 +811,7 @@ void FilesystemConfiguration::_load()
{
auto num = workspace["number"].as<int>();
auto type = container_type_from_string(workspace["layout"].as<std::string>());
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 };
}

View File

@ -129,7 +129,7 @@ struct BorderConfig
struct WorkspaceConfig
{
int num = -1;
ContainerType layout = ContainerType::tiled;
ContainerType layout = ContainerType::leaf;
};
class MiracleConfig

View File

@ -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<miral::MinimalWindowManager> const& floating_window_manager,
CompositorState& state,
std::shared_ptr<MiracleConfig> 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<Container> Output::advise_new_window(
std::shared_ptr<Container> 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<miracle::Container>& container)
void Output::delete_container(std::shared_ptr<miracle::Container> 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<miral::Window> 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<Container> 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

View File

@ -44,7 +44,7 @@ public:
WorkspaceManager& workspace_manager,
geom::Rectangle const& area,
miral::WindowManagerTools const& tools,
miral::MinimalWindowManager& floating_window_manager,
std::shared_ptr<miral::MinimalWindowManager> const& floating_window_manager,
CompositorState& state,
std::shared_ptr<MiracleConfig> 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<Container> advise_new_window(miral::WindowInfo const& window_info, ContainerType type) const;
void advise_delete_window(std::shared_ptr<miracle::Container> const& container);
[[nodiscard]] std::shared_ptr<Container> create_container(miral::WindowInfo const& window_info, ContainerType type) const;
void delete_container(std::shared_ptr<miracle::Container> 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<Container> 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<miral::MinimalWindowManager> floating_window_manager;
CompositorState& state;
geom::Rectangle area;
std::shared_ptr<MiracleConfig> config;

View File

@ -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;
}

View File

@ -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;

View File

@ -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<miral::MinimalWindowManager>(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);
}

View File

@ -130,7 +130,7 @@ private:
ContainerType pending_type;
std::vector<Window> orphaned_window_list;
miral::WindowManagerTools window_manager_tools;
miral::MinimalWindowManager floating_window_manager;
std::shared_ptr<miral::MinimalWindowManager> floating_window_manager;
AutoRestartingLauncher& external_client_launcher;
miral::MirRunner& runner;
std::shared_ptr<MiracleConfig> config;

View File

@ -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<Container>(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();

View File

@ -230,4 +230,9 @@ bool ShellComponentContainer::move_to(int x, int y)
return false;
}
bool ShellComponentContainer::is_fullscreen() const
{
return false;
}
} // miracle

View File

@ -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;

View File

@ -93,6 +93,20 @@ std::shared_ptr<LeafContainer> TilingWindowTree::confirm_window(
return parent->confirm_window(window_info.window());
}
void TilingWindowTree::graft(std::shared_ptr<ParentContainer> 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<LeafContainer> 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<LeafContainer> 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<LeafContainer> 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<LeafContainer> 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);
}

View File

@ -68,6 +68,9 @@ public:
miral::WindowInfo const&,
std::shared_ptr<ParentContainer> const& container);
void graft(std::shared_ptr<ParentContainer> const&);
void graft(std::shared_ptr<LeafContainer> const&);
/// Try to resize the current active window in the provided direction
bool resize_container(Direction direction, Container&);

View File

@ -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);

View File

@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#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<MiracleConfig> const& config,
WindowController& window_controller,
CompositorState const& state,
miral::MinimalWindowManager& floating_window_manager) :
std::shared_ptr<miral::MinimalWindowManager> 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<Container> Workspace::advise_new_window(
std::shared_ptr<Container> Workspace::create_container(
miral::WindowInfo const& window_info, ContainerType type)
{
std::shared_ptr<Container> 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<Container> 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<Container> const& container)
void Workspace::delete_container(std::shared_ptr<Container> 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<Container> 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<Container> 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<Container> 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<Container> 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<Container> 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<Workspace> const& oth
}
}
bool Workspace::has_floating_window(miral::Window const& window)
bool Workspace::has_floating_window(std::shared_ptr<Container> const& container)
{
for (auto const& other : floating_windows)
{
if (other->window() == window)
if (other == container)
return true;
}
@ -415,14 +417,6 @@ std::shared_ptr<FloatingContainer> 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<FloatingContainer> 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<Container> 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<ParentContainer> 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;
}

View File

@ -47,7 +47,7 @@ public:
std::shared_ptr<MiracleConfig> const& config,
WindowController& window_controller,
CompositorState const& state,
miral::MinimalWindowManager& floating_window_manager);
std::shared_ptr<miral::MinimalWindowManager> 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<Container> advise_new_window(
std::shared_ptr<Container> create_container(
miral::WindowInfo const& window_info, ContainerType type);
void handle_ready_hack(LeafContainer& container);
void advise_delete_window(const std::shared_ptr<Container>& container);
void delete_container(std::shared_ptr<Container> const &container);
void show();
void hide();
void transfer_pinned_windows_to(std::shared_ptr<Workspace> const& other);
void for_each_window(std::function<void(std::shared_ptr<Container>)> const&);
bool select_window_from_point(int x, int y);
void toggle_floating(std::shared_ptr<Container> const&);
bool has_floating_window(miral::Window const&);
bool has_floating_window(std::shared_ptr<Container> const&);
std::shared_ptr<FloatingContainer> 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<Container> const&);
static int workspace_to_number(int workspace);
private:
@ -84,7 +84,7 @@ private:
WindowController& window_controller;
CompositorState const& state;
std::shared_ptr<MiracleConfig> config;
miral::MinimalWindowManager& floating_window_manager;
std::shared_ptr<miral::MinimalWindowManager> floating_window_manager;
/// Retrieves the container that is currently being used for layout
std::shared_ptr<ParentContainer> get_layout_container();

View File

@ -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;
}