From c748f36939cdac74332dde3afb866ad35bea1825 Mon Sep 17 00:00:00 2001 From: vaxerski Date: Tue, 8 Aug 2023 16:16:34 +0200 Subject: [PATCH] internal: add lock files and hyprctl instances --- hyprctl/main.cpp | 92 ++++++++++++++++++++++++++++++++++++++++++++++ src/Compositor.cpp | 21 +++++++++++ src/Compositor.hpp | 5 ++- 3 files changed, 116 insertions(+), 2 deletions(-) diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 31efcd16..76d26e23 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -11,12 +11,16 @@ #include #include #include +#include #include #include #include #include +#include #include +#include +#include const std::string USAGE = R"#(usage: hyprctl [(opt)flags] [command] [(opt)args] @@ -45,6 +49,7 @@ commands: plugin notify globalshortcuts + instances flags: -j -> output in JSON @@ -53,6 +58,20 @@ flags: #define PAD +std::string getFormat(const char* fmt, ...) { + char* outputStr = nullptr; + + va_list args; + va_start(args, fmt); + vasprintf(&outputStr, fmt, args); + va_end(args); + + std::string output = std::string(outputStr); + free(outputStr); + + return output; +} + void request(std::string arg, int minArgs = 0) { const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); @@ -260,6 +279,75 @@ void batchRequest(std::string arg) { request(rq); } +void instancesRequest(bool json) { + std::string result = ""; + + struct SInstanceData { + std::string id; + uint64_t time; + uint64_t pid; + std::string wlSocket; + bool valid = true; + }; + + // gather instance data + std::vector instances; + + for (const auto& el : std::filesystem::directory_iterator("/tmp/hypr")) { + if (el.is_directory()) + continue; + + // read lock + SInstanceData* data = &instances.emplace_back(); + data->id = el.path().string(); + data->id = data->id.substr(data->id.find_last_of('/') + 1, data->id.find(".lock") - data->id.find_last_of('/') - 1); + + data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1)); + + // read file + std::ifstream ifs(el.path().string()); + + int i = 0; + for (std::string line; std::getline(ifs, line); ++i) { + if (i == 0) { + data->pid = std::stoull(line); + } else if (i == 1) { + data->wlSocket = line; + } else + break; + } + + ifs.close(); + } + + std::erase_if(instances, [&](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; }); + + std::sort(instances.begin(), instances.end(), [&](const auto& a, const auto& b) { return a.time < b.time; }); + + if (!json) { + for (auto& el : instances) { + result += getFormat("instance %s:\n\ttime: %llu\n\tpid: %llu\n\twl socket: %s\n\n", el.id.c_str(), el.time, el.pid, el.wlSocket.c_str()); + } + } else { + result += '['; + for (auto& el : instances) { + result += getFormat(R"#( +{ + "instance": "%s", + "time": %llu, + "pid": %llu, + "wl_socket": "%s" +},)#", + el.id.c_str(), el.time, el.pid, el.wlSocket.c_str()); + } + + result.pop_back(); + result += "\n]"; + } + + std::cout << result << "\n"; +} + std::deque splitArgs(int argc, char** argv) { std::deque result; @@ -287,6 +375,7 @@ int main(int argc, char** argv) { std::string fullRequest = ""; std::string fullArgs = ""; const auto ARGS = splitArgs(argc, argv); + bool json = false; for (auto i = 0; i < ARGS.size(); ++i) { if (ARGS[i] == "--") { @@ -298,6 +387,7 @@ int main(int argc, char** argv) { // parse if (ARGS[i] == "-j" && !fullArgs.contains("j")) { fullArgs += "j"; + json = true; } else if (ARGS[i] == "--batch") { fullRequest = "--batch "; } else { @@ -356,6 +446,8 @@ int main(int argc, char** argv) { request(fullRequest); else if (fullRequest.contains("/globalshortcuts")) request(fullRequest); + else if (fullRequest.contains("/instances")) + instancesRequest(json); else if (fullRequest.contains("/switchxkblayout")) request(fullRequest, 2); else if (fullRequest.contains("/seterror")) diff --git a/src/Compositor.cpp b/src/Compositor.cpp index d1124bc1..ec70bb68 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -312,6 +312,8 @@ void CCompositor::cleanup() { if (!m_sWLDisplay || m_bIsShuttingDown) return; + removeLockFile(); + m_bIsShuttingDown = true; #ifdef USES_SYSTEMD @@ -416,6 +418,23 @@ void CCompositor::initManagers(eManagersInitStage stage) { } } +void CCompositor::createLockFile() { + const auto PATH = "/tmp/hypr/" + m_szInstanceSignature + ".lock"; + + std::ofstream ofs(PATH, std::ios::trunc); + + ofs << m_iHyprlandPID << "\n" << m_szWLDisplaySocket << "\n"; + + ofs.close(); +} + +void CCompositor::removeLockFile() { + const auto PATH = "/tmp/hypr/" + m_szInstanceSignature + ".lock"; + + if (std::filesystem::exists(PATH)) + std::filesystem::remove(PATH); +} + void CCompositor::startCompositor() { initAllSignals(); @@ -477,6 +496,8 @@ void CCompositor::startCompositor() { Debug::log(LOG, "systemd integration is baked in but system itself is not booted à la systemd!"); #endif + createLockFile(); + // This blocks until we are done. Debug::log(LOG, "Hyprland is ready, running the event loop!"); wl_display_run(m_sWLDisplay); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 1be02e62..971b0fa2 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -28,8 +28,7 @@ #include "hyprerror/HyprError.hpp" #include "plugins/PluginSystem.hpp" -enum eManagersInitStage -{ +enum eManagersInitStage { STAGE_PRIORITY = 0, STAGE_LATE }; @@ -107,6 +106,8 @@ class CCompositor { void initServer(); void startCompositor(); void cleanup(); + void createLockFile(); + void removeLockFile(); wlr_surface* m_pLastFocus = nullptr; CWindow* m_pLastWindow = nullptr;