kranewm

An ICCCM & EWMH compliant X11 reparenting, dynamic window manager, written in C++
git clone git clone git://git.deurzen.net/kranewm.git
Log | Files | Refs | LICENSE

commit 7caedde35e017a6e0c626d36022e91ff671aac86
parent 09f7c748fe3e97f55351dad9313bb99a13573af2
Author: deurzen <m.deurzen@tum.de>
Date:   Thu,  2 Sep 2021 08:24:17 +0200

adds proper leader/group handling

Diffstat:
Msrc/core/client.cc | 2+-
Msrc/core/client.hh | 2+-
Msrc/core/model.cc | 115++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/core/model.hh | 1+
4 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/src/core/client.cc b/src/core/client.cc @@ -31,9 +31,9 @@ Client::Client( active_decoration(winsys::Decoration::FREE_DECORATION), size_hints(std::nullopt), warp_pos(std::nullopt), + leader(std::nullopt), parent(nullptr), children({}), - leader(nullptr), producer(nullptr), consumers({}), focused(false), diff --git a/src/core/client.hh b/src/core/client.hh @@ -96,9 +96,9 @@ typedef struct Client final winsys::Decoration active_decoration; std::optional<winsys::SizeHints> size_hints; std::optional<winsys::Pos> warp_pos; + std::optional<winsys::Window> leader; Client_ptr parent; std::vector<Client_ptr> children; - Client_ptr leader; Client_ptr producer; std::vector<Client_ptr> consumers; bool focused; diff --git a/src/core/model.cc b/src/core/model.cc @@ -58,6 +58,7 @@ Model::Model(Connection& conn) m_client_map({}), m_pid_map({}), m_fullscreen_map({}), + m_leader_map({}), m_sticky_clients({}), m_unmanaged_windows({}), m_ignored_producers({}), @@ -1775,12 +1776,12 @@ Model::manage(const Window window, const bool ignore, const bool may_map) } if (leader) { - Client_ptr leader_client = get_client(*leader); + if (m_leader_map.count(*leader) > 0) + m_leader_map[*leader].push_back(client); + else + m_leader_map[*leader] = { client }; - if (leader_client) { - client->leader = leader_client; - floating = true; - } + client->leader = leader; } Rules rules = retrieve_rules(client); @@ -1818,6 +1819,35 @@ Model::manage(const Window window, const bool ignore, const bool may_map) } else if (rules.to_workspace && *rules.to_workspace < m_workspaces.size()) client->workspace = *rules.to_workspace; + if (leader) { + std::vector<Client_ptr>& members = m_leader_map.at(*leader); + std::optional<Index> group_attachment = std::nullopt; + + if (std::any_of( + members.begin(), + members.end(), + [&group_attachment](Client_ptr member) mutable -> bool { + if (member->attaching) { + group_attachment = member->workspace; + return true; + } + + return false; + }) && group_attachment + ) { + client->workspace = *group_attachment; + } + } + + if (parent) { + Client_ptr parent_client = get_client(*parent); + + if (parent_client && parent_client->attaching) { + client->workspace = parent_client->workspace; + client->attaching = true; + } + } + if (pid) m_pid_map[*pid] = client; @@ -1907,6 +1937,14 @@ Model::unmanage(Client_ptr client) m_fullscreen_map.erase(client); + if (client->leader) { + std::vector<Client_ptr>& members = m_leader_map.at(*client->leader); + Util::erase_remove(members, client); + + if (members.empty()) + m_leader_map.erase(*client->leader); + } + Util::erase_remove(m_sticky_clients, client); Util::erase_remove(m_order, client->frame); @@ -2371,22 +2409,42 @@ Model::move_focus_to_workspace(Index index) void Model::move_client_to_workspace(Index index, Client_ptr client) { - if (index >= m_workspaces.size() || index == mp_workspace->index() || client->sticky) + if (index >= m_workspaces.size() + || index == client->workspace + || client->sticky + ) { return; + } + + Workspace_ptr from = get_workspace(client->workspace); + Workspace_ptr to = get_workspace(index); client->workspace = index; - Workspace_ptr workspace = get_workspace(index); - unmap_client(client); + if (from == mp_workspace) + unmap_client(client); - workspace->add_client(client); - apply_layout(workspace); - apply_stack(workspace); + to->add_client(client); + apply_layout(to); + apply_stack(to); - mp_workspace->remove_client(client); - apply_layout(mp_workspace); + from->remove_client(client); + apply_layout(from); + apply_stack(from); sync_focus(); + + if (client->leader) { + std::vector<Client_ptr>& members = m_leader_map.at(*client->leader); + + std::for_each( + members.begin(), + members.end(), + [this,index](Client_ptr member) { + move_client_to_workspace(index, member); + } + ); + } } @@ -2684,6 +2742,9 @@ Model::set_sticky_client(Toggle toggle, Client_ptr client) if (client->sticky) return; + if (client->iconified) + set_iconify_client(Toggle::Off, client); + std::for_each( m_workspaces.begin(), m_workspaces.end(), @@ -2706,6 +2767,18 @@ Model::set_sticky_client(Toggle toggle, Client_ptr client) apply_layout(workspace); render_decoration(client); + if (client->leader) { + std::vector<Client_ptr>& members = m_leader_map.at(*client->leader); + + std::for_each( + members.begin(), + members.end(), + [this,toggle](Client_ptr member) { + set_sticky_client(toggle, member); + } + ); + } + return; } case Toggle::Off: @@ -2717,7 +2790,7 @@ Model::set_sticky_client(Toggle toggle, Client_ptr client) m_workspaces.begin(), m_workspaces.end(), [=,this](Workspace_ptr workspace) { - if (workspace->index() != mp_workspace->index()) { + if (workspace != mp_workspace) { workspace->remove_client(client); workspace->remove_icon(client); workspace->remove_disowned(client); @@ -2738,6 +2811,18 @@ Model::set_sticky_client(Toggle toggle, Client_ptr client) apply_layout(mp_workspace); render_decoration(client); + if (client->leader) { + std::vector<Client_ptr>& members = m_leader_map.at(*client->leader); + + std::for_each( + members.begin(), + members.end(), + [this,toggle](Client_ptr member) { + set_sticky_client(toggle, member); + } + ); + } + return; } case Toggle::Reverse: @@ -2882,7 +2967,7 @@ Model::set_iconify_client(Toggle toggle, Client_ptr client) switch (toggle) { case Toggle::On: { - if (client->iconified) + if (client->iconified || client->sticky) return; Workspace_ptr workspace = get_workspace(client->workspace); diff --git a/src/core/model.hh b/src/core/model.hh @@ -233,6 +233,7 @@ private: std::unordered_map<winsys::Window, Client_ptr> m_client_map; std::unordered_map<winsys::Pid, Client_ptr> m_pid_map; std::unordered_map<Client_ptr, winsys::Region> m_fullscreen_map; + std::unordered_map<winsys::Window, std::vector<Client_ptr>> m_leader_map; std::vector<Client_ptr> m_sticky_clients; std::vector<winsys::Window> m_unmanaged_windows;