diff --git a/hyprctl/Makefile b/hyprctl/Makefile new file mode 100644 index 00000000..d279830a --- /dev/null +++ b/hyprctl/Makefile @@ -0,0 +1,4 @@ +clean: + rm -rf ./hyprctl ./hyprctl +all: + g++ -std=c++20 ./main.cpp -o ./hyprctl \ No newline at end of file diff --git a/hyprctl/hyprctl b/hyprctl/hyprctl new file mode 100755 index 00000000..43657fc0 Binary files /dev/null and b/hyprctl/hyprctl differ diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp new file mode 100644 index 00000000..12cac2ce --- /dev/null +++ b/hyprctl/main.cpp @@ -0,0 +1,96 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +const std::string USAGE = R"#( +usage: hyprctl [command] [(opt)args] + + monitors + workspaces + clients +)#"; + +void readReply() { + std::ifstream ifs; + + while (1) { + usleep(1000 * 25); + + ifs.open("/tmp/hypr/.hyprlandrq"); + + if (ifs.good()) { + std::string reply = ""; + std::getline(ifs, reply); + + if (reply.find("RPLY:") != std::string::npos) { + reply = ""; + std::string temp = ""; + while (std::getline(ifs, temp)) + reply += temp + '\n'; + + std::cout << reply; + + unlink("/tmp/hypr/.hyprlandrq"); // cleanup + break; + } + } + } +} + +void requestMonitors() { + std::ofstream ofs; + ofs.open("/tmp/hypr/.hyprlandrq", std::ios::trunc); + + ofs << "R>monitors"; + + ofs.close(); + + readReply(); +} + +void requestClients() { + std::ofstream ofs; + ofs.open("/tmp/hypr/.hyprlandrq", std::ios::trunc); + + ofs << "R>clients"; + + ofs.close(); + + readReply(); +} + +void requestWorkspaces() { + std::ofstream ofs; + ofs.open("/tmp/hypr/.hyprlandrq", std::ios::trunc); + + ofs << "R>workspaces"; + + ofs.close(); + + readReply(); +} + +int main(int argc, char** argv) { + int bflag = 0, sflag = 0, index, c; + + if (argc < 2) { + printf(USAGE.c_str()); + return 1; + } + + if (!strcmp(argv[1], "monitors")) requestMonitors(); + else if (!strcmp(argv[1], "clients")) requestClients(); + else if (!strcmp(argv[1], "workspaces")) requestWorkspaces(); + else { + printf(USAGE.c_str()); + return 1; + } + + return 0; +} \ No newline at end of file diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 27e0d2fd..294ea753 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -1,6 +1,9 @@ #include "Compositor.hpp" CCompositor::CCompositor() { + unlink("/tmp/hypr/hyprland.log"); + unlink("/tmp/hypr/hyprlandd.log"); + unlink("/tmp/hypr/.hyprlandrq"); m_sWLDisplay = wl_display_create(); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp new file mode 100644 index 00000000..1b06617a --- /dev/null +++ b/src/debug/HyprCtl.cpp @@ -0,0 +1,76 @@ +#include "HyprCtl.hpp" + +#include +#include + +#include + +std::string getFormat(const char* fmt, ...) { + char buf[2048] = ""; + + va_list args; + va_start(args, fmt); + + vsprintf(buf, fmt , args); + + va_end(args); + + return std::string(buf); +} + +std::string monitorsRequest() { + std::string result = ""; + for (auto& m : g_pCompositor->m_lMonitors) { + result += getFormat("Monitor %s (ID %i):\n\t%ix%i@%f at %ix%i\n\tactive workspace: %i\n\treserved: %i %i %i %i\n\n", + m.szName.c_str(), m.ID, (int)m.vecSize.x, (int)m.vecSize.y, m.refreshRate, (int)m.vecPosition.x, (int)m.vecPosition.y, m.activeWorkspace, (int)m.vecReservedTopLeft.x, (int)m.vecReservedTopLeft.y, (int)m.vecReservedBottomRight.x, (int)m.vecReservedBottomRight.y); + } + + return result; +} + +std::string clientsRequest() { + std::string result = ""; + for (auto& w : g_pCompositor->m_lWindows) { + result += getFormat("Window %x -> %s:\n\tat: %i,%i\n\tsize: %i, %i\n\tworkspace: %i\n\tfloating: %i\n\n", + &w, w.m_szTitle.c_str(), (int)w.m_vRealPosition.x, (int)w.m_vRealPosition.y, (int)w.m_vRealSize.x, (int)w.m_vRealSize.y, w.m_iWorkspaceID, (int)w.m_bIsFloating); + } + return result; +} + +std::string workspacesRequest() { + std::string result = ""; + for (auto& w : g_pCompositor->m_lWorkspaces) { + result += getFormat("workspace ID %i on monitor %s:\n\twindows: %i\n\thasfullscreen: %i\n\n", + w.ID, g_pCompositor->getMonitorFromID(w.monitorID)->szName.c_str(), g_pCompositor->getWindowsOnWorkspace(w.ID), (int)w.hasFullscreenWindow); + } + return result; +} + +void HyprCtl::tickHyprCtl() { + struct stat buf; + + if (stat("/tmp/hypr/.hyprlandrq", &buf) == 0) { + // file exists, let's open it + + requestStream.open("/tmp/hypr/.hyprlandrq"); + + std::string request = ""; + std::getline(requestStream, request); + + requestStream.close(); + + std::string reply = ""; + if (request == "R>monitors") reply = monitorsRequest(); + if (request == "R>workspaces") reply = workspacesRequest(); + if (request == "R>clients") reply = clientsRequest(); + + if (reply != "") { + std::ofstream ofs; + ofs.open("/tmp/hypr/.hyprlandrq", std::ios::trunc); + ofs << "RPLY:\n" << reply; + ofs.close(); + } + + // the hyprctl app deletes the file when done. + } +} \ No newline at end of file diff --git a/src/debug/HyprCtl.hpp b/src/debug/HyprCtl.hpp new file mode 100644 index 00000000..41303364 --- /dev/null +++ b/src/debug/HyprCtl.hpp @@ -0,0 +1,10 @@ +#pragma once + +#include "../Compositor.hpp" +#include + +namespace HyprCtl { + void tickHyprCtl(); + + inline std::ifstream requestStream; +}; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 3784b342..57016425 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,6 @@ #include "config/ConfigManager.hpp" int main(int argc, char** argv) { - const std::string DEBUGPATH = "/tmp/hypr/hyprland.log"; - const std::string DEBUGPATH2 = "/tmp/hypr/hyprlandd.log"; - unlink(DEBUGPATH2.c_str()); - unlink(DEBUGPATH.c_str()); if (!getenv("XDG_RUNTIME_DIR")) RIP("XDG_RUNTIME_DIR not set!"); diff --git a/src/managers/ThreadManager.cpp b/src/managers/ThreadManager.cpp index 003cb947..0e2e962c 100644 --- a/src/managers/ThreadManager.cpp +++ b/src/managers/ThreadManager.cpp @@ -1,4 +1,5 @@ #include "ThreadManager.hpp" +#include "../debug/HyprCtl.hpp" CThreadManager::CThreadManager() { m_tMainThread = new std::thread([&]() { @@ -20,6 +21,8 @@ void CThreadManager::handle() { while (3.1415f) { g_pConfigManager->tick(); + HyprCtl::tickHyprCtl(); + std::this_thread::sleep_for(std::chrono::microseconds(1000000 / g_pConfigManager->getInt("max_fps"))); } } \ No newline at end of file