Skip to content

Commit f4255c0

Browse files
committed
fix(hyprland): support additional v2 events
1 parent 24d391b commit f4255c0

File tree

1 file changed

+100
-67
lines changed

1 file changed

+100
-67
lines changed

src/modules/hyprland/workspaces.cpp

+100-67
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
namespace waybar::modules::hyprland {
1414

15+
constexpr int INVALID_WORKSPACE_ID = -100;
16+
1517
Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config)
1618
: AModule(config, "workspaces", id, false, false), m_bar(bar), m_box(bar.orientation, 0) {
1719
modulesReady = true;
@@ -50,13 +52,12 @@ Json::Value Workspaces::createMonitorWorkspaceData(std::string const &name,
5052
std::string const &monitor) {
5153
spdlog::trace("Creating persistent workspace: {} on monitor {}", name, monitor);
5254
Json::Value workspaceData;
53-
try {
54-
// numbered persistent workspaces get the name as ID
55-
workspaceData["id"] = name == "special" ? -99 : std::stoi(name);
56-
} catch (const std::exception &e) {
57-
// named persistent workspaces start with ID=0
58-
workspaceData["id"] = 0;
55+
56+
auto workspaceId = getWorkspaceId(name);
57+
if (workspaceId == INVALID_WORKSPACE_ID) {
58+
workspaceId = 0
5959
}
60+
workspaceData["id"] = workspaceId
6061
workspaceData["name"] = name;
6162
workspaceData["monitor"] = monitor;
6263
workspaceData["windows"] = 0;
@@ -67,6 +68,7 @@ void Workspaces::createWorkspace(Json::Value const &workspace_data,
6768
Json::Value const &clients_data) {
6869
auto workspaceName = workspace_data["name"].asString();
6970
spdlog::debug("Creating workspace {}", workspaceName);
71+
7072

7173
// avoid recreating existing workspaces
7274
auto workspace = std::find_if(
@@ -325,21 +327,21 @@ void Workspaces::onEvent(const std::string &ev) {
325327
onWorkspaceDestroyed(payload);
326328
} else if (eventName == "createworkspacev2") {
327329
onWorkspaceCreated(payload);
328-
} else if (eventName == "focusedmon") {
330+
} else if (eventName == "focusedmonv2") {
329331
onMonitorFocused(payload);
330-
} else if (eventName == "moveworkspace") {
332+
} else if (eventName == "moveworkspacev2") {
331333
onWorkspaceMoved(payload);
332334
} else if (eventName == "openwindow") {
333335
onWindowOpened(payload);
334336
} else if (eventName == "closewindow") {
335337
onWindowClosed(payload);
336-
} else if (eventName == "movewindow") {
338+
} else if (eventName == "movewindowv2") {
337339
onWindowMoved(payload);
338340
} else if (eventName == "urgent") {
339341
setUrgentWorkspace(payload);
340342
} else if (eventName == "renameworkspace") {
341343
onWorkspaceRenamed(payload);
342-
} else if (eventName == "windowtitle") {
344+
} else if (eventName == "windowtitlev2") {
343345
onWindowTitleEvent(payload);
344346
} else if (eventName == "configreloaded") {
345347
onConfigReloaded();
@@ -349,8 +351,11 @@ void Workspaces::onEvent(const std::string &ev) {
349351
}
350352

351353
void Workspaces::onWorkspaceActivated(std::string const &payload) {
352-
std::string workspaceIdStr = payload.substr(0, payload.find(','));
353-
m_activeWorkspaceId = std::stoi(workspaceIdStr);
354+
auto [workspaceIdStr, _] = splitDoublePayload(payload);
355+
auto workspaceId = getWorkspaceId(workspaceIdStr);
356+
if (workspaceId != INVALID_WORKSPACE_ID) {
357+
m_activeWorkspaceId = workspaceId;
358+
}
354359
}
355360

356361
void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
@@ -359,18 +364,22 @@ void Workspaces::onSpecialWorkspaceActivated(std::string const &payload) {
359364
}
360365

361366
void Workspaces::onWorkspaceDestroyed(std::string const &payload) {
362-
std::string workspaceIdStr = payload.substr(0, payload.find(','));
363-
std::string workspaceName = payload.substr(workspaceIdStr.size() + 1);
367+
auto [workspaceId, workspaceName] = splitDoublePayload(payload);
364368
if (!isDoubleSpecial(workspaceName)) {
365-
m_workspacesToRemove.push_back(workspaceIdStr);
369+
m_workspacesToRemove.push_back(workspaceId);
366370
}
367371
}
368372

369373
void Workspaces::onWorkspaceCreated(std::string const &payload,
370374
Json::Value const &clientsData) {
371375
spdlog::debug("Workspace created: {}", payload);
372-
std::string workspaceIdStr = payload.substr(0, payload.find(','));
373-
int workspaceId = std::stoi(workspaceIdStr);
376+
377+
auto [workspaceIdStr, _] = splitDoublePayload(payload);
378+
379+
auto workspaceId = getWorkspaceId(workspaceIdStr);
380+
if (workspaceId == INVALID_WORKSPACE_ID) {
381+
return;
382+
}
374383

375384
auto const workspaceRules = gIPC->getSocket1JsonReply("workspacerules");
376385
auto const workspacesJson = gIPC->getSocket1JsonReply("workspaces");
@@ -412,23 +421,26 @@ void Workspaces::onWorkspaceMoved(std::string const &payload) {
412421

413422
if (allOutputs()) return;
414423

415-
std::string workspaceName = payload.substr(0, payload.find(','));
416-
std::string monitorName = payload.substr(payload.find(',') + 1);
424+
auto [workspaceIdStr, workspaceName, monitorName] = splitTriplePayload(payload);
425+
426+
auto subPayload = joinDoublePayload(workspaceIdStr, workspaceName);
417427

418428
if (m_bar.output->name == monitorName) {
419429
Json::Value clientsData = gIPC->getSocket1JsonReply("clients");
420-
onWorkspaceCreated(workspaceName, clientsData);
430+
onWorkspaceCreated(subPayload, clientsData);
421431
} else {
422-
spdlog::debug("Removing workspace because it was moved to another monitor: {}");
423-
onWorkspaceDestroyed(workspaceName);
432+
spdlog::debug("Removing workspace because it was moved to another monitor: {}", subPayload);
433+
onWorkspaceDestroyed(subPayload);
424434
}
425435
}
426436

427437
void Workspaces::onWorkspaceRenamed(std::string const &payload) {
428438
spdlog::debug("Workspace renamed: {}", payload);
429-
std::string workspaceIdStr = payload.substr(0, payload.find(','));
430-
int workspaceId = workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
431-
std::string newName = payload.substr(payload.find(',') + 1);
439+
auto [workspaceIdStr, newName] = splitDoublePayload(payload);
440+
441+
auto workspaceId = getWorkspaceId(workspaceIdStr);
442+
if (workspaceId == INVALID_WORKSPACE_ID) return;
443+
432444
for (auto &workspace : m_workspaces) {
433445
if (workspace->id() == workspaceId) {
434446
workspace->setName(newName);
@@ -441,18 +453,15 @@ void Workspaces::onWorkspaceRenamed(std::string const &payload) {
441453
void Workspaces::onMonitorFocused(std::string const &payload) {
442454
spdlog::trace("Monitor focused: {}", payload);
443455

444-
std::string workspaceName = payload.substr(payload.find(',') + 1);
456+
auto [monitorName, workspaceIdStr] = splitDoublePayload(payload);
445457

446-
// TODO this will be in the payload when we upgrade to focusedmonv2
447-
for (auto &workspace : m_workspaces) {
448-
if (workspace->name() == workspaceName) {
449-
m_activeWorkspaceId = workspace->id();
450-
break;
451-
}
452-
}
458+
auto workspaceId = getWorkspaceId(workspaceIdStr);
459+
if (workspaceId == INVALID_WORKSPACE_ID) return;
460+
461+
m_activeWorkspaceId = workspaceId;
453462

454463
for (Json::Value &monitor : gIPC->getSocket1JsonReply("monitors")) {
455-
if (monitor["name"].asString() == payload.substr(0, payload.find(','))) {
464+
if (monitor["name"].asString() == monitorName) {
456465
auto name = monitor["specialWorkspace"]["name"].asString();
457466
m_activeSpecialWorkspaceName = !name.starts_with("special:") ? name : name.substr(8);
458467
}
@@ -492,13 +501,7 @@ void Workspaces::onWindowClosed(std::string const &addr) {
492501
void Workspaces::onWindowMoved(std::string const &payload) {
493502
spdlog::trace("Window moved: {}", payload);
494503
updateWindowCount();
495-
size_t lastCommaIdx = 0;
496-
size_t nextCommaIdx = payload.find(',');
497-
std::string windowAddress = payload.substr(lastCommaIdx, nextCommaIdx - lastCommaIdx);
498-
499-
std::string workspaceName = payload.substr(nextCommaIdx + 1, payload.length() - nextCommaIdx);
500-
501-
std::string windowRepr;
504+
auto [windowAddress, _, workspaceName] = splitTriplePayload(payload);
502505

503506
// If the window was still queued to be created, just change its destination
504507
// and exit
@@ -532,13 +535,15 @@ void Workspaces::onWindowTitleEvent(std::string const &payload) {
532535
spdlog::trace("Window title changed: {}", payload);
533536
std::optional<std::function<void(WindowCreationPayload)>> inserter;
534537

538+
auto [windowAddress, _] = splitDoublePayload(payload);
539+
535540
// If the window was an orphan, rename it at the orphan's vector
536-
if (m_orphanWindowMap.contains(payload)) {
541+
if (m_orphanWindowMap.contains(windowAddress)) {
537542
inserter = [this](WindowCreationPayload wcp) { this->registerOrphanWindow(std::move(wcp)); };
538543
} else {
539544
auto windowWorkspace =
540545
std::find_if(m_workspaces.begin(), m_workspaces.end(),
541-
[payload](auto &workspace) { return workspace->containsWindow(payload); });
546+
[windowAddress](auto &workspace) { return workspace->containsWindow(windowAddress); });
542547

543548
// If the window exists on a workspace, rename it at the workspace's window
544549
// map
@@ -681,20 +686,20 @@ auto Workspaces::registerIpc() -> void {
681686
gIPC->registerForIPC("activespecial", this);
682687
gIPC->registerForIPC("createworkspacev2", this);
683688
gIPC->registerForIPC("destroyworkspacev2", this);
684-
gIPC->registerForIPC("focusedmon", this);
685-
gIPC->registerForIPC("moveworkspace", this);
689+
gIPC->registerForIPC("focusedmonv2", this);
690+
gIPC->registerForIPC("moveworkspacev2", this);
686691
gIPC->registerForIPC("renameworkspace", this);
687692
gIPC->registerForIPC("openwindow", this);
688693
gIPC->registerForIPC("closewindow", this);
689-
gIPC->registerForIPC("movewindow", this);
694+
gIPC->registerForIPC("movewindowv2", this);
690695
gIPC->registerForIPC("urgent", this);
691696
gIPC->registerForIPC("configreloaded", this);
692697

693698
if (windowRewriteConfigUsesTitle()) {
694699
spdlog::info(
695-
"Registering for Hyprland's 'windowtitle' events because a user-defined window "
700+
"Registering for Hyprland's 'windowtitlev2' events because a user-defined window "
696701
"rewrite rule uses the 'title' field.");
697-
gIPC->registerForIPC("windowtitle", this);
702+
gIPC->registerForIPC("windowtitlev2", this);
698703
}
699704
}
700705

@@ -708,31 +713,29 @@ void Workspaces::removeWorkspacesToRemove() {
708713
void Workspaces::removeWorkspace(std::string const &workspaceString) {
709714
spdlog::debug("Removing workspace {}", workspaceString);
710715

711-
int id;
712-
std::string name;
713716

714-
try {
715-
// If this succeeds, we have a workspace ID.
716-
id = std::stoi(workspaceString);
717-
} catch (const std::exception &e) {
718-
// TODO: At some point we want to support all workspace selectors
719-
// This is just a subset.
720-
// https://wiki.hyprland.org/Configuring/Workspace-Rules/#workspace-selectors
721-
if (workspaceString.starts_with("special:")) {
722-
name = workspaceString.substr(8);
723-
} else if (workspaceString.starts_with("name:")) {
724-
name = workspaceString.substr(5);
725-
} else {
726-
name = workspaceString;
727-
}
717+
// If this succeeds, we have a workspace ID.
718+
int id = getWorkspaceId(workspaceString);
719+
auto matchByName = id == INVALID_WORKSPACE_ID;
720+
721+
std::string name;
722+
// TODO: At some point we want to support all workspace selectors
723+
// This is just a subset.
724+
// https://wiki.hyprland.org/Configuring/Workspace-Rules/#workspace-selectors
725+
if (workspaceString.starts_with("special:")) {
726+
name = workspaceString.substr(8);
727+
} else if (workspaceString.starts_with("name:")) {
728+
name = workspaceString.substr(5);
729+
} else {
730+
name = workspaceString;
728731
}
729732

730733
auto workspace =
731734
std::find_if(m_workspaces.begin(), m_workspaces.end(), [&](std::unique_ptr<Workspace> &x) {
732-
if (name.empty()) {
733-
return id == x->id();
735+
if (matchByName) {
736+
return name == x->name();
734737
}
735-
return name == x->name();
738+
return id == x->id();
736739
});
737740

738741
if (workspace == m_workspaces.end()) {
@@ -945,4 +948,34 @@ int Workspaces::windowRewritePriorityFunction(std::string const &window_rule) {
945948
return 0;
946949
}
947950

951+
std::string Workspaces::joinDoublePayload(std::string const &part1, std::string const &part2) {
952+
return part1 + "," + part2;
953+
}
954+
955+
std::pair<std::string, std::string> Workspaces::splitDoublePayload(std::string const &payload) {
956+
std::string part1 = payload.substr(0, payload.find(','));
957+
std::string part2 = payload.substr(part1.size() + 1);
958+
return {part1, part2};
959+
}
960+
961+
std::tuple<std::string, std::string, std::string> Workspaces::splitTriplePayload(std::string const &payload) {
962+
size_t firstComma = payload.find(',');
963+
size_t secondComma = payload.find(',', firstComma + 1);
964+
965+
std::string part1 = payload.substr(0, firstComma);
966+
std::string part2 = payload.substr(firstComma + 1, secondComma - (firstComma + 1));
967+
std::string part3 = payload.substr(secondComma + 1);
968+
969+
return {part1, part2, part3};
970+
}
971+
972+
std::int Workspaces::getWorkspaceId(std::string const &workspaceIdStr) {
973+
try {
974+
return workspaceIdStr == "special" ? -99 : std::stoi(workspaceIdStr);
975+
} catch (std::exception const &e) {
976+
spdlog::error("Failed to parse workspace ID: {}", e.what());
977+
return INVALID_WORKSPACE_ID;
978+
}
979+
}
980+
948981
} // namespace waybar::modules::hyprland

0 commit comments

Comments
 (0)