mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-30 02:09:10 +03:00
feature: workspace switching animations (#128)
This commit is contained in:
parent
6789815eaf
commit
a1da899ded
@ -29,6 +29,10 @@ AnimateableEvent miracle::from_string_animateable_event(std::string const& str)
|
||||
return AnimateableEvent::window_move;
|
||||
else if (str == "window_close")
|
||||
return AnimateableEvent::window_close;
|
||||
else if (str == "window_workspace_show")
|
||||
return AnimateableEvent::window_workspace_show;
|
||||
else if (str == "window_workspace_hide")
|
||||
return AnimateableEvent::window_workspace_hide;
|
||||
else
|
||||
{
|
||||
mir::log_error("from_string_animateable_eventfrom_string: unknown string: %s", str.c_str());
|
||||
|
@ -18,7 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef MIRACLE_WM_ANIMATION_DEFINTION_H
|
||||
#define MIRACLE_WM_ANIMATION_DEFINTION_H
|
||||
|
||||
#include "direction.h"
|
||||
#include "mir/geometry/point.h"
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace miracle
|
||||
@ -29,6 +30,8 @@ enum class AnimateableEvent
|
||||
window_open,
|
||||
window_move,
|
||||
window_close,
|
||||
window_workspace_show,
|
||||
window_workspace_hide,
|
||||
max
|
||||
};
|
||||
|
||||
@ -94,6 +97,10 @@ struct AnimationDefinition
|
||||
float c5 = 1.3962634015954636;
|
||||
float n1 = 7.5625;
|
||||
float d1 = 2.75;
|
||||
|
||||
// Slide-specific values
|
||||
std::optional<mir::geometry::Point> slide_to;
|
||||
std::optional<mir::geometry::Point> slide_from;
|
||||
};
|
||||
|
||||
AnimateableEvent from_string_animateable_event(std::string const&);
|
||||
|
@ -196,6 +196,16 @@ AnimationStepResult Animation::init()
|
||||
{},
|
||||
glm::mat4(0.f)
|
||||
};
|
||||
case AnimationType::slide:
|
||||
return {
|
||||
handle,
|
||||
false,
|
||||
from.has_value()
|
||||
? std::optional<glm::vec2>(glm::vec2(from.value().top_left.x.as_int(), from.value().top_left.y.as_int()))
|
||||
: std::nullopt,
|
||||
{},
|
||||
{}
|
||||
};
|
||||
default:
|
||||
return {
|
||||
handle,
|
||||
@ -215,8 +225,8 @@ AnimationStepResult Animation::step()
|
||||
return {
|
||||
handle,
|
||||
true,
|
||||
glm::vec2(to.top_left.x.as_int(), to.top_left.y.as_int()),
|
||||
glm::vec2(to.size.width.as_int(), to.size.height.as_int()),
|
||||
!to.has_value() ? std::nullopt : std::optional<glm::vec2>(glm::vec2(to.value().top_left.x.as_int(), to.value().top_left.y.as_int())),
|
||||
!to.has_value() ? std::nullopt : std::optional<glm::vec2>(glm::vec2(to.value().size.width.as_int(), to.value().size.height.as_int())),
|
||||
glm::mat4(1.f),
|
||||
};
|
||||
}
|
||||
@ -227,20 +237,20 @@ AnimationStepResult Animation::step()
|
||||
case AnimationType::slide:
|
||||
{
|
||||
auto p = ease(definition, t);
|
||||
auto distance = to.top_left - from.top_left;
|
||||
auto distance = to.value().top_left - from.value().top_left;
|
||||
float x = (float)distance.dx.as_int() * p;
|
||||
float y = (float)distance.dy.as_int() * p;
|
||||
|
||||
glm::vec2 position = {
|
||||
(float)from.top_left.x.as_int() + x,
|
||||
(float)from.top_left.y.as_int() + y
|
||||
(float)from.value().top_left.x.as_int() + x,
|
||||
(float)from.value().top_left.y.as_int() + y
|
||||
};
|
||||
|
||||
return {
|
||||
handle,
|
||||
false,
|
||||
position,
|
||||
glm::vec2(to.size.width.as_int(), to.size.height.as_int()),
|
||||
glm::vec2(to.value().size.width.as_int(), to.value().size.height.as_int()),
|
||||
std::nullopt
|
||||
};
|
||||
}
|
||||
@ -345,6 +355,57 @@ void Animator::window_open(
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
void Animator::workspace_move_to(
|
||||
AnimationHandle handle,
|
||||
int x_offset,
|
||||
std::function<void(AnimationStepResult const&)> const& from_callback,
|
||||
std::function<void(AnimationStepResult const&)> const& to_callback)
|
||||
{
|
||||
if (!config->are_animations_enabled())
|
||||
{
|
||||
from_callback({ handle, true });
|
||||
to_callback({ handle, true });
|
||||
return;
|
||||
}
|
||||
|
||||
mir::geometry::Rectangle from_start(
|
||||
mir::geometry::Point{0, 0},
|
||||
mir::geometry::Size{0, 0}
|
||||
);
|
||||
mir::geometry::Rectangle from_end(
|
||||
mir::geometry::Point{-x_offset, 0},
|
||||
mir::geometry::Size{0, 0}
|
||||
);
|
||||
|
||||
Animation from_animation = Animation::window_move(handle,
|
||||
config->get_animation_definitions()[(int)AnimateableEvent::window_workspace_hide],
|
||||
from_start,
|
||||
from_end,
|
||||
from_callback);
|
||||
|
||||
mir::geometry::Rectangle to_start(
|
||||
mir::geometry::Point{x_offset, 0},
|
||||
mir::geometry::Size{0, 0}
|
||||
);
|
||||
mir::geometry::Rectangle to_end(
|
||||
mir::geometry::Point{0, 0},
|
||||
mir::geometry::Size{0, 0}
|
||||
);
|
||||
Animation to_animation = Animation::window_move(handle,
|
||||
config->get_animation_definitions()[(int)AnimateableEvent::window_workspace_hide],
|
||||
to_start,
|
||||
to_end,
|
||||
to_callback);
|
||||
|
||||
from_callback(from_animation.init());
|
||||
to_callback(to_animation.init());
|
||||
|
||||
std::lock_guard<std::mutex> lock(processing_lock);
|
||||
queued_animations.push_back(std::move(from_animation));
|
||||
queued_animations.push_back(std::move(to_animation));
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct PendingUpdateData
|
||||
|
@ -75,8 +75,8 @@ public:
|
||||
private:
|
||||
AnimationHandle handle;
|
||||
AnimationDefinition definition;
|
||||
mir::geometry::Rectangle from;
|
||||
mir::geometry::Rectangle to;
|
||||
std::optional<mir::geometry::Rectangle> from;
|
||||
std::optional<mir::geometry::Rectangle> to;
|
||||
const float timestep_seconds = 0.016;
|
||||
std::function<void(AnimationStepResult const&)> callback;
|
||||
float runtime_seconds = 0.f;
|
||||
@ -106,6 +106,12 @@ public:
|
||||
AnimationHandle handle,
|
||||
std::function<void(AnimationStepResult const&)> const& callback);
|
||||
|
||||
void workspace_move_to(
|
||||
AnimationHandle handle,
|
||||
int x_offset, // The offset in X from which the "to" callback transform begins if it is a slide
|
||||
std::function<void(AnimationStepResult const&)> const& from_callback,
|
||||
std::function<void(AnimationStepResult const&)> const& to_callback);
|
||||
|
||||
void stop();
|
||||
|
||||
private:
|
||||
|
@ -85,9 +85,6 @@ glm::vec4 parse_color(YAML::Node const& node)
|
||||
|
||||
std::string wrap_command(std::string const& command)
|
||||
{
|
||||
if (std::getenv("SNAP"))
|
||||
return "miracle-wm-unsnap " + command;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
@ -799,6 +796,16 @@ void MiracleConfig::read_animation_definitions(YAML::Node const& root)
|
||||
AnimationType::shrink,
|
||||
EaseFunction::ease_out_back,
|
||||
0.25f,
|
||||
},
|
||||
{
|
||||
AnimationType::slide,
|
||||
EaseFunction::ease_in_out_elastic,
|
||||
0.5f
|
||||
},
|
||||
{
|
||||
AnimationType::slide,
|
||||
EaseFunction::ease_in_out_elastic,
|
||||
0.5f
|
||||
}
|
||||
});
|
||||
if (root["animations"])
|
||||
|
@ -15,15 +15,21 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
**/
|
||||
|
||||
#include "window_metadata.h"
|
||||
#include "workspace_content.h"
|
||||
#include <memory>
|
||||
#define MIR_LOG_COMPONENT "output_content"
|
||||
|
||||
#include "output_content.h"
|
||||
#include "animator.h"
|
||||
#include "leaf_node.h"
|
||||
#include "output_content.h"
|
||||
#include "window_helpers.h"
|
||||
#include "workspace_manager.h"
|
||||
#include <mir/log.h>
|
||||
#include <mir/scene/surface.h>
|
||||
#include <miral/toolkit_event.h>
|
||||
#include <miral/window_info.h>
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
@ -34,14 +40,17 @@ OutputContent::OutputContent(
|
||||
miral::WindowManagerTools const& tools,
|
||||
miral::MinimalWindowManager& floating_window_manager,
|
||||
std::shared_ptr<MiracleConfig> const& config,
|
||||
TilingInterface& node_interface) :
|
||||
TilingInterface& node_interface,
|
||||
Animator& animator) :
|
||||
output { output },
|
||||
workspace_manager { workspace_manager },
|
||||
area { area },
|
||||
tools { tools },
|
||||
floating_window_manager { floating_window_manager },
|
||||
config { config },
|
||||
node_interface { node_interface }
|
||||
node_interface { node_interface },
|
||||
animator { animator },
|
||||
animation_handle { animator.register_animateable() }
|
||||
{
|
||||
}
|
||||
|
||||
@ -402,41 +411,93 @@ void OutputContent::advise_workspace_deleted(int workspace)
|
||||
|
||||
bool OutputContent::advise_workspace_active(int key)
|
||||
{
|
||||
std::shared_ptr<WorkspaceContent> to = nullptr;
|
||||
std::shared_ptr<WorkspaceContent> from = nullptr;
|
||||
for (auto& workspace : workspaces)
|
||||
{
|
||||
if (workspace->get_workspace() == active_workspace)
|
||||
from = workspace;
|
||||
|
||||
if (workspace->get_workspace() == key)
|
||||
{
|
||||
if (active_workspace == key)
|
||||
return true;
|
||||
|
||||
std::shared_ptr<WorkspaceContent> previous_workspace = nullptr;
|
||||
std::vector<std::shared_ptr<WindowMetadata>> pinned_windows;
|
||||
for (auto& other : workspaces)
|
||||
{
|
||||
if (other->get_workspace() == active_workspace)
|
||||
{
|
||||
previous_workspace = other;
|
||||
pinned_windows = other->hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
active_workspace = key;
|
||||
workspace->show(pinned_windows);
|
||||
|
||||
// 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() && previous_workspace->get_floating_windows().empty())
|
||||
workspace_manager.delete_workspace(previous_workspace->get_workspace());
|
||||
}
|
||||
return true;
|
||||
to = workspace;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
// TODO: Handle pinned windows
|
||||
// TODO This is an abuse of the sliding animation system, but it at least proves a point. "Slide"
|
||||
// means different things in different contexts, so it seems.
|
||||
auto travel_distance = active_workspace > key ? (-area.size.width.as_int()) : area.size.width.as_int();
|
||||
animator.workspace_move_to(animation_handle,
|
||||
travel_distance,
|
||||
[from = from, this](AnimationStepResult const& asr)
|
||||
{
|
||||
if (!from)
|
||||
return;
|
||||
|
||||
if (asr.is_complete)
|
||||
{
|
||||
from->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
from->for_each_window([&](std::shared_ptr<WindowMetadata> const& metadata)
|
||||
{
|
||||
if (metadata->get_is_pinned())
|
||||
return;
|
||||
|
||||
auto& window = metadata->get_window();
|
||||
AnimationStepResult for_window = asr;
|
||||
if (for_window.position)
|
||||
{
|
||||
for_window.transform = glm::translate(
|
||||
for_window.transform ? for_window.transform.value() : glm::mat4(1.f),
|
||||
glm::vec3(asr.position.value().x, asr.position.value().y, 0));
|
||||
for_window.position = std::nullopt;
|
||||
for_window.size = std::nullopt;
|
||||
}
|
||||
|
||||
node_interface.on_animation(for_window, metadata);
|
||||
});
|
||||
},
|
||||
[to=to,from=from, this](AnimationStepResult const& asr)
|
||||
{
|
||||
to->for_each_window([&](std::shared_ptr<WindowMetadata> const& metadata)
|
||||
{
|
||||
if (metadata->get_is_pinned())
|
||||
return;
|
||||
|
||||
auto& window = metadata->get_window();
|
||||
AnimationStepResult for_window = asr;
|
||||
if (for_window.position)
|
||||
{
|
||||
for_window.transform = glm::translate(
|
||||
for_window.transform ? for_window.transform.value() : glm::mat4(1.f),
|
||||
glm::vec3(asr.position.value().x, asr.position.value().y, 0));
|
||||
for_window.position = std::nullopt;
|
||||
for_window.size = std::nullopt;
|
||||
}
|
||||
|
||||
node_interface.on_animation(for_window, metadata);
|
||||
});
|
||||
});
|
||||
|
||||
to->show({});
|
||||
active_workspace = key;
|
||||
|
||||
// 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 (from != nullptr)
|
||||
{
|
||||
auto active_tree = from->get_tree();
|
||||
if (active_tree->is_empty() && from->get_floating_windows().empty())
|
||||
workspace_manager.delete_workspace(from->get_workspace());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void OutputContent::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef MIRACLE_SCREEN_H
|
||||
#define MIRACLE_SCREEN_H
|
||||
|
||||
#include "animator.h"
|
||||
#include "miral/window.h"
|
||||
#include "tiling_window_tree.h"
|
||||
#include "window_metadata.h"
|
||||
@ -31,6 +32,7 @@ namespace miracle
|
||||
class WorkspaceManager;
|
||||
class MiracleConfig;
|
||||
class WindowManagerToolsTilingInterface;
|
||||
class Animator;
|
||||
|
||||
class OutputContent
|
||||
{
|
||||
@ -42,7 +44,8 @@ public:
|
||||
miral::WindowManagerTools const& tools,
|
||||
miral::MinimalWindowManager& floating_window_manager,
|
||||
std::shared_ptr<MiracleConfig> const& options,
|
||||
TilingInterface&);
|
||||
TilingInterface&,
|
||||
Animator&);
|
||||
~OutputContent() = default;
|
||||
|
||||
[[nodiscard]] std::shared_ptr<TilingWindowTree> get_active_tree() const;
|
||||
@ -113,11 +116,13 @@ private:
|
||||
geom::Rectangle area;
|
||||
std::shared_ptr<MiracleConfig> config;
|
||||
TilingInterface& node_interface;
|
||||
Animator& animator;
|
||||
int active_workspace = -1;
|
||||
std::vector<std::shared_ptr<WorkspaceContent>> workspaces;
|
||||
std::vector<miral::Zone> application_zone_list;
|
||||
bool is_active_ = false;
|
||||
miral::Window active_window;
|
||||
AnimationHandle animation_handle;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ void Policy::advise_output_create(miral::Output const& output)
|
||||
{
|
||||
auto new_tree = std::make_shared<OutputContent>(
|
||||
output, workspace_manager, output.extents(), window_manager_tools,
|
||||
floating_window_manager, config, node_interface);
|
||||
floating_window_manager, config, node_interface, animator);
|
||||
workspace_manager.request_first_available_workspace(new_tree);
|
||||
output_list.push_back(new_tree);
|
||||
if (active_output == nullptr)
|
||||
|
@ -26,6 +26,7 @@ namespace miracle
|
||||
{
|
||||
class WindowMetadata;
|
||||
class TilingWindowTree;
|
||||
class AnimationStepResult;
|
||||
|
||||
class TilingInterface
|
||||
{
|
||||
@ -42,6 +43,7 @@ public:
|
||||
virtual void raise(miral::Window const&) = 0;
|
||||
virtual void send_to_back(miral::Window const&) = 0;
|
||||
virtual void open(miral::Window const&) = 0;
|
||||
virtual void on_animation(miracle::AnimationStepResult const& result, std::shared_ptr<WindowMetadata> const&) = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -46,21 +46,9 @@ void WindowManagerToolsTilingInterface::open(miral::Window const& window)
|
||||
|
||||
animator.window_open(
|
||||
metadata->get_animation_handle(),
|
||||
[this, window = window](miracle::AnimationStepResult const& result)
|
||||
[this, metadata=metadata](miracle::AnimationStepResult const& result)
|
||||
{
|
||||
if (!result.transform)
|
||||
return;
|
||||
|
||||
auto surface = window.operator std::shared_ptr<mir::scene::Surface>();
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
surface->set_transformation(result.transform.value());
|
||||
|
||||
if (result.is_complete)
|
||||
clip(window, { window.top_left(), window.size() });
|
||||
else
|
||||
noclip(window);
|
||||
on_animation(result, metadata);
|
||||
});
|
||||
}
|
||||
|
||||
@ -86,41 +74,7 @@ void WindowManagerToolsTilingInterface::set_rectangle(
|
||||
r,
|
||||
[this, metadata = metadata](miracle::AnimationStepResult const& result)
|
||||
{
|
||||
auto window = metadata->get_window();
|
||||
auto surface = window.operator std::shared_ptr<mir::scene::Surface>();
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
if (result.transform)
|
||||
surface->set_transformation(result.transform.value());
|
||||
|
||||
miral::WindowSpecification spec;
|
||||
auto top_left = result.position
|
||||
? mir::geometry::Point(
|
||||
result.position.value().x,
|
||||
result.position.value().y)
|
||||
: window.top_left();
|
||||
auto size = result.size
|
||||
? mir::geometry::Size(
|
||||
result.size.value().x,
|
||||
result.size.value().y)
|
||||
: window.size();
|
||||
|
||||
spec.top_left() = top_left;
|
||||
spec.size() = size;
|
||||
tools.modify_window(window, spec);
|
||||
|
||||
auto& window_info = tools.info_for(window);
|
||||
mir::geometry::Rectangle new_rectangle(top_left, size);
|
||||
clip(window, new_rectangle);
|
||||
|
||||
for (auto const& child : window_info.children())
|
||||
{
|
||||
miral::WindowSpecification sub_spec;
|
||||
sub_spec.top_left() = spec.top_left();
|
||||
sub_spec.size() = spec.size();
|
||||
tools.modify_window(child, sub_spec);
|
||||
}
|
||||
on_animation(result, metadata);
|
||||
});
|
||||
}
|
||||
|
||||
@ -187,3 +141,47 @@ void WindowManagerToolsTilingInterface::send_to_back(miral::Window const& window
|
||||
{
|
||||
tools.send_tree_to_back(window);
|
||||
}
|
||||
|
||||
void WindowManagerToolsTilingInterface::on_animation(
|
||||
miracle::AnimationStepResult const& result, std::shared_ptr<WindowMetadata> const& metadata)
|
||||
{
|
||||
auto window = metadata->get_window();
|
||||
auto surface = window.operator std::shared_ptr<mir::scene::Surface>();
|
||||
if (!surface)
|
||||
return;
|
||||
|
||||
if (result.transform)
|
||||
surface->set_transformation(result.transform.value());
|
||||
|
||||
miral::WindowSpecification spec;
|
||||
auto top_left = result.position
|
||||
? mir::geometry::Point(
|
||||
result.position.value().x,
|
||||
result.position.value().y)
|
||||
: window.top_left();
|
||||
auto size = result.size
|
||||
? mir::geometry::Size(
|
||||
result.size.value().x,
|
||||
result.size.value().y)
|
||||
: window.size();
|
||||
|
||||
spec.top_left() = top_left;
|
||||
spec.size() = size;
|
||||
tools.modify_window(window, spec);
|
||||
|
||||
auto& window_info = tools.info_for(window);
|
||||
mir::geometry::Rectangle new_rectangle(top_left, size);
|
||||
|
||||
if (result.is_complete)
|
||||
clip(window, new_rectangle);
|
||||
else
|
||||
noclip(window);
|
||||
|
||||
for (auto const& child : window_info.children())
|
||||
{
|
||||
miral::WindowSpecification sub_spec;
|
||||
sub_spec.top_left() = spec.top_left();
|
||||
sub_spec.size() = spec.size();
|
||||
tools.modify_window(child, sub_spec);
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ public:
|
||||
std::shared_ptr<WindowMetadata> get_metadata(miral::Window const&, TilingWindowTree const*) override;
|
||||
void raise(miral::Window const&) override;
|
||||
void send_to_back(miral::Window const&) override;
|
||||
void on_animation(miracle::AnimationStepResult const& result, std::shared_ptr<WindowMetadata> const&) override;
|
||||
|
||||
private:
|
||||
miral::WindowManagerTools tools;
|
||||
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#define MIR_LOG_COMPONENT "workspace_content"
|
||||
|
||||
#include "workspace_content.h"
|
||||
#include "leaf_node.h"
|
||||
#include "tiling_window_tree.h"
|
||||
#include "window_helpers.h"
|
||||
#include "window_metadata.h"
|
||||
@ -71,6 +72,26 @@ void WorkspaceContent::show(std::vector<std::shared_ptr<WindowMetadata>> const&
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceContent::for_each_window(std::function<void(std::shared_ptr<WindowMetadata>)> const& f)
|
||||
{
|
||||
for (auto const& window : floating_windows)
|
||||
{
|
||||
auto metadata = window_helpers::get_metadata(window, tools);
|
||||
if (metadata)
|
||||
f(metadata);
|
||||
}
|
||||
|
||||
tree->foreach_node([&](std::shared_ptr<Node> const& node)
|
||||
{
|
||||
if (auto leaf = Node::as_leaf(node))
|
||||
{
|
||||
auto metadata = window_helpers::get_metadata(leaf->get_window(), tools);
|
||||
if (metadata)
|
||||
f(metadata);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<WindowMetadata>> WorkspaceContent::hide()
|
||||
{
|
||||
tree->hide();
|
||||
|
@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#ifndef MIRACLEWM_WORKSPACE_CONTENT_H
|
||||
#define MIRACLEWM_WORKSPACE_CONTENT_H
|
||||
|
||||
#include <memory>
|
||||
#include <miral/minimal_window_manager.h>
|
||||
#include <miral/window_manager_tools.h>
|
||||
|
||||
@ -43,6 +44,7 @@ public:
|
||||
[[nodiscard]] std::shared_ptr<TilingWindowTree> get_tree() const;
|
||||
void show(std::vector<std::shared_ptr<WindowMetadata>> const&);
|
||||
std::vector<std::shared_ptr<WindowMetadata>> hide();
|
||||
void for_each_window(std::function<void(std::shared_ptr<WindowMetadata>)> const&);
|
||||
|
||||
bool has_floating_window(miral::Window const&);
|
||||
void add_floating_window(miral::Window const&);
|
||||
|
Loading…
Reference in New Issue
Block a user