fix(hyprland): support additional v2 events
This commit is contained in:
@ -7,6 +7,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -55,7 +56,7 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
|
|
||||||
static Json::Value createMonitorWorkspaceData(std::string const& name,
|
static Json::Value createMonitorWorkspaceData(std::string const& name,
|
||||||
std::string const& monitor);
|
std::string const& monitor);
|
||||||
void removeWorkspace(std::string const& name);
|
void removeWorkspace(std::string const& workspaceString);
|
||||||
void setUrgentWorkspace(std::string const& windowaddress);
|
void setUrgentWorkspace(std::string const& windowaddress);
|
||||||
|
|
||||||
// Config
|
// Config
|
||||||
@ -74,10 +75,11 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
void onWorkspaceActivated(std::string const& payload);
|
void onWorkspaceActivated(std::string const& payload);
|
||||||
void onSpecialWorkspaceActivated(std::string const& payload);
|
void onSpecialWorkspaceActivated(std::string const& payload);
|
||||||
void onWorkspaceDestroyed(std::string const& payload);
|
void onWorkspaceDestroyed(std::string const& payload);
|
||||||
void onWorkspaceCreated(std::string const& workspaceName,
|
void onWorkspaceCreated(std::string const& payload,
|
||||||
Json::Value const& clientsData = Json::Value::nullRef);
|
Json::Value const& clientsData = Json::Value::nullRef);
|
||||||
void onWorkspaceMoved(std::string const& payload);
|
void onWorkspaceMoved(std::string const& payload);
|
||||||
void onWorkspaceRenamed(std::string const& payload);
|
void onWorkspaceRenamed(std::string const& payload);
|
||||||
|
static std::optional<int> parseWorkspaceId(std::string const& workspaceIdStr);
|
||||||
|
|
||||||
// monitor events
|
// monitor events
|
||||||
void onMonitorFocused(std::string const& payload);
|
void onMonitorFocused(std::string const& payload);
|
||||||
@ -93,11 +95,18 @@ class Workspaces : public AModule, public EventHandler {
|
|||||||
|
|
||||||
int windowRewritePriorityFunction(std::string const& window_rule);
|
int windowRewritePriorityFunction(std::string const& window_rule);
|
||||||
|
|
||||||
|
// event payload management
|
||||||
|
template <typename... Args>
|
||||||
|
static std::string makePayload(Args const&... args);
|
||||||
|
static std::pair<std::string, std::string> splitDoublePayload(std::string const& payload);
|
||||||
|
static std::tuple<std::string, std::string, std::string> splitTriplePayload(
|
||||||
|
std::string const& payload);
|
||||||
|
|
||||||
// Update methods
|
// Update methods
|
||||||
void doUpdate();
|
void doUpdate();
|
||||||
void removeWorkspacesToRemove();
|
void removeWorkspacesToRemove();
|
||||||
void createWorkspacesToCreate();
|
void createWorkspacesToCreate();
|
||||||
static std::vector<std::string> getVisibleWorkspaces();
|
static std::vector<int> getVisibleWorkspaces();
|
||||||
void updateWorkspaceStates();
|
void updateWorkspaceStates();
|
||||||
bool updateWindowsToCreate();
|
bool updateWindowsToCreate();
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@ -39,13 +40,7 @@ Workspaces::~Workspaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::init() {
|
void Workspaces::init() {
|
||||||
<<<<<<< HEAD
|
m_activeWorkspaceId = m_ipc.getSocket1JsonReply("activeworkspace")["id"].asInt();
|
||||||
m_activeWorkspaceName = (m_ipc.getSocket1JsonReply("activeworkspace"))["name"].asString();
|
|
||||||
||||||| parent of 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
|
||||||
=======
|
|
||||||
m_activeWorkspaceId = (gIPC->getSocket1JsonReply("activeworkspace"))["id"].asInt();
|
|
||||||
>>>>>>> 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
|
|
||||||
initializeWorkspaces();
|
initializeWorkspaces();
|
||||||
dp.emit();
|
dp.emit();
|
||||||
@ -55,13 +50,12 @@ Json::Value Workspaces::createMonitorWorkspaceData(std::string const &name,
|
|||||||
std::string const &monitor) {
|
std::string const &monitor) {
|
||||||
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
|
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
|
||||||
Json::Value workspaceData;
|
Json::Value workspaceData;
|
||||||
try {
|
|
||||||
// numbered persistent workspaces get the name as ID
|
auto workspaceId = parseWorkspaceId(name);
|
||||||
workspaceData["id"] = name == "special" ? -99 : std::stoi(name);
|
if (!workspaceId.has_value()) {
|
||||||
} catch (const std::exception &e) {
|
workspaceId = 0;
|
||||||
// named persistent workspaces start with ID=0
|
|
||||||
workspaceData["id"] = 0;
|
|
||||||
}
|
}
|
||||||
|
workspaceData["id"] = *workspaceId;
|
||||||
workspaceData["name"] = name;
|
workspaceData["name"] = name;
|
||||||
workspaceData["monitor"] = monitor;
|
workspaceData["monitor"] = monitor;
|
||||||
workspaceData["windows"] = 0;
|
workspaceData["windows"] = 0;
|
||||||
@ -74,9 +68,8 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
|
|||||||
spdlog::debug("Creating workspace {}", workspaceName);
|
spdlog::debug("Creating workspace {}", workspaceName);
|
||||||
|
|
||||||
// avoid recreating existing workspaces
|
// avoid recreating existing workspaces
|
||||||
auto workspace = std::find_if(
|
auto workspace =
|
||||||
m_workspaces.begin(), m_workspaces.end(),
|
std::ranges::find_if(m_workspaces, [workspaceName](std::unique_ptr<Workspace> const &w) {
|
||||||
[workspaceName](std::unique_ptr<Workspace> const &w) {
|
|
||||||
return (workspaceName.starts_with("special:") && workspaceName.substr(8) == w->name()) ||
|
return (workspaceName.starts_with("special:") && workspaceName.substr(8) == w->name()) ||
|
||||||
workspaceName == w->name();
|
workspaceName == w->name();
|
||||||
});
|
});
|
||||||
@ -164,18 +157,18 @@ std::string Workspaces::getRewrite(std::string window_class, std::string window_
|
|||||||
fmt::arg("title", window_title));
|
fmt::arg("title", window_title));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Workspaces::getVisibleWorkspaces() {
|
std::vector<int> Workspaces::getVisibleWorkspaces() {
|
||||||
std::vector<std::string> visibleWorkspaces;
|
std::vector<int> visibleWorkspaces;
|
||||||
auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
auto monitors = IPC::inst().getSocket1JsonReply("monitors");
|
||||||
for (const auto &monitor : monitors) {
|
for (const auto &monitor : monitors) {
|
||||||
auto ws = monitor["activeWorkspace"];
|
auto ws = monitor["activeWorkspace"];
|
||||||
if (ws.isObject() && ws["name"].isString()) {
|
if (ws.isObject() && ws["id"].isInt()) {
|
||||||
visibleWorkspaces.push_back(ws["name"].asString());
|
visibleWorkspaces.push_back(ws["id"].asInt());
|
||||||
}
|
}
|
||||||
auto sws = monitor["specialWorkspace"];
|
auto sws = monitor["specialWorkspace"];
|
||||||
auto name = sws["name"].asString();
|
auto name = sws["name"].asString();
|
||||||
if (sws.isObject() && sws["name"].isString() && !name.empty()) {
|
if (sws.isObject() && sws["id"].isInt() && !name.empty()) {
|
||||||
visibleWorkspaces.push_back(!name.starts_with("special:") ? name : name.substr(8));
|
visibleWorkspaces.push_back(sws["id"].asInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return visibleWorkspaces;
|
return visibleWorkspaces;
|
||||||
@ -253,7 +246,7 @@ void Workspaces::loadPersistentWorkspacesFromConfig(Json::Value const &clientsJs
|
|||||||
int amount = value.asInt();
|
int amount = value.asInt();
|
||||||
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
|
spdlog::debug("Creating {} persistent workspaces for monitor {}", amount, currentMonitor);
|
||||||
for (int i = 0; i < amount; i++) {
|
for (int i = 0; i < amount; i++) {
|
||||||
persistentWorkspacesToCreate.emplace_back(std::to_string(m_monitorId * amount + i + 1));
|
persistentWorkspacesToCreate.emplace_back(std::to_string((m_monitorId * amount) + i + 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (value.isArray() && !value.empty()) {
|
} else if (value.isArray() && !value.empty()) {
|
||||||
@ -331,21 +324,21 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||||||
onWorkspaceDestroyed(payload);
|
onWorkspaceDestroyed(payload);
|
||||||
} else if (eventName == "createworkspacev2") {
|
} else if (eventName == "createworkspacev2") {
|
||||||
onWorkspaceCreated(payload);
|
onWorkspaceCreated(payload);
|
||||||
} else if (eventName == "focusedmon") {
|
} else if (eventName == "focusedmonv2") {
|
||||||
onMonitorFocused(payload);
|
onMonitorFocused(payload);
|
||||||
} else if (eventName == "moveworkspace") {
|
} else if (eventName == "moveworkspacev2") {
|
||||||
onWorkspaceMoved(payload);
|
onWorkspaceMoved(payload);
|
||||||
} else if (eventName == "openwindow") {
|
} else if (eventName == "openwindow") {
|
||||||
onWindowOpened(payload);
|
onWindowOpened(payload);
|
||||||
} else if (eventName == "closewindow") {
|
} else if (eventName == "closewindow") {
|
||||||
onWindowClosed(payload);
|
onWindowClosed(payload);
|
||||||
} else if (eventName == "movewindow") {
|
} else if (eventName == "movewindowv2") {
|
||||||
onWindowMoved(payload);
|
onWindowMoved(payload);
|
||||||
} else if (eventName == "urgent") {
|
} else if (eventName == "urgent") {
|
||||||
setUrgentWorkspace(payload);
|
setUrgentWorkspace(payload);
|
||||||
} else if (eventName == "renameworkspace") {
|
} else if (eventName == "renameworkspace") {
|
||||||
onWorkspaceRenamed(payload);
|
onWorkspaceRenamed(payload);
|
||||||
} else if (eventName == "windowtitle") {
|
} else if (eventName == "windowtitlev2") {
|
||||||
onWindowTitleEvent(payload);
|
onWindowTitleEvent(payload);
|
||||||
} else if (eventName == "configreloaded") {
|
} else if (eventName == "configreloaded") {
|
||||||
onConfigReloaded();
|
onConfigReloaded();
|
||||||
@ -355,8 +348,11 @@ void Workspaces::onEvent(const std::string &ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceActivated(std::string const &payload) {
|
void Workspaces::onWorkspaceActivated(std::string const &payload) {
|
||||||
std::string workspaceIdStr = payload.substr(0, payload.find(','));
|
const auto [workspaceIdStr, workspaceName] = splitDoublePayload(payload);
|
||||||
m_activeWorkspaceId = std::stoi(workspaceIdStr);
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (workspaceId.has_value()) {
|
||||||
|
m_activeWorkspaceId = *workspaceId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
||||||
@ -365,50 +361,54 @@ void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
|
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
|
||||||
std::string workspaceIdStr = payload.substr(0, payload.find(','));
|
const auto [workspaceId, workspaceName] = splitDoublePayload(payload);
|
||||||
std::string workspaceName = payload.substr(workspaceIdStr.size() + 1);
|
|
||||||
if (!isDoubleSpecial(workspaceName)) {
|
if (!isDoubleSpecial(workspaceName)) {
|
||||||
m_workspacesToRemove.push_back(workspaceIdStr);
|
m_workspacesToRemove.push_back(workspaceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceCreated(std::string const &payload,
|
void Workspaces::onWorkspaceCreated(std::string const &payload, Json::Value const &clientsData) {
|
||||||
Json::Value const &clientsData) {
|
|
||||||
spdlog::debug("Workspace created: {}", payload);
|
spdlog::debug("Workspace created: {}", payload);
|
||||||
std::string workspaceIdStr = payload.substr(0, payload.find(','));
|
|
||||||
int workspaceId = std::stoi(workspaceIdStr);
|
|
||||||
|
|
||||||
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
|
const auto [workspaceIdStr, _] = splitDoublePayload(payload);
|
||||||
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
|
|
||||||
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const workspaceRules = m_ipc.getSocket1JsonReply("workspacerules");
|
||||||
|
auto const workspacesJson = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
|
|
||||||
for (Json::Value workspaceJson : workspacesJson) {
|
for (Json::Value workspaceJson : workspacesJson) {
|
||||||
int currentId = workspaceJson["id"].asInt();
|
const auto currentId = workspaceJson["id"].asInt();
|
||||||
if (currentId == workspaceId) {
|
if (currentId == *workspaceId) {
|
||||||
std::string name = workspaceJson["name"].asString();
|
std::string workspaceName = workspaceJson["name"].asString();
|
||||||
// This workspace name is more up-to-date than the one in the event payload.
|
// This workspace name is more up-to-date than the one in the event payload.
|
||||||
if (isWorkspaceIgnored(name)) {
|
if (isWorkspaceIgnored(workspaceName)) {
|
||||||
spdlog::trace("Not creating workspace because it is ignored: id={} name={}", workspaceId,
|
spdlog::trace("Not creating workspace because it is ignored: id={} name={}", *workspaceId,
|
||||||
name);
|
workspaceName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
if ((allOutputs() || m_bar.output->name == workspaceJson["monitor"].asString()) &&
|
||||||
(showSpecial() || !currentName.starts_with("special")) && !isDoubleSpecial(currentName)) {
|
(showSpecial() || !workspaceName.starts_with("special")) &&
|
||||||
for (Json::Value const &rule : workspaceRules) {
|
!isDoubleSpecial(workspaceName)) {
|
||||||
auto ruleWorkspaceName = rule.isMember("defaultName")
|
for (Json::Value const &rule : workspaceRules) {
|
||||||
? rule["defaultName"].asString()
|
auto ruleWorkspaceName = rule.isMember("defaultName")
|
||||||
: rule["workspaceString"].asString();
|
? rule["defaultName"].asString()
|
||||||
if (ruleWorkspaceName == workspaceName) {
|
: rule["workspaceString"].asString();
|
||||||
workspaceJson["persistent-rule"] = rule["persistent"].asBool();
|
if (ruleWorkspaceName == workspaceName) {
|
||||||
break;
|
workspaceJson["persistent-rule"] = rule["persistent"].asBool();
|
||||||
}
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
m_workspacesToCreate.emplace_back(workspaceJson, clientsData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
extendOrphans(workspaceId, clientsData);
|
extendOrphans(*workspaceId, clientsData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,35 +417,34 @@ void Workspaces::onWorkspaceMoved(std::string const &payload) {
|
|||||||
spdlog::debug("Workspace moved: {}", payload);
|
spdlog::debug("Workspace moved: {}", payload);
|
||||||
|
|
||||||
// Update active workspace
|
// Update active workspace
|
||||||
<<<<<<< HEAD
|
m_activeWorkspaceId = (m_ipc.getSocket1JsonReply("activeworkspace"))["id"].asInt();
|
||||||
m_activeWorkspaceName = (m_ipc.getSocket1JsonReply("activeworkspace"))["name"].asString();
|
|
||||||
||||||| parent of 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
m_activeWorkspaceName = (gIPC->getSocket1JsonReply("activeworkspace"))["name"].asString();
|
|
||||||
=======
|
|
||||||
m_activeWorkspaceId = (gIPC->getSocket1JsonReply("activeworkspace"))["id"].asInt();
|
|
||||||
>>>>>>> 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
|
|
||||||
if (allOutputs()) return;
|
if (allOutputs()) return;
|
||||||
|
|
||||||
std::string workspaceName = payload.substr(0, payload.find(','));
|
const auto [workspaceIdStr, workspaceName, monitorName] = splitTriplePayload(payload);
|
||||||
std::string monitorName = payload.substr(payload.find(',') + 1);
|
|
||||||
|
const auto subPayload = makePayload(workspaceIdStr, workspaceName);
|
||||||
|
|
||||||
if (m_bar.output->name == monitorName) {
|
if (m_bar.output->name == monitorName) {
|
||||||
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
Json::Value clientsData = m_ipc.getSocket1JsonReply("clients");
|
||||||
onWorkspaceCreated(workspaceName, clientsData);
|
onWorkspaceCreated(subPayload, clientsData);
|
||||||
} else {
|
} else {
|
||||||
spdlog::debug("Removing workspace because it was moved to another monitor: {}");
|
spdlog::debug("Removing workspace because it was moved to another monitor: {}", subPayload);
|
||||||
onWorkspaceDestroyed(workspaceName);
|
onWorkspaceDestroyed(subPayload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
||||||
spdlog::debug("Workspace renamed: {}", payload);
|
spdlog::debug("Workspace renamed: {}", payload);
|
||||||
std::string workspaceIdStr = payload.substr(0, payload.find(','));
|
const auto [workspaceIdStr, newName] = splitDoublePayload(payload);
|
||||||
int workspaceId = workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
|
|
||||||
std::string newName = payload.substr(payload.find(',') + 1);
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
|
if (!workspaceId.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
if (workspace->id() == workspaceId) {
|
if (workspace->id() == *workspaceId) {
|
||||||
workspace->setName(newName);
|
workspace->setName(newName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -456,19 +455,18 @@ void Workspaces::onWorkspaceRenamed(std::string const &payload) {
|
|||||||
void Workspaces::onMonitorFocused(std::string const &payload) {
|
void Workspaces::onMonitorFocused(std::string const &payload) {
|
||||||
spdlog::trace("Monitor focused: {}", payload);
|
spdlog::trace("Monitor focused: {}", payload);
|
||||||
|
|
||||||
std::string workspaceName = payload.substr(payload.find(',') + 1);
|
const auto [monitorName, workspaceIdStr] = splitDoublePayload(payload);
|
||||||
|
|
||||||
// TODO this will be in the payload when we upgrade to focusedmonv2
|
const auto workspaceId = parseWorkspaceId(workspaceIdStr);
|
||||||
for (auto &workspace : m_workspaces) {
|
if (!workspaceId.has_value()) {
|
||||||
if (workspace->name() == workspaceName) {
|
return;
|
||||||
m_activeWorkspaceId = workspace->id();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_activeWorkspaceId = *workspaceId;
|
||||||
|
|
||||||
for (Json::Value &monitor : m_ipc.getSocket1JsonReply("monitors")) {
|
for (Json::Value &monitor : m_ipc.getSocket1JsonReply("monitors")) {
|
||||||
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
|
if (monitor["name"].asString() == monitorName) {
|
||||||
auto name = monitor["specialWorkspace"]["name"].asString();
|
const auto name = monitor["specialWorkspace"]["name"].asString();
|
||||||
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
|
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,11 +505,7 @@ void Workspaces::onWindowClosed(std::string const &addr) {
|
|||||||
void Workspaces::onWindowMoved(std::string const &payload) {
|
void Workspaces::onWindowMoved(std::string const &payload) {
|
||||||
spdlog::trace("Window moved: {}", payload);
|
spdlog::trace("Window moved: {}", payload);
|
||||||
updateWindowCount();
|
updateWindowCount();
|
||||||
size_t lastCommaIdx = 0;
|
auto [windowAddress, _, workspaceName] = splitTriplePayload(payload);
|
||||||
size_t nextCommaIdx = payload.find(',');
|
|
||||||
std::string windowAddress = payload.substr(lastCommaIdx, nextCommaIdx - lastCommaIdx);
|
|
||||||
|
|
||||||
std::string workspaceName = payload.substr(nextCommaIdx + 1, payload.length() - nextCommaIdx);
|
|
||||||
|
|
||||||
std::string windowRepr;
|
std::string windowRepr;
|
||||||
|
|
||||||
@ -547,13 +541,15 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
spdlog::trace("Window title changed: {}", payload);
|
spdlog::trace("Window title changed: {}", payload);
|
||||||
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
std::optional<std::function<void(WindowCreationPayload)>> inserter;
|
||||||
|
|
||||||
|
const auto [windowAddress, _] = splitDoublePayload(payload);
|
||||||
|
|
||||||
// If the window was an orphan, rename it at the orphan's vector
|
// If the window was an orphan, rename it at the orphan's vector
|
||||||
if (m_orphanWindowMap.contains(payload)) {
|
if (m_orphanWindowMap.contains(windowAddress)) {
|
||||||
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
|
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
|
||||||
} else {
|
} else {
|
||||||
auto windowWorkspace =
|
auto windowWorkspace = std::ranges::find_if(m_workspaces, [windowAddress](auto &workspace) {
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(),
|
return workspace->containsWindow(windowAddress);
|
||||||
[payload](auto &workspace) { return workspace->containsWindow(payload); });
|
});
|
||||||
|
|
||||||
// If the window exists on a workspace, rename it at the workspace's window
|
// If the window exists on a workspace, rename it at the workspace's window
|
||||||
// map
|
// map
|
||||||
@ -562,9 +558,9 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
|
|||||||
(*windowWorkspace)->insertWindow(std::move(wcp));
|
(*windowWorkspace)->insertWindow(std::move(wcp));
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
auto queuedWindow = std::find_if(
|
auto queuedWindow = std::ranges::find_if(m_windowsToCreate, [payload](auto &windowPayload) {
|
||||||
m_windowsToCreate.begin(), m_windowsToCreate.end(),
|
return windowPayload.getAddress() == payload;
|
||||||
[payload](auto &windowPayload) { return windowPayload.getAddress() == payload; });
|
});
|
||||||
|
|
||||||
// If the window was queued, rename it in the queue
|
// If the window was queued, rename it in the queue
|
||||||
if (queuedWindow != m_windowsToCreate.end()) {
|
if (queuedWindow != m_windowsToCreate.end()) {
|
||||||
@ -692,57 +688,29 @@ void Workspaces::registerOrphanWindow(WindowCreationPayload create_window_payloa
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto Workspaces::registerIpc() -> void {
|
auto Workspaces::registerIpc() -> void {
|
||||||
<<<<<<< HEAD
|
m_ipc.registerForIPC("workspacev2", this);
|
||||||
m_ipc.registerForIPC("workspace", this);
|
|
||||||
m_ipc.registerForIPC("activespecial", this);
|
m_ipc.registerForIPC("activespecial", this);
|
||||||
m_ipc.registerForIPC("createworkspace", this);
|
m_ipc.registerForIPC("createworkspacev2", this);
|
||||||
m_ipc.registerForIPC("destroyworkspace", this);
|
m_ipc.registerForIPC("destroyworkspacev2", this);
|
||||||
m_ipc.registerForIPC("focusedmon", this);
|
m_ipc.registerForIPC("focusedmonv2", this);
|
||||||
m_ipc.registerForIPC("moveworkspace", this);
|
m_ipc.registerForIPC("moveworkspacev2", this);
|
||||||
m_ipc.registerForIPC("renameworkspace", this);
|
m_ipc.registerForIPC("renameworkspace", this);
|
||||||
m_ipc.registerForIPC("openwindow", this);
|
m_ipc.registerForIPC("openwindow", this);
|
||||||
m_ipc.registerForIPC("closewindow", this);
|
m_ipc.registerForIPC("closewindow", this);
|
||||||
m_ipc.registerForIPC("movewindow", this);
|
m_ipc.registerForIPC("movewindowv2", this);
|
||||||
m_ipc.registerForIPC("urgent", this);
|
m_ipc.registerForIPC("urgent", this);
|
||||||
m_ipc.registerForIPC("configreloaded", this);
|
m_ipc.registerForIPC("configreloaded", this);
|
||||||
||||||| parent of 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
gIPC->registerForIPC("workspace", this);
|
|
||||||
gIPC->registerForIPC("activespecial", this);
|
|
||||||
gIPC->registerForIPC("createworkspacev2", this);
|
|
||||||
gIPC->registerForIPC("destroyworkspacev2", this);
|
|
||||||
gIPC->registerForIPC("focusedmon", this);
|
|
||||||
gIPC->registerForIPC("moveworkspace", this);
|
|
||||||
gIPC->registerForIPC("renameworkspace", this);
|
|
||||||
gIPC->registerForIPC("openwindow", this);
|
|
||||||
gIPC->registerForIPC("closewindow", this);
|
|
||||||
gIPC->registerForIPC("movewindow", this);
|
|
||||||
gIPC->registerForIPC("urgent", this);
|
|
||||||
gIPC->registerForIPC("configreloaded", this);
|
|
||||||
=======
|
|
||||||
gIPC->registerForIPC("workspacev2", this);
|
|
||||||
gIPC->registerForIPC("activespecial", this);
|
|
||||||
gIPC->registerForIPC("createworkspacev2", this);
|
|
||||||
gIPC->registerForIPC("destroyworkspacev2", this);
|
|
||||||
gIPC->registerForIPC("focusedmon", this);
|
|
||||||
gIPC->registerForIPC("moveworkspace", this);
|
|
||||||
gIPC->registerForIPC("renameworkspace", this);
|
|
||||||
gIPC->registerForIPC("openwindow", this);
|
|
||||||
gIPC->registerForIPC("closewindow", this);
|
|
||||||
gIPC->registerForIPC("movewindow", this);
|
|
||||||
gIPC->registerForIPC("urgent", this);
|
|
||||||
gIPC->registerForIPC("configreloaded", this);
|
|
||||||
>>>>>>> 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
|
|
||||||
if (windowRewriteConfigUsesTitle()) {
|
if (windowRewriteConfigUsesTitle()) {
|
||||||
spdlog::info(
|
spdlog::info(
|
||||||
"Registering for Hyprland's 'windowtitle' events because a user-defined window "
|
"Registering for Hyprland's 'windowtitlev2' events because a user-defined window "
|
||||||
"rewrite rule uses the 'title' field.");
|
"rewrite rule uses the 'title' field.");
|
||||||
m_ipc.registerForIPC("windowtitle", this);
|
m_ipc.registerForIPC("windowtitlev2", this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::removeWorkspacesToRemove() {
|
void Workspaces::removeWorkspacesToRemove() {
|
||||||
for (const auto &workspaceString: m_workspacesToRemove) {
|
for (const auto &workspaceString : m_workspacesToRemove) {
|
||||||
removeWorkspace(workspaceString);
|
removeWorkspace(workspaceString);
|
||||||
}
|
}
|
||||||
m_workspacesToRemove.clear();
|
m_workspacesToRemove.clear();
|
||||||
@ -751,32 +719,27 @@ void Workspaces::removeWorkspacesToRemove() {
|
|||||||
void Workspaces::removeWorkspace(std::string const &workspaceString) {
|
void Workspaces::removeWorkspace(std::string const &workspaceString) {
|
||||||
spdlog::debug("Removing workspace {}", workspaceString);
|
spdlog::debug("Removing workspace {}", workspaceString);
|
||||||
|
|
||||||
int id;
|
// If this succeeds, we have a workspace ID.
|
||||||
std::string name;
|
const auto workspaceId = parseWorkspaceId(workspaceString);
|
||||||
|
|
||||||
try {
|
std::string name;
|
||||||
// If this succeeds, we have a workspace ID.
|
// TODO: At some point we want to support all workspace selectors
|
||||||
id = std::stoi(workspaceString);
|
// This is just a subset.
|
||||||
} catch (const std::exception &e) {
|
// https://wiki.hyprland.org/Configuring/Workspace-Rules/#workspace-selectors
|
||||||
// TODO: At some point we want to support all workspace selectors
|
if (workspaceString.starts_with("special:")) {
|
||||||
// This is just a subset.
|
name = workspaceString.substr(8);
|
||||||
// https://wiki.hyprland.org/Configuring/Workspace-Rules/#workspace-selectors
|
} else if (workspaceString.starts_with("name:")) {
|
||||||
if (workspaceString.starts_with("special:")) {
|
name = workspaceString.substr(5);
|
||||||
name = workspaceString.substr(8);
|
} else {
|
||||||
} else if (workspaceString.starts_with("name:")) {
|
name = workspaceString;
|
||||||
name = workspaceString.substr(5);
|
|
||||||
} else {
|
|
||||||
name = workspaceString;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto workspace =
|
const auto workspace = std::ranges::find_if(m_workspaces, [&](std::unique_ptr<Workspace> &x) {
|
||||||
std::find_if(m_workspaces.begin(), m_workspaces.end(), [&](std::unique_ptr<Workspace> &x) {
|
if (workspaceId.has_value()) {
|
||||||
if (name.empty()) {
|
return *workspaceId == x->id();
|
||||||
return id == x->id();
|
}
|
||||||
}
|
return name == x->name();
|
||||||
return name == x->name();
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (workspace == m_workspaces.end()) {
|
if (workspace == m_workspaces.end()) {
|
||||||
// happens when a workspace on another monitor is destroyed
|
// happens when a workspace on another monitor is destroyed
|
||||||
@ -784,7 +747,8 @@ void Workspaces::removeWorkspace(std::string const &workspaceString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((*workspace)->isPersistentConfig()) {
|
if ((*workspace)->isPersistentConfig()) {
|
||||||
spdlog::trace("Not removing config persistent workspace id={} name={}", (*workspace)->id(), (*workspace)->name());
|
spdlog::trace("Not removing config persistent workspace id={} name={}", (*workspace)->id(),
|
||||||
|
(*workspace)->name());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -808,62 +772,63 @@ void Workspaces::setCurrentMonitorId() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::sortWorkspaces() {
|
void Workspaces::sortWorkspaces() {
|
||||||
std::sort(m_workspaces.begin(), m_workspaces.end(),
|
std::ranges::sort( //
|
||||||
[&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
m_workspaces, [&](std::unique_ptr<Workspace> &a, std::unique_ptr<Workspace> &b) {
|
||||||
// Helper comparisons
|
// Helper comparisons
|
||||||
auto isIdLess = a->id() < b->id();
|
auto isIdLess = a->id() < b->id();
|
||||||
auto isNameLess = a->name() < b->name();
|
auto isNameLess = a->name() < b->name();
|
||||||
|
|
||||||
switch (m_sortBy) {
|
switch (m_sortBy) {
|
||||||
case SortMethod::ID:
|
case SortMethod::ID:
|
||||||
return isIdLess;
|
return isIdLess;
|
||||||
case SortMethod::NAME:
|
case SortMethod::NAME:
|
||||||
return isNameLess;
|
return isNameLess;
|
||||||
case SortMethod::NUMBER:
|
case SortMethod::NUMBER:
|
||||||
try {
|
try {
|
||||||
return std::stoi(a->name()) < std::stoi(b->name());
|
return std::stoi(a->name()) < std::stoi(b->name());
|
||||||
} catch (const std::invalid_argument &) {
|
} catch (const std::invalid_argument &) {
|
||||||
// Handle the exception if necessary.
|
// Handle the exception if necessary.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SortMethod::DEFAULT:
|
case SortMethod::DEFAULT:
|
||||||
default:
|
default:
|
||||||
// Handle the default case here.
|
// Handle the default case here.
|
||||||
// normal -> named persistent -> named -> special -> named special
|
// normal -> named persistent -> named -> special -> named special
|
||||||
|
|
||||||
// both normal (includes numbered persistent) => sort by ID
|
// both normal (includes numbered persistent) => sort by ID
|
||||||
if (a->id() > 0 && b->id() > 0) {
|
if (a->id() > 0 && b->id() > 0) {
|
||||||
return isIdLess;
|
return isIdLess;
|
||||||
}
|
}
|
||||||
|
|
||||||
// one normal, one special => normal first
|
// one normal, one special => normal first
|
||||||
if ((a->isSpecial()) ^ (b->isSpecial())) {
|
if ((a->isSpecial()) ^ (b->isSpecial())) {
|
||||||
return b->isSpecial();
|
return b->isSpecial();
|
||||||
}
|
}
|
||||||
|
|
||||||
// only one normal, one named
|
// only one normal, one named
|
||||||
if ((a->id() > 0) ^ (b->id() > 0)) {
|
if ((a->id() > 0) ^ (b->id() > 0)) {
|
||||||
return a->id() > 0;
|
return a->id() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// both special
|
// both special
|
||||||
if (a->isSpecial() && b->isSpecial()) {
|
if (a->isSpecial() && b->isSpecial()) {
|
||||||
// if one is -99 => put it last
|
// if one is -99 => put it last
|
||||||
if (a->id() == -99 || b->id() == -99) {
|
if (a->id() == -99 || b->id() == -99) {
|
||||||
return b->id() == -99;
|
return b->id() == -99;
|
||||||
}
|
|
||||||
// both are 0 (not yet named persistents) / named specials (-98 <= ID <= -1)
|
|
||||||
return isNameLess;
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort non-special named workspaces by name (ID <= -1377)
|
|
||||||
return isNameLess;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// both are 0 (not yet named persistents) / named specials
|
||||||
|
// (-98 <= ID <= -1)
|
||||||
|
return isNameLess;
|
||||||
|
}
|
||||||
|
|
||||||
// Return a default value if none of the cases match.
|
// sort non-special named workspaces by name (ID <= -1377)
|
||||||
return isNameLess; // You can adjust this to your specific needs.
|
return isNameLess;
|
||||||
});
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a default value if none of the cases match.
|
||||||
|
return isNameLess; // You can adjust this to your specific needs.
|
||||||
|
});
|
||||||
|
|
||||||
for (size_t i = 0; i < m_workspaces.size(); ++i) {
|
for (size_t i = 0; i < m_workspaces.size(); ++i) {
|
||||||
m_box.reorder_child(m_workspaces[i]->button(), i);
|
m_box.reorder_child(m_workspaces[i]->button(), i);
|
||||||
@ -941,22 +906,17 @@ bool Workspaces::updateWindowsToCreate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Workspaces::updateWorkspaceStates() {
|
void Workspaces::updateWorkspaceStates() {
|
||||||
const std::vector<std::string> visibleWorkspaces = getVisibleWorkspaces();
|
const std::vector<int> visibleWorkspaces = getVisibleWorkspaces();
|
||||||
auto updatedWorkspaces = m_ipc.getSocket1JsonReply("workspaces");
|
auto updatedWorkspaces = m_ipc.getSocket1JsonReply("workspaces");
|
||||||
for (auto &workspace : m_workspaces) {
|
for (auto &workspace : m_workspaces) {
|
||||||
workspace->setActive(workspace->id() == m_activeWorkspaceId ||
|
workspace->setActive(
|
||||||
workspace->name() == m_activeSpecialWorkspaceName);
|
workspace->id() == m_activeWorkspaceId ||
|
||||||
<<<<<<< HEAD
|
(workspace->isSpecial() && workspace->name() == m_activeSpecialWorkspaceName));
|
||||||
if (workspace->isActive() && workspace->isUrgent()) {
|
if (workspace->isActive() && workspace->isUrgent()) {
|
||||||
||||||| parent of 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
if (workspace->name() == m_activeWorkspaceName && workspace->isUrgent()) {
|
|
||||||
=======
|
|
||||||
if (workspace->id() == m_activeWorkspaceId && workspace->isUrgent()) {
|
|
||||||
>>>>>>> 24d391b9 (feat(hyprland): support workspacev2)
|
|
||||||
workspace->setUrgent(false);
|
workspace->setUrgent(false);
|
||||||
}
|
}
|
||||||
workspace->setVisible(std::find(visibleWorkspaces.begin(), visibleWorkspaces.end(),
|
workspace->setVisible(std::ranges::find(visibleWorkspaces, workspace->id()) !=
|
||||||
workspace->name()) != visibleWorkspaces.end());
|
visibleWorkspaces.end());
|
||||||
std::string &workspaceIcon = m_iconsMap[""];
|
std::string &workspaceIcon = m_iconsMap[""];
|
||||||
if (m_withIcon) {
|
if (m_withIcon) {
|
||||||
workspaceIcon = workspace->selectIcon(m_iconsMap);
|
workspaceIcon = workspace->selectIcon(m_iconsMap);
|
||||||
@ -994,4 +954,39 @@ int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string Workspaces::makePayload(Args const &...args) {
|
||||||
|
std::ostringstream result;
|
||||||
|
bool first = true;
|
||||||
|
((result << (first ? "" : ",") << args, first = false), ...);
|
||||||
|
return result.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> Workspaces::splitDoublePayload(std::string const &payload) {
|
||||||
|
const std::string part1 = payload.substr(0, payload.find(','));
|
||||||
|
const std::string part2 = payload.substr(part1.size() + 1);
|
||||||
|
return {part1, part2};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::tuple<std::string, std::string, std::string> Workspaces::splitTriplePayload(
|
||||||
|
std::string const &payload) {
|
||||||
|
const size_t firstComma = payload.find(',');
|
||||||
|
const size_t secondComma = payload.find(',', firstComma + 1);
|
||||||
|
|
||||||
|
const std::string part1 = payload.substr(0, firstComma);
|
||||||
|
const std::string part2 = payload.substr(firstComma + 1, secondComma - (firstComma + 1));
|
||||||
|
const std::string part3 = payload.substr(secondComma + 1);
|
||||||
|
|
||||||
|
return {part1, part2, part3};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<int> Workspaces::parseWorkspaceId(std::string const &workspaceIdStr) {
|
||||||
|
try {
|
||||||
|
return workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
|
||||||
|
} catch (std::exception const &e) {
|
||||||
|
spdlog::error("Failed to parse workspace ID: {}", e.what());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace waybar::modules::hyprland
|
} // namespace waybar::modules::hyprland
|
||||||
|
Reference in New Issue
Block a user