Skip to content

Commit

Permalink
feature: named workspaces + massively refactoring how workspaces are …
Browse files Browse the repository at this point in the history
…handled in preparation for named workspaces (#285)

- Implemented the beginnings of named workspaces
- Massively refactored how workspaces function by holding the list of workspaces in the outputs themselves and no longer making the list be static
  • Loading branch information
mattkae authored Nov 4, 2024
1 parent 176f8f0 commit ce24996
Show file tree
Hide file tree
Showing 20 changed files with 481 additions and 356 deletions.
14 changes: 11 additions & 3 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,11 +531,19 @@ void FilesystemConfiguration::read_workspaces(YAML::Node const& workspaces)
if (!try_parse_value(workspace, "number", num))
continue;

auto type = try_parse_string_to_optional_value<std::optional<ContainerType>>(workspace, "layout", container_type_from_string);
if (!type || type.value() == ContainerType::none)
std::optional<ContainerType> type;
if (workspace["key"])
{
type = try_parse_string_to_optional_value<std::optional<ContainerType>>(workspace, "layout", container_type_from_string);
if (!type || type.value() == ContainerType::none)
continue;
}

std::string name;
if (!try_parse_value(workspace, "name", name, true))
continue;

options.workspace_configs.push_back({ num, type.value() });
options.workspace_configs.push_back({ num, type, name });
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ struct BorderConfig
struct WorkspaceConfig
{
int num = -1;
ContainerType layout = ContainerType::leaf;
std::optional<ContainerType> layout;
std::optional<std::string> name;
};

enum class RenderFilter : int
Expand Down
15 changes: 12 additions & 3 deletions src/container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,18 @@ glm::mat4 Container::get_workspace_transform() const
if (!output)
return glm::mat4(1.f);

auto const workspace_rect = output->get_workspace_rectangle(get_workspace()->get_workspace());
return glm::translate(
glm::vec3(workspace_rect.top_left.x.as_int(), workspace_rect.top_left.y.as_int(), 0));
auto const& workspaces = output->get_workspaces();
for (size_t i = 0; i < workspaces.size(); i++)
{
if (workspaces[i].get() == get_workspace())
{
auto const workspace_rect = output->get_workspace_rectangle(i);
return glm::translate(
glm::vec3(workspace_rect.top_left.x.as_int(), workspace_rect.top_left.y.as_int(), 0));
}
}

return glm::mat4(1.f);
}

glm::mat4 Container::get_output_transform() const
Expand Down
2 changes: 1 addition & 1 deletion src/container_group_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ ContainerGroupContainer::confirm_placement(MirWindowState state, mir::geometry::

Workspace* ContainerGroupContainer::get_workspace() const
{
return state.active_output->get_active_workspace().get();
return state.active_output->active();
}

Output* ContainerGroupContainer::get_output() const
Expand Down
10 changes: 3 additions & 7 deletions src/floating_window_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ void FloatingWindowContainer::on_open()

void FloatingWindowContainer::on_focus_gained()
{
if (get_output()->get_active_workspace()->get_workspace() != workspace_->get_workspace())
if (get_output()->active() != workspace_)
return;

wm->advise_focus_gained(window_controller.info_for(window_));
Expand Down Expand Up @@ -270,11 +270,7 @@ glm::mat4 FloatingWindowContainer::get_workspace_transform() const
if (pinned())
return glm::mat4(1.f);

auto output = get_output();
auto workspace = get_workspace();
auto const workspace_rect = output->get_workspace_rectangle(workspace->get_workspace());
return glm::translate(
glm::vec3(workspace_rect.top_left.x.as_int(), workspace_rect.top_left.y.as_int(), 0));
return Container::get_workspace_transform();
}

glm::mat4 FloatingWindowContainer::get_output_transform() const
Expand Down Expand Up @@ -357,7 +353,7 @@ nlohmann::json FloatingWindowContainer::to_json() const
if (!output->is_active())
visible = false;

if (output->get_active_workspace_num() != workspace->get_workspace())
if (output->active() != workspace)
visible = false;

return {
Expand Down
2 changes: 1 addition & 1 deletion src/i3_command_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ void I3CommandExecutor::process_focus(I3Command const& command, I3ScopedCommandL
auto window = get_window_meeting_criteria(command_list);
auto container = window_controller.get_container(window);
if (container)
workspace_manager.request_focus(container->get_workspace()->get_workspace());
workspace_manager.request_focus(container->get_workspace()->id());
}
else if (arg == "left")
policy.try_select(Direction::left);
Expand Down
66 changes: 28 additions & 38 deletions src/ipc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,31 +76,35 @@ bool fd_is_valid(int fd)
return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
}

json workspace_to_json(Output const& screen, int key)
json workspace_to_json(WorkspaceManager const& workspace_manager, uint32_t id)
{
auto workspace = screen.workspace(key);
bool is_focused = screen.get_active_workspace_num() == key;
auto const& workspace = workspace_manager.workspace(id);
if (!workspace)
return {};

auto screen = workspace->get_output();
bool is_focused = screen->active() == workspace;

// Note: The reported workspace area appears to be the placement
// area of the root tree.
// See: https://i3wm.org/docs/ipc.html#_tree_reply
auto area = workspace->get_tree()->get_area();

return {
{ "num", key },
{ "id", reinterpret_cast<std::uintptr_t>(workspace) },
{ "type", "workspace" },
{ "name", std::to_string(key) },
{ "visible", screen.is_active() && is_focused },
{ "focused", screen.is_active() && is_focused },
{ "urgent", false },
{ "output", screen.get_output().name() },
{ "num", workspace->num() ? workspace->num().value() : -1 },
{ "id", reinterpret_cast<std::uintptr_t>(workspace) },
{ "type", "workspace" },
{ "name", workspace->display_name() },
{ "visible", screen->is_active() && is_focused },
{ "focused", screen->is_active() && is_focused },
{ "urgent", false },
{ "output", screen->get_output().name() },
{ "rect", {
{ "x", area.top_left.x.as_int() },
{ "y", area.top_left.y.as_int() },
{ "width", area.size.width.as_int() },
{ "height", area.size.height.as_int() },
} }
} }
};
}

Expand Down Expand Up @@ -369,12 +373,12 @@ Ipc::~Ipc()
{
}

void Ipc::on_created(Output const& info, int key)
void Ipc::on_created(uint32_t id)
{
json j = {
{ "change", "init" },
{ "old", nullptr },
{ "current", workspace_to_json(info, key) }
{ "current", workspace_to_json(workspace_manager, id) }
};

auto serialized_value = to_string(j);
Expand All @@ -389,11 +393,11 @@ void Ipc::on_created(Output const& info, int key)
}
}

void Ipc::on_removed(Output const& screen, int key)
void Ipc::on_removed(uint32_t id)
{
json j = {
{ "change", "empty" },
{ "current", workspace_to_json(screen, key) }
{ "current", workspace_to_json(workspace_manager, id) }
};

auto serialized_value = to_string(j);
Expand All @@ -409,18 +413,16 @@ void Ipc::on_removed(Output const& screen, int key)
}

void Ipc::on_focused(
Output const* previous,
int previous_key,
Output const* current,
int current_key)
std::optional<uint32_t> previous_id,
uint32_t current_id)
{
json j = {
{ "change", "focus" },
{ "current", workspace_to_json(*current, current_key) }
{ "current", workspace_to_json(workspace_manager, current_id) }
};

if (previous)
j["old"] = workspace_to_json(*previous, previous_key);
if (previous_id)
j["old"] = workspace_to_json(workspace_manager, previous_id.value());
else
j["old"] = nullptr;

Expand Down Expand Up @@ -540,12 +542,9 @@ void Ipc::handle_command(miracle::Ipc::IpcClient& client, uint32_t payload_lengt
case IPC_GET_WORKSPACES:
{
json j = json::array();
for (int i = 0; i < WorkspaceManager::NUM_WORKSPACES; i++)
{
auto workspace = workspace_manager.get_output_to_workspace_mapping()[i].get();
if (workspace)
j.push_back(workspace_to_json(*workspace, i));
}
for (auto const& workspace : workspace_manager.workspaces())
j.push_back(workspace_to_json(workspace_manager, workspace->id()));

auto json_string = to_string(j);
send_reply(client, payload_type, json_string);
break;
Expand Down Expand Up @@ -759,15 +758,6 @@ void Ipc::handle_writeable(miracle::Ipc::IpcClient& client)
client.write_buffer_len = 0;
}

namespace
{
bool equals(std::string_view const& s, const char* v)
{
// TODO: Perhaps this is a bit naive, as it is basically a "startswith"
return strncmp(s.data(), v, strlen(v)) == 0;
}
}

bool Ipc::parse_i3_command(std::string_view const& command)
{
{
Expand Down
6 changes: 3 additions & 3 deletions src/ipc.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ class Ipc : public virtual WorkspaceObserver, public virtual ModeObserver
std::shared_ptr<Config> const&);
~Ipc();

void on_created(Output const& info, int key) override;
void on_removed(Output const& info, int key) override;
void on_focused(Output const* previous, int, Output const* current, int) override;
void on_created(uint32_t id) override;
void on_removed(uint32_t id) override;
void on_focused(std::optional<uint32_t>, uint32_t) override;
void on_changed(WindowManagerMode mode) override;
void on_shutdown();

Expand Down
2 changes: 1 addition & 1 deletion src/leaf_container.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ nlohmann::json LeafContainer::to_json() const
if (!output->is_active())
visible = false;

if (output->get_active_workspace_num() != workspace->get_workspace())
if (output->active() != workspace)
visible = false;

if (locked_parent == nullptr)
Expand Down
Loading

0 comments on commit ce24996

Please sign in to comment.