diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp index 9cca9792..5b932441 100644 --- a/hyprctl/main.cpp +++ b/hyprctl/main.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -29,7 +30,7 @@ usage: hyprctl [command] [(opt)args] )#"; void request(std::string arg) { - const auto SERVERSOCKET = socket(AF_INET, SOCK_STREAM, 0); + const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SERVERSOCKET < 0) { std::cout << "Couldn't open a socket (1)"; @@ -43,39 +44,12 @@ void request(std::string arg) { return; } - sockaddr_in serverAddress = {0}; - serverAddress.sin_family = AF_INET; - bcopy((char*)SERVER->h_addr, (char*)&serverAddress.sin_addr.s_addr, SERVER->h_length); + sockaddr_un serverAddress = {0}; + serverAddress.sun_family = AF_UNIX; + strcpy(serverAddress.sun_path, "/tmp/hypr/.socket.sock"); - std::ifstream socketPortStream; - socketPortStream.open("/tmp/hypr/.socket"); - - if (!socketPortStream.good()) { - std::cout << "No socket port file (2a)"; - return; - } - - std::string port = ""; - std::getline(socketPortStream, port); - socketPortStream.close(); - - int portInt = 0; - try { - portInt = std::stoi(port.c_str()); - } catch (...) { - std::cout << "Port not an int?! (2b)"; - return; - } - - if (portInt == 0) { - std::cout << "Port not an int?! (2c)"; - return; - } - - serverAddress.sin_port = portInt; - - if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, sizeof(serverAddress)) < 0) { - std::cout << "Couldn't connect to port " << port << " (3) Is Hyprland running?"; + if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) { + std::cout << "Couldn't connect to /tmp/hypr/.socket.sock. (3) Is Hyprland running?"; return; } diff --git a/src/Compositor.cpp b/src/Compositor.cpp index ce807333..c8376c29 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -188,6 +188,10 @@ void CCompositor::startCompositor() { Debug::log(LOG, "Creating the LayoutManager!"); g_pLayoutManager = std::make_unique(); + + Debug::log(LOG, "Creating the EventManager!"); + g_pEventManager = std::make_unique(); + g_pEventManager->startThread(); // // diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 33fe7ba7..fadc4c20 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -14,6 +14,7 @@ #include "managers/LayoutManager.hpp" #include "managers/KeybindManager.hpp" #include "managers/AnimationManager.hpp" +#include "managers/EventManager.hpp" #include "helpers/Monitor.hpp" #include "helpers/Workspace.hpp" #include "Window.hpp" diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 5c4f42c1..2920045b 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -238,28 +239,20 @@ std::string getRequestFromThread(std::string rq) { void HyprCtl::startHyprCtlSocket() { std::thread([&]() { - uint16_t connectPort = 9187; - - const auto SOCKET = socket(AF_INET, SOCK_STREAM, 0); + const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); if (SOCKET < 0) { Debug::log(ERR, "Couldn't start the Hyprland Socket. (1) IPC will not work."); return; } - sockaddr_in SERVERADDRESS = {.sin_family = AF_INET, .sin_port = connectPort, .sin_addr = (in_addr)INADDR_ANY}; + unlink("/tmp/hypr/.socket.sock"); - while(connectPort < 11000) { - if (bind(SOCKET, (sockaddr*)&SERVERADDRESS, sizeof(SERVERADDRESS)) < 0) { - Debug::log(LOG, "IPC: Port %d failed with an error: %s", connectPort, strerror(errno)); - } else { - break; - } + sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; - connectPort++; - SERVERADDRESS.sin_port = connectPort; - } - + strcpy(SERVERADDRESS.sun_path, "/tmp/hypr/.socket.sock"); + + bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); // 10 max queued. listen(SOCKET, 10); @@ -269,12 +262,7 @@ void HyprCtl::startHyprCtlSocket() { char readBuffer[1024] = {0}; - Debug::log(LOG, "Hypr socket started on port %i", connectPort); - - std::string cmd = "rm -f /tmp/hypr/.socket"; - system(cmd.c_str()); // forgive me for using system() but it works and it doesnt matter here that much - cmd = "echo \"" + std::to_string(connectPort) + "\" > /tmp/hypr/.socket"; - system(cmd.c_str()); + Debug::log(LOG, "Hypr socket started."); while(1) { const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); @@ -285,7 +273,7 @@ void HyprCtl::startHyprCtlSocket() { } auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); - readBuffer[messageSize == 1024 ? 1024 : messageSize] = '\0'; + readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0'; std::string request(readBuffer); diff --git a/src/managers/EventManager.cpp b/src/managers/EventManager.cpp new file mode 100644 index 00000000..b4a697ed --- /dev/null +++ b/src/managers/EventManager.cpp @@ -0,0 +1,129 @@ +#include "EventManager.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +CEventManager::CEventManager() { +} + +void CEventManager::startThread() { + std::thread([&]() { + const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + + if (SOCKET < 0) { + Debug::log(ERR, "Couldn't start the Hyprland Socket 2. (1) IPC will not work."); + return; + } + + unlink("/tmp/hypr/.socket2.sock"); + + sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; + strcpy(SERVERADDRESS.sun_path, "/tmp/hypr/.socket2.sock"); + + bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); + + // 10 max queued. + listen(SOCKET, 10); + + char readBuf[1024] = {0}; + + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + + Debug::log(LOG, "Hypr socket 2 started."); + + // set the socket nonblock + int flags = fcntl(SOCKET, F_GETFL, 0); + fcntl(SOCKET, F_SETFL, flags | O_NONBLOCK); + + while (1) { + m_bCanWriteEventQueue = true; + + const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); + + if (ACCEPTEDCONNECTION > 0) { + // new connection! + m_dAcceptedSocketFDs.push_back(ACCEPTEDCONNECTION); + + int flagsNew = fcntl(ACCEPTEDCONNECTION, F_GETFL, 0); + fcntl(ACCEPTEDCONNECTION, F_SETFL, flagsNew | O_NONBLOCK); + + Debug::log(LOG, "Socket 2 accepted a new client at FD %d", ACCEPTEDCONNECTION); + } + + // pong if all FDs valid + for (auto it = m_dAcceptedSocketFDs.begin(); it != m_dAcceptedSocketFDs.end();) { + auto sizeRead = recv(*it, &readBuf, 1024, 0); + + if (sizeRead != 0) { + it++; + continue; + } + + // invalid! + Debug::log(LOG, "Removed invalid socket (2) FD: %d", *it); + it = m_dAcceptedSocketFDs.erase(it); + } + + // valid FDs, check the queue + // don't do anything if main thread is writing to the eventqueue + while (!m_bCanReadEventQueue) { + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + // if we got here, we'll be reading the queue, let's disallow writing + m_bCanWriteEventQueue = false; + + if (m_dQueuedEvents.empty()){ // if queue empty, sleep and ignore + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } + + // write all queued events + for (auto& ev : m_dQueuedEvents) { + std::string eventString = ev.event + ">>" + ev.data; + for (auto& fd : m_dAcceptedSocketFDs) { + write(fd, eventString.c_str(), eventString.length()); + } + } + + m_dQueuedEvents.clear(); + + m_bCanWriteEventQueue = true; + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + close(SOCKET); + }).detach(); +} + +void CEventManager::postEvent(const SHyprIPCEvent event) { + + m_bCanReadEventQueue = false; + if (!m_bCanWriteEventQueue) { + // if we can't write rn, make a thread to write whenever possible, don't block calling events. + std::thread([&](const SHyprIPCEvent ev) { + while(!m_bCanWriteEventQueue) { + std::this_thread::sleep_for(std::chrono::microseconds(200)); + } + + m_dQueuedEvents.push_back(ev); + m_bCanReadEventQueue = true; + }, event).detach(); + } else { + m_dQueuedEvents.push_back(event); + m_bCanReadEventQueue = true; + } +} \ No newline at end of file diff --git a/src/managers/EventManager.hpp b/src/managers/EventManager.hpp new file mode 100644 index 00000000..b5c4d3a6 --- /dev/null +++ b/src/managers/EventManager.hpp @@ -0,0 +1,30 @@ +#pragma once +#include +#include + +#include "../defines.hpp" +#include "../helpers/MiscFunctions.hpp" + +struct SHyprIPCEvent { + std::string event; + std::string data; +}; + +class CEventManager { +public: + CEventManager(); + + void postEvent(const SHyprIPCEvent event); + + void startThread(); + +private: + + bool m_bCanReadEventQueue = true; + bool m_bCanWriteEventQueue = true; + std::deque m_dQueuedEvents; + + std::deque m_dAcceptedSocketFDs; +}; + +inline std::unique_ptr g_pEventManager; \ No newline at end of file diff --git a/src/managers/InputManager.cpp b/src/managers/InputManager.cpp index 6c689c23..b5b8b806 100644 --- a/src/managers/InputManager.cpp +++ b/src/managers/InputManager.cpp @@ -89,6 +89,9 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { // set active workspace and deactivate all other in wlr g_pCompositor->deactivateAllWLRWorkspaces(g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->m_pWlrHandle); wlr_ext_workspace_handle_v1_set_active(g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->m_pWlrHandle, true); + + // event + g_pEventManager->postEvent(SHyprIPCEvent("workspace", g_pCompositor->getWorkspaceByID(PMONITOR->activeWorkspace)->m_szName)); } Vector2D surfaceCoords; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 72daf5ce..d4340545 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -183,6 +183,8 @@ void CKeybindManager::changeworkspace(std::string args) { if (g_pCompositor->getWorkspaceByID(workspaceToChangeTo)) { const auto PMONITOR = g_pCompositor->getMonitorFromID(g_pCompositor->getWorkspaceByID(workspaceToChangeTo)->m_iMonitorID); + const auto PWORKSPACETOCHANGETO = g_pCompositor->getWorkspaceByID(workspaceToChangeTo); + // if it's not visible, make it visible. if (!g_pCompositor->isWorkspaceVisible(workspaceToChangeTo)) { const auto OLDWORKSPACEID = PMONITOR->activeWorkspace; @@ -205,7 +207,7 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->getWorkspaceByID(OLDWORKSPACEID)->startAnim(false, ANIMTOLEFT); // start anim on new workspace - g_pCompositor->getWorkspaceByID(workspaceToChangeTo)->startAnim(true, ANIMTOLEFT); + PWORKSPACETOCHANGETO->startAnim(true, ANIMTOLEFT); } @@ -219,8 +221,8 @@ void CKeybindManager::changeworkspace(std::string args) { g_pCompositor->focusWindow(g_pCompositor->getFirstWindowOnWorkspace(workspaceToChangeTo)); // set active and deactivate all other in wlr - g_pCompositor->deactivateAllWLRWorkspaces(g_pCompositor->getWorkspaceByID(workspaceToChangeTo)->m_pWlrHandle); - wlr_ext_workspace_handle_v1_set_active(g_pCompositor->getWorkspaceByID(workspaceToChangeTo)->m_pWlrHandle, true); + g_pCompositor->deactivateAllWLRWorkspaces(PWORKSPACETOCHANGETO->m_pWlrHandle); + wlr_ext_workspace_handle_v1_set_active(PWORKSPACETOCHANGETO->m_pWlrHandle, true); Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo); @@ -230,6 +232,10 @@ void CKeybindManager::changeworkspace(std::string args) { // mark the monitor dirty g_pHyprRenderer->damageMonitor(PMONITOR); + // Event + if (!m_bSuppressWorkspaceChangeEvents) + g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACETOCHANGETO->m_szName)); + return; } @@ -273,6 +279,10 @@ void CKeybindManager::changeworkspace(std::string args) { // focus (clears the last) g_pInputManager->refocus(); + // Event + if (!m_bSuppressWorkspaceChangeEvents) + g_pEventManager->postEvent(SHyprIPCEvent("workspace", PWORKSPACE->m_szName)); + Debug::log(LOG, "Changed to workspace %i", workspaceToChangeTo); } @@ -376,6 +386,8 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { const auto POLDWORKSPACEONMON = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDONMONITOR); const auto POLDWORKSPACEIDRETURN = g_pCompositor->getWorkspaceByID(OLDWORKSPACEIDRETURN); + m_bSuppressWorkspaceChangeEvents = true; + moveActiveToWorkspace(args); PWORKSPACE = g_pCompositor->getWorkspaceByID(workspaceToMoveTo); @@ -392,6 +404,8 @@ void CKeybindManager::moveActiveToWorkspaceSilent(std::string args) { POLDWORKSPACEONMON->m_vRenderOffset.setValueAndWarp(Vector2D(0, 0)); POLDWORKSPACEONMON->m_fAlpha.setValueAndWarp(255.f); + + m_bSuppressWorkspaceChangeEvents = false; } void CKeybindManager::moveFocusTo(std::string args) { diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index 4317d7f6..b07510d0 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -30,6 +30,8 @@ private: bool handleInternalKeybinds(xkb_keysym_t); + inline static bool m_bSuppressWorkspaceChangeEvents = false; + // -------------- Dispatchers -------------- // static void killActive(std::string); static void spawn(std::string);