diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c206b7a..5b88440b 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -260,11 +260,11 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1. protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true) protocol("stable/xdg-shell/xdg-shell.xml" "xdg-shell" false) protocol("unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml" "linux-dmabuf-unstable-v1" false) -protocol("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false) protocol("staging/cursor-shape/cursor-shape-v1.xml" "cursor-shape-v1" false) protocolNew("staging/tearing-control/tearing-control-v1.xml" "tearing-control-v1" false) protocolNew("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-v1" false) +protocolNew("unstable/xdg-output/xdg-output-unstable-v1.xml" "xdg-output-unstable-v1" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index a429f7a9..150ea55f 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -27,7 +27,6 @@ protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'], [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'], - [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'], ['wlr-foreign-toplevel-management-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'], @@ -43,6 +42,7 @@ protocols = [ new_protocols = [ [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'], [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'], + [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], ] wl_protos_src = [] diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 60ff8314..873d1a17 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -2,18 +2,22 @@ #include "../protocols/TearingControl.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/XDGOutput.hpp" -#include "xdg-output-unstable-v1-protocol.h" #include "tearing-control-v1.hpp" #include "fractional-scale-v1.hpp" +#include "xdg-output-unstable-v1.hpp" CProtocolManager::CProtocolManager() { + + PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); + PROTO::fractional = std::make_unique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); + PROTO::xdgOutput = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); + + // Old protocol implementations. + // TODO: rewrite them to use hyprwayland-scanner. m_pToplevelExportProtocolManager = std::make_unique(); m_pTextInputV1ProtocolManager = std::make_unique(); m_pGlobalShortcutsProtocolManager = std::make_unique(); m_pScreencopyProtocolManager = std::make_unique(); - - m_pXDGOutputProtocol = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput"); - PROTO::tearing = std::make_unique(&wp_tearing_control_manager_v1_interface, 1, "TearingControl"); - PROTO::fractional = std::make_unique(&wp_fractional_scale_manager_v1_interface, 1, "FractionalScale"); } diff --git a/src/managers/ProtocolManager.hpp b/src/managers/ProtocolManager.hpp index 1c4073ef..9af7b928 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -5,7 +5,6 @@ #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" -#include "../protocols/XDGOutput.hpp" class CProtocolManager { public: @@ -16,9 +15,6 @@ class CProtocolManager { std::unique_ptr m_pTextInputV1ProtocolManager; std::unique_ptr m_pGlobalShortcutsProtocolManager; std::unique_ptr m_pScreencopyProtocolManager; - - // New protocols - std::unique_ptr m_pXDGOutputProtocol; }; inline std::unique_ptr g_pProtocolManager; diff --git a/src/managers/XWaylandManager.cpp b/src/managers/XWaylandManager.cpp index 325229e7..cc7a8cac 100644 --- a/src/managers/XWaylandManager.cpp +++ b/src/managers/XWaylandManager.cpp @@ -1,7 +1,6 @@ #include "XWaylandManager.hpp" #include "../Compositor.hpp" #include "../events/Events.hpp" -#include "xdg-output-unstable-v1-protocol.h" #include "../config/ConfigValue.hpp" #define OUTPUT_MANAGER_VERSION 3 diff --git a/src/protocols/XDGOutput.cpp b/src/protocols/XDGOutput.cpp index c097b551..265b88ed 100644 --- a/src/protocols/XDGOutput.cpp +++ b/src/protocols/XDGOutput.cpp @@ -2,60 +2,34 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" -#include "xdg-output-unstable-v1-protocol.h" - #define OUTPUT_MANAGER_VERSION 3 #define OUTPUT_DONE_DEPRECATED_SINCE_VERSION 3 #define OUTPUT_DESCRIPTION_MUTABLE_SINCE_VERSION 3 - -static void destroyManagerResource(wl_client* client, wl_resource* resource) { - RESOURCE_OR_BAIL(PRESOURCE); - reinterpret_cast(PRESOURCE->data())->onManagerResourceDestroy(resource); -} - -static void destroyOutputResource(wl_client* client, wl_resource* resource) { - RESOURCE_OR_BAIL(PRESOURCE); - reinterpret_cast(PRESOURCE->data())->onOutputResourceDestroy(resource); -} - -static void getXDGOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* outputResource) { - RESOURCE_OR_BAIL(PRESOURCE); - reinterpret_cast(PRESOURCE->data())->onManagerGetXDGOutput(client, resource, id, outputResource); -} +#define OUTPUT_NAME_SINCE_VERSION 2 +#define OUTPUT_DESCRIPTION_SINCE_VERSION 2 // -static const struct zxdg_output_manager_v1_interface MANAGER_IMPL = { - .destroy = destroyManagerResource, - .get_xdg_output = getXDGOutput, -}; - -static const struct zxdg_output_v1_interface OUTPUT_IMPL = { - .destroy = destroyOutputResource, -}; - void CXDGOutputProtocol::onManagerResourceDestroy(wl_resource* res) { std::erase_if(m_vManagerResources, [&](const auto& other) { return other->resource() == res; }); } void CXDGOutputProtocol::onOutputResourceDestroy(wl_resource* res) { - std::erase_if(m_vXDGOutputs, [&](const auto& other) { - if (!other->resource) - return false; // ??? - return other->resource->resource() == res; - }); + std::erase_if(m_vXDGOutputs, [&](const auto& other) { return other->resource->resource() == res; }); } void CXDGOutputProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { - const auto RESOURCE = m_vManagerResources.emplace_back(std::make_unique(client, &zxdg_output_manager_v1_interface, ver, id)).get(); + const auto RESOURCE = m_vManagerResources.emplace_back(std::make_unique(client, ver, id)).get(); - if (!RESOURCE->good()) { + if (!RESOURCE->resource()) { Debug::log(LOG, "Couldn't bind XDGOutputMgr"); + wl_client_post_no_memory(client); return; } - RESOURCE->setImplementation(&MANAGER_IMPL, nullptr); - RESOURCE->setData(this); + RESOURCE->setDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); + RESOURCE->setOnDestroy([this](CZxdgOutputManagerV1* res) { this->onManagerResourceDestroy(res->resource()); }); + RESOURCE->setGetXdgOutput([this](CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* output) { this->onManagerGetXDGOutput(mgr, id, output); }); } CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { @@ -63,81 +37,87 @@ CXDGOutputProtocol::CXDGOutputProtocol(const wl_interface* iface, const int& ver g_pHookSystem->hookDynamic("configReloaded", [this](void* self, SCallbackInfo& info, std::any param) { this->updateAllOutputs(); }); g_pHookSystem->hookDynamic("monitorRemoved", [this](void* self, SCallbackInfo& info, std::any param) { const auto PMONITOR = std::any_cast(param); - std::erase_if(m_vXDGOutputs, [&](const auto& other) { - const auto REMOVE = other->monitor == PMONITOR; - if (REMOVE) - other->resource->markDefunct(); // so that wl_resource_destroy is not sent - return REMOVE; - }); + for (auto& o : m_vXDGOutputs) { + if (o->monitor == PMONITOR) + o->monitor = nullptr; + } }); } -void CXDGOutputProtocol::onManagerGetXDGOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* outputResource) { +void CXDGOutputProtocol::onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource) { const auto OUTPUT = wlr_output_from_resource(outputResource); const auto PMONITOR = g_pCompositor->getMonitorFromOutput(OUTPUT); - SXDGOutput* pXDGOutput = m_vXDGOutputs.emplace_back(std::make_unique(PMONITOR)).get(); + const auto CLIENT = wl_resource_get_client(mgr->resource()); + + CXDGOutput* pXDGOutput = + m_vXDGOutputs.emplace_back(std::make_unique(std::make_shared(CLIENT, wl_resource_get_version(mgr->resource()), id), PMONITOR)).get(); #ifndef NO_XWAYLAND - if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == client) + if (g_pXWaylandManager->m_sWLRXWayland && g_pXWaylandManager->m_sWLRXWayland->server && g_pXWaylandManager->m_sWLRXWayland->server->client == CLIENT) pXDGOutput->isXWayland = true; #endif - pXDGOutput->client = client; + pXDGOutput->client = CLIENT; - pXDGOutput->resource = std::make_unique(client, &zxdg_output_v1_interface, wl_resource_get_version(resource), id); - - if (!pXDGOutput->resource->good()) { - pXDGOutput->resource.release(); + if (!pXDGOutput->resource->resource()) { m_vXDGOutputs.pop_back(); + wl_resource_post_no_memory(mgr->resource()); return; } - pXDGOutput->resource->setImplementation(&OUTPUT_IMPL, nullptr); - pXDGOutput->resource->setData(this); - if (!PMONITOR) return; - const auto XDGVER = pXDGOutput->resource->version(); + const auto XDGVER = wl_resource_get_version(pXDGOutput->resource->resource()); - if (XDGVER >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) - zxdg_output_v1_send_name(pXDGOutput->resource->resource(), PMONITOR->szName.c_str()); - if (XDGVER >= ZXDG_OUTPUT_V1_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description) - zxdg_output_v1_send_description(pXDGOutput->resource->resource(), PMONITOR->output->description); + if (XDGVER >= OUTPUT_NAME_SINCE_VERSION) + pXDGOutput->resource->sendName(PMONITOR->szName.c_str()); + if (XDGVER >= OUTPUT_DESCRIPTION_SINCE_VERSION && PMONITOR->output->description) + pXDGOutput->resource->sendDescription(PMONITOR->output->description); - updateOutputDetails(pXDGOutput); + pXDGOutput->sendDetails(); const auto OUTPUTVER = wl_resource_get_version(outputResource); if (OUTPUTVER >= WL_OUTPUT_DONE_SINCE_VERSION && XDGVER >= OUTPUT_DONE_DEPRECATED_SINCE_VERSION) wl_output_send_done(outputResource); } -void CXDGOutputProtocol::updateOutputDetails(SXDGOutput* pOutput) { - static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); - - if (!pOutput->resource->good() || !pOutput->monitor) - return; - - const auto POS = pOutput->isXWayland ? pOutput->monitor->vecXWaylandPosition : pOutput->monitor->vecPosition; - zxdg_output_v1_send_logical_position(pOutput->resource->resource(), POS.x, POS.y); - - if (*PXWLFORCESCALEZERO && pOutput->isXWayland) - zxdg_output_v1_send_logical_size(pOutput->resource->resource(), pOutput->monitor->vecTransformedSize.x, pOutput->monitor->vecTransformedSize.y); - else - zxdg_output_v1_send_logical_size(pOutput->resource->resource(), pOutput->monitor->vecSize.x, pOutput->monitor->vecSize.y); - - if (wl_resource_get_version(pOutput->resource->resource()) < OUTPUT_DONE_DEPRECATED_SINCE_VERSION) - zxdg_output_v1_send_done(pOutput->resource->resource()); -} - void CXDGOutputProtocol::updateAllOutputs() { for (auto& o : m_vXDGOutputs) { if (!o->monitor) continue; - updateOutputDetails(o.get()); + o->sendDetails(); wlr_output_schedule_done(o->monitor->output); } } + +// + +CXDGOutput::CXDGOutput(SP resource_, CMonitor* monitor_) : monitor(monitor_), resource(resource_) { + if (!resource->resource()) + return; + + resource->setDestroy([](CZxdgOutputV1* pMgr) { PROTO::xdgOutput->onOutputResourceDestroy(pMgr->resource()); }); + resource->setOnDestroy([](CZxdgOutputV1* pMgr) { PROTO::xdgOutput->onOutputResourceDestroy(pMgr->resource()); }); +} + +void CXDGOutput::sendDetails() { + static auto PXWLFORCESCALEZERO = CConfigValue("xwayland:force_zero_scaling"); + + if (!monitor) + return; + + const auto POS = isXWayland ? monitor->vecXWaylandPosition : monitor->vecPosition; + resource->sendLogicalPosition(POS.x, POS.y); + + if (*PXWLFORCESCALEZERO && isXWayland) + resource->sendLogicalSize(monitor->vecTransformedSize.x, monitor->vecTransformedSize.y); + else + resource->sendLogicalSize(monitor->vecSize.x, monitor->vecSize.y); + + if (wl_resource_get_version(resource->resource()) < OUTPUT_DONE_DEPRECATED_SINCE_VERSION) + resource->sendDone(); +} \ No newline at end of file diff --git a/src/protocols/XDGOutput.hpp b/src/protocols/XDGOutput.hpp index 2469e600..d2314b7b 100644 --- a/src/protocols/XDGOutput.hpp +++ b/src/protocols/XDGOutput.hpp @@ -1,18 +1,28 @@ #pragma once +#include "xdg-output-unstable-v1.hpp" #include "WaylandProtocol.hpp" #include class CMonitor; +class CXDGOutputProtocol; -struct SXDGOutput { - CMonitor* monitor = nullptr; - std::unique_ptr resource; +class CXDGOutput { + public: + CXDGOutput(SP resource, CMonitor* monitor_); - std::optional overridePosition; + void sendDetails(); - wl_client* client = nullptr; - bool isXWayland = false; + private: + CMonitor* monitor = nullptr; + SP resource; + + std::optional overridePosition; + + wl_client* client = nullptr; + bool isXWayland = false; + + friend class CXDGOutputProtocol; }; class CXDGOutputProtocol : public IWaylandProtocol { @@ -23,12 +33,15 @@ class CXDGOutputProtocol : public IWaylandProtocol { void onManagerResourceDestroy(wl_resource* res); void onOutputResourceDestroy(wl_resource* res); - void onManagerGetXDGOutput(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* outputResource); + void onManagerGetXDGOutput(CZxdgOutputManagerV1* mgr, uint32_t id, wl_resource* outputResource); private: - void updateOutputDetails(SXDGOutput* pOutput); - void updateAllOutputs(); + void updateAllOutputs(); - std::vector> m_vManagerResources; - std::vector> m_vXDGOutputs; -}; \ No newline at end of file + std::vector> m_vManagerResources; + std::vector> m_vXDGOutputs; +}; + +namespace PROTO { + inline UP xdgOutput; +};