mirror of
https://github.com/miracle-wm-org/miracle-wm.git
synced 2024-11-23 04:08:27 +03:00
feature: rudimentary workspace foundation (#18)
* workspace data structure in place * feature: rudimentary workspace support, but I expect some bugs * bugfix: unfocusable nodes
This commit is contained in:
parent
b8ebe4ab8c
commit
b9405e62d9
@ -29,6 +29,8 @@ add_executable(miracle-wm
|
||||
src/window_helpers.cpp
|
||||
src/miracle_config.cpp
|
||||
src/miracle_config.h
|
||||
src/screen.cpp
|
||||
src/workspace_manager.cpp
|
||||
)
|
||||
|
||||
target_include_directories(miracle-wm PUBLIC SYSTEM ${MIRAL_INCLUDE_DIRS})
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <miral/keymap.h>
|
||||
#include <miral/x11_support.h>
|
||||
#include <miral/wayland_extensions.h>
|
||||
#include <miral/command_line_option.h>
|
||||
#include <miral/display_configuration_option.h>
|
||||
#include <miral/add_init_callback.h>
|
||||
#include "miracle_window_management_policy.h"
|
||||
|
@ -101,6 +101,26 @@ MiracleConfig::MiracleConfig()
|
||||
key_command = DefaultKeyCommand::QuitCompositor;
|
||||
else if (name == "fullscreen")
|
||||
key_command = DefaultKeyCommand::Fullscreen;
|
||||
else if (name == "select_workspace_1")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace1;
|
||||
else if (name == "select_workspace_2")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace2;
|
||||
else if (name == "select_workspace_3")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace3;
|
||||
else if (name == "select_workspace_4")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace4;
|
||||
else if (name == "select_workspace_5")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace5;
|
||||
else if (name == "select_workspace_6")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace6;
|
||||
else if (name == "select_workspace_7")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace7;
|
||||
else if (name == "select_workspace_8")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace8;
|
||||
else if (name == "select_workspace_9")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace9;
|
||||
else if (name == "select_workspace_0")
|
||||
key_command = DefaultKeyCommand::SelectWorkspace0;
|
||||
else {
|
||||
mir::log_error("default_action_overrides: Unknown key command override: %s", name.c_str());
|
||||
continue;
|
||||
@ -229,6 +249,56 @@ MiracleConfig::MiracleConfig()
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_F
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_1
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_2
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_3
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_4
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_5
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_6
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_7
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_8
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_9
|
||||
},
|
||||
{
|
||||
MirKeyboardAction ::mir_keyboard_action_down,
|
||||
miracle_input_event_modifier_default,
|
||||
KEY_0
|
||||
}
|
||||
};
|
||||
for (int i = 0; i < DefaultKeyCommand::MAX; i++)
|
||||
|
@ -26,6 +26,16 @@ enum DefaultKeyCommand
|
||||
QuitActiveWindow,
|
||||
QuitCompositor,
|
||||
Fullscreen,
|
||||
SelectWorkspace1,
|
||||
SelectWorkspace2,
|
||||
SelectWorkspace3,
|
||||
SelectWorkspace4,
|
||||
SelectWorkspace5,
|
||||
SelectWorkspace6,
|
||||
SelectWorkspace7,
|
||||
SelectWorkspace8,
|
||||
SelectWorkspace9,
|
||||
SelectWorkspace0,
|
||||
MAX
|
||||
};
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "miracle_window_management_policy.h"
|
||||
#include "window_helpers.h"
|
||||
#include "miracle_config.h"
|
||||
#include "workspace_manager.h"
|
||||
|
||||
#include <mir_toolkit/events/enums.h>
|
||||
#include <miral/toolkit_event.h>
|
||||
@ -80,7 +81,8 @@ MiracleWindowManagementPolicy::MiracleWindowManagementPolicy(
|
||||
external_client_launcher{external_client_launcher},
|
||||
internal_client_launcher{internal_client_launcher},
|
||||
runner{runner},
|
||||
config{config}
|
||||
config{config},
|
||||
workspace_manager{WorkspaceManager(tools)}
|
||||
{
|
||||
}
|
||||
|
||||
@ -104,59 +106,89 @@ bool MiracleWindowManagementPolicy::handle_keyboard_event(MirKeyboardEvent const
|
||||
}
|
||||
return true;
|
||||
case RequestVertical:
|
||||
active_tree->tree.request_vertical();
|
||||
active_output->screen->get_active_tree().request_vertical();
|
||||
return true;
|
||||
case RequestHorizontal:
|
||||
active_tree->tree.request_horizontal();
|
||||
active_output->screen->get_active_tree().request_horizontal();
|
||||
return true;
|
||||
case ToggleResize:
|
||||
active_tree->tree.toggle_resize_mode();
|
||||
active_output->screen->get_active_tree().toggle_resize_mode();
|
||||
return true;
|
||||
case MoveUp:
|
||||
if (active_tree->tree.try_move_active_window(Direction::up))
|
||||
if (active_output->screen->get_active_tree().try_move_active_window(Direction::up))
|
||||
return true;
|
||||
return false;
|
||||
case MoveDown:
|
||||
if (active_tree->tree.try_move_active_window(Direction::down))
|
||||
if (active_output->screen->get_active_tree().try_move_active_window(Direction::down))
|
||||
return true;
|
||||
return false;
|
||||
case MoveLeft:
|
||||
if (active_tree->tree.try_move_active_window(Direction::left))
|
||||
if (active_output->screen->get_active_tree().try_move_active_window(Direction::left))
|
||||
return true;
|
||||
return false;
|
||||
case MoveRight:
|
||||
if (active_tree->tree.try_move_active_window(Direction::right))
|
||||
if (active_output->screen->get_active_tree().try_move_active_window(Direction::right))
|
||||
return true;
|
||||
return false;
|
||||
case SelectUp:
|
||||
if (active_tree->tree.try_resize_active_window(Direction::up)
|
||||
|| active_tree->tree.try_select_next(Direction::up))
|
||||
if (active_output->screen->get_active_tree().try_resize_active_window(Direction::up)
|
||||
|| active_output->screen->get_active_tree().try_select_next(Direction::up))
|
||||
return true;
|
||||
return false;
|
||||
case SelectDown:
|
||||
if (active_tree->tree.try_resize_active_window(Direction::down)
|
||||
|| active_tree->tree.try_select_next(Direction::down))
|
||||
if (active_output->screen->get_active_tree().try_resize_active_window(Direction::down)
|
||||
|| active_output->screen->get_active_tree().try_select_next(Direction::down))
|
||||
return true;
|
||||
return false;
|
||||
case SelectLeft:
|
||||
if (active_tree->tree.try_resize_active_window(Direction::left)
|
||||
|| active_tree->tree.try_select_next(Direction::left))
|
||||
if (active_output->screen->get_active_tree().try_resize_active_window(Direction::left)
|
||||
|| active_output->screen->get_active_tree().try_select_next(Direction::left))
|
||||
return true;
|
||||
return false;
|
||||
case SelectRight:
|
||||
if (active_tree->tree.try_resize_active_window(Direction::right)
|
||||
|| active_tree->tree.try_select_next(Direction::right))
|
||||
if (active_output->screen->get_active_tree().try_resize_active_window(Direction::right)
|
||||
|| active_output->screen->get_active_tree().try_select_next(Direction::right))
|
||||
return true;
|
||||
return false;
|
||||
case QuitActiveWindow:
|
||||
active_tree->tree.close_active_window();
|
||||
active_output->screen->get_active_tree().close_active_window();
|
||||
return true;
|
||||
case QuitCompositor:
|
||||
runner.stop();
|
||||
return true;
|
||||
case Fullscreen:
|
||||
active_tree->tree.try_toggle_active_fullscreen();
|
||||
active_output->screen->get_active_tree().try_toggle_active_fullscreen();
|
||||
return true;
|
||||
case SelectWorkspace1:
|
||||
workspace_manager.request_workspace(active_output->screen, '1');
|
||||
break;
|
||||
case SelectWorkspace2:
|
||||
workspace_manager.request_workspace(active_output->screen, '2');
|
||||
break;
|
||||
case SelectWorkspace3:
|
||||
workspace_manager.request_workspace(active_output->screen, '3');
|
||||
break;
|
||||
case SelectWorkspace4:
|
||||
workspace_manager.request_workspace(active_output->screen, '4');
|
||||
break;
|
||||
case SelectWorkspace5:
|
||||
workspace_manager.request_workspace(active_output->screen, '5');
|
||||
break;
|
||||
case SelectWorkspace6:
|
||||
workspace_manager.request_workspace(active_output->screen, '6');
|
||||
break;
|
||||
case SelectWorkspace7:
|
||||
workspace_manager.request_workspace(active_output->screen, '7');
|
||||
break;
|
||||
case SelectWorkspace8:
|
||||
workspace_manager.request_workspace(active_output->screen, '8');
|
||||
break;
|
||||
case SelectWorkspace9:
|
||||
workspace_manager.request_workspace(active_output->screen, '9');
|
||||
break;
|
||||
case SelectWorkspace0:
|
||||
workspace_manager.request_workspace(active_output->screen, '0');
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Unknown key_command: " << key_command << std::endl;
|
||||
break;
|
||||
@ -169,12 +201,12 @@ bool MiracleWindowManagementPolicy::handle_pointer_event(MirPointerEvent const*
|
||||
auto x = miral::toolkit::mir_pointer_event_axis_value(event, MirPointerAxis::mir_pointer_axis_x);
|
||||
auto y = miral::toolkit::mir_pointer_event_axis_value(event, MirPointerAxis::mir_pointer_axis_y);
|
||||
|
||||
for (auto const& pair : tree_list)
|
||||
for (auto const& pair : output_list)
|
||||
{
|
||||
if (pair->tree.point_is_in_output(static_cast<int>(x), static_cast<int>(y)))
|
||||
if (active_output->screen->get_active_tree().point_is_in_output(static_cast<int>(x), static_cast<int>(y)))
|
||||
{
|
||||
active_tree = pair;
|
||||
active_tree->tree.select_window_from_point(static_cast<int>(x), static_cast<int>(y));
|
||||
active_output = pair;
|
||||
active_output->screen->get_active_tree().select_window_from_point(static_cast<int>(x), static_cast<int>(y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -190,7 +222,7 @@ auto MiracleWindowManagementPolicy::place_new_window(
|
||||
{
|
||||
// In this step, we'll ask the WindowTree where we should place the window on the display
|
||||
// We will also resize the adjacent windows accordingly in this step.
|
||||
return active_tree->tree.allocate_position(requested_specification);
|
||||
return active_output->screen->get_active_tree().allocate_position(requested_specification);
|
||||
}
|
||||
|
||||
return requested_specification;
|
||||
@ -200,7 +232,7 @@ void MiracleWindowManagementPolicy::advise_new_window(miral::WindowInfo const& w
|
||||
{
|
||||
miral::WindowManagementPolicy::advise_new_window(window_info);
|
||||
if (is_tileable(window_info))
|
||||
active_tree->tree.advise_new_window(window_info);
|
||||
active_output->screen->get_active_tree().advise_new_window(window_info);
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::handle_window_ready(miral::WindowInfo &window_info)
|
||||
@ -210,30 +242,30 @@ void MiracleWindowManagementPolicy::handle_window_ready(miral::WindowInfo &windo
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto const& tree : tree_list)
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
if (tree->tree.handle_window_ready(window_info))
|
||||
if (output->screen->get_active_tree().handle_window_ready(window_info))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_focus_gained(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_focus_gained(window_info.window());
|
||||
for (auto const& output : output_list)
|
||||
output->screen->get_active_tree().advise_focus_gained(window_info.window());
|
||||
window_manager_tools.raise_tree(window_info.window());
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_focus_lost(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_focus_lost(window_info.window());
|
||||
for (auto const& output : output_list)
|
||||
output->screen->get_active_tree().advise_focus_lost(window_info.window());
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_delete_window(const miral::WindowInfo &window_info)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_delete_window(window_info.window());
|
||||
for (auto const& output : output_list)
|
||||
output->screen->get_active_tree().advise_delete_window(window_info.window());
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_move_to(miral::WindowInfo const& window_info, geom::Point top_left)
|
||||
@ -244,21 +276,25 @@ void MiracleWindowManagementPolicy::advise_move_to(miral::WindowInfo const& wind
|
||||
void MiracleWindowManagementPolicy::advise_output_create(miral::Output const& output)
|
||||
{
|
||||
WindowTreeOptions options = { config.get_gap_size_x(), config.get_gap_size_y() };
|
||||
auto new_tree = std::make_shared<OutputTreePair>(
|
||||
auto new_tree = std::make_shared<OutputInfo>(
|
||||
output,
|
||||
WindowTree(output.extents(), window_manager_tools, options));
|
||||
tree_list.push_back(new_tree);
|
||||
if (active_tree == nullptr)
|
||||
active_tree = new_tree;
|
||||
std::make_shared<Screen>(workspace_manager, output.extents(), window_manager_tools, options));
|
||||
workspace_manager.request_first_available_workspace(new_tree->screen);
|
||||
output_list.push_back(new_tree);
|
||||
if (active_output == nullptr)
|
||||
active_output = new_tree;
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_output_update(miral::Output const& updated, miral::Output const& original)
|
||||
{
|
||||
for (auto& pair : tree_list)
|
||||
for (auto& output : output_list)
|
||||
{
|
||||
if (pair->output.is_same_output(original))
|
||||
if (output->output.is_same_output(original))
|
||||
{
|
||||
pair->tree.set_output_area(updated.extents());
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
{
|
||||
workspace.tree.set_output_area(updated.extents());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -266,20 +302,21 @@ void MiracleWindowManagementPolicy::advise_output_update(miral::Output const& up
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_output_delete(miral::Output const& output)
|
||||
{
|
||||
for (auto const& it : tree_list)
|
||||
for (auto const& it : output_list)
|
||||
{
|
||||
if (it->output.is_same_output(output))
|
||||
{
|
||||
// TODO: Move windows open on the dying output to the other output
|
||||
auto did_remove = std::remove(tree_list.begin(), tree_list.end(), it);
|
||||
if (did_remove != tree_list.end() && it == active_tree)
|
||||
auto did_remove = std::remove(output_list.begin(), output_list.end(), it);
|
||||
if (did_remove != output_list.end() && it == active_output)
|
||||
{
|
||||
if (tree_list.empty())
|
||||
active_tree = nullptr;
|
||||
if (output_list.empty())
|
||||
active_output = nullptr;
|
||||
else
|
||||
{
|
||||
active_tree = tree_list[0];
|
||||
active_tree->tree.add_tree(it->tree);
|
||||
// TODO: Add ALL Trees
|
||||
active_output = output_list[0];
|
||||
active_output->screen->get_active_tree().add_tree(it->screen->get_active_tree());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -289,9 +326,9 @@ void MiracleWindowManagementPolicy::advise_output_delete(miral::Output const& ou
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_state_change(miral::WindowInfo const& window_info, MirWindowState state)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
if (tree->tree.advise_state_change(window_info, state))
|
||||
if (active_output->screen->get_active_tree().advise_state_change(window_info, state))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -306,27 +343,55 @@ void MiracleWindowManagementPolicy::handle_modify_window(
|
||||
{
|
||||
if (modifications.state().value() == mir_window_state_fullscreen || modifications.state().value() == mir_window_state_maximized)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
if (tree->tree.advise_fullscreen_window(window_info))
|
||||
break;
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
bool found = false;
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
{
|
||||
if (workspace.tree.advise_fullscreen_window(window_info))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
else if (modifications.state().value() == mir_window_state_restored)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
if (tree->tree.advise_restored_window(window_info))
|
||||
break;
|
||||
bool found = false;
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
{
|
||||
if (workspace.tree.advise_restored_window(window_info))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& tree :tree_list)
|
||||
for (auto const& output :output_list)
|
||||
{
|
||||
if (tree->tree.constrain(window_info))
|
||||
break;
|
||||
}
|
||||
bool found = false;
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
{
|
||||
if (workspace.tree.constrain(window_info))
|
||||
{
|
||||
found = true;
|
||||
window_manager_tools.modify_window(window_info.window(), modifications);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_tools.modify_window(window_info.window(), modifications);
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::handle_raise_window(miral::WindowInfo &window_info)
|
||||
@ -341,12 +406,19 @@ MiracleWindowManagementPolicy::confirm_placement_on_display(
|
||||
const mir::geometry::Rectangle &new_placement)
|
||||
{
|
||||
mir::geometry::Rectangle modified_placement = new_placement;
|
||||
for (auto const& tree : tree_list) {
|
||||
|
||||
if (tree->tree.confirm_placement_on_display(window_info, new_state, modified_placement))
|
||||
for (auto const& output : output_list)\
|
||||
{
|
||||
bool found = false;
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
{
|
||||
break;
|
||||
if (workspace.tree.confirm_placement_on_display(window_info, new_state, modified_placement))
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) break;
|
||||
}
|
||||
return modified_placement;
|
||||
}
|
||||
@ -378,18 +450,27 @@ mir::geometry::Rectangle MiracleWindowManagementPolicy::confirm_inherited_move(
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_application_zone_create(miral::Zone const& application_zone)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_application_zone_create(application_zone);
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
workspace.tree.advise_application_zone_create(application_zone);
|
||||
}
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_application_zone_update(miral::Zone const& updated, miral::Zone const& original)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_application_zone_update(updated, original);
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
workspace.tree.advise_application_zone_update(updated, original);
|
||||
}
|
||||
}
|
||||
|
||||
void MiracleWindowManagementPolicy::advise_application_zone_delete(miral::Zone const& application_zone)
|
||||
{
|
||||
for (auto const& tree : tree_list)
|
||||
tree->tree.advise_application_zone_delete(application_zone);
|
||||
for (auto const& output : output_list)
|
||||
{
|
||||
for (auto workspace : output->screen->get_workspaces())
|
||||
workspace.tree.advise_application_zone_delete(application_zone);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
#ifndef MIRIE_WINDOW_MANAGEMENT_POLICY_H
|
||||
#define MIRIE_WINDOW_MANAGEMENT_POLICY_H
|
||||
|
||||
#include "window_tree.h"
|
||||
#include "screen.h"
|
||||
#include "miracle_config.h"
|
||||
#include "workspace_manager.h"
|
||||
|
||||
#include <miral/window_manager_tools.h>
|
||||
#include <miral/window_management_policy.h>
|
||||
@ -20,10 +21,10 @@ class MirRunner;
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
struct OutputTreePair
|
||||
struct OutputInfo
|
||||
{
|
||||
miral::Output output;
|
||||
WindowTree tree;
|
||||
std::shared_ptr<Screen> screen;
|
||||
};
|
||||
|
||||
class MiracleWindowManagementPolicy : public miral::WindowManagementPolicy
|
||||
@ -80,13 +81,14 @@ public:
|
||||
void advise_application_zone_delete(miral::Zone const& application_zone) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<OutputTreePair> active_tree;
|
||||
std::vector<std::shared_ptr<OutputTreePair>> tree_list;
|
||||
std::shared_ptr<OutputInfo> active_output;
|
||||
std::vector<std::shared_ptr<OutputInfo>> output_list;
|
||||
miral::WindowManagerTools window_manager_tools;
|
||||
miral::ExternalClientLauncher const external_client_launcher;
|
||||
miral::InternalClientLauncher const internal_client_launcher;
|
||||
miral::MirRunner& runner;
|
||||
MiracleConfig const& config;
|
||||
WorkspaceManager workspace_manager;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -47,9 +47,9 @@ InsertNodeInternalResult insert_node_internal(
|
||||
int lane_pos,
|
||||
int index,
|
||||
int node_count,
|
||||
std::function<int(int)> get_node_size,
|
||||
std::function<int(int)> get_node_position,
|
||||
std::function<void(int, int, int)> set_node_size_position)
|
||||
std::function<int(int)> const& get_node_size,
|
||||
std::function<int(int)> const& get_node_position,
|
||||
std::function<void(int, int, int)> const& set_node_size_position)
|
||||
{
|
||||
int new_item_size = floorf64((double)lane_size / (double)(node_count + 1));
|
||||
int new_item_position = lane_pos + index * new_item_size;
|
||||
|
75
src/screen.cpp
Normal file
75
src/screen.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
#include "screen.h"
|
||||
#include "workspace_manager.h"
|
||||
#include <miral/window_info.h>
|
||||
|
||||
using namespace miracle;
|
||||
|
||||
Screen::Screen(
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
WindowTreeOptions const& options)
|
||||
: workspace_manager{workspace_manager},
|
||||
area{area},
|
||||
tools{tools},
|
||||
options{options}
|
||||
{
|
||||
}
|
||||
|
||||
WindowTree &Screen::get_active_tree()
|
||||
{
|
||||
for (auto& info : workspaces)
|
||||
{
|
||||
if (info.workspace == active_workspace)
|
||||
return info.tree;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Unable to find the active tree. We shouldn't be here");
|
||||
}
|
||||
|
||||
void Screen::advise_new_workspace(char workspace)
|
||||
{
|
||||
workspaces.push_back({
|
||||
workspace,
|
||||
WindowTree(area, tools, options)
|
||||
});
|
||||
make_workspace_active(workspace);
|
||||
}
|
||||
|
||||
bool Screen::make_workspace_active(char key)
|
||||
{
|
||||
for (auto& workspace : workspaces)
|
||||
{
|
||||
if (workspace.workspace == key)
|
||||
{
|
||||
// Deactivate current workspace
|
||||
for (auto& other : workspaces)
|
||||
{
|
||||
if (other.workspace == active_workspace)
|
||||
{
|
||||
hide(other);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Active new workspace
|
||||
show(workspace);
|
||||
|
||||
active_workspace = key;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
active_workspace = key;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Screen::hide(ScreenWorkspaceInfo& info)
|
||||
{
|
||||
info.tree.hide();
|
||||
}
|
||||
|
||||
void Screen::show(ScreenWorkspaceInfo& info)
|
||||
{
|
||||
info.tree.show();
|
||||
}
|
57
src/screen.h
Normal file
57
src/screen.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef MIRACLE_SCREEN_H
|
||||
#define MIRACLE_SCREEN_H
|
||||
|
||||
#include "window_tree.h"
|
||||
#include <memory>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
struct WorkspaceManager;
|
||||
|
||||
struct NodeResurrection
|
||||
{
|
||||
std::shared_ptr<Node> node;
|
||||
MirWindowState state;
|
||||
};
|
||||
|
||||
struct ScreenWorkspaceInfo
|
||||
{
|
||||
char workspace;
|
||||
WindowTree tree;
|
||||
std::vector<NodeResurrection> nodes_to_resurrect;
|
||||
};
|
||||
|
||||
/// A screen is comprised of a map of workspaces, each having their own tree.
|
||||
// Workspaces are shared across screens such that screens a workspace with a
|
||||
// particular index can ONLY ever live on one screen at a time.
|
||||
class Screen
|
||||
{
|
||||
public:
|
||||
Screen(
|
||||
WorkspaceManager& workspace_manager,
|
||||
geom::Rectangle const& area,
|
||||
miral::WindowManagerTools const& tools,
|
||||
WindowTreeOptions const& options);
|
||||
~Screen() = default;
|
||||
|
||||
WindowTree& get_active_tree();
|
||||
void advise_new_workspace(char workspace);
|
||||
bool make_workspace_active(char workspace);
|
||||
std::vector<ScreenWorkspaceInfo>& get_workspaces() { return workspaces; }
|
||||
|
||||
private:
|
||||
WorkspaceManager& workspace_manager;
|
||||
miral::WindowManagerTools tools;
|
||||
geom::Rectangle area;
|
||||
WindowTreeOptions options;
|
||||
char active_workspace;
|
||||
std::vector<ScreenWorkspaceInfo> workspaces;
|
||||
|
||||
void hide(ScreenWorkspaceInfo&);
|
||||
void show(ScreenWorkspaceInfo&);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -655,6 +655,9 @@ bool WindowTree::advise_state_change(const miral::WindowInfo &window_info, MirWi
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
if (is_hidden)
|
||||
return true;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case mir_window_state_restored:
|
||||
@ -705,6 +708,9 @@ bool WindowTree::constrain(miral::WindowInfo &window_info)
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
if (is_hidden)
|
||||
return false;
|
||||
|
||||
if (!node->get_parent())
|
||||
{
|
||||
std::cerr << "Unable to constrain node without parent\n";
|
||||
@ -752,4 +758,55 @@ void WindowTree::close_active_window()
|
||||
{
|
||||
tools.ask_client_to_close(active_window->get_window());
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTree::hide()
|
||||
{
|
||||
if (is_hidden)
|
||||
{
|
||||
mir::log_warning("Tree is already hidden");
|
||||
return;
|
||||
}
|
||||
|
||||
is_hidden = true;
|
||||
foreach_node([&](auto node)
|
||||
{
|
||||
if (node->is_window())
|
||||
{
|
||||
miral::WindowInfo& window_info = tools.info_for(node->get_window());
|
||||
nodes_to_resurrect.push_back({
|
||||
node,
|
||||
window_info.state()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
for (auto& node : nodes_to_resurrect)
|
||||
{
|
||||
miral::WindowInfo& window_info = tools.info_for(node.node->get_window());
|
||||
miral::WindowSpecification modifications;
|
||||
modifications.state() = mir_window_state_hidden;
|
||||
tools.place_and_size_for_state(modifications, window_info);
|
||||
tools.modify_window(window_info.window(), modifications);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowTree::show()
|
||||
{
|
||||
if (!is_hidden)
|
||||
{
|
||||
mir::log_warning("Tree is already shown");
|
||||
return;
|
||||
}
|
||||
|
||||
is_hidden = false;
|
||||
for (auto other_node : nodes_to_resurrect)
|
||||
{
|
||||
auto& window_info = tools.info_for(other_node.node->get_window());
|
||||
miral::WindowSpecification modifications;
|
||||
modifications.state() = other_node.state;
|
||||
tools.place_and_size_for_state(modifications, window_info);
|
||||
tools.modify_window(window_info.window(), modifications);
|
||||
}
|
||||
nodes_to_resurrect.clear();
|
||||
}
|
@ -102,6 +102,12 @@ public:
|
||||
void foreach_node(std::function<void(std::shared_ptr<Node>)>);
|
||||
void close_active_window();
|
||||
|
||||
/// Hides the entire tree
|
||||
void hide();
|
||||
|
||||
/// Shows the entire tree
|
||||
void show();
|
||||
|
||||
private:
|
||||
struct MoveResult
|
||||
{
|
||||
@ -114,6 +120,12 @@ private:
|
||||
std::shared_ptr<Node> node = nullptr;
|
||||
};
|
||||
|
||||
struct NodeResurrection
|
||||
{
|
||||
std::shared_ptr<Node> node;
|
||||
MirWindowState state;
|
||||
};
|
||||
|
||||
miral::WindowManagerTools tools;
|
||||
WindowTreeOptions options;
|
||||
std::shared_ptr<Node> root_lane;
|
||||
@ -122,6 +134,8 @@ private:
|
||||
bool is_resizing = false;
|
||||
std::vector<miral::Zone> application_zone_list;
|
||||
bool is_active_window_fullscreen = false;
|
||||
bool is_hidden = false;
|
||||
std::vector<NodeResurrection> nodes_to_resurrect;
|
||||
|
||||
std::shared_ptr<Node> _get_active_lane();
|
||||
void _handle_direction_request(NodeLayoutDirection direction);
|
||||
|
275
src/workspace_manager.cpp
Normal file
275
src/workspace_manager.cpp
Normal file
@ -0,0 +1,275 @@
|
||||
#include "workspace_manager.h"
|
||||
#include "screen.h"
|
||||
|
||||
using namespace mir::geometry;
|
||||
using namespace miral;
|
||||
using namespace miracle;
|
||||
|
||||
namespace
|
||||
{
|
||||
char DEFAULT_WORKSPACES[] = {'1','2','3','4','5','6','7','8','9', '0'};
|
||||
}
|
||||
|
||||
WorkspaceManager::WorkspaceManager(WindowManagerTools const& tools) :
|
||||
tools_{tools}
|
||||
{
|
||||
}
|
||||
|
||||
bool WorkspaceManager::request_workspace(std::shared_ptr<Screen> screen, char key)
|
||||
{
|
||||
for (auto workspace : workspaces)
|
||||
{
|
||||
if (workspace.key == key)
|
||||
{
|
||||
workspace.screen->make_workspace_active(key);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
workspaces.push_back({
|
||||
key,
|
||||
screen
|
||||
});
|
||||
screen->advise_new_workspace(key);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorkspaceManager::request_first_available_workspace(std::shared_ptr<Screen> screen)
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
bool can_use = true;
|
||||
for (auto workspace : workspaces)
|
||||
{
|
||||
if (workspace.key == DEFAULT_WORKSPACES[i])
|
||||
{
|
||||
can_use = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (can_use)
|
||||
return request_workspace(screen, DEFAULT_WORKSPACES[i]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//void miracle::WorkspaceManager::jump_to_workspace(bool take_active, int index)
|
||||
//{
|
||||
// tools_.invoke_under_lock(
|
||||
// [this, take_active, index]
|
||||
// {
|
||||
// if (active_workspace_index != index)
|
||||
// {
|
||||
// auto const old_workspace = active_workspace_index;
|
||||
// auto const& window = take_active ? tools_.active_window() : Window{};
|
||||
// auto const& old_active = workspaces[active_workspace_index];
|
||||
//
|
||||
// while (workspaces.size() - 1 < index)
|
||||
// workspaces.push_back(tools_.create_workspace());
|
||||
//
|
||||
// auto const& new_active = workspaces[index];
|
||||
// change_active_workspace(new_active, old_active, window);
|
||||
// erase_if_empty(std::next(workspaces.begin(), old_workspace));
|
||||
// active_workspace_index = index;
|
||||
// }
|
||||
// });
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::workspace_begin(bool take_active)
|
||||
//{
|
||||
// jump_to_workspace(take_active, 0);
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::workspace_end(bool take_active)
|
||||
//{
|
||||
// jump_to_workspace(take_active, workspaces.size() - 1);
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::workspace_up(bool take_active)
|
||||
//{
|
||||
// if (active_workspace_index != 0)
|
||||
// jump_to_workspace(take_active, active_workspace_index - 1);
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::workspace_down(bool take_active)
|
||||
//{
|
||||
// if (active_workspace_index != workspaces.size() - 1)
|
||||
// jump_to_workspace(active_workspace_index + 1, take_active);
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::erase_if_empty(workspace_list::iterator const& old_workspace)
|
||||
//{
|
||||
// bool empty = true;
|
||||
// tools_.for_each_window_in_workspace(*old_workspace, [&](auto ww)
|
||||
// {
|
||||
// if (is_application(tools_.info_for(ww).depth_layer()))
|
||||
// empty = false;
|
||||
// });
|
||||
// if (empty)
|
||||
// {
|
||||
// workspace_to_active.erase(*old_workspace);
|
||||
// workspaces.erase(old_workspace);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::apply_workspace_hidden_to(Window const& window)
|
||||
//{
|
||||
// auto const& window_info = tools_.info_for(window);
|
||||
// auto& workspace_info = workspace_info_for(window_info);
|
||||
// if (!workspace_info.in_hidden_workspace)
|
||||
// {
|
||||
// workspace_info.in_hidden_workspace = true;
|
||||
// workspace_info.old_state = window_info.state();
|
||||
//
|
||||
// WindowSpecification modifications;
|
||||
// modifications.state() = mir_window_state_hidden;
|
||||
// tools_.place_and_size_for_state(modifications, window_info);
|
||||
// tools_.modify_window(window_info.window(), modifications);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::apply_workspace_visible_to(Window const& window)
|
||||
//{
|
||||
// auto const& window_info = tools_.info_for(window);
|
||||
// auto& workspace_info = workspace_info_for(window_info);
|
||||
// if (workspace_info.in_hidden_workspace)
|
||||
// {
|
||||
// workspace_info.in_hidden_workspace = false;
|
||||
// WindowSpecification modifications;
|
||||
// modifications.state() = workspace_info.old_state;
|
||||
// tools_.place_and_size_for_state(modifications, window_info);
|
||||
// tools_.modify_window(window_info.window(), modifications);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::change_active_workspace(
|
||||
// std::shared_ptr<Workspace> const& new_active,
|
||||
// std::shared_ptr<Workspace> const& old_active,
|
||||
// Window const& window)
|
||||
//{
|
||||
// if (new_active == old_active) return;
|
||||
//
|
||||
// auto const old_active_window = tools_.active_window();
|
||||
// auto const old_active_window_shell = old_active_window &&
|
||||
// !is_application(tools_.info_for(old_active_window).depth_layer());
|
||||
//
|
||||
// if (!old_active_window || old_active_window_shell)
|
||||
// {
|
||||
// // If there's no active window, the first shown grabs focus: get the right one
|
||||
// if (auto const ww = workspace_to_active[new_active])
|
||||
// {
|
||||
// tools_.for_each_workspace_containing(ww, [&](std::shared_ptr<Workspace> const& ws)
|
||||
// {
|
||||
// if (ws == new_active)
|
||||
// {
|
||||
// apply_workspace_visible_to(ww);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // If focus was on a shell window, put it on an app
|
||||
// if (old_active_window_shell)
|
||||
// tools_.select_active_window(ww);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// tools_.remove_tree_from_workspace(window, old_active);
|
||||
// tools_.add_tree_to_workspace(window, new_active);
|
||||
//
|
||||
// tools_.for_each_window_in_workspace(new_active, [&](Window const& ww)
|
||||
// {
|
||||
// if (is_application(tools_.info_for(ww).depth_layer()))
|
||||
// {
|
||||
// apply_workspace_visible_to(ww);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// bool hide_old_active = false;
|
||||
// tools_.for_each_window_in_workspace(old_active, [&](Window const& ww)
|
||||
// {
|
||||
// if (is_application(tools_.info_for(ww).depth_layer()))
|
||||
// {
|
||||
// if (ww == old_active_window)
|
||||
// {
|
||||
// // If we hide the active window focus will shift: do that last
|
||||
// hide_old_active = true;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// apply_workspace_hidden_to(ww);
|
||||
// return;
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// if (hide_old_active)
|
||||
// {
|
||||
// apply_workspace_hidden_to(old_active_window);
|
||||
//
|
||||
// // Remember the old active_window when we switch away
|
||||
// workspace_to_active[old_active] = old_active_window;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::advise_adding_to_workspace(std::shared_ptr<Workspace> const& workspace,
|
||||
// std::vector<Window> const& windows)
|
||||
//{
|
||||
// if (windows.empty())
|
||||
// return;
|
||||
//
|
||||
// for (auto const& window : windows)
|
||||
// {
|
||||
// if (workspace == workspaces[active_workspace_index])
|
||||
// {
|
||||
// apply_workspace_visible_to(window);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// apply_workspace_hidden_to(window);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//auto miracle::WorkspaceManager::active_workspace() const -> std::shared_ptr<Workspace>
|
||||
//{
|
||||
// return workspaces[active_workspace_index];
|
||||
//}
|
||||
//
|
||||
//bool miracle::WorkspaceManager::is_application(MirDepthLayer layer)
|
||||
//{
|
||||
// switch (layer)
|
||||
// {
|
||||
// case mir_depth_layer_application:
|
||||
// case mir_depth_layer_always_on_top:
|
||||
// return true;
|
||||
//
|
||||
// default:;
|
||||
// return false;
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//bool miracle::WorkspaceManager::in_hidden_workspace(WindowInfo const& info) const
|
||||
//{
|
||||
// auto& workspace_info = workspace_info_for(info);
|
||||
//
|
||||
// return workspace_info.in_hidden_workspace;
|
||||
//}
|
||||
//
|
||||
//void miracle::WorkspaceManager::advise_new_window(WindowInfo const& window_info)
|
||||
//{
|
||||
// if (auto const& parent = window_info.parent())
|
||||
// {
|
||||
// if (workspace_info_for(tools_.info_for(parent)).in_hidden_workspace)
|
||||
// apply_workspace_hidden_to(window_info.window());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// tools_.add_tree_to_workspace(window_info.window(), active_workspace());
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//auto miracle::WorkspaceManager::make_workspace_info() -> std::shared_ptr<WorkspaceInfo>
|
||||
//{
|
||||
// return std::make_shared<WorkspaceInfo>();
|
||||
//}
|
90
src/workspace_manager.h
Normal file
90
src/workspace_manager.h
Normal file
@ -0,0 +1,90 @@
|
||||
#ifndef WORKSPACE_MANAGER_H
|
||||
#define WORKSPACE_MANAGER_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <miral/window_manager_tools.h>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
namespace miracle
|
||||
{
|
||||
|
||||
using miral::Window;
|
||||
using miral::WindowInfo;
|
||||
using miral::WindowManagerTools;
|
||||
using miral::WindowSpecification;
|
||||
using miral::Workspace;
|
||||
|
||||
class Screen;
|
||||
|
||||
// TODO:
|
||||
// As it stands, this isn't exactly what I want. What I do want
|
||||
// is a workspace manager that is output-aware. The data structure
|
||||
// should be a global WorkspaceManager who holds a mapping of Screens -> Workspaces.
|
||||
// Workspaces should have a name and be organized according to that name. This
|
||||
// goes to mean that we should ignore the idea of a vector of workspaces, and settle
|
||||
// for char-encoded workspaces instead.
|
||||
|
||||
struct WorkspaceInfo
|
||||
{
|
||||
char key;
|
||||
std::shared_ptr<Screen> screen;
|
||||
};
|
||||
|
||||
|
||||
class WorkspaceManager
|
||||
{
|
||||
public:
|
||||
explicit WorkspaceManager(WindowManagerTools const& tools);
|
||||
virtual ~WorkspaceManager() = default;
|
||||
|
||||
/// Request the workspace. If it does not yet exist, then one
|
||||
/// is created on the current Screen. If it does exist, we navigate
|
||||
/// to the screen containing that workspace and show it if it
|
||||
/// isn't already shown.
|
||||
bool request_workspace(std::shared_ptr<Screen> screen, char workspace);
|
||||
|
||||
bool request_first_available_workspace(std::shared_ptr<Screen> screen);
|
||||
|
||||
// void workspace_begin(bool take_active);
|
||||
//
|
||||
// void workspace_end(bool take_active);
|
||||
//
|
||||
// void workspace_up(bool take_active);
|
||||
//
|
||||
// void workspace_down(bool take_active);
|
||||
//
|
||||
// void jump_to_workspace(bool take_active, int index);
|
||||
//
|
||||
// void apply_workspace_hidden_to(Window const& window);
|
||||
//
|
||||
// void apply_workspace_visible_to(Window const& window);
|
||||
//
|
||||
// void change_active_workspace(
|
||||
// std::shared_ptr<Workspace> const& ww,
|
||||
// std::shared_ptr<Workspace> const& old_active,
|
||||
// miral::Window const& window);
|
||||
//
|
||||
// void advise_new_window(const WindowInfo &window_info);
|
||||
//
|
||||
// void advise_adding_to_workspace(
|
||||
// std::shared_ptr<Workspace> const& workspace,
|
||||
// std::vector<Window> const& windows);
|
||||
//
|
||||
// auto active_workspace() const -> std::shared_ptr<Workspace>;
|
||||
//
|
||||
// bool in_hidden_workspace(WindowInfo const& info) const;
|
||||
//
|
||||
// static bool is_application(MirDepthLayer layer);
|
||||
|
||||
private:
|
||||
WindowManagerTools tools_;
|
||||
|
||||
std::vector<WorkspaceInfo> workspaces;
|
||||
|
||||
void erase_if_empty(std::vector<std::shared_ptr<Workspace>>::iterator const& old_workspace);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user