From e13715c514a5f895ec78ef19553f09ee73ab933d Mon Sep 17 00:00:00 2001 From: vaxerski <43317083+vaxerski@users.noreply.github.com> Date: Sat, 2 Jul 2022 18:26:59 +0200 Subject: [PATCH] added ipc and dynamic wp changes --- src/Hyprpaper.cpp | 127 +++++++++++++++++++++++++++++------ src/Hyprpaper.hpp | 14 +++- src/config/ConfigManager.cpp | 3 +- src/config/ConfigManager.hpp | 4 ++ src/events/Events.cpp | 6 +- src/helpers/Monitor.hpp | 3 + src/helpers/PoolBuffer.hpp | 10 +-- src/ipc/Socket.cpp | 122 +++++++++++++++++++++++++++++++++ src/ipc/Socket.hpp | 23 +++++++ 9 files changed, 283 insertions(+), 29 deletions(-) create mode 100644 src/ipc/Socket.cpp create mode 100644 src/ipc/Socket.hpp diff --git a/src/Hyprpaper.cpp b/src/Hyprpaper.cpp index 559de83..6f186fe 100644 --- a/src/Hyprpaper.cpp +++ b/src/Hyprpaper.cpp @@ -4,6 +4,7 @@ CHyprpaper::CHyprpaper() { } void CHyprpaper::init() { g_pConfigManager = std::make_unique(); + g_pIPCSocket = std::make_unique(); m_sDisplay = (wl_display *)wl_display_connect(NULL); @@ -15,37 +16,114 @@ void CHyprpaper::init() { preloadAllWallpapersFromConfig(); + g_pIPCSocket->initialize(); + // run wl_registry *registry = wl_display_get_registry(m_sDisplay); wl_registry_add_listener(registry, &Events::registryListener, nullptr); - while (wl_display_dispatch(m_sDisplay) != -1) { - recheckAllMonitors(); + std::thread([&]() { // we dispatch wl events cuz we have to + while (wl_display_dispatch(m_sDisplay) != -1) { + tick(); + } + + m_bShouldExit = true; + }).detach(); + + while (1) { // we also tick every 1ms for socket and other shit's updates + tick(); std::this_thread::sleep_for(std::chrono::milliseconds(1)); + + if (m_bShouldExit) + break; } } +void CHyprpaper::tick() { + m_mtTickMutex.lock(); + + recheckAllMonitors(); + preloadAllWallpapersFromConfig(); + g_pIPCSocket->mainThreadParseRequest(); + + m_mtTickMutex.unlock(); +} + +bool CHyprpaper::isPreloaded(const std::string& path) { + for (auto&[pt, wt] : m_mWallpaperTargets) { + if (pt == path) + return true; + } + + return false; +} + void CHyprpaper::preloadAllWallpapersFromConfig() { + if (g_pConfigManager->m_dRequestedPreloads.empty()) + return; + for (auto& wp : g_pConfigManager->m_dRequestedPreloads) { m_mWallpaperTargets[wp] = CWallpaperTarget(); m_mWallpaperTargets[wp].create(wp); } + + g_pConfigManager->m_dRequestedPreloads.clear(); } void CHyprpaper::recheckAllMonitors() { for (auto& m : m_vMonitors) { - ensureMonitorHasActiveWallpaper(&m); + recheckMonitor(m.get()); + } +} - if (m.wantsACK) { - m.wantsACK = false; - zwlr_layer_surface_v1_ack_configure(m.pLayerSurface, m.configureSerial); - } +void CHyprpaper::recheckMonitor(SMonitor* pMonitor) { + ensureMonitorHasActiveWallpaper(pMonitor); - if (m.wantsReload) { - m.wantsReload = false; - renderWallpaperForMonitor(&m); - } + if (pMonitor->wantsACK) { + pMonitor->wantsACK = false; + zwlr_layer_surface_v1_ack_configure(pMonitor->pLayerSurface, pMonitor->configureSerial); + } + + if (pMonitor->wantsReload) { + pMonitor->wantsReload = false; + renderWallpaperForMonitor(pMonitor); + } +} + +SMonitor* CHyprpaper::getMonitorFromName(const std::string& monname) { + for (auto& m : m_vMonitors) { + if (m->name == monname) + return m.get(); + } + + return nullptr; +} + +void CHyprpaper::clearWallpaperFromMonitor(const std::string& monname) { + + const auto PMONITOR = getMonitorFromName(monname); + + if (!PMONITOR) + return; + + auto it = m_mMonitorActiveWallpaperTargets.find(PMONITOR); + + if (it != m_mMonitorActiveWallpaperTargets.end()) + m_mMonitorActiveWallpaperTargets.erase(it); + + if (PMONITOR->pSurface) { + wl_surface_destroy(PMONITOR->pSurface); + zwlr_layer_surface_v1_destroy(PMONITOR->pLayerSurface); + PMONITOR->pSurface = nullptr; + PMONITOR->pLayerSurface = nullptr; + + PMONITOR->wantsACK = false; + PMONITOR->wantsReload = false; + PMONITOR->initialized = false; + PMONITOR->readyForLS = true; + + wl_display_flush(m_sDisplay); } } @@ -82,8 +160,11 @@ void CHyprpaper::ensureMonitorHasActiveWallpaper(SMonitor* pMonitor) { return; } - // create it for thy - createLSForMonitor(pMonitor); + // create it for thy if it doesnt have + if (!pMonitor->pLayerSurface) + createLSForMonitor(pMonitor); + else + pMonitor->wantsReload = true; } void CHyprpaper::createLSForMonitor(SMonitor* pMonitor) { @@ -120,6 +201,8 @@ void CHyprpaper::createLSForMonitor(SMonitor* pMonitor) { wl_surface_commit(pMonitor->pSurface); wl_region_destroy(PINPUTREGION); + + wl_display_flush(m_sDisplay); } bool CHyprpaper::setCloexec(const int& FD) { @@ -195,13 +278,18 @@ void CHyprpaper::destroyBuffer(SPoolBuffer* pBuffer) { cairo_destroy(pBuffer->cairo); cairo_surface_destroy(pBuffer->surface); munmap(pBuffer->data, pBuffer->size); + + pBuffer->buffer = nullptr; } void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { - SPoolBuffer buffer; - createBuffer(&buffer, pMonitor->size.x * pMonitor->scale, pMonitor->size.y * pMonitor->scale, WL_SHM_FORMAT_ARGB8888); + auto *const PBUFFER = &pMonitor->buffer; - const auto PCAIRO = buffer.cairo; + if (!PBUFFER->buffer) { + createBuffer(PBUFFER, pMonitor->size.x * pMonitor->scale, pMonitor->size.y * pMonitor->scale, WL_SHM_FORMAT_ARGB8888); + } + + const auto PCAIRO = PBUFFER->cairo; cairo_save(PCAIRO); cairo_set_operator(PCAIRO, CAIRO_OPERATOR_CLEAR); cairo_paint(PCAIRO); @@ -239,11 +327,10 @@ void CHyprpaper::renderWallpaperForMonitor(SMonitor* pMonitor) { cairo_paint(PCAIRO); cairo_restore(PCAIRO); + wl_surface_attach(pMonitor->pSurface, PBUFFER->buffer, 0, 0); wl_surface_set_buffer_scale(pMonitor->pSurface, pMonitor->scale); - wl_surface_attach(pMonitor->pSurface, buffer.buffer, 0, 0); - wl_surface_damage_buffer(pMonitor->pSurface, 0, 0, INT32_MAX, INT32_MAX); + wl_surface_damage_buffer(pMonitor->pSurface, 0, 0, pMonitor->size.x, pMonitor->size.y); wl_surface_commit(pMonitor->pSurface); - // we will not reuse the buffer, so destroy it immediately - destroyBuffer(&buffer); + destroyBuffer(PBUFFER); } \ No newline at end of file diff --git a/src/Hyprpaper.hpp b/src/Hyprpaper.hpp index 70ffa06..4e71c24 100644 --- a/src/Hyprpaper.hpp +++ b/src/Hyprpaper.hpp @@ -6,6 +6,8 @@ #include "helpers/Monitor.hpp" #include "events/Events.hpp" #include "helpers/PoolBuffer.hpp" +#include "ipc/Socket.hpp" +#include class CHyprpaper { public: @@ -18,11 +20,13 @@ public: // init the utility CHyprpaper(); void init(); + void tick(); std::unordered_map m_mWallpaperTargets; std::unordered_map m_mMonitorActiveWallpapers; std::unordered_map m_mMonitorActiveWallpaperTargets; - std::vector m_vMonitors; + std::vector> m_mBuffers; + std::vector> m_vMonitors; void preloadAllWallpapersFromConfig(); void recheckAllMonitors(); @@ -33,6 +37,14 @@ public: void destroyBuffer(SPoolBuffer*); int createPoolFile(size_t, std::string&); bool setCloexec(const int&); + void clearWallpaperFromMonitor(const std::string&); + SMonitor* getMonitorFromName(const std::string&); + bool isPreloaded(const std::string&); + void recheckMonitor(SMonitor*); + +private: + std::mutex m_mtTickMutex; + bool m_bShouldExit = false; }; inline std::unique_ptr g_pHyprpaper; \ No newline at end of file diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index cfbdeff..95f0150 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -116,11 +116,12 @@ void CConfigManager::handleWallpaper(const std::string& COMMAND, const std::stri return; } - if (std::find(m_dRequestedPreloads.begin(), m_dRequestedPreloads.end(), WALLPAPER) == m_dRequestedPreloads.end()) { + if (std::find(m_dRequestedPreloads.begin(), m_dRequestedPreloads.end(), WALLPAPER) == m_dRequestedPreloads.end() && !g_pHyprpaper->isPreloaded(WALLPAPER)) { parseError = "wallpaper failed (not preloaded)"; return; } + g_pHyprpaper->clearWallpaperFromMonitor(MONITOR); g_pHyprpaper->m_mMonitorActiveWallpapers[MONITOR] = WALLPAPER; } diff --git a/src/config/ConfigManager.hpp b/src/config/ConfigManager.hpp index c0d0590..b5c8c3a 100644 --- a/src/config/ConfigManager.hpp +++ b/src/config/ConfigManager.hpp @@ -1,6 +1,8 @@ #pragma once #include "../defines.hpp" +class CIPCSocket; + class CConfigManager { public: // gets all the data from the config @@ -17,6 +19,8 @@ private: void handleWallpaper(const std::string&, const std::string&); void handlePreload(const std::string&, const std::string&); + + friend class CIPCSocket; }; inline std::unique_ptr g_pConfigManager; \ No newline at end of file diff --git a/src/events/Events.cpp b/src/events/Events.cpp index 5b28bdb..73dbeb6 100644 --- a/src/events/Events.cpp +++ b/src/events/Events.cpp @@ -26,7 +26,7 @@ void Events::scale(void *data, wl_output *wl_output, int32_t scale) { void Events::name(void *data, wl_output *wl_output, const char *name) { const auto PMONITOR = (SMonitor*)data; - PMONITOR->name = std::string(name); + PMONITOR->name = name; } void Events::description(void *data, wl_output *wl_output, const char *description) { @@ -40,6 +40,7 @@ void Events::ls_configure(void *data, zwlr_layer_surface_v1 *surface, uint32_t s PMONITOR->wantsReload = true; PMONITOR->configureSerial = serial; PMONITOR->wantsACK = true; + PMONITOR->initialized = true; Debug::log(LOG, "configure for %s", PMONITOR->name.c_str()); } @@ -50,8 +51,9 @@ void Events::handleGlobal(void *data, struct wl_registry *registry, uint32_t nam } else if (strcmp(interface, wl_shm_interface.name) == 0) { g_pHyprpaper->m_sSHM = (wl_shm *)wl_registry_bind(registry, name, &wl_shm_interface, 1); } else if (strcmp(interface, wl_output_interface.name) == 0) { - const auto PMONITOR = &g_pHyprpaper->m_vMonitors.emplace_back(); + const auto PMONITOR = g_pHyprpaper->m_vMonitors.emplace_back(std::make_unique()).get(); PMONITOR->wayland_name = name; + PMONITOR->name = ""; PMONITOR->output = (wl_output *)wl_registry_bind(registry, name, &wl_output_interface, 4); wl_output_add_listener(PMONITOR->output, &Events::outputListener, PMONITOR); } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index 4b8ec0e..93027ca 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -1,6 +1,7 @@ #pragma once #include "../defines.hpp" +#include "PoolBuffer.hpp" struct SMonitor { std::string name = ""; @@ -15,7 +16,9 @@ struct SMonitor { zwlr_layer_surface_v1* pLayerSurface = nullptr; wl_surface* pSurface = nullptr; uint32_t configureSerial = 0; + SPoolBuffer buffer; bool wantsReload = false; bool wantsACK = false; + bool initialized = false; }; \ No newline at end of file diff --git a/src/helpers/PoolBuffer.hpp b/src/helpers/PoolBuffer.hpp index 4f1f870..35b9703 100644 --- a/src/helpers/PoolBuffer.hpp +++ b/src/helpers/PoolBuffer.hpp @@ -3,9 +3,9 @@ #include "../defines.hpp" struct SPoolBuffer { - wl_buffer* buffer; - cairo_surface_t *surface; - cairo_t *cairo; - void* data; - size_t size; + wl_buffer* buffer = nullptr; + cairo_surface_t* surface = nullptr; + cairo_t* cairo = nullptr; + void* data = nullptr; + size_t size = 0; }; \ No newline at end of file diff --git a/src/ipc/Socket.cpp b/src/ipc/Socket.cpp new file mode 100644 index 0000000..71053f7 --- /dev/null +++ b/src/ipc/Socket.cpp @@ -0,0 +1,122 @@ +#include "Socket.hpp" +#include "../Hyprpaper.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void CIPCSocket::initialize() { + std::thread([&]() { + const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + + if (SOCKET < 0) { + Debug::log(ERR, "Couldn't start the hyprpaper Socket. (1) IPC will not work."); + return; + } + + sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; + + const auto HISenv = getenv("HYPRLAND_INSTANCE_SIGNATURE"); + + std::string socketPath = HISenv ? "/tmp/hypr/" + std::string(HISenv) + "/.hyprpaper.sock" : "/tmp/hypr/.hyprpaper.sock"; + + if (!HISenv) { + mkdir("/tmp/hypr", S_IRWXU | S_IRWXG); + } + + unlink(socketPath.c_str()); + + strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); + + bind(SOCKET, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)); + + // 10 max queued. + listen(SOCKET, 10); + + sockaddr_in clientAddress; + socklen_t clientSize = sizeof(clientAddress); + + char readBuffer[1024] = {0}; + + Debug::log(LOG, "hyprpaper socket started at %s (fd: %i)", socketPath.c_str(), SOCKET); + + while(1) { + const auto ACCEPTEDCONNECTION = accept(SOCKET, (sockaddr*)&clientAddress, &clientSize); + + Debug::log(LOG, "Accepted incoming socket connection request on fd %i", ACCEPTEDCONNECTION); + + if (ACCEPTEDCONNECTION < 0) { + Debug::log(ERR, "Couldn't listen on the hyprpaper Socket. (3) IPC will not work."); + break; + } + + auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); + readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0'; + + std::string request(readBuffer); + + m_szRequest = request; + m_bRequestReady = true; + + while (1) { + if (m_bReplyReady) + break; + + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + } + + write(ACCEPTEDCONNECTION, m_szReply.c_str(), m_szReply.length()); + + close(ACCEPTEDCONNECTION); + + m_bReplyReady = false; + m_szReply = ""; + } + + close(SOCKET); + }).detach(); +} + +void CIPCSocket::mainThreadParseRequest() { + + if (!m_bRequestReady) + return; + + std::string copy = m_szRequest; + + // now we can work on the copy + + if (copy == "") + return; + + Debug::log(LOG, "Received a request: %s", copy.c_str()); + + // parse + if (copy.find("wallpaper") == 0 || copy.find("preload") == 0) { + g_pConfigManager->parseKeyword(copy.substr(0, copy.find_first_of(' ')), copy.substr(copy.find_first_of(' ') + 1)); + + if (g_pConfigManager->parseError != "") { + m_szReply = g_pConfigManager->parseError; + m_bReplyReady = true; + m_bRequestReady = false; + return; + } + } + else { + m_szReply = "invalid command"; + m_bReplyReady = true; + m_bRequestReady = false; + return; + } + + m_szReply = "ok"; + m_bReplyReady = true; + m_bRequestReady = false; +} \ No newline at end of file diff --git a/src/ipc/Socket.hpp b/src/ipc/Socket.hpp new file mode 100644 index 0000000..985e53a --- /dev/null +++ b/src/ipc/Socket.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include "../defines.hpp" +#include + +class CIPCSocket { +public: + void initialize(); + + void mainThreadParseRequest(); + +private: + + std::mutex m_mtRequestMutex; + std::string m_szRequest = ""; + std::string m_szReply = ""; + + bool m_bRequestReady = false; + bool m_bReplyReady = false; + +}; + +inline std::unique_ptr g_pIPCSocket; \ No newline at end of file