Merge pull request #1376 from languitar/bugfix/sway-workspace-sorting

fix: match sway workspace order with sway one
This commit is contained in:
Alex 2022-01-07 10:30:19 +01:00 committed by GitHub
commit d9b5c2595a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 40 deletions

View File

@ -69,10 +69,6 @@ Addressed by *sway/workspaces*
typeof: string ++
Command to execute when the module is updated.
*numeric-first*: ++
typeof: bool ++
Whether to put workspaces starting with numbers before workspaces that do not start with a number.
*disable-auto-back-and-forth*: ++
typeof: bool ++
Whether to disable *workspace_auto_back_and_forth* when clicking on workspaces. If this is set to *true*, clicking on a workspace you are already on won't do anything, even if *workspace_auto_back_and_forth* is enabled in the Sway configuration.
@ -120,7 +116,6 @@ n.b.: the list of outputs can be obtained from command line using *swaymsg -t ge
"sway/workspaces": {
"disable-scroll": true,
"all-outputs": true,
"numeric-first": false,
"format": "{name}: {icon}",
"format-icons": {
"1": "",

View File

@ -2,6 +2,7 @@
#include <spdlog/spdlog.h>
#include <algorithm>
#include <cctype>
#include <string>
@ -98,6 +99,7 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
Json::Value v;
v["name"] = p_w_name;
v["target_output"] = bar_.output->name;
v["num"] = convertWorkspaceNameToNum(p_w_name);
workspaces_.emplace_back(std::move(v));
break;
}
@ -107,57 +109,59 @@ void Workspaces::onCmd(const struct Ipc::ipc_response &res) {
Json::Value v;
v["name"] = p_w_name;
v["target_output"] = "";
v["num"] = convertWorkspaceNameToNum(p_w_name);
workspaces_.emplace_back(std::move(v));
}
}
}
// config option to sort numeric workspace names before others
bool config_numeric_first = config_["numeric-first"].asBool();
// sway has a defined ordering of workspaces that should be preserved in
// the representation displayed by waybar to ensure that commands such
// as "workspace prev" or "workspace next" make sense when looking at
// the workspace representation in the bar.
// Due to waybar's own feature of persistent workspaces unknown to sway,
// custom sorting logic is necessary to make these workspaces appear
// naturally in the list of workspaces without messing up sway's
// sorting. For this purpose, a custom numbering property is created
// that preserves the order provided by sway while inserting numbered
// persistent workspaces at their natural positions.
//
// All of this code assumes that sway provides numbered workspaces first
// and other workspaces are sorted by their creation time.
//
// In a first pass, the maximum "num" value is computed to enqueue
// unnumbered workspaces behind numbered ones when computing the sort
// attribute.
int max_num = -1;
for (auto & workspace : workspaces_) {
max_num = std::max(workspace["num"].asInt(), max_num);
}
for (auto & workspace : workspaces_) {
auto workspace_num = workspace["num"].asInt();
if (workspace_num > -1) {
workspace["sort"] = workspace_num;
} else {
workspace["sort"] = ++max_num;
}
}
std::sort(workspaces_.begin(),
workspaces_.end(),
[config_numeric_first](const Json::Value &lhs, const Json::Value &rhs) {
// the "num" property (integer type):
// The workspace number or -1 for workspaces that do
// not start with a number.
// 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.
[](const Json::Value &lhs, const Json::Value &rhs) {
auto lname = lhs["name"].asString();
auto rname = rhs["name"].asString();
int l = convertWorkspaceNameToNum(lname);
int r = convertWorkspaceNameToNum(rname);
int l = lhs["sort"].asInt();
int r = rhs["sort"].asInt();
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).
// In case both integers are the same, lexicographical
// sort. The code above already ensure that this will only
// happend in case of explicitly numbered workspaces.
return lname < rname;
}
// one of the workspaces doesn't begin with a number, so
// num is -1.
if (l < 0 || r < 0) {
if (config_numeric_first) {
return r < 0;
}
return l < 0;
}
// both workspaces have a "num" so let's just compare those
return l < r;
});
}
dp.emit();
} catch (const std::exception &e) {