/**
Copyright (C) 2024 Matthew Kosarek
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
**/
#include "compositor_state.h"
#include "leaf_container.h"
#include "stub_configuration.h"
#include "stub_session.h"
#include "stub_surface.h"
#include "tiling_window_tree.h"
#include "window_controller.h"
#include
#include
using namespace miracle;
namespace
{
geom::Rectangle r {
geom::Point(0, 0),
geom::Size(1280, 720)
};
}
class SimpleTilingWindowTreeInterface : public TilingWindowTreeInterface
{
public:
std::vector const& get_zones() override
{
return zones;
}
Workspace* get_workspace() const override
{
return nullptr;
}
private:
std::vector zones = { r };
};
class StubWindowController : public miracle::WindowController
{
public:
StubWindowController(std::vector>>& pairs) :
pairs { pairs }
{
}
bool is_fullscreen(miral::Window const&) override
{
return false;
}
void set_rectangle(miral::Window const&, geom::Rectangle const&, geom::Rectangle const&) override { }
MirWindowState get_state(miral::Window const&) override
{
return mir_window_state_restored;
}
void change_state(miral::Window const&, MirWindowState state) override { }
void clip(miral::Window const&, geom::Rectangle const&) override { }
void noclip(miral::Window const&) override { }
void select_active_window(miral::Window const&) override { }
std::shared_ptr get_container(miral::Window const& window) override
{
for (auto const& p : pairs)
{
if (p.first == window)
return p.second;
}
return nullptr;
}
void raise(miral::Window const&) override { }
void send_to_back(miral::Window const&) override { }
void open(miral::Window const&) override { }
void close(miral::Window const&) override { }
void on_animation(miracle::AnimationStepResult const& result, std::shared_ptr const&) override { }
void set_user_data(miral::Window const&, std::shared_ptr const&) override { }
void modify(miral::Window const&, miral::WindowSpecification const&) override { }
miral::WindowInfo& info_for(miral::Window const&) override { }
private:
std::vector>>& pairs;
};
class TilingWindowTreeTest : public testing::Test
{
public:
TilingWindowTreeTest() :
tree(
std::make_unique(),
window_controller,
state,
std::make_shared(),
r)
{
}
std::shared_ptr create_leaf()
{
miral::WindowSpecification spec;
spec = tree.place_new_window(spec, nullptr);
auto session = std::make_shared();
sessions.push_back(session);
auto surface = std::make_shared();
surfaces.push_back(surface);
miral::Window window(session, surface);
miral::WindowInfo info(window, spec);
auto leaf = tree.confirm_window(info, nullptr);
pairs.push_back({ window, leaf });
state.active = leaf;
tree.advise_focus_gained(*leaf);
return leaf;
}
CompositorState state;
std::vector> sessions;
std::vector> surfaces;
std::vector>> pairs;
StubWindowController window_controller { pairs };
TilingWindowTree tree;
};
TEST_F(TilingWindowTreeTest, can_add_single_window_without_border_and_gaps)
{
auto leaf = create_leaf();
ASSERT_EQ(leaf->get_logical_area().size, geom::Size(1280, 720));
ASSERT_EQ(leaf->get_logical_area().top_left, geom::Point(0, 0));
}
TEST_F(TilingWindowTreeTest, can_add_two_windows_horizontally_without_border_and_gaps)
{
auto leaf1 = create_leaf();
auto leaf2 = create_leaf();
ASSERT_EQ(leaf1->get_logical_area().size, geom::Size(1280 / 2.f, 720));
ASSERT_EQ(leaf1->get_logical_area().top_left, geom::Point(0, 0));
ASSERT_EQ(leaf2->get_logical_area().size, geom::Size(1280 / 2.f, 720));
ASSERT_EQ(leaf2->get_logical_area().top_left, geom::Point(1280 / 2.f, 0));
}
TEST_F(TilingWindowTreeTest, can_add_two_windows_vertically_without_border_and_gaps)
{
auto leaf1 = create_leaf();
tree.request_vertical_layout(*leaf1);
auto leaf2 = create_leaf();
ASSERT_EQ(leaf1->get_logical_area().size, geom::Size(1280, 720 / 2.f));
ASSERT_EQ(leaf1->get_logical_area().top_left, geom::Point(0, 0));
ASSERT_EQ(leaf2->get_logical_area().size, geom::Size(1280, 720 / 2.f));
ASSERT_EQ(leaf2->get_logical_area().top_left, geom::Point(0, 720 / 2.f));
}
TEST_F(TilingWindowTreeTest, can_add_three_windows_horizontally_without_border_and_gaps)
{
auto leaf1 = create_leaf();
auto leaf2 = create_leaf();
auto leaf3 = create_leaf();
ASSERT_EQ(leaf1->get_logical_area().size, geom::Size(ceilf(1280 / 3.f), 720));
ASSERT_EQ(leaf1->get_logical_area().top_left, geom::Point(0, 0));
ASSERT_EQ(leaf2->get_logical_area().size, geom::Size(ceilf(1280 / 3.f), 720));
ASSERT_EQ(leaf2->get_logical_area().top_left, geom::Point(ceilf(1280 / 3.f), 0));
ASSERT_EQ(leaf3->get_logical_area().size, geom::Size(floorf(1280 / 3.f), 720));
ASSERT_EQ(leaf3->get_logical_area().top_left, geom::Point(floorf(1280 * (2.f / 3.f)) - 1, 0));
}