diff --git a/src/Hyprpaper.cpp b/src/Hyprpaper.cpp index 8e6fcad..d0bddb6 100644 --- a/src/Hyprpaper.cpp +++ b/src/Hyprpaper.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "render/Egl.hpp" #include "protocols/wayland.hpp" @@ -21,15 +22,11 @@ static void handleGlobal(CCWlRegistry* registry, uint32_t name, const char* inte } else if (strcmp(interface, wl_shm_interface.name) == 0) { g_pHyprpaper->m_pSHM = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_shm_interface, 1)); } else if (strcmp(interface, wl_output_interface.name) == 0) { - g_pHyprpaper->m_mtTickMutex.lock(); - const auto PMONITOR = g_pHyprpaper->m_vMonitors.emplace_back(std::make_unique()).get(); PMONITOR->wayland_name = name; PMONITOR->name = ""; PMONITOR->output = makeShared((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_output_interface, 4)); PMONITOR->registerListeners(); - - g_pHyprpaper->m_mtTickMutex.unlock(); } else if (strcmp(interface, wl_seat_interface.name) == 0) { g_pHyprpaper->createSeat(makeShared((wl_proxy*)wl_registry_bind((wl_registry*)registry->resource(), name, &wl_seat_interface, 1))); } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) { @@ -124,18 +121,66 @@ void CHyprpaper::init() { if (std::any_cast(g_pConfigManager->config->getConfigValue("ipc"))) g_pIPCSocket->initialize(); - do { - std::lock_guard lg(m_mtTickMutex); - tick(true); - } while (wl_display_dispatch(m_sDisplay) != -1); + pollfd pollFDs[] = { + { + .fd = wl_display_get_fd(m_sDisplay), + .events = POLLIN, + }, + { + .fd = g_pIPCSocket->fd, + .events = POLLIN, + }, + }; + + tick(true); + + while (1) { + int ret = poll(pollFDs, 2, 5000 /* 5 seconds, reasonable. Just in case we need to terminate and the signal fails */); + + if (ret < 0) { + if (errno == EINTR) + continue; + + Debug::log(CRIT, "[core] Polling fds failed with {}", errno); + exit(1); + } + + for (size_t i = 0; i < 2; ++i) { + if (pollFDs[i].revents & POLLHUP) { + Debug::log(CRIT, "[core] Disconnected from pollfd id {}", i); + exit(1); + } + } + + if (ret != 0) { + if (pollFDs[0].revents & POLLIN) { // wayland + wl_display_flush(m_sDisplay); + if (wl_display_prepare_read(m_sDisplay) == 0) { + wl_display_read_events(m_sDisplay); + wl_display_dispatch_pending(m_sDisplay); + } else + wl_display_dispatch(m_sDisplay); + } + + if (pollFDs[1].revents & POLLIN) { // socket + if (g_pIPCSocket->parseRequest()) + tick(true); + } + + // finalize wayland dispatching. Dispatch pending on the queue + int ret2 = 0; + do { + ret2 = wl_display_dispatch_pending(m_sDisplay); + wl_display_flush(m_sDisplay); + } while (ret2 > 0); + } + } unlockSingleInstance(); } void CHyprpaper::tick(bool force) { - bool reload = g_pIPCSocket && g_pIPCSocket->mainThreadParseRequest(); - - if (!reload && !force) + if (!force) return; preloadAllWallpapersFromConfig(); @@ -388,7 +433,7 @@ void CHyprpaper::ensureMonitorHasActiveWallpaper(SMonitor* pMonitor) { } void CHyprpaper::createLSForMonitor(SMonitor* pMonitor) { - pMonitor->pCurrentLayerSurface = pMonitor->layerSurfaces.emplace_back(std::make_unique(pMonitor)).get(); + pMonitor->pCurrentLayerSurface = pMonitor->layerSurfaces.emplace_back(makeShared(pMonitor)); } bool CHyprpaper::lockSingleInstance() { diff --git a/src/Hyprpaper.hpp b/src/Hyprpaper.hpp index a5854d6..54ba348 100644 --- a/src/Hyprpaper.hpp +++ b/src/Hyprpaper.hpp @@ -74,8 +74,6 @@ class CHyprpaper { bool lockSingleInstance(); // fails on multi-instance void unlockSingleInstance(); - std::mutex m_mtTickMutex; - SMonitor* m_pLastMonitor = nullptr; private: diff --git a/src/helpers/Monitor.cpp b/src/helpers/Monitor.cpp index e458816..abae60a 100644 --- a/src/helpers/Monitor.cpp +++ b/src/helpers/Monitor.cpp @@ -8,7 +8,6 @@ void SMonitor::registerListeners() { output->setDone([this](CCWlOutput* r) { readyForLS = true; - std::lock_guard lg(g_pHyprpaper->m_mtTickMutex); if (g_pConfigManager) // don't tick if this is the first roundtrip g_pHyprpaper->tick(true); }); diff --git a/src/helpers/Monitor.hpp b/src/helpers/Monitor.hpp index db2577b..ebe250a 100644 --- a/src/helpers/Monitor.hpp +++ b/src/helpers/Monitor.hpp @@ -6,26 +6,26 @@ class CCWlOutput; struct SMonitor { - std::string name = ""; - std::string description = ""; - SP output; - uint32_t wayland_name = 0; - Vector2D size; - int scale; + std::string name = ""; + std::string description = ""; + SP output; + uint32_t wayland_name = 0; + Vector2D size; + int scale; - bool readyForLS = false; - bool hasATarget = true; + bool readyForLS = false; + bool hasATarget = true; - bool wildcard = true; + bool wildcard = true; - uint32_t configureSerial = 0; + uint32_t configureSerial = 0; - bool wantsReload = false; - bool wantsACK = false; - bool initialized = false; + bool wantsReload = false; + bool wantsACK = false; + bool initialized = false; - std::vector> layerSurfaces; - CLayerSurface* pCurrentLayerSurface = nullptr; + std::vector> layerSurfaces; + SP pCurrentLayerSurface = nullptr; - void registerListeners(); + void registerListeners(); }; \ No newline at end of file diff --git a/src/ipc/Socket.cpp b/src/ipc/Socket.cpp index 852b79f..2395342 100644 --- a/src/ipc/Socket.cpp +++ b/src/ipc/Socket.cpp @@ -15,155 +15,134 @@ #include void CIPCSocket::initialize() { - std::thread([&]() { - const auto SOCKET = socket(AF_UNIX, SOCK_STREAM, 0); + fd = 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"); - const auto RUNTIMEdir = getenv("XDG_RUNTIME_DIR"); - const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid); - - const auto USERDIR = RUNTIMEdir ? RUNTIMEdir + std::string{"/hypr/"} : "/run/user/" + USERID + "/hypr/"; - - std::string socketPath = HISenv ? USERDIR + std::string(HISenv) + "/.hyprpaper.sock" : USERDIR + ".hyprpaper.sock"; - - if (!HISenv) - mkdir(USERDIR.c_str(), S_IRWXU); - - 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); - if (ACCEPTEDCONNECTION < 0) { - Debug::log(ERR, "Couldn't listen on the hyprpaper Socket. (3) IPC will not work."); - break; - } else { - do { - Debug::log(LOG, "Accepted incoming socket connection request on fd %i", ACCEPTEDCONNECTION); - std::lock_guard lg(g_pHyprpaper->m_mtTickMutex); - - auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); - readBuffer[messageSize == 1024 ? 1023 : messageSize] = '\0'; - if (messageSize == 0) - break; - std::string request(readBuffer); - - m_szRequest = request; - m_bRequestReady = true; - - g_pHyprpaper->tick(true); - while (!m_bReplyReady) { // wait for Hyprpaper to finish processing the request - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - write(ACCEPTEDCONNECTION, m_szReply.c_str(), m_szReply.length()); - m_bReplyReady = false; - m_szReply = ""; - - } while (1); - Debug::log(LOG, "Closing Accepted Connection"); - close(ACCEPTEDCONNECTION); - } - } - - close(SOCKET); - }).detach(); -} - -bool CIPCSocket::mainThreadParseRequest() { - - if (!m_bRequestReady) - return false; - - std::string copy = m_szRequest; - - if (copy == "") - return false; - - // now we can work on the copy - - Debug::log(LOG, "Received a request: %s", copy.c_str()); - - // set default reply - m_szReply = "ok"; - m_bReplyReady = true; - m_bRequestReady = false; - - // config commands - if (copy.find("wallpaper") == 0 || copy.find("preload") == 0 || copy.find("unload") == 0 || copy.find("reload") == 0) { - - const auto RESULT = g_pConfigManager->config->parseDynamic(copy.substr(0, copy.find_first_of(' ')).c_str(), copy.substr(copy.find_first_of(' ') + 1).c_str()); - - if (RESULT.error) { - m_szReply = RESULT.getError(); - return false; - } - - return true; + if (fd < 0) { + Debug::log(ERR, "Couldn't start the hyprpaper Socket. (1) IPC will not work."); + return; } - if (copy.find("listloaded") == 0) { + sockaddr_un SERVERADDRESS = {.sun_family = AF_UNIX}; + + const auto HISenv = getenv("HYPRLAND_INSTANCE_SIGNATURE"); + const auto RUNTIMEdir = getenv("XDG_RUNTIME_DIR"); + const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid); + + const auto USERDIR = RUNTIMEdir ? RUNTIMEdir + std::string{"/hypr/"} : "/run/user/" + USERID + "/hypr/"; + + std::string socketPath = HISenv ? USERDIR + std::string(HISenv) + "/.hyprpaper.sock" : USERDIR + ".hyprpaper.sock"; + + if (!HISenv) + mkdir(USERDIR.c_str(), S_IRWXU); + + unlink(socketPath.c_str()); + + strcpy(SERVERADDRESS.sun_path, socketPath.c_str()); + + if (bind(fd, (sockaddr*)&SERVERADDRESS, SUN_LEN(&SERVERADDRESS)) < 0) { + Debug::log(ERR, "Couldn't bind the hyprpaper Socket. IPC will not work."); + fd = -1; + return; + } + + // 10 max queued. + listen(fd, 10); + + Debug::log(LOG, "hyprpaper socket started at %s (fd: %i)", socketPath.c_str(), fd); +} + +CIPCSocket::~CIPCSocket() { + if (fd >= 0) + close(fd); +} + +bool CIPCSocket::parseRequest() { + sockaddr_in clientAddress = {}; + socklen_t clientSize = sizeof(clientAddress); + + char readBuffer[1024] = {0}; + + const auto ACCEPTEDCONNECTION = accept(fd, (sockaddr*)&clientAddress, &clientSize); + if (ACCEPTEDCONNECTION < 0) { + Debug::log(ERR, "Couldn't listen on the hyprpaper Socket. (3)"); + return false; + } else { + + Debug::log(LOG, "Accepted incoming socket connection request on fd %i", ACCEPTEDCONNECTION); + std::string body = ""; + do { + auto messageSize = read(ACCEPTEDCONNECTION, readBuffer, 1024); + body += std::string{readBuffer, messageSize}; + if (messageSize < 1024) + break; + } while (1); + + auto reply = processRequest(body); + write(ACCEPTEDCONNECTION, reply.c_str(), reply.length()); + + Debug::log(LOG, "Closing Accepted Connection"); + close(ACCEPTEDCONNECTION); + } + + return true; +} + +std::string CIPCSocket::processRequest(const std::string& body) { + + std::string reply = "ok"; + + Debug::log(LOG, "Received a request: %s", body.c_str()); + + // config commands + if (body.find("wallpaper") == 0 || body.find("preload") == 0 || body.find("unload") == 0 || body.find("reload") == 0) { + + const auto RESULT = g_pConfigManager->config->parseDynamic(body.substr(0, body.find_first_of(' ')).c_str(), body.substr(body.find_first_of(' ') + 1).c_str()); + + if (RESULT.error) + reply = RESULT.getError(); + + return reply; + } + + if (body.find("listloaded") == 0) { const auto numWallpapersLoaded = g_pHyprpaper->m_mWallpaperTargets.size(); Debug::log(LOG, "numWallpapersLoaded: %d", numWallpapersLoaded); - if (numWallpapersLoaded == 0) { - m_szReply = "no wallpapers loaded"; - return false; - } + if (numWallpapersLoaded == 0) + return "no wallpapers loaded"; - m_szReply = ""; + reply = ""; long unsigned int i = 0; for (auto& [name, target] : g_pHyprpaper->m_mWallpaperTargets) { - m_szReply += name; + reply += name; i++; if (i < numWallpapersLoaded) - m_szReply += '\n'; // dont add newline on last entry + reply += '\n'; // dont add newline on last entry } - return true; + return reply; } - if (copy.find("listactive") == 0) { + if (body.find("listactive") == 0) { const auto numWallpapersActive = g_pHyprpaper->m_mMonitorActiveWallpapers.size(); Debug::log(LOG, "numWallpapersActive: %d", numWallpapersActive); - if (numWallpapersActive == 0) { - m_szReply = "no wallpapers active"; - return false; - } + if (numWallpapersActive == 0) + return "no wallpapers active"; - m_szReply = ""; + reply = ""; long unsigned int i = 0; for (auto& [mon, path1] : g_pHyprpaper->m_mMonitorActiveWallpapers) { - m_szReply += mon + " = " + path1; + reply += mon + " = " + path1; i++; if (i < numWallpapersActive) - m_szReply += '\n'; // dont add newline on last entry + reply += '\n'; // dont add newline on last entry } - return true; + return reply; } - m_szReply = "invalid command"; - return false; + return "invalid command"; } diff --git a/src/ipc/Socket.hpp b/src/ipc/Socket.hpp index 1e064da..16874c8 100644 --- a/src/ipc/Socket.hpp +++ b/src/ipc/Socket.hpp @@ -5,17 +5,16 @@ class CIPCSocket { public: + ~CIPCSocket(); + void initialize(); - bool mainThreadParseRequest(); + bool parseRequest(); + + int fd = -1; private: - std::mutex m_mtRequestMutex; - std::string m_szRequest = ""; - std::string m_szReply = ""; - - bool m_bRequestReady = false; - bool m_bReplyReady = false; + std::string processRequest(const std::string& body); }; inline std::unique_ptr g_pIPCSocket; \ No newline at end of file diff --git a/src/render/LayerSurface.cpp b/src/render/LayerSurface.cpp index f05e9cf..e4c969d 100644 --- a/src/render/LayerSurface.cpp +++ b/src/render/LayerSurface.cpp @@ -47,16 +47,18 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { m_pMonitor->initialized = true; Debug::log(LOG, "configure for %s", m_pMonitor->name.c_str()); + + g_pHyprpaper->tick(true); }); pLayerSurface->setClosed([this](CCZwlrLayerSurfaceV1* r) { for (auto& m : g_pHyprpaper->m_vMonitors) { std::erase_if(m->layerSurfaces, [&](const auto& other) { return other.get() == this; }); - if (m->pCurrentLayerSurface == this) { + if (m->pCurrentLayerSurface.get() == this) { if (m->layerSurfaces.empty()) { m->pCurrentLayerSurface = nullptr; } else { - m->pCurrentLayerSurface = m->layerSurfaces.begin()->get(); + m->pCurrentLayerSurface = *m->layerSurfaces.begin(); g_pHyprpaper->recheckMonitor(m.get()); } } @@ -75,7 +77,6 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { if (fScale != SCALE) { fScale = SCALE; - std::lock_guard lg(g_pHyprpaper->m_mtTickMutex); m_pMonitor->wantsReload = true; g_pHyprpaper->tick(true); } @@ -92,6 +93,8 @@ CLayerSurface::CLayerSurface(SMonitor* pMonitor) { CLayerSurface::~CLayerSurface() { // hyprwayland-scanner will send the destructors automatically. Neat. + pLayerSurface->sendDestroy(); + pLayerSurface.reset(); pFractionalScaleInfo.reset(); pViewport.reset(); diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index b6458e6..e7c1081 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -188,8 +188,8 @@ void CRenderer::renderWallpaperForMonitor(SMonitor* pMonitor) { pMonitor->pCurrentLayerSurface->pSurface->sendSetOpaqueRegion(opaqueRegion.get()); if (pMonitor->pCurrentLayerSurface->pFractionalScaleInfo) { - Debug::log(LOG, "Submitting viewport dest size %ix%i for %x", static_cast(std::round(pMonitor->size.x)), static_cast(std::round(pMonitor->size.y)), - pMonitor->pCurrentLayerSurface); + Debug::log(LOG, "Submitting viewport dest size %ix%i for %lx", static_cast(std::round(pMonitor->size.x)), static_cast(std::round(pMonitor->size.y)), + pMonitor->pCurrentLayerSurface.get()); pMonitor->pCurrentLayerSurface->pViewport->sendSetDestination(static_cast(std::round(pMonitor->size.x)), static_cast(std::round(pMonitor->size.y))); } pMonitor->pCurrentLayerSurface->pSurface->sendCommit(); @@ -198,7 +198,7 @@ void CRenderer::renderWallpaperForMonitor(SMonitor* pMonitor) { // check if we dont need to remove a wallpaper if (pMonitor->layerSurfaces.size() > 1) { for (auto it = pMonitor->layerSurfaces.begin(); it != pMonitor->layerSurfaces.end(); it++) { - if (pMonitor->pCurrentLayerSurface != it->get()) { + if (pMonitor->pCurrentLayerSurface != *it) { pMonitor->layerSurfaces.erase(it); break; } @@ -309,7 +309,7 @@ void CRenderer::renderGpu(SMonitor* pMonitor, SP buf) { origin.x = -(PWALLPAPERTARGET->m_vSize.x * scale - DIMENSIONS.x) / 2.0 / scale; } - renderTexture(PWALLPAPERTARGET->gpu.textureID, CBox{origin, PWALLPAPERTARGET->m_vSize * scale}, buf->pixelSize); + renderTexture(PWALLPAPERTARGET->gpu.textureID, CBox{origin * scale, PWALLPAPERTARGET->m_vSize * scale}, buf->pixelSize); // then, any decoration we got from cairo renderTexture(fromTex.texid, {{}, buf->pixelSize}, buf->pixelSize); @@ -328,7 +328,7 @@ void CRenderer::renderGpu(SMonitor* pMonitor, SP buf) { } void CRenderer::renderTexture(GLuint texid, const CBox& box, const Vector2D& viewport) { - CBox renderBox = {{}, viewport}; + CBox renderBox = box; float mtx[9]; float base[9]; diff --git a/src/render/WallpaperTarget.cpp b/src/render/WallpaperTarget.cpp index cdc0764..80ae6cc 100644 --- a/src/render/WallpaperTarget.cpp +++ b/src/render/WallpaperTarget.cpp @@ -6,6 +6,8 @@ #include "Renderer.hpp" CWallpaperTarget::~CWallpaperTarget() { + if (g_pEGL) + g_pEGL->makeCurrent(EGL_NO_SURFACE); if (cpu.cairoSurface) cairo_surface_destroy(cpu.cairoSurface); if (gpu.textureID) @@ -69,6 +71,8 @@ void CWallpaperTarget::create(const std::string& path) { Debug::log(LOG, "GPU mode, uploading the preloaded image into VRAM and deleting from RAM"); + g_pEGL->makeCurrent(EGL_NO_SURFACE); + auto tex = g_pRenderer->glTex(cairo_image_surface_get_data(CAIROSURFACE), m_vSize); gpu.textureID = tex.texid;