mirror of
https://github.com/hyprwm/Hyprland
synced 2026-01-06 04:50:16 +01:00
hyprctl: use hyprtavern first
This commit is contained in:
parent
9aa313402b
commit
e6ccce7f4b
2 changed files with 144 additions and 54 deletions
|
|
@ -16,21 +16,28 @@ target_include_directories(hyprctl PRIVATE "hw-protocols")
|
|||
|
||||
# Hyprwire
|
||||
|
||||
function(hyprprotocol protoPath protoName)
|
||||
set(path ${CMAKE_CURRENT_SOURCE_DIR}/${protoPath})
|
||||
pkg_get_variable(HYPRWIRE_PROTOCOLS_DIR hyprwire-protocols pkgdatadir)
|
||||
message(STATUS "Found hyprwire-protocols at ${HYPRWIRE_PROTOCOLS_DIR}")
|
||||
|
||||
function(hyprprotocol protoPath protoName external)
|
||||
if(external)
|
||||
set(path ${protoPath})
|
||||
else()
|
||||
set(path ${HYPRWIRE_PROTOCOLS_DIR}/${protoPath})
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.hpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-spec.hpp
|
||||
COMMAND hyprwire-scanner --client ${path}/${protoName}.xml
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_sources(hyprctl PRIVATE hw-protocols/${protoName}-client.cpp
|
||||
hw-protocols/${protoName}-client.hpp
|
||||
hw-protocols/${protoName}-spec.hpp)
|
||||
)
|
||||
endfunction()
|
||||
|
||||
hyprprotocol(hw-protocols hyprpaper_core)
|
||||
hyprprotocol(hw-protocols hyprpaper_core true)
|
||||
hyprprotocol(hyprtavern hp_hyprtavern_core_v1 false)
|
||||
|
||||
# binary
|
||||
install(TARGETS hyprctl)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,19 @@
|
|||
#include <filesystem>
|
||||
|
||||
#include <hyprpaper_core-client.hpp>
|
||||
#include <hp_hyprtavern_core_v1-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 char* SOCKET_NAME = ".hyprpaper.sock";
|
||||
static SP<CCHyprpaperCoreImpl> g_coreImpl;
|
||||
static SP<CCHpHyprtavernCoreV1Impl> g_tavernImpl;
|
||||
|
||||
constexpr const uint32_t PROTOCOL_VERSION_SUPPORTED = 1;
|
||||
constexpr const uint32_t HYPRPAPER_PROTOCOL_VERSION_SUPPORTED = 1;
|
||||
constexpr const uint32_t HYPRTAVERN_PROTOCOL_VERSION_SUPPORTED = 1;
|
||||
|
||||
//
|
||||
static hyprpaperCoreWallpaperFitMode fitFromString(const std::string_view& sv) {
|
||||
|
|
@ -53,6 +56,128 @@ static std::expected<std::string, std::string> getFullPath(const std::string_vie
|
|||
return resolvePath(sv);
|
||||
}
|
||||
|
||||
static std::expected<void, std::string> makeRequestToSocket(SP<Hyprwire::IClientSocket> socket, const std::string& PATH, const std::string& MONITOR, const std::string_view& FIT) {
|
||||
g_coreImpl = makeShared<CCHyprpaperCoreImpl>(HYPRPAPER_PROTOCOL_VERSION_SUPPORTED);
|
||||
|
||||
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(), HYPRPAPER_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");
|
||||
|
||||
std::optional<std::string> err;
|
||||
|
||||
wallpaper->setFailed([&err](uint32_t code) { err = std::format("failed to set wallpaper, code {}", code); });
|
||||
|
||||
wallpaper->sendPath(PATH.c_str());
|
||||
wallpaper->sendMonitorName(MONITOR.c_str());
|
||||
if (!FIT.empty())
|
||||
wallpaper->sendFitMode(fitFromString(FIT));
|
||||
|
||||
wallpaper->sendApply();
|
||||
|
||||
socket->roundtrip();
|
||||
|
||||
if (err)
|
||||
return std::unexpected(*err);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
static bool attemptHyprtavern(const std::string& PATH, const std::string& MONITOR, const std::string_view& FIT) {
|
||||
// try to connect to hyprtavern
|
||||
g_tavernImpl = makeShared<CCHpHyprtavernCoreV1Impl>(HYPRTAVERN_PROTOCOL_VERSION_SUPPORTED);
|
||||
|
||||
const auto RTDIR = getenv("XDG_RUNTIME_DIR");
|
||||
|
||||
auto socketPath = RTDIR + "/hyprtavern/ht.sock"s;
|
||||
|
||||
auto socket = Hyprwire::IClientSocket::open(socketPath);
|
||||
|
||||
if (!socket)
|
||||
return false;
|
||||
|
||||
socket->addImplementation(g_tavernImpl);
|
||||
|
||||
if (!socket->waitForHandshake())
|
||||
return false;
|
||||
|
||||
auto spec = socket->getSpec(g_tavernImpl->protocol()->specName());
|
||||
|
||||
if (!spec)
|
||||
return false;
|
||||
|
||||
auto manager = makeShared<CCHpHyprtavernCoreManagerV1Object>(socket->bindProtocol(g_tavernImpl->protocol(), HYPRTAVERN_PROTOCOL_VERSION_SUPPORTED));
|
||||
|
||||
if (!manager)
|
||||
return false;
|
||||
|
||||
// run a query, find all possible candidates
|
||||
const auto WAYLAND_DISPLAY = getenv("WAYLAND_DISPLAY");
|
||||
|
||||
if (!WAYLAND_DISPLAY)
|
||||
return false;
|
||||
|
||||
std::string propStr = std::format("GLOBAL:WAYLAND_DISPLAY={}", WAYLAND_DISPLAY);
|
||||
|
||||
std::vector<const char*> props = {propStr.c_str()};
|
||||
std::vector<const char*> protos = {"hyprpaper_core"};
|
||||
|
||||
auto query = makeShared<CCHpHyprtavernBusQueryV1Object>(
|
||||
manager->sendGetQueryObject(protos, HP_HYPRTAVERN_CORE_V1_BUS_QUERY_FILTER_MODE_ALL, props, HP_HYPRTAVERN_CORE_V1_BUS_QUERY_FILTER_MODE_ALL));
|
||||
|
||||
uint32_t candidateId = 0;
|
||||
|
||||
query->setResults([&candidateId](const std::vector<uint32_t>& vec) {
|
||||
if (vec.empty())
|
||||
return;
|
||||
|
||||
candidateId = vec.at(0);
|
||||
});
|
||||
|
||||
socket->roundtrip();
|
||||
|
||||
if (candidateId == 0)
|
||||
return false; // no hyprpaper-compatible thing in the tavern
|
||||
|
||||
auto handle = makeShared<CCHpHyprtavernBusObjectHandleV1Object>(manager->sendGetObjectHandle(candidateId));
|
||||
|
||||
if (!handle)
|
||||
return false;
|
||||
|
||||
int newSocketFd = -1;
|
||||
|
||||
handle->setSocket([&newSocketFd](int fd) { newSocketFd = fd; });
|
||||
|
||||
handle->sendConnect();
|
||||
|
||||
socket->roundtrip();
|
||||
|
||||
if (newSocketFd < 0)
|
||||
return false;
|
||||
|
||||
auto newSocket = Hyprwire::IClientSocket::open(newSocketFd);
|
||||
|
||||
if (!newSocket)
|
||||
return false;
|
||||
|
||||
return !!makeRequestToSocket(newSocket, PATH, MONITOR, FIT);
|
||||
}
|
||||
|
||||
std::expected<void, std::string> Hyprpaper::makeHyprpaperRequest(const std::string_view& rq) {
|
||||
if (!rq.contains(' '))
|
||||
return std::unexpected("Invalid request");
|
||||
|
|
@ -92,6 +217,9 @@ std::expected<void, std::string> Hyprpaper::makeHyprpaperRequest(const std::stri
|
|||
if (!PATH)
|
||||
return std::unexpected(std::format("bad path: {}", PATH_RAW));
|
||||
|
||||
if (attemptHyprtavern(*PATH, MONITOR, FIT))
|
||||
return {};
|
||||
|
||||
auto socketPath = RTDIR + "/hypr/"s + HIS + "/"s + SOCKET_NAME;
|
||||
|
||||
auto socket = Hyprwire::IClientSocket::open(socketPath);
|
||||
|
|
@ -99,50 +227,5 @@ std::expected<void, std::string> Hyprpaper::makeHyprpaperRequest(const std::stri
|
|||
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 {};
|
||||
return makeRequestToSocket(socket, *PATH, MONITOR, FIT);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue