mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-23 04:08:27 +03:00
refactor: establish the OutputContent
as a source of truth for an Output's layout in preparation for floating windows (#44)
* Establish the concept of `WindowMetadata` which every window must have. This data is used to associate a `Window` to its `OutputContent` and `Tree` * The `Policy` now defers to the `OutputContent` for decisions on how a window should behave. The `Policy` is more of a metadata-resolver than anything, as it leaves the heavy-lifting to the `OutputContent` * Prepares for the integration of a `FloatingWindowManager` that the `OutputContent` will be able to defer to when a window is of type `WindowType::floating`
This commit is contained in:
parent
9dca0468be
commit
0601a51be3
@ -26,19 +26,20 @@ include(GNUInstallDirs)
|
||||
|
||||
add_executable(miracle-wm
|
||||
src/main.cpp
|
||||
src/tiling_window_management_policy.cpp
|
||||
src/policy.cpp
|
||||
src/tree.cpp
|
||||
src/node.cpp
|
||||
src/window_helpers.h
|
||||
src/window_helpers.cpp
|
||||
src/miracle_config.cpp
|
||||
src/miracle_config.h
|
||||
src/screen.cpp
|
||||
src/output_content.cpp
|
||||
src/workspace_manager.cpp
|
||||
src/ipc.cpp
|
||||
src/auto_restarting_launcher.cpp
|
||||
src/workspace_observer.cpp
|
||||
src/window_metadata.cpp
|
||||
src/workspace_content.cpp
|
||||
)
|
||||
|
||||
target_include_directories(miracle-wm PUBLIC SYSTEM ${MIRAL_INCLUDE_DIRS})
|
||||
|
14
src/ipc.cpp
14
src/ipc.cpp
@ -1,7 +1,7 @@
|
||||
#define MIR_LOG_COMPONENT "miracle_ipc"
|
||||
|
||||
#include "ipc.h"
|
||||
#include "screen.h"
|
||||
#include "output_content.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
@ -47,9 +47,9 @@ struct sockaddr_un *ipc_user_sockaddr() {
|
||||
return ipc_sockaddr;
|
||||
}
|
||||
|
||||
json workspace_to_json(std::shared_ptr<Screen> const& screen, int key)
|
||||
json workspace_to_json(std::shared_ptr<OutputContent> const& screen, int key)
|
||||
{
|
||||
bool is_focused = screen->get_active_workspace() == key;
|
||||
bool is_focused = screen->get_active_workspace_num() == key;
|
||||
auto area = screen->get_area();
|
||||
|
||||
return {
|
||||
@ -199,7 +199,7 @@ Ipc::Ipc(miral::MirRunner& runner, miracle::WorkspaceManager& workspace_manager)
|
||||
});
|
||||
}
|
||||
|
||||
void Ipc::on_created(std::shared_ptr<Screen> const& info, int key)
|
||||
void Ipc::on_created(std::shared_ptr<OutputContent> const& info, int key)
|
||||
{
|
||||
json j = {
|
||||
{"change", "init"},
|
||||
@ -218,7 +218,7 @@ void Ipc::on_created(std::shared_ptr<Screen> const& info, int key)
|
||||
}
|
||||
}
|
||||
|
||||
void Ipc::on_removed(std::shared_ptr<Screen> const& screen, int key)
|
||||
void Ipc::on_removed(std::shared_ptr<OutputContent> const& screen, int key)
|
||||
{
|
||||
json j = {
|
||||
{"change", "empty"},
|
||||
@ -237,9 +237,9 @@ void Ipc::on_removed(std::shared_ptr<Screen> const& screen, int key)
|
||||
}
|
||||
|
||||
void Ipc::on_focused(
|
||||
std::shared_ptr<Screen> const& previous,
|
||||
std::shared_ptr<OutputContent> const& previous,
|
||||
int previous_key,
|
||||
std::shared_ptr<Screen> const& current,
|
||||
std::shared_ptr<OutputContent> const& current,
|
||||
int current_key)
|
||||
{
|
||||
json j = {
|
||||
|
@ -57,9 +57,9 @@ class Ipc : public WorkspaceObserver
|
||||
public:
|
||||
Ipc(miral::MirRunner& runner, WorkspaceManager&);
|
||||
|
||||
void on_created(std::shared_ptr<Screen> const& info, int key) override;
|
||||
void on_removed(std::shared_ptr<Screen> const& info, int key) override;
|
||||
void on_focused(std::shared_ptr<Screen> const& previous, int, std::shared_ptr<Screen> const& current, int) override;
|
||||
void on_created(std::shared_ptr<OutputContent> const& info, int key) override;
|
||||
void on_removed(std::shared_ptr<OutputContent> const& info, int key) override;
|
||||
void on_focused(std::shared_ptr<OutputContent> const& previous, int, std::shared_ptr<OutputContent> const& current, int) override;
|
||||
void disconnect_all();
|
||||
private:
|
||||
struct IpcClient
|
||||
|
@ -1,6 +1,6 @@
|
||||
#define MIR_LOG_COMPONENT "miracle-main"
|
||||
|
||||
#include "tiling_window_management_policy.h"
|
||||
#include "policy.h"
|
||||
#include "miracle_config.h"
|
||||
#include "auto_restarting_launcher.h"
|
||||
|
||||
@ -24,14 +24,13 @@ int main(int argc, char const* argv[])
|
||||
std::function<void()> shutdown_hook{[]{}};
|
||||
runner.add_stop_callback([&] { shutdown_hook(); });
|
||||
|
||||
InternalClientLauncher internal_client_launcher;
|
||||
ExternalClientLauncher external_client_launcher;
|
||||
miracle::AutoRestartingLauncher auto_restarting_launcher(runner, external_client_launcher);
|
||||
auto config = std::make_shared<miracle::MiracleConfig>(runner);
|
||||
WindowManagerOptions window_managers
|
||||
{
|
||||
add_window_manager_policy<miracle::TilingWindowManagementPolicy>(
|
||||
"tiling", external_client_launcher, internal_client_launcher, runner, config)
|
||||
add_window_manager_policy<miracle::Policy>(
|
||||
"tiling", external_client_launcher, runner, config)
|
||||
};
|
||||
|
||||
Keymap config_keymap;
|
||||
@ -65,7 +64,6 @@ int main(int argc, char const* argv[])
|
||||
X11Support{}.default_to_enabled(),
|
||||
config_keymap,
|
||||
external_client_launcher,
|
||||
internal_client_launcher,
|
||||
display_configuration_options,
|
||||
AddInitCallback(run_startup_apps)
|
||||
});
|
||||
|
34
src/node.cpp
34
src/node.cpp
@ -1,3 +1,5 @@
|
||||
#include "window_metadata.h"
|
||||
#include <memory>
|
||||
#define MIR_LOG_COMPONENT "node"
|
||||
|
||||
#include "node.h"
|
||||
@ -13,7 +15,7 @@ Node::Node(
|
||||
miral::WindowManagerTools const& tools_,
|
||||
geom::Rectangle const& area,
|
||||
std::shared_ptr<MiracleConfig> const& config,
|
||||
Tree const* tree)
|
||||
Tree* tree)
|
||||
: tools{tools_},
|
||||
state{NodeState::lane},
|
||||
logical_area{area},
|
||||
@ -26,20 +28,17 @@ Node::Node(
|
||||
miral::WindowManagerTools const& tools_,
|
||||
geom::Rectangle const& area,
|
||||
std::shared_ptr<Node> parent,
|
||||
std::shared_ptr<WindowMetadata> const& metadata,
|
||||
miral::Window const& window,
|
||||
std::shared_ptr<MiracleConfig> const& config,
|
||||
Tree const* tree)
|
||||
Tree* tree)
|
||||
: tools{tools_},
|
||||
parent{std::move(parent)},
|
||||
metadata{metadata},
|
||||
window{window},
|
||||
state{NodeState::window},
|
||||
logical_area{area},
|
||||
config{config},
|
||||
tree{tree}
|
||||
{
|
||||
miral::WindowSpecification spec;
|
||||
spec.userdata() = metadata;
|
||||
tools.modify_window(metadata->get_window(), spec);
|
||||
}
|
||||
|
||||
geom::Rectangle Node::get_logical_area_internal(geom::Rectangle const& rectangle)
|
||||
@ -217,26 +216,25 @@ geom::Rectangle Node::create_new_node_position(int index)
|
||||
}
|
||||
}
|
||||
|
||||
void Node::add_window(miral::Window& new_window)
|
||||
std::shared_ptr<Node> Node::add_window(miral::Window& new_window)
|
||||
{
|
||||
if (pending_index < 0)
|
||||
{
|
||||
mir::fatal_error("Unable to add the window to the scene. Was create_new_node_position called?");
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto node_metadata = std::make_shared<WindowMetadata>(WindowType::tiled, new_window);
|
||||
auto node = std::make_shared<Node>(
|
||||
tools,
|
||||
pending_logical_rect,
|
||||
shared_from_this(),
|
||||
node_metadata,
|
||||
new_window,
|
||||
config,
|
||||
tree);
|
||||
node_metadata->associate_to_node(node);
|
||||
|
||||
sub_nodes.insert(sub_nodes.begin() + pending_index, node);
|
||||
pending_index = -1;
|
||||
return node;
|
||||
}
|
||||
|
||||
void Node::_refit_node_to_area()
|
||||
@ -286,7 +284,7 @@ void Node::set_logical_area(geom::Rectangle const& target_rect)
|
||||
{
|
||||
if (is_window())
|
||||
{
|
||||
auto& info = tools.info_for(metadata->get_window());
|
||||
auto& info = tools.info_for(get_window());
|
||||
if (!window_helpers::is_window_fullscreen(info.state()))
|
||||
{
|
||||
_set_window_rectangle(target_rect);
|
||||
@ -389,12 +387,13 @@ std::shared_ptr<Node> Node::to_lane()
|
||||
tools,
|
||||
logical_area,
|
||||
shared_from_this(),
|
||||
metadata,
|
||||
get_window(),
|
||||
config,
|
||||
tree);
|
||||
metadata->associate_to_node(window_node);
|
||||
sub_nodes.push_back(window_node);
|
||||
metadata = nullptr;
|
||||
auto metadata = window_helpers::get_metadata(window, tools);
|
||||
metadata->associate_to_node(window_node);
|
||||
window = miral::Window();
|
||||
return window_node;
|
||||
}
|
||||
|
||||
@ -584,7 +583,6 @@ int Node::get_min_height() const
|
||||
void Node::_set_window_rectangle(geom::Rectangle area)
|
||||
{
|
||||
auto visible_rect = _get_visible_from_logical(area, config);
|
||||
auto window = metadata->get_window();
|
||||
window.move_to(visible_rect.top_left);
|
||||
window.resize(visible_rect.size);
|
||||
auto& window_info = tools.info_for(window);
|
||||
@ -599,7 +597,7 @@ void Node::constrain()
|
||||
{
|
||||
if (is_window())
|
||||
{
|
||||
auto& info = tools.info_for(metadata->get_window());
|
||||
auto& info = tools.info_for(window);
|
||||
if (window_helpers::is_window_fullscreen(info.state()))
|
||||
info.clip_area(mir::optional_value<geom::Rectangle>());
|
||||
else
|
||||
|
16
src/node.h
16
src/node.h
@ -35,14 +35,14 @@ public:
|
||||
Node(miral::WindowManagerTools const& tools,
|
||||
geom::Rectangle const& area,
|
||||
std::shared_ptr<MiracleConfig> const& config,
|
||||
Tree const* tree);
|
||||
Tree* tree);
|
||||
|
||||
Node(miral::WindowManagerTools const& tools,
|
||||
geom::Rectangle const& area,
|
||||
std::shared_ptr<Node> parent,
|
||||
std::shared_ptr<WindowMetadata> const& metadata,
|
||||
miral::Window const& window,
|
||||
std::shared_ptr<MiracleConfig> const& config,
|
||||
Tree const* tree);
|
||||
Tree* tree);
|
||||
|
||||
/// Area taken up by the node including gaps.
|
||||
geom::Rectangle get_logical_area();
|
||||
@ -54,7 +54,7 @@ public:
|
||||
geom::Rectangle create_new_node_position(int index = -1);
|
||||
|
||||
/// Append the node to the lane
|
||||
void add_window(miral::Window&);
|
||||
std::shared_ptr<Node> add_window(miral::Window&);
|
||||
|
||||
/// Updates the node's logical area (including gaps)
|
||||
void set_logical_area(geom::Rectangle const& target_rect);
|
||||
@ -97,16 +97,16 @@ public:
|
||||
bool is_window() const { return state == NodeState::window; }
|
||||
bool is_lane() const { return state == NodeState::lane; }
|
||||
NodeLayoutDirection get_direction() const { return direction; }
|
||||
miral::Window& get_window() { return metadata->get_window(); }
|
||||
miral::Window& get_window() { return window; }
|
||||
std::shared_ptr<Node> get_parent() const { return parent; }
|
||||
std::vector<std::shared_ptr<Node>> const& get_sub_nodes() const { return sub_nodes; }
|
||||
Tree const* get_tree() { return tree; }
|
||||
Tree* get_tree() { return tree; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Node> parent;
|
||||
miral::WindowManagerTools tools;
|
||||
Tree const* tree;
|
||||
std::shared_ptr<WindowMetadata> metadata;
|
||||
Tree* tree;
|
||||
miral::Window window;
|
||||
std::vector<std::shared_ptr<Node>> sub_nodes;
|
||||
std::vector<std::shared_ptr<Node>> hidden_nodes;
|
||||
NodeState state;
|
||||
|
374
src/output_content.cpp
Normal file
374
src/output_content.cpp
Normal file
@ -0,0 +1,374 @@
|
||||
#define MIR_LOG_COMPONENT "output_content"
|
||||
|
||||
#include "output_content.h"
|
||||
#include "window_helpers.h"
|
||||
#include "workspace_manager.h"
|
||||
#include <miral/window_info.h>
|
||||
#include <mir/log.h>
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
OutputContent::OutputContent(
|
||||
miral::Output const& output,
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
std::shared_ptr<MiracleConfig> const& config)
|
||||
: output{output},
|
||||
workspace_manager{workspace_manager},
|
||||
area{area},
|
||||
tools{tools},
|
||||
config{config}
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Tree> OutputContent::get_active_tree() const
|
||||
{
|
||||
return get_active_workspace()->get_tree();
|
||||
}
|
||||
|
||||
std::shared_ptr<WorkspaceContent> OutputContent::get_active_workspace() const
|
||||
{
|
||||
for (auto& info : workspaces)
|
||||
{
|
||||
if (info->get_workspace() == active_workspace)
|
||||
return info;
|
||||
}
|
||||
|
||||
throw std::runtime_error("get_active_workspace: unable to find the active workspace. We shouldn't be here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WindowType OutputContent::allocate_position(miral::WindowSpecification& requested_specification)
|
||||
{
|
||||
if (!window_helpers::is_tileable(requested_specification))
|
||||
return WindowType::other;
|
||||
|
||||
requested_specification = get_active_tree()->allocate_position(requested_specification);
|
||||
return WindowType::tiled;
|
||||
}
|
||||
|
||||
void OutputContent::advise_new_window(miral::WindowInfo const& window_info, WindowType type)
|
||||
{
|
||||
std::shared_ptr<WindowMetadata> metadata = nullptr;
|
||||
switch (type)
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
auto node = get_active_tree()->advise_new_window(window_info);
|
||||
metadata = std::make_shared<WindowMetadata>(WindowType::tiled, window_info.window(), this);
|
||||
metadata->associate_to_node(node);
|
||||
break;
|
||||
}
|
||||
case WindowType::other:
|
||||
if (window_info.state() == MirWindowState::mir_window_state_attached)
|
||||
{
|
||||
tools.select_active_window(window_info.window());
|
||||
}
|
||||
metadata = std::make_shared<WindowMetadata>(WindowType::other, window_info.window(), this);
|
||||
break;
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)type);
|
||||
break;
|
||||
}
|
||||
|
||||
if (metadata)
|
||||
{
|
||||
miral::WindowSpecification spec;
|
||||
spec.userdata() = metadata;
|
||||
tools.modify_window(window_info.window(), spec);
|
||||
}
|
||||
else
|
||||
{
|
||||
mir::log_error("Window failed to set metadata");
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::handle_window_ready(miral::WindowInfo &window_info, std::shared_ptr<miracle::WindowMetadata> const& metadata)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
metadata->get_tiling_node()->get_tree()->handle_window_ready(window_info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_focus_gained(const std::shared_ptr<miracle::WindowMetadata> &metadata)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
metadata->get_tiling_node()->get_tree()->advise_focus_gained(metadata->get_window());
|
||||
tools.raise_tree(metadata->get_window());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_focus_lost(const std::shared_ptr<miracle::WindowMetadata> &metadata)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
metadata->get_tiling_node()->get_tree()->advise_focus_lost(metadata->get_window());
|
||||
tools.raise_tree(metadata->get_window());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_delete_window(const std::shared_ptr<miracle::WindowMetadata> &metadata)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
metadata->get_tiling_node()->get_tree()->advise_delete_window(metadata->get_window());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_state_change(const std::shared_ptr<miracle::WindowMetadata> &metadata, MirWindowState state)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
if (get_active_tree().get() != metadata->get_tiling_node()->get_tree())
|
||||
break;
|
||||
|
||||
metadata->get_tiling_node()->get_tree()->advise_state_change(metadata->get_window(), state);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::handle_modify_window(const std::shared_ptr<miracle::WindowMetadata> &metadata,
|
||||
const miral::WindowSpecification &modifications)
|
||||
{
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
if (get_active_tree().get() != metadata->get_tiling_node()->get_tree())
|
||||
break;
|
||||
|
||||
if (modifications.state().is_set())
|
||||
{
|
||||
if (modifications.state().value() == mir_window_state_fullscreen || modifications.state().value() == mir_window_state_maximized)
|
||||
metadata->get_tiling_node()->get_tree()->advise_fullscreen_window(metadata->get_window());
|
||||
else if (modifications.state().value() == mir_window_state_restored)
|
||||
metadata->get_tiling_node()->get_tree()->advise_restored_window(metadata->get_window());
|
||||
}
|
||||
|
||||
metadata->get_tiling_node()->get_tree()->constrain(metadata->get_window());
|
||||
tools.modify_window(metadata->get_window(), modifications);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
mir::geometry::Rectangle
|
||||
OutputContent::confirm_placement_on_display(
|
||||
const std::shared_ptr<miracle::WindowMetadata> &metadata,
|
||||
MirWindowState new_state,
|
||||
const mir::geometry::Rectangle &new_placement)
|
||||
{
|
||||
mir::geometry::Rectangle modified_placement = new_placement;
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
metadata->get_tiling_node()->get_tree()->confirm_placement_on_display(
|
||||
metadata->get_window(), new_state, modified_placement);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Unsupported window type: %d", (int)metadata->get_type());
|
||||
break;
|
||||
}
|
||||
return new_placement;
|
||||
}
|
||||
|
||||
void OutputContent::select_window_from_point(int x, int y)
|
||||
{
|
||||
get_active_tree()->select_window_from_point(x, y);
|
||||
}
|
||||
|
||||
void OutputContent::advise_new_workspace(int workspace)
|
||||
{
|
||||
workspaces.push_back(
|
||||
std::make_shared<WorkspaceContent>(this, tools, workspace, config));
|
||||
}
|
||||
|
||||
void OutputContent::advise_workspace_deleted(int workspace)
|
||||
{
|
||||
for (auto it = workspaces.begin(); it != workspaces.end(); it++)
|
||||
{
|
||||
if (it->get()->get_workspace() == workspace)
|
||||
{
|
||||
workspaces.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OutputContent::advise_workspace_active(int key)
|
||||
{
|
||||
for (auto& workspace : workspaces)
|
||||
{
|
||||
if (workspace->get_workspace() == key)
|
||||
{
|
||||
std::shared_ptr<WorkspaceContent> previous_workspace = nullptr;
|
||||
for (auto& other : workspaces)
|
||||
{
|
||||
if (other->get_workspace() == active_workspace)
|
||||
{
|
||||
previous_workspace = other;
|
||||
other->hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
active_workspace = key;
|
||||
workspace->show();
|
||||
|
||||
// Important: Delete the workspace only after we have shown the new one because we may want
|
||||
// to move a node to the new workspace.
|
||||
if (previous_workspace != nullptr)
|
||||
{
|
||||
auto active_tree = previous_workspace->get_tree();
|
||||
if (active_tree->is_empty())
|
||||
workspace_manager.delete_workspace(previous_workspace->get_workspace());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OutputContent::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
{
|
||||
if (application_zone.extents().contains(area))
|
||||
{
|
||||
application_zone_list.push_back(application_zone);
|
||||
for (auto& workspace : workspaces)
|
||||
workspace->get_tree()->recalculate_root_node_area();
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
|
||||
{
|
||||
for (auto& zone : application_zone_list)
|
||||
if (zone == original)
|
||||
{
|
||||
zone = updated;
|
||||
for (auto& workspace : workspaces)
|
||||
workspace->get_tree()->recalculate_root_node_area();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void OutputContent::advise_application_zone_delete(miral::Zone const& application_zone)
|
||||
{
|
||||
if (std::remove(application_zone_list.begin(), application_zone_list.end(), application_zone) != application_zone_list.end())
|
||||
{
|
||||
for (auto& workspace : workspaces)
|
||||
workspace->get_tree()->recalculate_root_node_area();
|
||||
}
|
||||
}
|
||||
|
||||
bool OutputContent::point_is_in_output(int x, int y)
|
||||
{
|
||||
return area.contains(geom::Point(x, y));
|
||||
}
|
||||
|
||||
void OutputContent::close_active_window()
|
||||
{
|
||||
get_active_tree()->close_active_window();
|
||||
}
|
||||
|
||||
bool OutputContent::resize_active_window(miracle::Direction direction)
|
||||
{
|
||||
return get_active_tree()->try_resize_active_window(direction);
|
||||
}
|
||||
|
||||
bool OutputContent::select(miracle::Direction direction)
|
||||
{
|
||||
return get_active_tree()->try_select_next(direction);
|
||||
}
|
||||
|
||||
bool OutputContent::move_active_window(miracle::Direction direction)
|
||||
{
|
||||
return get_active_tree()->try_move_active_window(direction);
|
||||
}
|
||||
|
||||
void OutputContent::request_vertical()
|
||||
{
|
||||
get_active_tree()->request_vertical();
|
||||
}
|
||||
|
||||
void OutputContent::request_horizontal()
|
||||
{
|
||||
get_active_tree()->request_horizontal();
|
||||
}
|
||||
|
||||
void OutputContent::toggle_resize_mode()
|
||||
{
|
||||
get_active_tree()->toggle_resize_mode();
|
||||
}
|
||||
|
||||
void OutputContent::toggle_fullscreen()
|
||||
{
|
||||
get_active_tree()->try_toggle_active_fullscreen();
|
||||
}
|
||||
|
||||
void OutputContent::update_area(geom::Rectangle const& new_area)
|
||||
{
|
||||
area = new_area;
|
||||
for (auto& workspace : workspaces)
|
||||
{
|
||||
workspace->get_tree()->set_output_area(area);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<miral::Window> OutputContent::collect_all_windows() const
|
||||
{
|
||||
std::vector<miral::Window> windows;
|
||||
for (auto& workspace : get_workspaces())
|
||||
{
|
||||
workspace->get_tree()->foreach_node([&](auto node)
|
||||
{
|
||||
if (node->is_window())
|
||||
{
|
||||
windows.push_back(node->get_window());
|
||||
}
|
||||
});
|
||||
}
|
||||
return windows;
|
||||
}
|
80
src/output_content.h
Normal file
80
src/output_content.h
Normal file
@ -0,0 +1,80 @@
|
||||
#ifndef MIRACLE_SCREEN_H
|
||||
#define MIRACLE_SCREEN_H
|
||||
|
||||
#include "tree.h"
|
||||
#include "workspace_content.h"
|
||||
#include <memory>
|
||||
#include <miral/output.h>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
class WorkspaceManager;
|
||||
class MiracleConfig;
|
||||
|
||||
class OutputContent
|
||||
{
|
||||
public:
|
||||
OutputContent(
|
||||
miral::Output const& output,
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
std::shared_ptr<MiracleConfig> const& options);
|
||||
~OutputContent() = default;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<Tree> get_active_tree() const;
|
||||
[[nodiscard]] int get_active_workspace_num() const { return active_workspace; }
|
||||
[[nodiscard]] std::shared_ptr<WorkspaceContent> get_active_workspace() const;
|
||||
WindowType allocate_position(miral::WindowSpecification& requested_specification);
|
||||
void advise_new_window(miral::WindowInfo const& window_info, WindowType type);
|
||||
void handle_window_ready(miral::WindowInfo &window_info, std::shared_ptr<miracle::WindowMetadata> const& metadata);
|
||||
void advise_focus_gained(std::shared_ptr<miracle::WindowMetadata> const& metadata);
|
||||
void advise_focus_lost(std::shared_ptr<miracle::WindowMetadata> const& metadata);
|
||||
void advise_delete_window(std::shared_ptr<miracle::WindowMetadata> const& metadata);
|
||||
void advise_state_change(std::shared_ptr<miracle::WindowMetadata> const& metadata, MirWindowState state);
|
||||
void handle_modify_window(std::shared_ptr<miracle::WindowMetadata> const& metadata, const miral::WindowSpecification &modifications);
|
||||
mir::geometry::Rectangle confirm_placement_on_display(
|
||||
std::shared_ptr<miracle::WindowMetadata> const& metadata,
|
||||
MirWindowState new_state,
|
||||
const mir::geometry::Rectangle &new_placement);
|
||||
void select_window_from_point(int x, int y);
|
||||
void advise_new_workspace(int workspace);
|
||||
void advise_workspace_deleted(int workspace);
|
||||
bool advise_workspace_active(int workspace);
|
||||
std::vector<std::shared_ptr<WorkspaceContent>> const& get_workspaces() const { return workspaces; }
|
||||
void advise_application_zone_create(miral::Zone const& application_zone);
|
||||
void advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original);
|
||||
void advise_application_zone_delete(miral::Zone const& application_zone);
|
||||
bool point_is_in_output(int x, int y);
|
||||
void close_active_window();
|
||||
bool resize_active_window(Direction direction);
|
||||
bool select(Direction direction);
|
||||
bool move_active_window(Direction direction);
|
||||
void request_vertical();
|
||||
void request_horizontal();
|
||||
void toggle_resize_mode();
|
||||
void toggle_fullscreen();
|
||||
void update_area(geom::Rectangle const& area);
|
||||
std::vector<miral::Window> collect_all_windows() const;
|
||||
|
||||
geom::Rectangle const& get_area() { return area; }
|
||||
std::vector<miral::Zone> const& get_app_zones() { return application_zone_list; }
|
||||
miral::Output const& get_output() { return output; }
|
||||
[[nodiscard]] bool is_active() const { return is_active_; }
|
||||
void set_is_active(bool new_is_active) { is_active_ = new_is_active; }
|
||||
|
||||
private:
|
||||
miral::Output output;
|
||||
WorkspaceManager& workspace_manager;
|
||||
miral::WindowManagerTools tools;
|
||||
geom::Rectangle area;
|
||||
std::shared_ptr<MiracleConfig> config;
|
||||
int active_workspace = -1;
|
||||
std::vector<std::shared_ptr<WorkspaceContent>> workspaces;
|
||||
std::vector<miral::Zone> application_zone_list;
|
||||
bool is_active_ = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,6 +1,8 @@
|
||||
#include "miral/window_specification.h"
|
||||
#include "window_metadata.h"
|
||||
#define MIR_LOG_COMPONENT "miracle"
|
||||
|
||||
#include "tiling_window_management_policy.h"
|
||||
#include "policy.h"
|
||||
#include "window_helpers.h"
|
||||
#include "miracle_config.h"
|
||||
#include "workspace_manager.h"
|
||||
@ -27,15 +29,13 @@ const int MODIFIER_MASK =
|
||||
mir_input_event_modifier_meta;
|
||||
}
|
||||
|
||||
TilingWindowManagementPolicy::TilingWindowManagementPolicy(
|
||||
Policy::Policy(
|
||||
miral::WindowManagerTools const& tools,
|
||||
miral::ExternalClientLauncher const& external_client_launcher,
|
||||
miral::InternalClientLauncher const& internal_client_launcher,
|
||||
miral::MirRunner& runner,
|
||||
std::shared_ptr<MiracleConfig> const& config)
|
||||
: window_manager_tools{tools},
|
||||
external_client_launcher{external_client_launcher},
|
||||
internal_client_launcher{internal_client_launcher},
|
||||
runner{runner},
|
||||
config{config},
|
||||
workspace_manager{WorkspaceManager(
|
||||
@ -51,12 +51,12 @@ TilingWindowManagementPolicy::TilingWindowManagementPolicy(
|
||||
}, 1);
|
||||
}
|
||||
|
||||
TilingWindowManagementPolicy::~TilingWindowManagementPolicy()
|
||||
Policy::~Policy()
|
||||
{
|
||||
workspace_observer_registrar.unregister_interest(*ipc);
|
||||
}
|
||||
|
||||
bool TilingWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const* event)
|
||||
bool Policy::handle_keyboard_event(MirKeyboardEvent const* event)
|
||||
{
|
||||
auto const action = miral::toolkit::mir_keyboard_event_action(event);
|
||||
auto const scan_code = miral::toolkit::mir_keyboard_event_scan_code(event);
|
||||
@ -83,58 +83,58 @@ bool TilingWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const*
|
||||
return true;
|
||||
}
|
||||
case RequestVertical:
|
||||
if(active_output) active_output->get_active_tree().request_vertical();
|
||||
if(active_output) active_output->request_vertical();
|
||||
return true;
|
||||
case RequestHorizontal:
|
||||
if(active_output) active_output->get_active_tree().request_horizontal();
|
||||
if(active_output) active_output->request_horizontal();
|
||||
return true;
|
||||
case ToggleResize:
|
||||
if(active_output) active_output->get_active_tree().toggle_resize_mode();
|
||||
if(active_output) active_output->toggle_resize_mode();
|
||||
return true;
|
||||
case MoveUp:
|
||||
if (active_output && active_output->get_active_tree().try_move_active_window(Direction::up))
|
||||
if (active_output && active_output->move_active_window(Direction::up))
|
||||
return true;
|
||||
return false;
|
||||
case MoveDown:
|
||||
if (active_output && active_output->get_active_tree().try_move_active_window(Direction::down))
|
||||
if (active_output && active_output->move_active_window(Direction::down))
|
||||
return true;
|
||||
return false;
|
||||
case MoveLeft:
|
||||
if (active_output && active_output->get_active_tree().try_move_active_window(Direction::left))
|
||||
if (active_output && active_output->move_active_window(Direction::left))
|
||||
return true;
|
||||
return false;
|
||||
case MoveRight:
|
||||
if (active_output && active_output->get_active_tree().try_move_active_window(Direction::right))
|
||||
if (active_output && active_output->move_active_window(Direction::right))
|
||||
return true;
|
||||
return false;
|
||||
case SelectUp:
|
||||
if (active_output && (active_output->get_active_tree().try_resize_active_window(Direction::up)
|
||||
|| active_output->get_active_tree().try_select_next(Direction::up)))
|
||||
if (active_output && (active_output->resize_active_window(Direction::up)
|
||||
|| active_output->select(Direction::up)))
|
||||
return true;
|
||||
return false;
|
||||
case SelectDown:
|
||||
if (active_output && (active_output->get_active_tree().try_resize_active_window(Direction::down)
|
||||
|| active_output->get_active_tree().try_select_next(Direction::down)))
|
||||
if (active_output && (active_output->resize_active_window(Direction::down)
|
||||
|| active_output->select(Direction::down)))
|
||||
return true;
|
||||
return false;
|
||||
case SelectLeft:
|
||||
if (active_output && (active_output->get_active_tree().try_resize_active_window(Direction::left)
|
||||
|| active_output->get_active_tree().try_select_next(Direction::left)))
|
||||
if (active_output && (active_output->resize_active_window(Direction::left)
|
||||
|| active_output->select(Direction::left)))
|
||||
return true;
|
||||
return false;
|
||||
case SelectRight:
|
||||
if (active_output && (active_output->get_active_tree().try_resize_active_window(Direction::right)
|
||||
|| active_output->get_active_tree().try_select_next(Direction::right)))
|
||||
if (active_output && (active_output->resize_active_window(Direction::right)
|
||||
|| active_output->select(Direction::right)))
|
||||
return true;
|
||||
return false;
|
||||
case QuitActiveWindow:
|
||||
if (active_output) active_output->get_active_tree().close_active_window();
|
||||
if (active_output) active_output->close_active_window();
|
||||
return true;
|
||||
case QuitCompositor:
|
||||
runner.stop();
|
||||
return true;
|
||||
case Fullscreen:
|
||||
if (active_output) active_output->get_active_tree().try_toggle_active_fullscreen();
|
||||
if (active_output) active_output->toggle_fullscreen();
|
||||
return true;
|
||||
case SelectWorkspace1:
|
||||
if (active_output) workspace_manager.request_workspace(active_output, 1);
|
||||
@ -203,7 +203,7 @@ bool TilingWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const*
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TilingWindowManagementPolicy::handle_pointer_event(MirPointerEvent const* event)
|
||||
bool Policy::handle_pointer_event(MirPointerEvent const* event)
|
||||
{
|
||||
auto x = miral::toolkit::mir_pointer_event_axis_value(event, MirPointerAxis::mir_pointer_axis_x);
|
||||
auto y = miral::toolkit::mir_pointer_event_axis_value(event, MirPointerAxis::mir_pointer_axis_y);
|
||||
@ -217,12 +217,12 @@ bool TilingWindowManagementPolicy::handle_pointer_event(MirPointerEvent const* e
|
||||
if (active_output) active_output->set_is_active(false);
|
||||
active_output = output;
|
||||
active_output->set_is_active(true);
|
||||
workspace_manager.request_focus(output->get_active_workspace());
|
||||
workspace_manager.request_focus(output->get_active_workspace_num());
|
||||
}
|
||||
|
||||
if (output->get_active_workspace() >= 0)
|
||||
if (output->get_active_workspace_num() >= 0)
|
||||
{
|
||||
active_output->get_active_tree().select_window_from_point(static_cast<int>(x), static_cast<int>(y));
|
||||
active_output->select_window_from_point(static_cast<int>(x), static_cast<int>(y));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -231,7 +231,7 @@ bool TilingWindowManagementPolicy::handle_pointer_event(MirPointerEvent const* e
|
||||
return false;
|
||||
}
|
||||
|
||||
auto TilingWindowManagementPolicy::place_new_window(
|
||||
auto Policy::place_new_window(
|
||||
const miral::ApplicationInfo &app_info,
|
||||
const miral::WindowSpecification &requested_specification) -> miral::WindowSpecification
|
||||
{
|
||||
@ -241,19 +241,22 @@ auto TilingWindowManagementPolicy::place_new_window(
|
||||
return requested_specification;
|
||||
}
|
||||
|
||||
auto new_spec = requested_specification;
|
||||
pending_output = active_output;
|
||||
return active_output->get_active_tree().allocate_position(requested_specification);
|
||||
pending_type = active_output->allocate_position(new_spec);
|
||||
return new_spec;
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::_add_to_output_immediately(miral::Window& window, std::shared_ptr<Screen>& output)
|
||||
void Policy::_add_to_output_immediately(miral::Window& window, std::shared_ptr<OutputContent>& output)
|
||||
{
|
||||
miral::WindowSpecification spec;
|
||||
spec = output->get_active_tree().allocate_position(spec);
|
||||
pending_output = output;
|
||||
pending_type = output->allocate_position(spec);
|
||||
window_manager_tools.modify_window(window, spec);
|
||||
output->get_active_tree().advise_new_window(window_manager_tools.info_for(window));
|
||||
handle_window_ready(window_manager_tools.info_for(window));
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_new_window(miral::WindowInfo const& window_info)
|
||||
void Policy::advise_new_window(miral::WindowInfo const& window_info)
|
||||
{
|
||||
auto shared_output = pending_output.lock();
|
||||
if (!shared_output)
|
||||
@ -275,53 +278,74 @@ void TilingWindowManagementPolicy::advise_new_window(miral::WindowInfo const& wi
|
||||
return;
|
||||
}
|
||||
|
||||
shared_output->get_active_tree().advise_new_window(window_info);
|
||||
shared_output->advise_new_window(window_info, pending_type);
|
||||
pending_type = WindowType::none;
|
||||
pending_output.reset();
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::handle_window_ready(miral::WindowInfo &window_info)
|
||||
void Policy::handle_window_ready(miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
if (output->get_active_tree().handle_window_ready(window_info))
|
||||
break;
|
||||
}
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
return;
|
||||
|
||||
metadata->get_output()->handle_window_ready(window_info, metadata);
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_focus_gained(const miral::WindowInfo &window_info)
|
||||
void Policy::advise_focus_gained(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
output->get_active_tree().advise_focus_gained(window_info.window());
|
||||
window_manager_tools.raise_tree(window_info.window());
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
mir::fatal_error("advise_focus_gained: metadata is not provided");
|
||||
return;
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_focus_lost(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
output->get_active_tree().advise_focus_lost(window_info.window());
|
||||
metadata->get_output()->advise_focus_gained(metadata);
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_delete_window(const miral::WindowInfo &window_info)
|
||||
void Policy::advise_focus_lost(const miral::WindowInfo &window_info)
|
||||
{
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
mir::fatal_error("advise_focus_lost: metadata is not provided");
|
||||
return;
|
||||
}
|
||||
|
||||
metadata->get_output()->advise_focus_lost(metadata);
|
||||
}
|
||||
|
||||
void Policy::advise_delete_window(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto it = orphaned_window_list.begin(); it != orphaned_window_list.end();)
|
||||
{
|
||||
if (*it == window_info.window())
|
||||
it = orphaned_window_list.erase(it);
|
||||
{
|
||||
orphaned_window_list.erase(it);
|
||||
return;
|
||||
}
|
||||
else
|
||||
it++;
|
||||
}
|
||||
|
||||
for (auto const& output : output_list)
|
||||
output->get_active_tree().advise_delete_window(window_info.window());
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
mir::fatal_error("advise_delete_window: metadata is not provided");
|
||||
return;
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_move_to(miral::WindowInfo const& window_info, geom::Point top_left)
|
||||
metadata->get_output()->advise_delete_window(metadata);
|
||||
}
|
||||
|
||||
void Policy::advise_move_to(miral::WindowInfo const& window_info, geom::Point top_left)
|
||||
{
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_output_create(miral::Output const& output)
|
||||
void Policy::advise_output_create(miral::Output const& output)
|
||||
{
|
||||
auto new_tree = std::make_shared<Screen>(
|
||||
auto new_tree = std::make_shared<OutputContent>(
|
||||
output, workspace_manager, output.extents(), window_manager_tools, config);
|
||||
workspace_manager.request_first_available_workspace(new_tree);
|
||||
output_list.push_back(new_tree);
|
||||
@ -339,54 +363,45 @@ void TilingWindowManagementPolicy::advise_output_create(miral::Output const& out
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_output_update(miral::Output const& updated, miral::Output const& original)
|
||||
void Policy::advise_output_update(miral::Output const& updated, miral::Output const& original)
|
||||
{
|
||||
for (auto& output : output_list)
|
||||
{
|
||||
if (output->get_output().is_same_output(original))
|
||||
{
|
||||
for (auto& workspace : output->get_workspaces())
|
||||
{
|
||||
workspace.tree->set_output_area(updated.extents());
|
||||
}
|
||||
output->update_area(updated.extents());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_output_delete(miral::Output const& output)
|
||||
void Policy::advise_output_delete(miral::Output const& output)
|
||||
{
|
||||
for (auto it = output_list.begin(); it != output_list.end();)
|
||||
{
|
||||
auto other_output = *it;
|
||||
if (other_output->get_output().is_same_output(output))
|
||||
{
|
||||
it = output_list.erase(it);
|
||||
if (other_output == active_output)
|
||||
{
|
||||
output_list.erase(it);
|
||||
if (output_list.empty())
|
||||
{
|
||||
// All nodes should become orphaned
|
||||
for (auto& workspace : other_output->get_workspaces())
|
||||
for (auto& window : other_output->collect_all_windows())
|
||||
{
|
||||
workspace.tree->foreach_node([&](auto node)
|
||||
{
|
||||
if (node->is_window())
|
||||
{
|
||||
orphaned_window_list.push_back(node->get_window());
|
||||
}
|
||||
});
|
||||
orphaned_window_list.push_back(window);
|
||||
WindowSpecification spec;
|
||||
spec.userdata() = nullptr;
|
||||
window_manager_tools.modify_window(window, spec);
|
||||
}
|
||||
|
||||
active_output = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
active_output = output_list[0];
|
||||
for (auto& workspace : other_output->get_workspaces())
|
||||
active_output = output_list.front();
|
||||
for (auto& window : other_output->collect_all_windows())
|
||||
{
|
||||
active_output->get_active_tree().add_tree(workspace.tree);
|
||||
}
|
||||
_add_to_output_immediately(window, active_output);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -394,107 +409,66 @@ void TilingWindowManagementPolicy::advise_output_delete(miral::Output const& out
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_state_change(miral::WindowInfo const& window_info, MirWindowState state)
|
||||
void Policy::advise_state_change(miral::WindowInfo const& window_info, MirWindowState state)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
if (output->get_active_tree().advise_state_change(window_info, state))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
mir::fatal_error("advise_state_changed: metadata is not provided");
|
||||
return;
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::handle_modify_window(
|
||||
metadata->get_output()->advise_state_change(metadata, state);
|
||||
}
|
||||
|
||||
void Policy::handle_modify_window(
|
||||
miral::WindowInfo &window_info,
|
||||
const miral::WindowSpecification &modifications)
|
||||
{
|
||||
if (modifications.state().is_set())
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
if (modifications.state().value() == mir_window_state_fullscreen || modifications.state().value() == mir_window_state_maximized)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& workspace : output->get_workspaces())
|
||||
{
|
||||
if (workspace.tree->advise_fullscreen_window(window_info))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
mir::fatal_error("handle_modify_window: metadata is not provided");
|
||||
return;
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
else if (modifications.state().value() == mir_window_state_restored)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& workspace : output->get_workspaces())
|
||||
{
|
||||
if (workspace.tree->advise_restored_window(window_info))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
metadata->get_output()->handle_modify_window(metadata, modifications);
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& output :output_list)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto& workspace : output->get_workspaces())
|
||||
{
|
||||
if (workspace.tree->constrain(window_info))
|
||||
{
|
||||
found = true;
|
||||
window_manager_tools.modify_window(window_info.window(), modifications);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::handle_raise_window(miral::WindowInfo &window_info)
|
||||
void Policy::handle_raise_window(miral::WindowInfo &window_info)
|
||||
{
|
||||
window_manager_tools.select_active_window(window_info.window());
|
||||
}
|
||||
|
||||
mir::geometry::Rectangle
|
||||
TilingWindowManagementPolicy::confirm_placement_on_display(
|
||||
Policy::confirm_placement_on_display(
|
||||
const miral::WindowInfo &window_info,
|
||||
MirWindowState new_state,
|
||||
const mir::geometry::Rectangle &new_placement)
|
||||
{
|
||||
mir::geometry::Rectangle modified_placement = new_placement;
|
||||
for (auto const& output : output_list)
|
||||
auto metadata = window_helpers::get_metadata(window_info);
|
||||
if (!metadata)
|
||||
{
|
||||
if (output->get_active_tree().confirm_placement_on_display(window_info, new_state, modified_placement))
|
||||
break;
|
||||
mir::log_error("confirm_placement_on_display: window lacks metadata");
|
||||
return new_placement;
|
||||
}
|
||||
|
||||
mir::geometry::Rectangle modified_placement = metadata->get_output()->confirm_placement_on_display(
|
||||
metadata, new_state, new_placement);
|
||||
return modified_placement;
|
||||
}
|
||||
|
||||
bool TilingWindowManagementPolicy::handle_touch_event(const MirTouchEvent *event)
|
||||
bool Policy::handle_touch_event(const MirTouchEvent *event)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::handle_request_move(miral::WindowInfo &window_info, const MirInputEvent *input_event)
|
||||
void Policy::handle_request_move(miral::WindowInfo &window_info, const MirInputEvent *input_event)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::handle_request_resize(
|
||||
void Policy::handle_request_resize(
|
||||
miral::WindowInfo &window_info,
|
||||
const MirInputEvent *input_event,
|
||||
MirResizeEdge edge)
|
||||
@ -502,14 +476,14 @@ void TilingWindowManagementPolicy::handle_request_resize(
|
||||
|
||||
}
|
||||
|
||||
mir::geometry::Rectangle TilingWindowManagementPolicy::confirm_inherited_move(
|
||||
mir::geometry::Rectangle Policy::confirm_inherited_move(
|
||||
const miral::WindowInfo &window_info,
|
||||
mir::geometry::Displacement movement)
|
||||
{
|
||||
return { window_info.window().top_left() + movement, window_info.window().size() };
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
void Policy::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
@ -517,7 +491,7 @@ void TilingWindowManagementPolicy::advise_application_zone_create(miral::Zone co
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
|
||||
void Policy::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
@ -525,7 +499,7 @@ void TilingWindowManagementPolicy::advise_application_zone_update(miral::Zone co
|
||||
}
|
||||
}
|
||||
|
||||
void TilingWindowManagementPolicy::advise_application_zone_delete(miral::Zone const& application_zone)
|
||||
void Policy::advise_application_zone_delete(miral::Zone const& application_zone)
|
||||
{
|
||||
for (auto const& output : output_list)
|
||||
{
|
@ -1,7 +1,7 @@
|
||||
#ifndef MIRACLE_TILING_WINDOW_MANAGEMENT_POLICY_H
|
||||
#define MIRACLE_TILING_WINDOW_MANAGEMENT_POLICY_H
|
||||
#ifndef MIRACLE_POLICY_H
|
||||
#define MIRACLE_POLICY_H
|
||||
|
||||
#include "screen.h"
|
||||
#include "output_content.h"
|
||||
#include "miracle_config.h"
|
||||
#include "workspace_manager.h"
|
||||
#include "ipc.h"
|
||||
@ -22,16 +22,15 @@ class MirRunner;
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
class TilingWindowManagementPolicy : public miral::WindowManagementPolicy
|
||||
class Policy : public miral::WindowManagementPolicy
|
||||
{
|
||||
public:
|
||||
TilingWindowManagementPolicy(
|
||||
Policy(
|
||||
miral::WindowManagerTools const&,
|
||||
miral::ExternalClientLauncher const&,
|
||||
miral::InternalClientLauncher const&,
|
||||
miral::MirRunner&,
|
||||
std::shared_ptr<MiracleConfig> const&);
|
||||
~TilingWindowManagementPolicy() override;
|
||||
~Policy() override;
|
||||
|
||||
bool handle_keyboard_event(MirKeyboardEvent const* event) override;
|
||||
bool handle_pointer_event(MirPointerEvent const* event) override;
|
||||
@ -75,24 +74,24 @@ public:
|
||||
void advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original) override;
|
||||
void advise_application_zone_delete(miral::Zone const& application_zone) override;
|
||||
|
||||
std::shared_ptr<Screen> const& get_active_output() { return active_output; }
|
||||
std::shared_ptr<OutputContent> const& get_active_output() { return active_output; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Screen> active_output;
|
||||
std::vector<std::shared_ptr<Screen>> output_list;
|
||||
std::weak_ptr<Screen> pending_output;
|
||||
std::shared_ptr<OutputContent> active_output;
|
||||
std::vector<std::shared_ptr<OutputContent>> output_list;
|
||||
std::weak_ptr<OutputContent> pending_output;
|
||||
WindowType pending_type;
|
||||
std::vector<Window> orphaned_window_list;
|
||||
miral::WindowManagerTools window_manager_tools;
|
||||
miral::ExternalClientLauncher const external_client_launcher;
|
||||
miral::InternalClientLauncher const internal_client_launcher;
|
||||
miral::MirRunner& runner;
|
||||
std::shared_ptr<MiracleConfig> config;
|
||||
WorkspaceObserverRegistrar workspace_observer_registrar;
|
||||
WorkspaceManager workspace_manager;
|
||||
std::shared_ptr<Ipc> ipc;
|
||||
|
||||
void _add_to_output_immediately(Window&, std::shared_ptr<Screen>&);
|
||||
void _add_to_output_immediately(Window&, std::shared_ptr<OutputContent>&);
|
||||
};
|
||||
}
|
||||
|
||||
#endif //MIRACLE_TILING_WINDOW_MANAGEMENT_POLICY_H
|
||||
#endif //MIRACLE_POLICY_H
|
139
src/screen.cpp
139
src/screen.cpp
@ -1,139 +0,0 @@
|
||||
#include "screen.h"
|
||||
#include "workspace_manager.h"
|
||||
#include <miral/window_info.h>
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
Screen::Screen(
|
||||
miral::Output const& output,
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
std::shared_ptr<MiracleConfig> const& config)
|
||||
: output{output},
|
||||
workspace_manager{workspace_manager},
|
||||
area{area},
|
||||
tools{tools},
|
||||
config{config}
|
||||
{
|
||||
}
|
||||
|
||||
Tree &Screen::get_active_tree()
|
||||
{
|
||||
for (auto& info : workspaces)
|
||||
{
|
||||
if (info.workspace == active_workspace)
|
||||
return *info.tree;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unable to find the active tree. We shouldn't be here");
|
||||
}
|
||||
|
||||
void Screen::advise_new_workspace(int workspace)
|
||||
{
|
||||
workspaces.push_back({workspace, std::make_shared<Tree>(this, tools, config)});
|
||||
}
|
||||
|
||||
void Screen::advise_workspace_deleted(int workspace)
|
||||
{
|
||||
for (auto it = workspaces.begin(); it != workspaces.end(); it++)
|
||||
{
|
||||
if (it->workspace == workspace)
|
||||
{
|
||||
workspaces.erase(it);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen::advise_workspace_active(int key)
|
||||
{
|
||||
for (auto& workspace : workspaces)
|
||||
{
|
||||
if (workspace.workspace == key)
|
||||
{
|
||||
ScreenWorkspaceInfo* previous_workspace = nullptr;
|
||||
for (auto& other : workspaces)
|
||||
{
|
||||
if (other.workspace == active_workspace)
|
||||
{
|
||||
previous_workspace = &other;
|
||||
hide(other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
active_workspace = key;
|
||||
show(workspace);
|
||||
|
||||
// Important: Delete the workspace only after we have shown the new one because we may want
|
||||
// to move a node to the new workspace.
|
||||
if (previous_workspace != nullptr)
|
||||
{
|
||||
auto& active_tree = previous_workspace->tree;
|
||||
if (active_tree->is_empty())
|
||||
workspace_manager.delete_workspace(previous_workspace->workspace);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Screen::hide(ScreenWorkspaceInfo& info)
|
||||
{
|
||||
info.tree->hide();
|
||||
}
|
||||
|
||||
void Screen::show(ScreenWorkspaceInfo& info)
|
||||
{
|
||||
info.tree->show();
|
||||
}
|
||||
|
||||
const ScreenWorkspaceInfo &Screen::get_workspace(int key)
|
||||
{
|
||||
for (auto const& workspace : workspaces)
|
||||
{
|
||||
if (workspace.workspace == key)
|
||||
return workspace;
|
||||
}
|
||||
|
||||
mir::fatal_error("Cannot find workspace with key: %c", key);
|
||||
}
|
||||
|
||||
void Screen::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
{
|
||||
if (application_zone.extents().contains(area))
|
||||
{
|
||||
application_zone_list.push_back(application_zone);
|
||||
for (auto& workspace : workspaces)
|
||||
workspace.tree->recalculate_root_node_area();
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
|
||||
{
|
||||
for (auto& zone : application_zone_list)
|
||||
if (zone == original)
|
||||
{
|
||||
zone = updated;
|
||||
for (auto& workspace : workspaces)
|
||||
workspace.tree->recalculate_root_node_area();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Screen::advise_application_zone_delete(miral::Zone const& application_zone)
|
||||
{
|
||||
if (std::remove(application_zone_list.begin(), application_zone_list.end(), application_zone) != application_zone_list.end())
|
||||
{
|
||||
for (auto& workspace : workspaces)
|
||||
workspace.tree->recalculate_root_node_area();
|
||||
}
|
||||
}
|
||||
|
||||
bool Screen::point_is_in_output(int x, int y)
|
||||
{
|
||||
return area.contains(geom::Point(x, y));
|
||||
}
|
76
src/screen.h
76
src/screen.h
@ -1,76 +0,0 @@
|
||||
#ifndef MIRACLE_SCREEN_H
|
||||
#define MIRACLE_SCREEN_H
|
||||
|
||||
#include "tree.h"
|
||||
#include <memory>
|
||||
#include <miral/output.h>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
struct WorkspaceManager;
|
||||
class MiracleConfig;
|
||||
|
||||
struct NodeResurrection
|
||||
{
|
||||
std::shared_ptr<Node> node;
|
||||
MirWindowState state;
|
||||
};
|
||||
|
||||
struct ScreenWorkspaceInfo
|
||||
{
|
||||
int workspace;
|
||||
std::shared_ptr<Tree> tree;
|
||||
std::vector<NodeResurrection> nodes_to_resurrect;
|
||||
};
|
||||
|
||||
/// A screen is comprised of a map of workspaces, each having their own tree.
|
||||
// Workspaces are shared across screens such that screens a workspace with a
|
||||
// particular index can ONLY ever live on one screen at a time.
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
Screen(
|
||||
miral::Output const& output,
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
std::shared_ptr<MiracleConfig> const& options);
|
||||
~Screen() = default;
|
||||
|
||||
Tree& get_active_tree();
|
||||
int get_active_workspace() const { return active_workspace; }
|
||||
void advise_new_workspace(int workspace);
|
||||
void advise_workspace_deleted(int workspace);
|
||||
bool advise_workspace_active(int workspace);
|
||||
std::vector<ScreenWorkspaceInfo>& get_workspaces() { return workspaces; }
|
||||
ScreenWorkspaceInfo const& get_workspace(int key);
|
||||
void advise_application_zone_create(miral::Zone const& application_zone);
|
||||
void advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original);
|
||||
void advise_application_zone_delete(miral::Zone const& application_zone);
|
||||
bool point_is_in_output(int x, int y);
|
||||
|
||||
geom::Rectangle const& get_area() { return area; }
|
||||
std::vector<miral::Zone> const& get_app_zones() { return application_zone_list; }
|
||||
miral::Output const& get_output() { return output; }
|
||||
bool is_active() const { return is_active_; }
|
||||
void set_is_active(bool new_is_active) { is_active_ = new_is_active; }
|
||||
|
||||
private:
|
||||
miral::Output output;
|
||||
WorkspaceManager& workspace_manager;
|
||||
miral::WindowManagerTools tools;
|
||||
geom::Rectangle area;
|
||||
std::shared_ptr<MiracleConfig> config;
|
||||
int active_workspace = -1;
|
||||
std::vector<ScreenWorkspaceInfo> workspaces;
|
||||
std::vector<miral::Zone> application_zone_list;
|
||||
bool is_active_ = false;
|
||||
|
||||
void hide(ScreenWorkspaceInfo&);
|
||||
void show(ScreenWorkspaceInfo&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
64
src/tree.cpp
64
src/tree.cpp
@ -1,8 +1,9 @@
|
||||
#include "window_metadata.h"
|
||||
#define MIR_LOG_COMPONENT "window_tree"
|
||||
|
||||
#include "tree.h"
|
||||
#include "window_helpers.h"
|
||||
#include "screen.h"
|
||||
#include "output_content.h"
|
||||
#include "miracle_config.h"
|
||||
|
||||
#include <memory>
|
||||
@ -13,7 +14,7 @@
|
||||
using namespace miracle;
|
||||
|
||||
Tree::Tree(
|
||||
Screen* screen,
|
||||
OutputContent* screen,
|
||||
miral::WindowManagerTools const& tools,
|
||||
std::shared_ptr<MiracleConfig> const& config)
|
||||
: screen{screen},
|
||||
@ -40,9 +41,6 @@ Tree::~Tree()
|
||||
miral::WindowSpecification Tree::allocate_position(const miral::WindowSpecification &requested_specification)
|
||||
{
|
||||
miral::WindowSpecification new_spec = requested_specification;
|
||||
if (!window_helpers::is_tileable(requested_specification))
|
||||
return new_spec;
|
||||
|
||||
new_spec.server_side_decorated() = false;
|
||||
new_spec.min_width() = geom::Width{0};
|
||||
new_spec.max_width() = geom::Width{std::numeric_limits<int>::max()};
|
||||
@ -60,23 +58,16 @@ miral::WindowSpecification Tree::allocate_position(const miral::WindowSpecificat
|
||||
return new_spec;
|
||||
}
|
||||
|
||||
void Tree::advise_new_window(miral::WindowInfo const& window_info)
|
||||
std::shared_ptr<Node> Tree::advise_new_window(miral::WindowInfo const& window_info)
|
||||
{
|
||||
if (!window_helpers::is_tileable(window_info))
|
||||
{
|
||||
if (window_info.state() == MirWindowState::mir_window_state_attached)
|
||||
{
|
||||
tools.select_active_window(window_info.window());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_get_active_lane()->add_window(window_info.window());
|
||||
auto node = _get_active_lane()->add_window(window_info.window());
|
||||
if (window_helpers::is_window_fullscreen(window_info.state()))
|
||||
{
|
||||
tools.select_active_window(window_info.window());
|
||||
advise_fullscreen_window(window_info);
|
||||
advise_fullscreen_window(window_info.window());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void Tree::toggle_resize_mode()
|
||||
@ -164,9 +155,9 @@ bool Tree::try_toggle_active_fullscreen()
|
||||
tools.place_and_size_for_state(spec, window_info);
|
||||
tools.modify_window(active_window->get_window(), spec);
|
||||
if (is_active_window_fullscreen)
|
||||
advise_restored_window(window_info);
|
||||
advise_restored_window(window_info.window());
|
||||
else
|
||||
advise_fullscreen_window(window_info);
|
||||
advise_fullscreen_window(window_info.window());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -634,9 +625,9 @@ void Tree::recalculate_root_node_area()
|
||||
}
|
||||
}
|
||||
|
||||
bool Tree::advise_fullscreen_window(miral::WindowInfo const& window_info)
|
||||
bool Tree::advise_fullscreen_window(miral::Window& window)
|
||||
{
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window_info.window(), tools, this);
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window, tools, this);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
@ -646,9 +637,9 @@ bool Tree::advise_fullscreen_window(miral::WindowInfo const& window_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tree::advise_restored_window(miral::WindowInfo const& window_info)
|
||||
bool Tree::advise_restored_window(miral::Window& window)
|
||||
{
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window_info.window(), tools, this);
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window, tools, this);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
@ -670,13 +661,13 @@ bool Tree::handle_window_ready(miral::WindowInfo &window_info)
|
||||
if (window_info.can_be_active())
|
||||
tools.select_active_window(window_info.window());
|
||||
|
||||
constrain(window_info);
|
||||
constrain(window_info.window());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tree::advise_state_change(const miral::WindowInfo &window_info, MirWindowState state)
|
||||
bool Tree::advise_state_change(miral::Window const& window, MirWindowState state)
|
||||
{
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window_info.window(), tools, this);
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window, tools, this);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
@ -706,11 +697,11 @@ bool Tree::advise_state_change(const miral::WindowInfo &window_info, MirWindowSt
|
||||
}
|
||||
|
||||
bool Tree::confirm_placement_on_display(
|
||||
const miral::WindowInfo &window_info,
|
||||
miral::Window const& window,
|
||||
MirWindowState new_state,
|
||||
mir::geometry::Rectangle &new_placement)
|
||||
{
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window_info.window(), tools, this);
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window, tools, this);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
@ -727,9 +718,9 @@ bool Tree::confirm_placement_on_display(
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tree::constrain(miral::WindowInfo &window_info)
|
||||
bool Tree::constrain(miral::Window& window)
|
||||
{
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window_info.window(), tools, this);
|
||||
auto node = window_helpers::get_node_for_window_by_tree(window, tools, this);
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
@ -746,19 +737,6 @@ bool Tree::constrain(miral::WindowInfo &window_info)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Tree::add_tree(std::shared_ptr<Tree> const& other_tree)
|
||||
{
|
||||
other_tree->foreach_node([&](auto node)
|
||||
{
|
||||
if (node->is_window())
|
||||
{
|
||||
auto new_node_position = root_lane->create_new_node_position();
|
||||
node->set_logical_area(new_node_position);
|
||||
root_lane->add_window(node->get_window());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void foreach_node_internal(std::function<void(std::shared_ptr<Node>)> const& f, std::shared_ptr<Node> const& parent)
|
||||
|
26
src/tree.h
26
src/tree.h
@ -1,5 +1,5 @@
|
||||
#ifndef WINDOW_TREE_H
|
||||
#define WINDOW_TREE_H
|
||||
#ifndef MIRACLE_TREE_H
|
||||
#define MIRACLE_TREE_H
|
||||
|
||||
#include "node.h"
|
||||
#include <memory>
|
||||
@ -16,7 +16,7 @@ namespace geom = mir::geometry;
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
class Screen;
|
||||
class OutputContent;
|
||||
class MiracleConfig;
|
||||
|
||||
enum class Direction
|
||||
@ -30,14 +30,14 @@ enum class Direction
|
||||
class Tree
|
||||
{
|
||||
public:
|
||||
Tree(Screen* parent, miral::WindowManagerTools const& tools, std::shared_ptr<MiracleConfig> const& options);
|
||||
Tree(OutputContent* parent, miral::WindowManagerTools const& tools, std::shared_ptr<MiracleConfig> const& options);
|
||||
~Tree();
|
||||
|
||||
/// Makes space for the new window and returns its specified spot in the grid. Note that the returned
|
||||
/// position is the position WITH GAPS.
|
||||
miral::WindowSpecification allocate_position(const miral::WindowSpecification &requested_specification);
|
||||
|
||||
void advise_new_window(miral::WindowInfo const&);
|
||||
std::shared_ptr<Node> advise_new_window(miral::WindowInfo const&);
|
||||
|
||||
/// Places us into resize mode. Other operations are prohibited while we are in resize mode.
|
||||
void toggle_resize_mode();
|
||||
@ -74,20 +74,18 @@ public:
|
||||
|
||||
bool select_window_from_point(int x, int y);
|
||||
|
||||
bool advise_fullscreen_window(miral::WindowInfo const&);
|
||||
bool advise_restored_window(miral::WindowInfo const &window_info);
|
||||
bool advise_fullscreen_window(miral::Window&);
|
||||
bool advise_restored_window(miral::Window&);
|
||||
bool handle_window_ready(miral::WindowInfo& window_info);
|
||||
|
||||
bool advise_state_change(miral::WindowInfo const& window_info, MirWindowState state);
|
||||
bool advise_state_change(miral::Window const& window, MirWindowState state);
|
||||
bool confirm_placement_on_display(
|
||||
const miral::WindowInfo &window_info,
|
||||
miral::Window const& window,
|
||||
MirWindowState new_state,
|
||||
mir::geometry::Rectangle &new_placement);
|
||||
|
||||
/// Constrains the window to its tile if it is in this tree.
|
||||
bool constrain(miral::WindowInfo& window_info);
|
||||
|
||||
void add_tree(std::shared_ptr<Tree> const&);
|
||||
bool constrain(miral::Window& window);
|
||||
|
||||
void foreach_node(std::function<void(std::shared_ptr<Node>)> const&);
|
||||
void close_active_window();
|
||||
@ -120,7 +118,7 @@ private:
|
||||
MirWindowState state;
|
||||
};
|
||||
|
||||
Screen* screen;
|
||||
OutputContent* screen;
|
||||
miral::WindowManagerTools tools;
|
||||
std::shared_ptr<MiracleConfig> config;
|
||||
std::shared_ptr<Node> root_lane;
|
||||
@ -144,4 +142,4 @@ private:
|
||||
}
|
||||
|
||||
|
||||
#endif //MIRCOMPOSITOR_WINDOW_TREE_H
|
||||
#endif //MIRACLE_TREE_H
|
||||
|
@ -13,16 +13,33 @@ bool miracle::window_helpers::is_window_fullscreen(MirWindowState state)
|
||||
|| state == mir_window_state_vertmaximized;
|
||||
}
|
||||
|
||||
std::shared_ptr<miracle::WindowMetadata> miracle::window_helpers::get_metadata(const miral::WindowInfo &info)
|
||||
{
|
||||
if (info.userdata())
|
||||
return static_pointer_cast<WindowMetadata>(info.userdata());
|
||||
|
||||
mir::log_error("Unable to find metadata for window");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<miracle::WindowMetadata>
|
||||
miracle::window_helpers::get_metadata(const miral::Window &window, const miral::WindowManagerTools &tools)
|
||||
{
|
||||
auto& info = tools.info_for(window);
|
||||
if (info.userdata())
|
||||
return static_pointer_cast<WindowMetadata>(info.userdata());
|
||||
|
||||
mir::log_error("Unable to find metadata for window");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<miracle::Node> miracle::window_helpers::get_node_for_window(
|
||||
miral::Window const& window,
|
||||
miral::WindowManagerTools const& tools)
|
||||
{
|
||||
auto& info = tools.info_for(window);
|
||||
if (info.userdata())
|
||||
{
|
||||
std::shared_ptr<WindowMetadata> data = static_pointer_cast<WindowMetadata>(info.userdata());
|
||||
return data->get_tiling_node();
|
||||
}
|
||||
auto metadata = get_metadata(window, tools);
|
||||
if (metadata)
|
||||
return metadata->get_tiling_node();
|
||||
|
||||
mir::log_error("Unable to find node for window");
|
||||
return nullptr;
|
||||
@ -35,9 +52,7 @@ std::shared_ptr<miracle::Node> miracle::window_helpers::get_node_for_window_by_t
|
||||
{
|
||||
auto node = get_node_for_window(window, tools);
|
||||
if (node && node->get_tree() == tree)
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
@ -8,6 +8,7 @@ namespace miracle
|
||||
{
|
||||
class Node;
|
||||
class Tree;
|
||||
class WindowMetadata;
|
||||
|
||||
namespace window_helpers
|
||||
{
|
||||
@ -24,6 +25,13 @@ bool is_tileable(T const& requested_specification)
|
||||
&& !has_exclusive_rect;
|
||||
}
|
||||
|
||||
std::shared_ptr<WindowMetadata> get_metadata(
|
||||
miral::WindowInfo const& info);
|
||||
|
||||
std::shared_ptr<WindowMetadata> get_metadata(
|
||||
miral::Window const& window,
|
||||
miral::WindowManagerTools const& tools);
|
||||
|
||||
std::shared_ptr<Node> get_node_for_window(
|
||||
miral::Window const& window,
|
||||
miral::WindowManagerTools const& tools);
|
||||
|
@ -2,9 +2,13 @@
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
WindowMetadata::WindowMetadata(miracle::WindowType type, miral::Window const& window)
|
||||
WindowMetadata::WindowMetadata(
|
||||
miracle::WindowType type,
|
||||
miral::Window const& window,
|
||||
OutputContent* output)
|
||||
: type{type},
|
||||
window{window}
|
||||
window{window},
|
||||
output{output}
|
||||
{}
|
||||
|
||||
void WindowMetadata::associate_to_node(std::shared_ptr<Node> const& node)
|
||||
|
@ -7,20 +7,22 @@
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
class OutputContent;
|
||||
class Node;
|
||||
|
||||
enum class WindowType
|
||||
{
|
||||
none,
|
||||
tiled,
|
||||
floating
|
||||
floating,
|
||||
other
|
||||
};
|
||||
|
||||
/// Applied to WindowInfo to enable
|
||||
class WindowMetadata
|
||||
{
|
||||
public:
|
||||
WindowMetadata(WindowType type, miral::Window const& window);
|
||||
WindowMetadata(WindowType type, miral::Window const& window, OutputContent* output);
|
||||
void associate_to_node(std::shared_ptr<Node> const&);
|
||||
miral::Window& get_window() { return window; }
|
||||
std::shared_ptr<Node> get_tiling_node() {
|
||||
@ -28,11 +30,14 @@ public:
|
||||
return tiling_node;
|
||||
return nullptr;
|
||||
}
|
||||
WindowType get_type() { return type; }
|
||||
OutputContent* get_output() { return output; }
|
||||
|
||||
private:
|
||||
|
||||
WindowType type;
|
||||
miral::Window window;
|
||||
OutputContent* output;
|
||||
std::shared_ptr<Node> tiling_node;
|
||||
};
|
||||
|
||||
|
34
src/workspace_content.cpp
Normal file
34
src/workspace_content.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "workspace_content.h"
|
||||
#include "tree.h"
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
WorkspaceContent::WorkspaceContent(
|
||||
miracle::OutputContent *screen,
|
||||
miral::WindowManagerTools const& tools,
|
||||
int workspace,
|
||||
std::shared_ptr<MiracleConfig> const& config)
|
||||
: tree(std::make_shared<Tree>(screen, tools, config)),
|
||||
workspace{workspace}
|
||||
{
|
||||
}
|
||||
|
||||
int WorkspaceContent::get_workspace() const
|
||||
{
|
||||
return workspace;
|
||||
}
|
||||
|
||||
std::shared_ptr<Tree> WorkspaceContent::get_tree() const
|
||||
{
|
||||
return tree;
|
||||
}
|
||||
|
||||
void WorkspaceContent::show()
|
||||
{
|
||||
tree->show();
|
||||
}
|
||||
|
||||
void WorkspaceContent::hide()
|
||||
{
|
||||
tree->hide();
|
||||
}
|
33
src/workspace_content.h
Normal file
33
src/workspace_content.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef MIRACLEWM_WORKSPACE_CONTENT_H
|
||||
#define MIRACLEWM_WORKSPACE_CONTENT_H
|
||||
|
||||
#include <miral/window_manager_tools.h>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
class OutputContent;
|
||||
class MiracleConfig;
|
||||
class Tree;
|
||||
|
||||
class WorkspaceContent
|
||||
{
|
||||
public:
|
||||
WorkspaceContent(
|
||||
OutputContent* screen,
|
||||
miral::WindowManagerTools const& tools,
|
||||
int workspace,
|
||||
std::shared_ptr<MiracleConfig> const& config);
|
||||
|
||||
[[nodiscard]] int get_workspace() const;
|
||||
[[nodiscard]] std::shared_ptr<Tree> get_tree() const;
|
||||
void show();
|
||||
void hide();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Tree> tree;
|
||||
int workspace;
|
||||
};
|
||||
|
||||
} // miracle
|
||||
|
||||
#endif //MIRACLEWM_WORKSPACE_CONTENT_H
|
@ -1,6 +1,6 @@
|
||||
#define MIR_LOG_COMPONENT "workspace_manager"
|
||||
#include "workspace_manager.h"
|
||||
#include "screen.h"
|
||||
#include "output_content.h"
|
||||
#include "window_helpers.h"
|
||||
#include <mir/log.h>
|
||||
|
||||
@ -11,19 +11,19 @@ using namespace miracle;
|
||||
WorkspaceManager::WorkspaceManager(
|
||||
WindowManagerTools const& tools,
|
||||
WorkspaceObserverRegistrar& registry,
|
||||
std::function<std::shared_ptr<Screen> const()> const& get_active_screen) :
|
||||
std::function<std::shared_ptr<OutputContent> const()> const& get_active_screen) :
|
||||
tools_{tools},
|
||||
registry{registry},
|
||||
get_active_screen{get_active_screen}
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<Screen> WorkspaceManager::request_workspace(std::shared_ptr<Screen> screen, int key)
|
||||
std::shared_ptr<OutputContent> WorkspaceManager::request_workspace(std::shared_ptr<OutputContent> screen, int key)
|
||||
{
|
||||
if (workspaces[key] != nullptr)
|
||||
{
|
||||
auto workspace = workspaces[key];
|
||||
auto active_workspace = workspace->get_active_workspace();
|
||||
auto active_workspace = workspace->get_active_workspace_num();
|
||||
if (active_workspace == key)
|
||||
{
|
||||
mir::log_warning("Same workspace selected twice in a row");
|
||||
@ -42,7 +42,7 @@ std::shared_ptr<Screen> WorkspaceManager::request_workspace(std::shared_ptr<Scre
|
||||
return screen;
|
||||
}
|
||||
|
||||
bool WorkspaceManager::request_first_available_workspace(std::shared_ptr<Screen> screen)
|
||||
bool WorkspaceManager::request_first_available_workspace(std::shared_ptr<OutputContent> screen)
|
||||
{
|
||||
for (int i = 1; i < NUM_WORKSPACES; i++)
|
||||
{
|
||||
@ -62,27 +62,45 @@ bool WorkspaceManager::request_first_available_workspace(std::shared_ptr<Screen>
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WorkspaceManager::move_active_to_workspace(std::shared_ptr<Screen> screen, int workspace)
|
||||
bool WorkspaceManager::move_active_to_workspace(std::shared_ptr<OutputContent> screen, int workspace)
|
||||
{
|
||||
auto window = tools_.active_window();
|
||||
if (!window)
|
||||
return false;
|
||||
|
||||
auto& original_tree = screen->get_active_tree();
|
||||
auto metadata = window_helpers::get_metadata(window, tools_);
|
||||
switch (metadata->get_type())
|
||||
{
|
||||
case WindowType::tiled:
|
||||
{
|
||||
auto original_tree = screen->get_active_tree();
|
||||
auto window_node = window_helpers::get_node_for_window(window, tools_);
|
||||
original_tree.advise_delete_window(window);
|
||||
original_tree->advise_delete_window(window);
|
||||
|
||||
auto screen_to_move_to = request_workspace(screen, workspace);
|
||||
auto& prev_info = tools_.info_for(window);
|
||||
|
||||
// TODO: These need to be set so that the window is correctly seen as tileable
|
||||
// WARNING: These need to be set so that the window is correctly seen as tileable
|
||||
miral::WindowSpecification spec;
|
||||
spec.type() = prev_info.type();
|
||||
spec.state() = prev_info.state();
|
||||
spec = screen_to_move_to->get_active_tree().allocate_position(spec);
|
||||
spec = screen_to_move_to->get_active_tree()->allocate_position(spec);
|
||||
tools_.modify_window(window, spec);
|
||||
screen_to_move_to->get_active_tree().advise_new_window(prev_info);
|
||||
screen_to_move_to->get_active_tree().handle_window_ready(prev_info);
|
||||
|
||||
auto new_node = screen_to_move_to->get_active_tree()->advise_new_window(prev_info);
|
||||
metadata->associate_to_node(new_node);
|
||||
miral::WindowSpecification next_spec;
|
||||
next_spec.userdata() = metadata;
|
||||
tools_.modify_window(window, next_spec);
|
||||
|
||||
screen_to_move_to->get_active_tree()->handle_window_ready(prev_info);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
mir::log_error("Cannot move window of type %d to a new workspace", (int)metadata->get_type());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -109,7 +127,7 @@ void WorkspaceManager::request_focus(int key)
|
||||
|
||||
if (active_screen != nullptr)
|
||||
{
|
||||
auto active_workspace = active_screen->get_active_workspace();
|
||||
auto active_workspace = active_screen->get_active_workspace_num();
|
||||
registry.advise_focused(active_screen, active_workspace, workspaces[key], key);
|
||||
}
|
||||
else
|
||||
|
@ -19,7 +19,7 @@ using miral::WindowManagerTools;
|
||||
using miral::WindowSpecification;
|
||||
using miral::Workspace;
|
||||
|
||||
class Screen;
|
||||
class OutputContent;
|
||||
|
||||
class WorkspaceManager
|
||||
{
|
||||
@ -27,30 +27,30 @@ public:
|
||||
explicit WorkspaceManager(
|
||||
WindowManagerTools const& tools,
|
||||
WorkspaceObserverRegistrar& registry,
|
||||
std::function<std::shared_ptr<Screen> const()> const& get_active_screen);
|
||||
std::function<std::shared_ptr<OutputContent> const()> const& get_active_screen);
|
||||
virtual ~WorkspaceManager() = default;
|
||||
|
||||
/// Request the workspace. If it does not yet exist, then one
|
||||
/// is created on the current Screen. If it does exist, we navigate
|
||||
/// to the screen containing that workspace and show it if it
|
||||
/// isn't already shown.
|
||||
std::shared_ptr<Screen> request_workspace(std::shared_ptr<Screen> screen, int workspace);
|
||||
std::shared_ptr<OutputContent> request_workspace(std::shared_ptr<OutputContent> screen, int workspace);
|
||||
|
||||
bool request_first_available_workspace(std::shared_ptr<Screen> screen);
|
||||
bool request_first_available_workspace(std::shared_ptr<OutputContent> screen);
|
||||
|
||||
bool move_active_to_workspace(std::shared_ptr<Screen> screen, int workspace);
|
||||
bool move_active_to_workspace(std::shared_ptr<OutputContent> screen, int workspace);
|
||||
|
||||
bool delete_workspace(int workspace);
|
||||
|
||||
void request_focus(int workspace);
|
||||
|
||||
static int constexpr NUM_WORKSPACES = 10;
|
||||
std::array<std::shared_ptr<Screen>, NUM_WORKSPACES> const& get_workspaces() { return workspaces; }
|
||||
std::array<std::shared_ptr<OutputContent>, NUM_WORKSPACES> const& get_workspaces() { return workspaces; }
|
||||
private:
|
||||
WindowManagerTools tools_;
|
||||
WorkspaceObserverRegistrar& registry;
|
||||
std::function<std::shared_ptr<Screen> const()> get_active_screen;
|
||||
std::array<std::shared_ptr<Screen>, NUM_WORKSPACES> workspaces;
|
||||
std::function<std::shared_ptr<OutputContent> const()> get_active_screen;
|
||||
std::array<std::shared_ptr<OutputContent>, NUM_WORKSPACES> workspaces;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ void WorkspaceObserverRegistrar::unregister_interest(miracle::WorkspaceObserver&
|
||||
}));
|
||||
}
|
||||
|
||||
void WorkspaceObserverRegistrar::advise_created(std::shared_ptr<Screen> const& info, int key)
|
||||
void WorkspaceObserverRegistrar::advise_created(std::shared_ptr<OutputContent> const& info, int key)
|
||||
{
|
||||
for (auto& observer : observers)
|
||||
{
|
||||
@ -41,7 +41,7 @@ void WorkspaceObserverRegistrar::advise_created(std::shared_ptr<Screen> const& i
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceObserverRegistrar::advise_removed(std::shared_ptr<Screen> const& info, int key)
|
||||
void WorkspaceObserverRegistrar::advise_removed(std::shared_ptr<OutputContent> const& info, int key)
|
||||
{
|
||||
for (auto& observer : observers)
|
||||
{
|
||||
@ -51,9 +51,9 @@ void WorkspaceObserverRegistrar::advise_removed(std::shared_ptr<Screen> const& i
|
||||
}
|
||||
|
||||
void WorkspaceObserverRegistrar::advise_focused(
|
||||
std::shared_ptr<Screen> const& previous,
|
||||
std::shared_ptr<OutputContent> const& previous,
|
||||
int previous_key,
|
||||
std::shared_ptr<Screen> const& current,
|
||||
std::shared_ptr<OutputContent> const& current,
|
||||
int current_key)
|
||||
{
|
||||
for (auto& observer : observers)
|
||||
|
@ -1,22 +1,22 @@
|
||||
#ifndef MIRACLEWM_WORKSPACE_OBSERVER_H
|
||||
#define MIRACLEWM_WORKSPACE_OBSERVER_H
|
||||
|
||||
#include "screen.h"
|
||||
#include "output_content.h"
|
||||
#include <mir/executor.h>
|
||||
#include <memory>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
class Screen;
|
||||
class OutputContent;
|
||||
|
||||
class WorkspaceObserver
|
||||
{
|
||||
public:
|
||||
virtual ~WorkspaceObserver() = default;
|
||||
virtual void on_created(std::shared_ptr<Screen> const&, int) = 0;
|
||||
virtual void on_removed(std::shared_ptr<Screen> const&, int) = 0;
|
||||
virtual void on_focused(std::shared_ptr<Screen> const& previous, int, std::shared_ptr<Screen> const& current, int) = 0;
|
||||
virtual void on_created(std::shared_ptr<OutputContent> const&, int) = 0;
|
||||
virtual void on_removed(std::shared_ptr<OutputContent> const&, int) = 0;
|
||||
virtual void on_focused(std::shared_ptr<OutputContent> const& previous, int, std::shared_ptr<OutputContent> const& current, int) = 0;
|
||||
|
||||
int get_id() const;
|
||||
protected:
|
||||
@ -32,9 +32,9 @@ public:
|
||||
WorkspaceObserverRegistrar() = default;
|
||||
void register_interest(std::weak_ptr<WorkspaceObserver>);
|
||||
void unregister_interest(WorkspaceObserver&);
|
||||
void advise_created(std::shared_ptr<Screen> const&, int);
|
||||
void advise_removed(std::shared_ptr<Screen> const&, int);
|
||||
void advise_focused(std::shared_ptr<Screen> const& previous, int, std::shared_ptr<Screen> const& current, int);
|
||||
void advise_created(std::shared_ptr<OutputContent> const&, int);
|
||||
void advise_removed(std::shared_ptr<OutputContent> const&, int);
|
||||
void advise_focused(std::shared_ptr<OutputContent> const& previous, int, std::shared_ptr<OutputContent> const& current, int);
|
||||
|
||||
private:
|
||||
std::vector<std::weak_ptr<WorkspaceObserver>> observers;
|
||||
|
Loading…
Reference in New Issue
Block a user