bugfix: exclusion areas now work across workspaces

This commit is contained in:
Matthew Kosarek 2024-02-09 15:42:34 -05:00
parent 0e9eea63e2
commit c6dbc2c402
5 changed files with 72 additions and 76 deletions

View File

@ -233,7 +233,7 @@ bool MiracleWindowManagementPolicy::handle_pointer_event(MirPointerEvent const*
for (auto const& pair : output_list)
{
if (pair->screen->get_active_tree().point_is_in_output(static_cast<int>(x), static_cast<int>(y)))
if (pair->screen->point_is_in_output(static_cast<int>(x), static_cast<int>(y)))
{
if (active_output != pair)
{
@ -485,8 +485,7 @@ void MiracleWindowManagementPolicy::advise_application_zone_create(miral::Zone c
{
for (auto const& output : output_list)
{
for (auto& workspace : output->screen->get_workspaces())
workspace.tree.advise_application_zone_create(application_zone);
output->screen->advise_application_zone_create(application_zone);
}
}
@ -494,8 +493,7 @@ void MiracleWindowManagementPolicy::advise_application_zone_update(miral::Zone c
{
for (auto const& output : output_list)
{
for (auto& workspace : output->screen->get_workspaces())
workspace.tree.advise_application_zone_update(updated, original);
output->screen->advise_application_zone_update(updated, original);
}
}
@ -503,7 +501,6 @@ void MiracleWindowManagementPolicy::advise_application_zone_delete(miral::Zone c
{
for (auto const& output : output_list)
{
for (auto& workspace : output->screen->get_workspaces())
workspace.tree.advise_application_zone_delete(application_zone);
output->screen->advise_application_zone_delete(application_zone);
}
}

View File

@ -31,7 +31,7 @@ void Screen::advise_new_workspace(char workspace)
{
workspaces.push_back({
workspace,
WindowTree(area, tools, options)
WindowTree(this, tools, options)
});
make_workspace_active(workspace);
}
@ -73,3 +73,39 @@ void Screen::show(ScreenWorkspaceInfo& info)
{
info.tree.show();
}
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));
}

View File

@ -33,12 +33,19 @@ public:
geom::Rectangle const& area,
miral::WindowManagerTools const& tools,
WindowTreeOptions const& options);
~Screen() = default;
~Screen() = default;
WindowTree& get_active_tree();
void advise_new_workspace(char workspace);
bool make_workspace_active(char workspace);
std::vector<ScreenWorkspaceInfo>& get_workspaces() { return workspaces; }
WindowTree& get_active_tree();
void advise_new_workspace(char workspace);
bool make_workspace_active(char workspace);
std::vector<ScreenWorkspaceInfo>& get_workspaces() { 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);
geom::Rectangle const& get_area() { return area; }
std::vector<miral::Zone> const& get_app_zones() { return application_zone_list; }
private:
WorkspaceManager& workspace_manager;
@ -47,6 +54,7 @@ private:
WindowTreeOptions options;
char active_workspace;
std::vector<ScreenWorkspaceInfo> workspaces;
std::vector<miral::Zone> application_zone_list;
void hide(ScreenWorkspaceInfo&);
void show(ScreenWorkspaceInfo&);

View File

@ -2,6 +2,7 @@
#include "window_tree.h"
#include "window_helpers.h"
#include "screen.h"
#include <memory>
#include <mir/log.h>
#include <iostream>
@ -9,27 +10,19 @@
using namespace miracle;
namespace
{
bool point_in_rect(geom::Rectangle const& area, int x, int y)
{
return x >= area.top_left.x.as_int() && x < area.top_left.x.as_int() + area.size.width.as_int()
&& y >= area.top_left.y.as_int() && y < area.top_left.y.as_int() + area.size.height.as_int();
}
}
WindowTree::WindowTree(
geom::Rectangle const& default_area,
Screen* screen,
miral::WindowManagerTools const& tools,
WindowTreeOptions const& options)
: root_lane{std::make_shared<Node>(
: screen{screen},
root_lane{std::make_shared<Node>(
tools,
std::move(geom::Rectangle{default_area.top_left, default_area.size}),
std::move(geom::Rectangle{screen->get_area().top_left, screen->get_area().size}),
options.gap_x, options.gap_y)},
tools{tools},
area{default_area},
options{options}
{
_recalculate_root_node_area();
}
miral::WindowSpecification WindowTree::allocate_position(const miral::WindowSpecification &requested_specification)
@ -154,6 +147,7 @@ bool WindowTree::try_toggle_active_fullscreen()
void WindowTree::set_output_area(geom::Rectangle const& new_area)
{
auto area = screen->get_area();
double x_scale = static_cast<double>(new_area.size.width.as_int()) / static_cast<double>(area.size.width.as_int());
double y_scale = static_cast<double>(new_area.size.height.as_int()) / static_cast<double>(area.size.height.as_int());
@ -168,11 +162,6 @@ void WindowTree::set_output_area(geom::Rectangle const& new_area)
root_lane->translate_by(position_diff_x, position_diff_y);
}
bool WindowTree::point_is_in_output(int x, int y)
{
return point_in_rect(area, x, y);
}
bool WindowTree::select_window_from_point(int x, int y)
{
if (is_active_window_fullscreen)
@ -183,7 +172,7 @@ bool WindowTree::select_window_from_point(int x, int y)
auto node = root_lane->find_where([&](std::shared_ptr<Node> const& node)
{
return node->is_window() && point_in_rect(node->get_logical_area(), x, y);
return node->is_window() && node->get_logical_area().contains(geom::Point(x, y));
});
if (!node)
return false;
@ -368,7 +357,7 @@ std::shared_ptr<Node> get_closest_window_to_select_from_node(
if (is_negative)
{
auto sub_nodes = node->get_sub_nodes();
for (auto i = sub_nodes.size() - 1; i >= 0; i--)
for (auto i = sub_nodes.size() - 1; i != 0; i--)
{
if (auto retval = get_closest_window_to_select_from_node(sub_nodes[i], direction))
return retval;
@ -376,7 +365,7 @@ std::shared_ptr<Node> get_closest_window_to_select_from_node(
}
}
for (auto sub_node : node->get_sub_nodes())
for (auto const& sub_node : node->get_sub_nodes())
{
if (auto retval = get_closest_window_to_select_from_node(sub_node, direction))
return retval;
@ -552,7 +541,7 @@ void WindowTree::_handle_resize_request(
}
}
void WindowTree::_handle_node_remove(std::shared_ptr<Node> node)
void WindowTree::_handle_node_remove(std::shared_ptr<Node> const& node)
{
auto parent = node->get_parent();
if (parent == nullptr)
@ -571,38 +560,9 @@ void WindowTree::_handle_node_remove(std::shared_ptr<Node> node)
}
}
void WindowTree::advise_application_zone_create(miral::Zone const& application_zone)
{
if (application_zone.extents().contains(area))
{
application_zone_list.push_back(application_zone);
_recalculate_root_node_area();
}
}
void WindowTree::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
{
for (auto& zone : application_zone_list)
if (zone == original)
{
zone = updated;
_recalculate_root_node_area();
break;
}
}
void WindowTree::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())
{
_recalculate_root_node_area();
}
}
void WindowTree::_recalculate_root_node_area()
{
// TODO: We don't take care of multiple application zones, so maybe that has to do with multiple outputs?
for (auto const& zone : application_zone_list)
for (auto const& zone : screen->get_app_zones())
{
root_lane->set_logical_area(zone.extents());
break;

View File

@ -16,6 +16,8 @@ namespace geom = mir::geometry;
namespace miracle
{
class Screen;
enum class Direction
{
up,
@ -34,7 +36,7 @@ struct WindowTreeOptions
class WindowTree
{
public:
WindowTree(geom::Rectangle const& area, miral::WindowManagerTools const& tools, WindowTreeOptions const& options);
WindowTree(Screen* parent, miral::WindowManagerTools const& tools, WindowTreeOptions const& options);
~WindowTree() = default;
/// Makes space for the new window and returns its specified spot in the grid. Note that the returned
@ -76,14 +78,8 @@ public:
/// Called when the physical display is resized.
void set_output_area(geom::Rectangle const& new_area);
bool point_is_in_output(int x, int y);
bool select_window_from_point(int x, int y);
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 advise_fullscreen_window(miral::WindowInfo const&);
bool advise_restored_window(miral::WindowInfo const &window_info);
bool handle_window_ready(miral::WindowInfo& window_info);
@ -109,6 +105,7 @@ public:
void show();
std::shared_ptr<Node> get_root_node();
void _recalculate_root_node_area();
private:
struct MoveResult
@ -128,13 +125,12 @@ private:
MirWindowState state;
};
Screen* screen;
miral::WindowManagerTools tools;
WindowTreeOptions options;
std::shared_ptr<Node> root_lane;
std::shared_ptr<Node> active_window;
geom::Rectangle area;
bool is_resizing = false;
std::vector<miral::Zone> application_zone_list;
bool is_active_window_fullscreen = false;
bool is_hidden = false;
std::vector<NodeResurrection> nodes_to_resurrect;
@ -142,12 +138,11 @@ private:
std::shared_ptr<Node> _get_active_lane();
void _handle_direction_request(NodeLayoutDirection direction);
void _handle_resize_request(std::shared_ptr<Node> const& node, Direction direction, int amount);
void _handle_node_remove(std::shared_ptr<Node> node);
void _handle_node_remove(std::shared_ptr<Node> const& node);
/// From the provided node, find the next node in the provided direction.
/// This method is guaranteed to return a Window node, not a Lane.
MoveResult _move(std::shared_ptr<Node> const& from, Direction direction);
static std::shared_ptr<Node> _select(std::shared_ptr<Node> const& from, Direction direction);
void _recalculate_root_node_area();
};
}