feature: implementing the remainder of the focus IPC (#298)
Some checks failed
Build & Test / build (push) Has been cancelled
Snap Publish / Snap (amd64) (push) Has been cancelled
Snap Publish / Snap (arm64) (push) Has been cancelled
Snap Publish / Snap (armhf) (push) Has been cancelled

This commit is contained in:
Matthew Kosarek 2024-11-17 11:21:42 -05:00 committed by GitHub
parent 514f39fbc2
commit 0297e0a424
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 403 additions and 120 deletions

View File

@ -75,6 +75,7 @@ add_library(miracle-wm-implementation
src/minimal_window_manager.cpp src/minimal_window_manager.h
src/config_error_handler.cpp src/config_error_handler.h
src/scratchpad.h src/scratchpad.cpp
src/compositor_state.h src/compositor_state.cpp
)
add_executable(miracle-wm

75
src/compositor_state.cpp Normal file
View File

@ -0,0 +1,75 @@
/**
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 <http://www.gnu.org/licenses/>.
**/
#include "compositor_state.h"
using namespace miracle;
[[nodiscard]] std::shared_ptr<Container> CompositorState::active() const
{
if (!focused.expired())
return focused.lock();
return nullptr;
}
void CompositorState::focus(std::shared_ptr<Container> const& container)
{
auto it = std::find_if(focus_order.begin(), focus_order.end(), [&](auto const& element)
{
return !element.expired() && element.lock() == container;
});
if (it != focus_order.end())
{
std::rotate(focus_order.begin(), it, it + 1);
focused = container;
}
}
void CompositorState::unfocus(std::shared_ptr<Container> const& container)
{
if (!focused.expired())
{
if (focused.lock() == container)
focused.reset();
}
}
void CompositorState::add(std::shared_ptr<Container> const& container)
{
CompositorState::focus_order.push_back(container);
}
void CompositorState::remove(std::shared_ptr<Container> const& container)
{
focus_order.erase(std::remove_if(focus_order.begin(), focus_order.end(), [&](auto const& element)
{
return !element.expired() && element.lock() == container;
}));
}
std::shared_ptr<Container> CompositorState::get_first_with_type(ContainerType type) const
{
for (auto const& container : focus_order)
{
if (!container.expired() && container.lock()->get_type() == type)
return container.lock();
}
return nullptr;
}

View File

@ -18,12 +18,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef MIRACLE_WM_COMPOSITOR_STATE_H
#define MIRACLE_WM_COMPOSITOR_STATE_H
#include "container.h"
#include <algorithm>
#include <memory>
#include <mir/geometry/point.h>
#include <vector>
namespace miracle
{
class Container;
class Output;
enum class WindowManagerMode
@ -40,14 +43,26 @@ enum class WindowManagerMode
selecting
};
struct CompositorState
class CompositorState
{
public:
WindowManagerMode mode = WindowManagerMode::normal;
std::shared_ptr<Output> active_output;
std::shared_ptr<Container> active;
std::shared_ptr<Output> active_output = nullptr;
mir::geometry::Point cursor_position;
uint32_t modifiers = 0;
bool has_clicked_floating_window = false;
[[nodiscard]] std::shared_ptr<Container> active() const;
void focus(std::shared_ptr<Container> const& container);
void unfocus(std::shared_ptr<Container> const& container);
void add(std::shared_ptr<Container> const& container);
void remove(std::shared_ptr<Container> const& container);
[[nodiscard]] std::shared_ptr<Container> get_first_with_type(ContainerType type) const;
[[nodiscard]] std::vector<std::weak_ptr<Container>> const& containers() const { return focus_order; }
private:
std::weak_ptr<Container> focused;
std::vector<std::weak_ptr<Container>> focus_order;
};
}

View File

@ -282,7 +282,7 @@ void ContainerGroupContainer::animation_handle(uint32_t uint_32)
bool ContainerGroupContainer::is_focused() const
{
return state.active.get() == this;
return state.active().get() == this;
}
bool ContainerGroupContainer::is_fullscreen() const

View File

@ -274,7 +274,7 @@ void FloatingWindowContainer::animation_handle(uint32_t handle)
bool FloatingWindowContainer::is_focused() const
{
return state.active.get() == this;
return state.active().get() == this;
}
bool FloatingWindowContainer::is_fullscreen() const

View File

@ -15,6 +15,8 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
#define MIR_LOG_COMPONENT "miracle::i3_command"
#include "i3_command.h"
#include "jpcre2.h"
#include "string_extensions.h"
@ -22,9 +24,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "window_helpers.h"
#include <cstring>
#include <ranges>
#define MIR_LOG_COMPONENT "miracle::i3_command"
#include <mir/log.h>
#include <miral/application.h>
#include <miral/application_info.h>
#include <ranges>
using namespace miracle;
@ -171,7 +174,7 @@ bool I3ScopedCommandList::meets_criteria(miral::Window const& window, WindowCont
switch (criteria.type)
{
case I3ScopeType::all:
break;
return true;
case I3ScopeType::title:
{
auto& info = window_controller.info_for(window);
@ -179,6 +182,13 @@ bool I3ScopedCommandList::meets_criteria(miral::Window const& window, WindowCont
auto const& name = info.name();
return re.match(name);
}
case I3ScopeType::class_:
{
auto& info = window_controller.app_info(window);
jp::Regex re(criteria.regex.value());
auto const& name = miral::name_of(info.application());
return re.match(name);
}
default:
break;
}

View File

@ -55,6 +55,7 @@ enum class I3CommandType
input
};
// https://i3wm.org/docs/userguide.html#command_criteria
enum class I3ScopeType
{
none,

View File

@ -35,12 +35,12 @@ using namespace miracle;
I3CommandExecutor::I3CommandExecutor(
miracle::Policy& policy,
WorkspaceManager& workspace_manager,
miral::WindowManagerTools const& tools,
CompositorState const& state,
AutoRestartingLauncher& launcher,
WindowController& window_controller) :
policy { policy },
workspace_manager { workspace_manager },
tools { tools },
state { state },
launcher { launcher },
window_controller { window_controller }
{
@ -90,21 +90,20 @@ void I3CommandExecutor::process(miracle::I3ScopedCommandList const& command_list
miral::Window I3CommandExecutor::get_window_meeting_criteria(I3ScopedCommandList const& command_list)
{
miral::Window result;
tools.find_application([&](miral::ApplicationInfo const& info)
for (auto const& container : state.containers())
{
for (auto const& window : info.windows())
{
if (command_list.meets_criteria(window, window_controller))
{
result = window;
return true;
}
}
if (container.expired())
continue;
return false;
});
return result;
auto window = container.lock()->window();
if (auto const& w = window.value())
{
if (command_list.meets_criteria(w, window_controller))
return window.value();
}
}
return miral::Window {};
}
void I3CommandExecutor::process_exec(miracle::I3Command const& command, miracle::I3ScopedCommandList const& command_list)
@ -203,16 +202,12 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL
else if (arg == "down")
policy.try_select(Direction::down);
else if (arg == "parent")
mir::log_warning("'focus parent' is not supported, see https://github.com/mattkae/miracle-wm/issues/117"); // TODO
policy.try_select_parent();
else if (arg == "child")
mir::log_warning("'focus child' is not supported, see https://github.com/mattkae/miracle-wm/issues/117"); // TODO
else if (arg == "prev")
{
auto active_window = tools.active_window();
if (!active_window)
return;
auto container = window_controller.get_container(active_window);
auto container = state.active();
if (!container)
return;
@ -234,11 +229,7 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL
}
else if (arg == "next")
{
auto active_window = tools.active_window();
if (!active_window)
return;
auto container = window_controller.get_container(active_window);
auto container = state.active();
if (!container)
return;
@ -259,13 +250,38 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL
}
}
else if (arg == "floating")
mir::log_warning("'focus floating' is not supported, see https://github.com/mattkae/miracle-wm/issues/117"); // TODO
policy.try_select_floating();
else if (arg == "tiling")
mir::log_warning("'focus tiling' is not supported, see https://github.com/mattkae/miracle-wm/issues/117"); // TODO
policy.try_select_tiling();
else if (arg == "mode_toggle")
mir::log_warning("'focus mode_toggle' is not supported, see https://github.com/mattkae/miracle-wm/issues/117"); // TODO
policy.try_select_toggle();
else if (arg == "output")
mir::log_warning("'focus output' is not supported, see https://github.com/canonical/mir/issues/3357"); // TODO
{
if (command.arguments.size() < 2)
{
mir::log_error("process_focus: 'focus output' must have more than two arguments");
return;
}
auto const& arg1 = command.arguments[1];
if (arg1 == "next")
policy.try_select_next_output();
else if (arg1 == "prev")
policy.try_select_prev_output();
else if (arg1 == "left")
policy.try_select_output(Direction::left);
else if (arg1 == "right")
policy.try_select_output(Direction::right);
else if (arg1 == "up")
policy.try_select_output(Direction::up);
else if (arg1 == "down")
policy.try_select_output(Direction::down);
else
{
auto names = std::vector<std::string>(command.arguments.begin() + 1, command.arguments.end());
policy.try_select_output(names);
}
}
}
namespace
@ -350,7 +366,7 @@ void I3CommandExecutor::process_move(I3Command const& command, I3ScopedCommandLi
auto const& arg1 = command.arguments[index++];
if (arg1 == "center")
{
auto active = policy.get_state().active.get();
auto active = policy.get_state().active().get();
auto area = active_output->get_area();
float x = (float)area.size.width.as_int() / 2.f - (float)active->get_visible_area().size.width.as_int() / 2.f;
float y = (float)area.size.height.as_int() / 2.f - (float)active->get_visible_area().size.height.as_int() / 2.f;
@ -410,7 +426,7 @@ void I3CommandExecutor::process_move(I3Command const& command, I3ScopedCommandLi
y = end_y;
}
auto active = policy.get_state().active;
auto active = policy.get_state().active();
float x_pos = x / 2.f - (float)active->get_visible_area().size.width.as_int() / 2.f;
float y_pos = y / 2.f - (float)active->get_visible_area().size.height.as_int() / 2.f;
policy.try_move_to((int)x_pos, (int)y_pos);
@ -653,7 +669,7 @@ void I3CommandExecutor::process_layout(I3Command const& command, I3ScopedCommand
}
else
{
auto const& container = policy.get_state().active;
auto container = policy.get_state().active();
if (!container)
{
mir::log_error("process_layout: container unavailable");

View File

@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef MIRACLEWM_I_3_COMMAND_EXECUTOR_H
#define MIRACLEWM_I_3_COMMAND_EXECUTOR_H
#include "compositor_state.h"
#include "i3_command.h"
#include <mir/glib_main_loop.h>
@ -37,7 +38,7 @@ public:
I3CommandExecutor(
Policy&,
WorkspaceManager&,
miral::WindowManagerTools const&,
CompositorState const&,
AutoRestartingLauncher&,
WindowController&);
void process(I3ScopedCommandList const&);
@ -45,7 +46,7 @@ public:
private:
Policy& policy;
WorkspaceManager& workspace_manager;
miral::WindowManagerTools tools;
CompositorState const& state;
AutoRestartingLauncher& launcher;
WindowController& window_controller;

View File

@ -323,10 +323,10 @@ void LeafContainer::animation_handle(uint32_t handle)
bool LeafContainer::is_focused() const
{
if (state.active.get() == this || parent.lock()->is_focused())
if (state.active().get() == this || parent.lock()->is_focused())
return true;
auto group = Container::as_group(state.active);
auto group = Container::as_group(state.active());
if (!group)
return false;

View File

@ -640,7 +640,7 @@ void ParentContainer::on_focus_gained()
{
for (auto const& container : sub_nodes)
{
if (container != state.active && container->window())
if (container != state.active() && container->window())
node_interface.send_to_back(container->window().value());
}
}

View File

@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "container_group_container.h"
#include "feature_flags.h"
#include "floating_tree_container.h"
#include "parent_container.h"
#include "shell_component_container.h"
#include "window_helpers.h"
#include "window_tools_accessor.h"
@ -70,7 +71,7 @@ Policy::Policy(
{ return get_output_list(); }) },
animator(server.the_main_loop(), config),
window_controller(tools, animator, state),
i3_command_executor(*this, workspace_manager, tools, external_client_launcher, window_controller),
i3_command_executor(*this, workspace_manager, compositor_state, external_client_launcher, window_controller),
surface_tracker { surface_tracker },
ipc { std::make_shared<Ipc>(runner, workspace_manager, *this, server.the_main_loop(), i3_command_executor, config) },
scratchpad_(window_controller, state)
@ -244,7 +245,7 @@ bool Policy::handle_pointer_event(MirPointerEvent const* event)
{
state.mode = WindowManagerMode::selecting;
group_selection = std::make_shared<ContainerGroupContainer>(state);
state.active = group_selection;
state.add(group_selection);
mode_observer_registrar.advise_changed(state.mode);
}
}
@ -268,14 +269,12 @@ bool Policy::handle_pointer_event(MirPointerEvent const* event)
{
if (auto window = intersected->window().value())
{
if (state.active != intersected)
{
if (state.active() != intersected)
window_controller.select_active_window(window);
}
}
}
if (state.has_clicked_floating_window || (state.active && state.active->get_type() == ContainerType::floating_window))
if (state.has_clicked_floating_window || (state.active() && state.active()->get_type() == ContainerType::floating_window))
{
if (action == mir_pointer_action_button_down)
state.has_clicked_floating_window = true;
@ -311,15 +310,13 @@ auto Policy::place_new_window(
}
auto new_spec = requested_specification;
pending_output = state.active_output;
pending_allocation = state.active_output->allocate_position(app_info, new_spec, {});
return new_spec;
}
void Policy::advise_new_window(miral::WindowInfo const& window_info)
{
auto shared_output = pending_output.lock();
if (!shared_output)
if (!state.active_output)
{
mir::log_warning("create_container: output unavailable");
auto window = window_info.window();
@ -340,14 +337,12 @@ void Policy::advise_new_window(miral::WindowInfo const& window_info)
return;
}
auto container = shared_output->create_container(window_info, pending_allocation);
auto container = state.active_output->create_container(window_info, pending_allocation);
container->animation_handle(animator.register_animateable());
container->on_open();
state.add(container);
pending_allocation.container_type = ContainerType::none;
pending_output.reset();
surface_tracker.add(window_info.window());
}
@ -400,7 +395,7 @@ void Policy::advise_focus_gained(const miral::WindowInfo& window_info)
if (workspace && workspace != state.active_output->active())
return;
state.active = container;
state.focus(container);
container->on_focus_gained();
break;
}
@ -416,8 +411,7 @@ void Policy::advise_focus_lost(const miral::WindowInfo& window_info)
return;
}
if (container == state.active)
state.active = nullptr;
state.unfocus(container);
container->on_focus_lost();
}
@ -446,9 +440,7 @@ void Policy::advise_delete_window(const miral::WindowInfo& window_info)
scratchpad_.remove(container);
surface_tracker.remove(window_info.window());
if (state.active == container)
state.active = nullptr;
state.unfocus(container);
}
void Policy::advise_move_to(miral::WindowInfo const& window_info, geom::Point top_left)
@ -662,13 +654,13 @@ void Policy::advise_end()
void Policy::try_toggle_resize_mode()
{
if (!state.active)
if (!state.active())
{
state.mode = WindowManagerMode::normal;
return;
}
if (state.active->get_type() != ContainerType::leaf)
if (state.active()->get_type() != ContainerType::leaf)
{
state.mode = WindowManagerMode::normal;
return;
@ -687,10 +679,10 @@ bool Policy::try_request_vertical()
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
state.active->request_vertical_layout();
state.active()->request_vertical_layout();
return true;
}
@ -699,10 +691,10 @@ bool Policy::try_toggle_layout(bool cycle_thru_all)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
state.active->toggle_layout(cycle_thru_all);
state.active()->toggle_layout(cycle_thru_all);
return true;
}
@ -711,10 +703,10 @@ bool Policy::try_request_horizontal()
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
state.active->request_horizontal_layout();
state.active()->request_horizontal_layout();
return true;
}
@ -723,10 +715,10 @@ bool Policy::try_resize(miracle::Direction direction)
if (state.mode != WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->resize(direction);
return state.active()->resize(direction);
}
bool Policy::try_move(miracle::Direction direction)
@ -734,10 +726,10 @@ bool Policy::try_move(miracle::Direction direction)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->move(direction);
return state.active()->move(direction);
}
bool Policy::try_move_by(miracle::Direction direction, int pixels)
@ -745,10 +737,10 @@ bool Policy::try_move_by(miracle::Direction direction, int pixels)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->move_by(direction, pixels);
return state.active()->move_by(direction, pixels);
}
bool Policy::try_move_to(int x, int y)
@ -756,10 +748,10 @@ bool Policy::try_move_to(int x, int y)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->move_to(x, y);
return state.active()->move_to(x, y);
}
bool Policy::try_select(miracle::Direction direction)
@ -767,18 +759,88 @@ bool Policy::try_select(miracle::Direction direction)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->select_next(direction);
return state.active()->select_next(direction);
}
bool Policy::try_select_parent()
{
if (state.mode != WindowManagerMode::normal)
return false;
if (!state.active())
return false;
if (!state.active()->get_parent().expired())
{
state.focus(state.active()->get_parent().lock());
return true;
}
else
{
mir::log_error("try_select_parent: no parent to select");
return false;
}
}
bool Policy::try_select_floating()
{
if (state.mode != WindowManagerMode::normal)
return false;
if (auto to_select = state.get_first_with_type(ContainerType::floating_window))
{
if (auto const& window = to_select->window())
{
window_controller.select_active_window(window.value());
return true;
}
}
return false;
}
bool Policy::try_select_tiling()
{
if (state.mode != WindowManagerMode::normal)
return false;
if (auto to_select = state.get_first_with_type(ContainerType::leaf))
{
if (auto const& window = to_select->window())
{
window_controller.select_active_window(window.value());
return true;
}
}
return false;
}
bool Policy::try_select_toggle()
{
if (state.mode != WindowManagerMode::normal)
return false;
if (auto const active = state.active())
{
if (active->get_type() == ContainerType::leaf)
return try_select_floating();
else if (active->get_type() == ContainerType::floating_window)
return try_select_tiling();
}
return false;
}
bool Policy::try_close_window()
{
if (!state.active)
if (!state.active())
return false;
auto window = state.active->window();
auto window = state.active()->window();
if (!window)
return false;
@ -798,10 +860,10 @@ bool Policy::try_toggle_fullscreen()
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->toggle_fullscreen();
return state.active()->toggle_fullscreen();
}
bool Policy::select_workspace(int number, bool back_and_forth)
@ -873,9 +935,9 @@ bool Policy::move_active_to_workspace(int number, bool back_and_forth)
if (!can_move_container())
return false;
auto container = state.active;
auto container = state.active();
container->get_output()->delete_container(container);
state.active = nullptr;
state.unfocus(container);
if (workspace_manager.request_workspace(
state.active_output.get(), number, back_and_forth))
@ -892,9 +954,9 @@ bool Policy::move_active_to_workspace_named(std::string const& name, bool back_a
if (!can_move_container())
return false;
auto container = state.active;
auto container = state.active();
container->get_output()->delete_container(container);
state.active = nullptr;
state.unfocus(nullptr);
if (workspace_manager.request_workspace(state.active_output.get(), name, back_and_forth))
{
@ -910,9 +972,9 @@ bool Policy::move_active_to_next()
if (!can_move_container())
return false;
auto container = state.active;
auto container = state.active();
container->get_output()->delete_container(container);
state.active = nullptr;
state.unfocus(container);
if (workspace_manager.request_next(state.active_output))
{
@ -928,9 +990,9 @@ bool Policy::move_active_to_prev()
if (!can_move_container())
return false;
auto container = state.active;
auto container = state.active();
container->get_output()->delete_container(container);
state.active = nullptr;
state.unfocus(container);
if (workspace_manager.request_prev(state.active_output))
{
@ -946,9 +1008,9 @@ bool Policy::move_active_to_back_and_forth()
if (!can_move_container())
return false;
auto container = state.active;
auto container = state.active();
container->get_output()->delete_container(container);
state.active = nullptr;
state.unfocus(container);
if (workspace_manager.request_back_and_forth())
{
@ -965,7 +1027,7 @@ bool Policy::move_to_scratchpad()
return false;
// Only floating or tiled windows can be moved to the scratchpad
auto container = state.active;
auto container = state.active();
if (container->get_type() != ContainerType::floating_window
&& container->get_type() != ContainerType::leaf)
{
@ -1000,10 +1062,10 @@ bool Policy::can_move_container() const
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
if (state.active->is_fullscreen())
if (state.active()->is_fullscreen())
return false;
return true;
@ -1018,7 +1080,8 @@ std::shared_ptr<Container> Policy::toggle_floating_internal(std::shared_ptr<Cont
auto& info = window_controller.info_for(window);
auto new_container = state.active_output->create_container(info, result);
new_container->handle_ready();
window_controller.select_active_window(state.active->window().value());
state.add(new_container);
window_controller.select_active_window(state.active()->window().value());
return new_container;
};
@ -1041,6 +1104,8 @@ std::shared_ptr<Container> Policy::toggle_floating_internal(std::shared_ptr<Cont
auto result = state.active_output->allocate_position(window_manager_tools.info_for(window->application()), spec, { ContainerType::floating_window });
window_controller.modify(*window, spec);
state.remove(container);
// Finally, declare it ready
return handle_ready(*window, result);
}
@ -1062,6 +1127,8 @@ std::shared_ptr<Container> Policy::toggle_floating_internal(std::shared_ptr<Cont
auto result = state.active_output->allocate_position(window_manager_tools.info_for(window->application()), spec, { ContainerType::leaf });
window_controller.modify(*window, spec);
state.remove(container);
// Finally, declare it ready
return handle_ready(*window, result);
}
@ -1076,10 +1143,10 @@ bool Policy::toggle_floating()
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
toggle_floating_internal(state.active);
toggle_floating_internal(state.active());
return true;
}
@ -1088,10 +1155,10 @@ bool Policy::toggle_pinned_to_workspace()
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->pinned(!state.active->pinned());
return state.active()->pinned(!state.active()->pinned());
}
bool Policy::set_is_pinned(bool pinned)
@ -1099,10 +1166,10 @@ bool Policy::set_is_pinned(bool pinned)
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return state.active->pinned(pinned);
return state.active()->pinned(pinned);
}
bool Policy::toggle_tabbing()
@ -1110,7 +1177,7 @@ bool Policy::toggle_tabbing()
if (!can_set_layout())
return false;
return state.active->toggle_tabbing();
return state.active()->toggle_tabbing();
}
bool Policy::toggle_stacking()
@ -1118,7 +1185,7 @@ bool Policy::toggle_stacking()
if (!can_set_layout())
return false;
return state.active->toggle_stacking();
return state.active()->toggle_stacking();
}
bool Policy::set_layout(LayoutScheme scheme)
@ -1126,7 +1193,7 @@ bool Policy::set_layout(LayoutScheme scheme)
if (!can_set_layout())
return false;
return state.active->set_layout(scheme);
return state.active()->set_layout(scheme);
}
bool Policy::set_layout_default()
@ -1134,15 +1201,94 @@ bool Policy::set_layout_default()
if (!can_set_layout())
return false;
return state.active->set_layout(config->get_default_layout_scheme());
};
return state.active()->set_layout(config->get_default_layout_scheme());
}
void Policy::move_cursor_to_output(std::shared_ptr<Output> const& output)
{
auto const& extents = output->get_output().extents();
window_manager_tools.move_cursor_to({ extents.top_left.x.as_int() + extents.size.width.as_int() / 2.f,
extents.top_left.y.as_int() + extents.size.height.as_int() / 2.f });
}
bool Policy::try_select_next_output()
{
for (size_t i = 0; i < output_list.size(); i++)
{
if (output_list[i] == state.active_output)
{
size_t j = i + 1;
if (j == output_list.size())
j = 0;
move_cursor_to_output(output_list[j]);
return true;
}
}
return false;
}
bool Policy::try_select_prev_output()
{
for (int i = output_list.size() - 1; i >= 0; i++)
{
if (output_list[i] == state.active_output)
{
size_t j = i - 1;
if (j < 0)
j = output_list.size() - 1;
move_cursor_to_output(output_list[j]);
return true;
}
}
return false;
}
bool Policy::try_select_output(Direction direction)
{
return false;
}
bool Policy::try_select_output(std::vector<std::string> const& names)
{
if (!state.active_output)
return false;
auto current_name = state.active_output->get_output().name();
size_t next = 0;
for (size_t i = 0; i < names.size(); i++)
{
if (names[i] == current_name)
{
next = i + 1;
break;
}
}
if (next == names.size())
next = 0;
for (auto const& output : output_list)
{
if (output->get_output().name() == names[next])
{
move_cursor_to_output(output);
return true;
}
}
return false;
}
bool Policy::can_set_layout() const
{
if (state.mode == WindowManagerMode::resizing)
return false;
if (!state.active)
if (!state.active())
return false;
return true;

View File

@ -110,6 +110,10 @@ public:
bool try_move_by(Direction direction, int pixels);
bool try_move_to(int x, int y);
bool try_select(Direction direction);
bool try_select_parent();
bool try_select_floating();
bool try_select_tiling();
bool try_select_toggle();
bool try_close_window();
bool quit();
bool try_toggle_fullscreen();
@ -134,6 +138,11 @@ public:
bool toggle_stacking();
bool set_layout(LayoutScheme scheme);
bool set_layout_default();
void move_cursor_to_output(std::shared_ptr<Output> const&);
bool try_select_next_output();
bool try_select_prev_output();
bool try_select_output(Direction direction);
bool try_select_output(std::vector<std::string> const& names);
// Getters
@ -150,7 +159,6 @@ private:
bool is_starting_ = true;
CompositorState& state;
std::vector<std::shared_ptr<Output>> output_list;
std::weak_ptr<Output> pending_output;
AllocationHint pending_allocation;
std::vector<miral::Window> orphaned_window_list;
miral::WindowManagerTools window_manager_tools;

View File

@ -790,5 +790,5 @@ Workspace* TilingWindowTree::get_workspace() const
std::shared_ptr<LeafContainer> TilingWindowTree::active_container() const
{
return Container::as_leaf(state.active);
return Container::as_leaf(state.active());
}

View File

@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef MIRACLEWM_TILING_INTERFACE_H
#define MIRACLEWM_TILING_INTERFACE_H
#include <miral/application_info.h>
#include <miral/window.h>
#include <miral/window_info.h>
@ -52,6 +53,7 @@ public:
virtual void set_user_data(miral::Window const&, std::shared_ptr<void> const&) = 0;
virtual void modify(miral::Window const&, miral::WindowSpecification const&) = 0;
virtual miral::WindowInfo& info_for(miral::Window const&) = 0;
virtual miral::ApplicationInfo& app_info(miral::Window const&) = 0;
};
}

View File

@ -236,6 +236,11 @@ miral::WindowInfo& WindowManagerToolsWindowController::info_for(miral::Window co
return tools.info_for(window);
}
miral::ApplicationInfo& WindowManagerToolsWindowController::app_info(miral::Window const& window)
{
return tools.info_for(window.application());
}
void WindowManagerToolsWindowController::close(miral::Window const& window)
{
tools.ask_client_to_close(window);

View File

@ -48,6 +48,7 @@ public:
void set_user_data(miral::Window const&, std::shared_ptr<void> const&) override;
void modify(miral::Window const&, miral::WindowSpecification const&) override;
miral::WindowInfo& info_for(miral::Window const&) override;
miral::ApplicationInfo& app_info(miral::Window const&) override;
void close(miral::Window const& window) override;
private:

View File

@ -178,7 +178,7 @@ void Workspace::handle_ready_hack(LeafContainer& container)
window_controller.raise(window->window().value());
if (tree->has_fullscreen_window())
window_controller.raise(state.active->window().value());
window_controller.raise(state.active()->window().value());
}
void Workspace::delete_container(std::shared_ptr<Container> const& container)
@ -347,10 +347,10 @@ void Workspace::graft(std::shared_ptr<Container> const& container)
std::shared_ptr<ParentContainer> Workspace::get_layout_container()
{
if (!state.active)
if (!state.active())
return nullptr;
auto parent = state.active->get_parent().lock();
auto parent = state.active()->get_parent().lock();
if (!parent)
return nullptr;

View File

@ -91,6 +91,7 @@ public:
void set_user_data(miral::Window const&, std::shared_ptr<void> const&) override { }
void modify(miral::Window const&, miral::WindowSpecification const&) override { }
miral::WindowInfo& info_for(miral::Window const&) override { }
miral::ApplicationInfo& app_info(miral::Window const&) override { }
private:
std::vector<std::pair<miral::Window, std::shared_ptr<Container>>>& pairs;
@ -125,8 +126,9 @@ public:
auto leaf = tree.confirm_window(info, nullptr);
pairs.push_back({ window, leaf });
state.active = leaf;
state.add(leaf);
tree.advise_focus_gained(*leaf);
state.focus(leaf);
return leaf;
}