mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-22 03:02:17 +03:00
feature: implementing the remainder of the focus IPC (#298)
This commit is contained in:
parent
514f39fbc2
commit
0297e0a424
@ -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
75
src/compositor_state.cpp
Normal 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;
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ enum class I3CommandType
|
||||
input
|
||||
};
|
||||
|
||||
// https://i3wm.org/docs/userguide.html#command_criteria
|
||||
enum class I3ScopeType
|
||||
{
|
||||
none,
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
280
src/policy.cpp
280
src/policy.cpp
@ -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;
|
||||
|
10
src/policy.h
10
src/policy.h
@ -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;
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user