summaryrefslogtreecommitdiff
path: root/hyprctl/src/hyprpaper/Hyprpaper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'hyprctl/src/hyprpaper/Hyprpaper.cpp')
-rw-r--r--hyprctl/src/hyprpaper/Hyprpaper.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/hyprctl/src/hyprpaper/Hyprpaper.cpp b/hyprctl/src/hyprpaper/Hyprpaper.cpp
new file mode 100644
index 00000000..afa7f653
--- /dev/null
+++ b/hyprctl/src/hyprpaper/Hyprpaper.cpp
@@ -0,0 +1,148 @@
+#include "Hyprpaper.hpp"
+#include "../helpers/Memory.hpp"
+
+#include <optional>
+#include <format>
+#include <filesystem>
+
+#include <hyprpaper_core-client.hpp>
+
+#include <hyprutils/string/VarList2.hpp>
+using namespace Hyprutils::String;
+
+using namespace std::string_literals;
+
+constexpr const char* SOCKET_NAME = ".hyprpaper.sock";
+static SP<CCHyprpaperCoreImpl> g_coreImpl;
+
+constexpr const uint32_t PROTOCOL_VERSION_SUPPORTED = 1;
+
+//
+static hyprpaperCoreWallpaperFitMode fitFromString(const std::string_view& sv) {
+ if (sv == "contain")
+ return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_CONTAIN;
+ if (sv == "fit" || sv == "stretch")
+ return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_STRETCH;
+ if (sv == "tile")
+ return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_TILE;
+ return HYPRPAPER_CORE_WALLPAPER_FIT_MODE_COVER;
+}
+
+static std::expected<std::string, std::string> resolvePath(const std::string_view& sv) {
+ std::error_code ec;
+ auto can = std::filesystem::canonical(sv, ec);
+
+ if (ec)
+ return std::unexpected(std::format("invalid path: {}", ec.message()));
+
+ return can;
+}
+
+static std::expected<std::string, std::string> getFullPath(const std::string_view& sv) {
+ if (sv.empty())
+ return std::unexpected("empty path");
+
+ if (sv[0] == '~') {
+ static auto HOME = getenv("HOME");
+ if (!HOME || HOME[0] == '\0')
+ return std::unexpected("home path but no $HOME");
+
+ return resolvePath(std::string{HOME} + "/"s + std::string{sv.substr(1)});
+ }
+
+ return resolvePath(sv);
+}
+
+std::expected<void, std::string> Hyprpaper::makeHyprpaperRequest(const std::string_view& rq) {
+ if (!rq.contains(' '))
+ return std::unexpected("Invalid request");
+
+ if (!rq.starts_with("/hyprpaper "))
+ return std::unexpected("Invalid request");
+
+ std::string_view LHS, RHS;
+ auto spacePos = rq.find(' ', 12);
+ LHS = rq.substr(11, spacePos - 11);
+ RHS = rq.substr(spacePos + 1);
+
+ if (LHS != "wallpaper")
+ return std::unexpected("Unknown hyprpaper request");
+
+ CVarList2 args(std::string{RHS}, 0, ',');
+
+ const std::string MONITOR = std::string{args[0]};
+ const auto& PATH_RAW = args[1];
+ const auto& FIT = args[2];
+
+ if (PATH_RAW.empty())
+ return std::unexpected("not enough args");
+
+ const auto RTDIR = getenv("XDG_RUNTIME_DIR");
+
+ if (!RTDIR || RTDIR[0] == '\0')
+ return std::unexpected("can't send: no XDG_RUNTIME_DIR");
+
+ const auto HIS = getenv("HYPRLAND_INSTANCE_SIGNATURE");
+
+ if (!HIS || HIS[0] == '\0')
+ return std::unexpected("can't send: no HYPRLAND_INSTANCE_SIGNATURE (not running under hyprland)");
+
+ const auto PATH = getFullPath(PATH_RAW);
+
+ if (!PATH)
+ return std::unexpected(std::format("bad path: {}", PATH_RAW));
+
+ auto socketPath = RTDIR + "/hypr/"s + HIS + "/"s + SOCKET_NAME;
+
+ auto socket = Hyprwire::IClientSocket::open(socketPath);
+
+ if (!socket)
+ return std::unexpected("can't send: failed to connect to hyprpaper (is it running?)");
+
+ g_coreImpl = makeShared<CCHyprpaperCoreImpl>(1);
+
+ socket->addImplementation(g_coreImpl);
+
+ if (!socket->waitForHandshake())
+ return std::unexpected("can't send: wire handshake failed");
+
+ auto spec = socket->getSpec(g_coreImpl->protocol()->specName());
+
+ if (!spec)
+ return std::unexpected("can't send: hyprpaper doesn't have the spec?!");
+
+ auto manager = makeShared<CCHyprpaperCoreManagerObject>(socket->bindProtocol(g_coreImpl->protocol(), PROTOCOL_VERSION_SUPPORTED));
+
+ if (!manager)
+ return std::unexpected("wire error: couldn't create manager");
+
+ auto wallpaper = makeShared<CCHyprpaperWallpaperObject>(manager->sendGetWallpaperObject());
+
+ if (!wallpaper)
+ return std::unexpected("wire error: couldn't create wallpaper object");
+
+ bool canExit = false;
+ std::optional<std::string> err;
+
+ wallpaper->setFailed([&canExit, &err](uint32_t code) {
+ canExit = true;
+ err = std::format("failed to set wallpaper, code {}", code);
+ });
+ wallpaper->setSuccess([&canExit]() { canExit = true; });
+
+ wallpaper->sendPath(PATH->c_str());
+ wallpaper->sendMonitorName(MONITOR.c_str());
+ if (!FIT.empty())
+ wallpaper->sendFitMode(fitFromString(FIT));
+
+ wallpaper->sendApply();
+
+ while (!canExit) {
+ socket->dispatchEvents(true);
+ }
+
+ if (err)
+ return std::unexpected(*err);
+
+ return {};
+} \ No newline at end of file