diff --git a/include/modules/sway/workspaces.hpp b/include/modules/sway/workspaces.hpp index 228c71c7..92ec0516 100644 --- a/include/modules/sway/workspaces.hpp +++ b/include/modules/sway/workspaces.hpp @@ -22,6 +22,8 @@ class Workspaces : public AModule, public sigc::trackable { private: static inline const std::string workspace_switch_cmd_ = "workspace --no-auto-back-and-forth \"{}\""; + static int convertWorkspaceNameToNum(std::string name); + void onCmd(const struct Ipc::ipc_response&); void onEvent(const struct Ipc::ipc_response&); bool filterButtons(); diff --git a/src/modules/sway/workspaces.cpp b/src/modules/sway/workspaces.cpp index 5f7c3f61..fc6d5eb8 100644 --- a/src/modules/sway/workspaces.cpp +++ b/src/modules/sway/workspaces.cpp @@ -2,8 +2,27 @@ #include +#include +#include + namespace waybar::modules::sway { +// Helper function to to assign a number to a workspace, just like sway. In fact +// this is taken quite verbatim from `sway/ipc-json.c`. +int Workspaces::convertWorkspaceNameToNum(std::string name) { + if (isdigit(name[0])) { + errno = 0; + char * endptr = NULL; + long long parsed_num = strtoll(name.c_str(), &endptr, 10); + if (errno != 0 || parsed_num > INT32_MAX || parsed_num < 0 || endptr == name.c_str()) { + return -1; + } else { + return (int)parsed_num; + } + } + return -1; +} + Workspaces::Workspaces(const std::string &id, const Bar &bar, const Json::Value &config) : AModule(config, "workspaces", id, false, !config["disable-scroll"].asBool()), bar_(bar), @@ -102,13 +121,29 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) { // the "num" property (integer type): // The workspace number or -1 for workspaces that do // not start with a number. - auto l = lhs["num"].asInt(); - auto r = rhs["num"].asInt(); + // We could rely on sway providing this property: + // + // auto l = lhs["num"].asInt(); + // auto r = rhs["num"].asInt(); + // + // We cannot rely on the "num" property as provided by sway + // via IPC, because persistent workspace might not exist in + // sway's view. However, we need this property also for + // not-yet created persistent workspace. As such, we simply + // duplicate sway's logic of assigning the "num" property + // into waybar (see convertWorkspaceNameToNum). This way the + // sorting should work out even when we include workspaces + // that do not currently exist. + auto lname = lhs["name"].asString(); + auto rname = rhs["name"].asString(); + int l = convertWorkspaceNameToNum(lname); + int r = convertWorkspaceNameToNum(rname); + if (l == r) { // in case both integers are the same, lexicographical // sort. This also covers the case when both don't have a // number (i.e., l == r == -1). - return lhs["name"].asString() < rhs["name"].asString(); + return lname < rname; } // one of the workspaces doesn't begin with a number, so