Files
illogical-impulse/early/.config/eww/scripts/taskviewlayout.cpp
T
2024-02-22 15:35:06 +07:00

187 lines
6.4 KiB
C++
Executable File

#include <array> // This script tries to show windows of workspaces
#include <cmath> // in a reasonable way in Task View
#include <filesystem> //
#include <fstream> // Goal: all windows on the same row have equal height
#include <iostream> //
#include <memory> //
#include <regex> // binary search -> ok scale
#include <stdexcept> // -> sort small-wide windows -> match pairs -> rows
#include <string>
#include "nlohmann/json.hpp"
using namespace std;
using json = nlohmann::json;
#define COLS 10
#define RES_WIDTH 1920
#define RES_HEIGHT 1080
#define RESERVED_BOTTOM 250
#define SPACING 30
#define TITLEBAR_AND_BORDER_HEIGHT 51
#define MIN_ROW_HEIGHT 186 // 100px (else scroll down)
#define MAX_ROW_HEIGHT 300 // 100px (else scroll down)
const json EMPTY_JSON = R"([])"_json;
const string workspaceInitTemplate = "[]";
int numOfApps[COLS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
string clients;
json clientjson, workspaces;
json workspacesArranged;
string exec(const char* cmd) {
array<char, 128> buffer;
string result;
unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd, "r"), pclose);
if (!pipe) {
throw runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
result += buffer.data();
}
return result;
}
void initWorkspaces() {
int i = 0;
for (int j = 0; j < COLS; j++) {
int workspaceNum = i * COLS + j + 1; // Note: Workspaces are 1-base
string workspaceInitString =
regex_replace(workspaceInitTemplate, regex("__WORKSPACE_ID"),
to_string(workspaceNum));
json thisWorkspaceInit = json::parse(workspaceInitString);
workspaces.push_back(thisWorkspaceInit);
}
}
void addApp(json& client) {
if(string(client["class"]).size() == 0) return;
// Calculate position in overview tile
int workspaceNum = int(client["workspace"]["id"]) - 1; // 1-base to 0-base
if (workspaceNum < 0)
return; // Skip scratchpads/specials, as they have negative ids
int i = workspaceNum / COLS, j = workspaceNum % COLS;
// New JSON for app
json newApp =
R"({"class": "", "workspace": {"id": 8, "name": "8"}, "title": "", "at": [0, 0], "size": [0, 0], "address": [], "icon": ""})"_json;
// Add normal stuff
newApp["class"] = client["class"];
newApp["address"] = client["address"];
newApp["workspace"] = client["workspace"];
newApp["title"] = client["title"];
newApp["size"] = client["size"];
// Icon path
string filename = string("./scripts/cache/" + string(client["class"]));
std::ifstream ifs(filename);
std::string iconpath((std::istreambuf_iterator<char>(ifs)),
(std::istreambuf_iterator<char>()));
while (iconpath.size() > 0 && *iconpath.rbegin() == '\n')
iconpath.pop_back(); // Remove '\n'
newApp["icon"] = iconpath;
// Counting
int size_x = int(newApp["size"][0]);
int size_y = int(newApp["size"][1]);
if (size_x <= size_y * 2) { // Normal
newApp["countAs"] = 1; // count as 1 window
} else { // Very wide
newApp["countAs"] = 2; // count as 2 windows
}
numOfApps[int(newApp["workspace"]["id"]) - 1] += int(newApp["countAs"]);
// Push
workspaces[j].push_back(newApp);
}
void getApps() {
// Get clients
clients = exec("hyprctl clients -j | gojq -c -M");
clientjson = json::parse(clients);
// Access the values
for (json client : clientjson) {
addApp(client);
}
}
void scaleWindows() {
for (int i = 0; i < workspaces.size(); i++) {
if (workspaces[i].size() == 0) {
workspacesArranged.push_back(EMPTY_JSON);
continue;
}
// Declare
int numOfRows = numOfApps[i] > 3 ? int(ceil(sqrt(numOfApps[i]))) : 1;
int winsPerRow = (numOfApps[i] + (numOfRows - 1)) / numOfRows; // ceil
json thisWorkspace = EMPTY_JSON;
for (int i = 0; i < numOfRows; i++) thisWorkspace.push_back(EMPTY_JSON);
int rowHeight =
min(max(MIN_ROW_HEIGHT,
(RES_HEIGHT - RESERVED_BOTTOM - SPACING) / numOfRows -
TITLEBAR_AND_BORDER_HEIGHT - SPACING),
MAX_ROW_HEIGHT);
int thisRowCnt = 0, rowsDone = 0;
// cout << "Workspace " << i + 1 << " | Rows: " << numOfRows
// << " | Per row: " << winsPerRow << '\n';
// Scale
for (json& window : workspaces[i]) {
int cntAs = int(window["countAs"]);
if (cntAs == 1) {
window["size"][0] = int(window["size"][0]) /
(float(window["size"][1]) / rowHeight);
window["size"][1] = rowHeight;
} else { // cntAs == 2
window["size"][1] =
int(float(window["size"][1]) /
(float(window["size"][0]) / (rowHeight * 2)));
window["size"][0] = rowHeight * 2;
}
// int minWidth = string(window["title"]).size() * 9;
// cout << "Window: " << string(window["title"])
// << ", min width: " << minWidth << '\n';
// if (window["size"][0] < minWidth) {
// window["size"][1] = int(window["size"][1]) *
// (float(minWidth) /
// int(window["size"][0]));
// window["size"][0] = minWidth;
// }
// cout << " --> " << window["size"][0] << "x" << window["size"][1]
// << '\n';
thisWorkspace[rowsDone].push_back(window);
thisRowCnt += int(window["countAs"]);
if (thisRowCnt >= winsPerRow) {
rowsDone++;
thisRowCnt = 0;
}
}
workspacesArranged.push_back(thisWorkspace);
}
}
int main(int argc, char* argv[]) {
ios::sync_with_stdio(false);
// Get windows in workspaces, counting
initWorkspaces();
getApps();
// cout << ">>>>>>>> [DEBUG INGO START] >>>>>>>>" << '\n';
// cout << workspaces << '\n';
// cout << "<<<<<<<< [DEBUG INGO END] <<<<<<<<" << '\n' << '\n';
// cout << "# of apps: ";
// for (int i = 0; i < COLS; i++) cout << numOfApps[i] << ' ';
// cout << '\n';
// Scaling, arranging
scaleWindows();
cout << workspacesArranged << '\n';
}