diff --git a/CMakeLists.txt b/CMakeLists.txt index e5917e63e..b5e45d7b7 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,10 +273,10 @@ protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.x 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("staging/fractional-scale/fractional-scale-v1.xml" "fractional-scale-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) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 76dbcacbe..a429f7a92 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -28,7 +28,6 @@ protocols = [ [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/fractional-scale/fractional-scale-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_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index 6e739c5f2..bc229d327 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -12,6 +12,7 @@ #endif #include #include "helpers/VarList.hpp" +#include "protocols/FractionalScale.hpp" int handleCritSignal(int signo, void* data) { Debug::log(LOG, "Hyprland received signal {}", signo); @@ -2849,7 +2850,7 @@ void CCompositor::leaveUnsafeState() { } void CCompositor::setPreferredScaleForSurface(wlr_surface* pSurface, double scale) { - g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(pSurface, scale); + PROTO::fractional->sendScale(pSurface, scale); wlr_surface_set_preferred_buffer_scale(pSurface, static_cast(std::ceil(scale))); const auto PSURFACE = CWLSurface::surfaceFromWlr(pSurface); diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index 312202762..60ff83148 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -1,17 +1,19 @@ #include "ProtocolManager.hpp" #include "../protocols/TearingControl.hpp" +#include "../protocols/FractionalScale.hpp" #include "xdg-output-unstable-v1-protocol.h" #include "tearing-control-v1.hpp" +#include "fractional-scale-v1.hpp" CProtocolManager::CProtocolManager() { m_pToplevelExportProtocolManager = std::make_unique(); - m_pFractionalScaleProtocolManager = 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 223460a1b..1c4073eff 100644 --- a/src/managers/ProtocolManager.hpp +++ b/src/managers/ProtocolManager.hpp @@ -2,7 +2,6 @@ #include "../defines.hpp" #include "../protocols/ToplevelExport.hpp" -#include "../protocols/FractionalScale.hpp" #include "../protocols/TextInputV1.hpp" #include "../protocols/GlobalShortcuts.hpp" #include "../protocols/Screencopy.hpp" @@ -14,7 +13,6 @@ class CProtocolManager { // TODO: rewrite to use the new protocol framework std::unique_ptr m_pToplevelExportProtocolManager; - std::unique_ptr m_pFractionalScaleProtocolManager; std::unique_ptr m_pTextInputV1ProtocolManager; std::unique_ptr m_pGlobalShortcutsProtocolManager; std::unique_ptr m_pScreencopyProtocolManager; diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index a0374b85e..d6fc912cd 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -1,6 +1,7 @@ #include "SessionLockManager.hpp" #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" +#include "../protocols/FractionalScale.hpp" static void handleSurfaceMap(void* owner, void* data) { const auto PSURFACE = (SSessionLockSurface*)owner; @@ -74,7 +75,7 @@ void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) { PSURFACE->pWlrLockSurface = PWLRSURFACE; PSURFACE->iMonitorID = PMONITOR->ID; - g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(PSURFACE->pWlrLockSurface->surface, PMONITOR->scale); + PROTO::fractional->sendScale(PSURFACE->pWlrLockSurface->surface, PMONITOR->scale); wlr_session_lock_surface_v1_configure(PWLRSURFACE, PMONITOR->vecSize.x, PMONITOR->vecSize.y); diff --git a/src/managers/input/InputMethodPopup.cpp b/src/managers/input/InputMethodPopup.cpp index 7d101e10d..3a56d30cd 100644 --- a/src/managers/input/InputMethodPopup.cpp +++ b/src/managers/input/InputMethodPopup.cpp @@ -1,6 +1,7 @@ #include "InputMethodPopup.hpp" #include "InputManager.hpp" #include "../../Compositor.hpp" +#include "../../protocols/FractionalScale.hpp" CInputPopup::CInputPopup(wlr_input_popup_surface_v2* surf) : pWlr(surf) { surface.assign(surf->surface); @@ -63,7 +64,7 @@ void CInputPopup::onMap() { if (!PMONITOR) return; - g_pProtocolManager->m_pFractionalScaleProtocolManager->setPreferredScaleForSurface(surface.wlr(), PMONITOR->scale); + PROTO::fractional->sendScale(surface.wlr(), PMONITOR->scale); } void CInputPopup::onUnmap() { diff --git a/src/protocols/FractionalScale.cpp b/src/protocols/FractionalScale.cpp index 86b5afbc7..993d963b6 100644 --- a/src/protocols/FractionalScale.cpp +++ b/src/protocols/FractionalScale.cpp @@ -1,118 +1,93 @@ #include "FractionalScale.hpp" -#include "../Compositor.hpp" +static void onWlrSurfaceDestroy(void* owner, void* data) { + const auto SURF = (wlr_surface*)owner; -#define FRACTIONAL_SCALE_VERSION 1 - -static void bindManagerInt(wl_client* client, void* data, uint32_t version, uint32_t id) { - g_pProtocolManager->m_pFractionalScaleProtocolManager->bindManager(client, data, version, id); + PROTO::fractional->onSurfaceDestroy(SURF); } -static void handleDisplayDestroy(struct wl_listener* listener, void* data) { - g_pProtocolManager->m_pFractionalScaleProtocolManager->displayDestroy(); +CFractionalScaleProtocol::CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; } -void CFractionalScaleProtocolManager::displayDestroy() { - wl_global_destroy(m_pGlobal); +void CFractionalScaleProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get(); + RESOURCE->setOnDestroy([this](CWpFractionalScaleManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CWpFractionalScaleManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setGetFractionalScale( + [this](CWpFractionalScaleManagerV1* pMgr, uint32_t id, wl_resource* surface) { this->onGetFractionalScale(pMgr, id, wlr_surface_from_resource(surface)); }); } -static void handleDestroy(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); +void CFractionalScaleProtocol::removeAddon(CFractionalScaleAddon* addon) { + m_mAddons.erase(addon->surf()); } -void handleGetFractionalScale(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) { - g_pProtocolManager->m_pFractionalScaleProtocolManager->getFractionalScale(client, resource, id, surface); +void CFractionalScaleProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [res](const auto& other) { return other->resource() == res; }); } -CFractionalScaleProtocolManager::CFractionalScaleProtocolManager() { - m_pGlobal = wl_global_create(g_pCompositor->m_sWLDisplay, &wp_fractional_scale_manager_v1_interface, FRACTIONAL_SCALE_VERSION, this, bindManagerInt); +void CFractionalScaleProtocol::onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface) { + const auto PADDON = m_mAddons + .emplace(surface, + std::make_unique( + std::make_shared(wl_resource_get_client(pMgr->resource()), wl_resource_get_version(pMgr->resource()), id), surface)) + .first->second.get(); - if (!m_pGlobal) { - Debug::log(ERR, "FractionalScaleManager could not start! Fractional scaling will not work!"); + if (!PADDON->good()) { + m_mAddons.erase(surface); + wl_resource_post_no_memory(pMgr->resource()); return; } - m_liDisplayDestroy.notify = handleDisplayDestroy; - wl_display_add_destroy_listener(g_pCompositor->m_sWLDisplay, &m_liDisplayDestroy); + PADDON->resource->setOnDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); + PADDON->resource->setDestroy([this, PADDON](CWpFractionalScaleV1* self) { this->removeAddon(PADDON); }); - Debug::log(LOG, "FractionalScaleManager started successfully!"); + if (!m_mSurfaceScales.contains(surface)) + m_mSurfaceScales[surface] = 1.F; + + PADDON->setScale(m_mSurfaceScales[surface]); + registerSurface(surface); } -static const struct wp_fractional_scale_manager_v1_interface fractionalScaleManagerImpl = { - .destroy = handleDestroy, - .get_fractional_scale = handleGetFractionalScale, -}; - -void CFractionalScaleProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) { - const auto RESOURCE = wl_resource_create(client, &wp_fractional_scale_manager_v1_interface, version, id); - wl_resource_set_implementation(RESOURCE, &fractionalScaleManagerImpl, this, nullptr); - - Debug::log(LOG, "FractionalScaleManager bound successfully!"); +void CFractionalScaleProtocol::sendScale(wlr_surface* surf, const float& scale) { + m_mSurfaceScales[surf] = scale; + if (m_mAddons.contains(surf)) + m_mAddons[surf]->setScale(scale); + registerSurface(surf); } -static void handleDestroyScaleAddon(wl_client* client, wl_resource* resource); -// - -static const struct wp_fractional_scale_v1_interface fractionalScaleAddonImpl { - .destroy = handleDestroyScaleAddon -}; - -// -SFractionalScaleAddon* addonFromResource(wl_resource* resource) { - ASSERT(wl_resource_instance_of(resource, &wp_fractional_scale_v1_interface, &fractionalScaleAddonImpl)); - return (SFractionalScaleAddon*)wl_resource_get_user_data(resource); -} - -static void handleDestroyScaleAddon(wl_client* client, wl_resource* resource) { - wl_resource_destroy(resource); -} - -static void handleAddonDestroy(wl_resource* resource) { - const auto PADDON = addonFromResource(resource); - if (PADDON->pResource) { - wl_resource_set_user_data(PADDON->pResource, nullptr); - } - - g_pProtocolManager->m_pFractionalScaleProtocolManager->removeAddon(PADDON->pSurface); -} - -void CFractionalScaleProtocolManager::getFractionalScale(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface) { - const auto PSURFACE = wlr_surface_from_resource(surface); - const auto PADDON = getAddonForSurface(PSURFACE); - - if (PADDON->pResource) { - wl_resource_post_error(resource, WP_FRACTIONAL_SCALE_MANAGER_V1_ERROR_FRACTIONAL_SCALE_EXISTS, "Fractional scale exists."); +void CFractionalScaleProtocol::registerSurface(wlr_surface* surf) { + if (m_mSurfaceDestroyListeners.contains(surf)) return; - } - PADDON->pResource = wl_resource_create(client, &wp_fractional_scale_v1_interface, wl_resource_get_version(resource), id); - wl_resource_set_implementation(PADDON->pResource, &fractionalScaleAddonImpl, PADDON, handleAddonDestroy); - - wp_fractional_scale_v1_send_preferred_scale(PADDON->pResource, (uint32_t)std::round(PADDON->preferredScale * 120.0)); + m_mSurfaceDestroyListeners[surf].hyprListener_surfaceDestroy.initCallback(&surf->events.destroy, ::onWlrSurfaceDestroy, surf, "FractionalScale"); } -SFractionalScaleAddon* CFractionalScaleProtocolManager::getAddonForSurface(wlr_surface* surface) { - const auto IT = std::find_if(m_vFractionalScaleAddons.begin(), m_vFractionalScaleAddons.end(), [&](const auto& other) { return other->pSurface == surface; }); - - if (IT != m_vFractionalScaleAddons.end()) - return IT->get(); - - m_vFractionalScaleAddons.emplace_back(std::make_unique()); - - m_vFractionalScaleAddons.back()->pSurface = surface; - - return m_vFractionalScaleAddons.back().get(); +void CFractionalScaleProtocol::onSurfaceDestroy(wlr_surface* surf) { + m_mSurfaceDestroyListeners.erase(surf); + m_mSurfaceScales.erase(surf); + if (m_mAddons.contains(surf)) + m_mAddons[surf]->onSurfaceDestroy(); } -void CFractionalScaleProtocolManager::setPreferredScaleForSurface(wlr_surface* surface, double scale) { - const auto PADDON = getAddonForSurface(surface); - - PADDON->preferredScale = scale; - - if (PADDON->pResource) - wp_fractional_scale_v1_send_preferred_scale(PADDON->pResource, (uint32_t)std::round(scale * 120.0)); +CFractionalScaleAddon::CFractionalScaleAddon(SP resource_, wlr_surface* surf_) : resource(resource_), surface(surf_) { + resource->setDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); + resource->setOnDestroy([this](CWpFractionalScaleV1* self) { PROTO::fractional->removeAddon(this); }); } -void CFractionalScaleProtocolManager::removeAddon(wlr_surface* surface) { - std::erase_if(m_vFractionalScaleAddons, [&](const auto& other) { return other->pSurface == surface; }); +void CFractionalScaleAddon::onSurfaceDestroy() { + surfaceGone = true; +} + +void CFractionalScaleAddon::setScale(const float& scale) { + resource->sendPreferredScale(std::round(scale * 120.0)); +} + +bool CFractionalScaleAddon::good() { + return resource->resource(); +} + +wlr_surface* CFractionalScaleAddon::surf() { + return surface; } \ No newline at end of file diff --git a/src/protocols/FractionalScale.hpp b/src/protocols/FractionalScale.hpp index 71b2c8588..b800124fb 100644 --- a/src/protocols/FractionalScale.hpp +++ b/src/protocols/FractionalScale.hpp @@ -1,38 +1,68 @@ #pragma once -#include "../defines.hpp" -#include "fractional-scale-v1-protocol.h" +#include +#include +#include "WaylandProtocol.hpp" +#include "fractional-scale-v1.hpp" -#include -#include +class CFractionalScaleProtocol; -struct SFractionalScaleAddon { - wlr_surface* pSurface = nullptr; - double preferredScale = 1.0; - wl_resource* pResource = nullptr; -}; - -class CFractionalScaleProtocolManager { +class CFractionalScaleAddon { public: - CFractionalScaleProtocolManager(); + CFractionalScaleAddon(SP resource_, wlr_surface* surf_); - void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id); + void setScale(const float& scale); + void onSurfaceDestroy(); - void displayDestroy(); + bool good(); - void setPreferredScaleForSurface(wlr_surface*, double); + wlr_surface* surf(); - void removeAddon(wlr_surface*); + bool operator==(const wl_resource* other) const { + return other == resource->resource(); + } - // handlers - - void getFractionalScale(wl_client* client, wl_resource* resource, uint32_t id, wl_resource* surface); + bool operator==(const CFractionalScaleAddon* other) const { + return other->resource == resource; + } private: - SFractionalScaleAddon* getAddonForSurface(wlr_surface*); + SP resource; + float scale = 1.F; + wlr_surface* surface = nullptr; + bool surfaceGone = false; - std::vector> m_vFractionalScaleAddons; + friend class CFractionalScaleProtocol; +}; - wl_global* m_pGlobal = nullptr; - wl_listener m_liDisplayDestroy; +struct SSurfaceListener { + DYNLISTENER(surfaceDestroy); +}; + +class CFractionalScaleProtocol : public IWaylandProtocol { + public: + CFractionalScaleProtocol(const wl_interface* iface, const int& ver, const std::string& name); + + virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); + + void onManagerResourceDestroy(wl_resource* res); + void onGetFractionalScale(CWpFractionalScaleManagerV1* pMgr, uint32_t id, wlr_surface* surface); + + void sendScale(wlr_surface* surf, const float& scale); + void onSurfaceDestroy(wlr_surface* surf); + + void removeAddon(CFractionalScaleAddon*); + + private: + void registerSurface(wlr_surface*); + + std::unordered_map m_mSurfaceDestroyListeners; + + std::unordered_map m_mSurfaceScales; + std::unordered_map> m_mAddons; + std::vector> m_vManagers; +}; + +namespace PROTO { + inline UP fractional; }; \ No newline at end of file