protocols: add Hyprland toplevel mapping implementation (#9775)

This commit is contained in:
WhySoBad 2025-04-24 18:10:57 +02:00 committed by GitHub
parent b06fbdb743
commit a9549dbca0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 147 additions and 11 deletions

View file

@ -316,7 +316,7 @@ endfunction()
target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads) target_link_libraries(Hyprland OpenGL::EGL OpenGL::GL Threads::Threads)
pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.2) pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
if(hyprland_protocols_dep_FOUND) if(hyprland_protocols_dep_FOUND)
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir) pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}") message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
@ -348,6 +348,7 @@ protocolnew("protocols" "wayland-drm" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true) protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1" true)
protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/tearing-control" "tearing-control-v1" false)
protocolnew("staging/fractional-scale" "fractional-scale-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false)

View file

@ -7,7 +7,7 @@ wayland_protos = dependency(
hyprland_protos = dependency( hyprland_protos = dependency(
'hyprland-protocols', 'hyprland-protocols',
version: '>=0.6.2', version: '>=0.6.4',
fallback: 'hyprland-protocols', fallback: 'hyprland-protocols',
) )
@ -37,6 +37,7 @@ protocols = [
'frog-color-management-v1.xml', 'frog-color-management-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-toplevel-mapping-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-focus-grab-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-ctm-control-v1.xml',
hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml', hyprland_protocol_dir / 'protocols/hyprland-surface-v1.xml',

View file

@ -42,6 +42,7 @@
#include "../protocols/DRMSyncobj.hpp" #include "../protocols/DRMSyncobj.hpp"
#include "../protocols/Screencopy.hpp" #include "../protocols/Screencopy.hpp"
#include "../protocols/ToplevelExport.hpp" #include "../protocols/ToplevelExport.hpp"
#include "../protocols/ToplevelMapping.hpp"
#include "../protocols/TextInputV1.hpp" #include "../protocols/TextInputV1.hpp"
#include "../protocols/GlobalShortcuts.hpp" #include "../protocols/GlobalShortcuts.hpp"
#include "../protocols/XDGDialog.hpp" #include "../protocols/XDGDialog.hpp"
@ -68,6 +69,7 @@
#include <aquamarine/buffer/Buffer.hpp> #include <aquamarine/buffer/Buffer.hpp>
#include <aquamarine/backend/Backend.hpp> #include <aquamarine/backend/Backend.hpp>
#include <hyprutils/memory/UniquePtr.hpp>
// ******************************************************************************************** // ********************************************************************************************
// * IMPORTANT: make sure to .reset() any protocol UP's you create! (put reset in destructor) * // * IMPORTANT: make sure to .reset() any protocol UP's you create! (put reset in destructor) *
@ -175,6 +177,7 @@ CProtocolManager::CProtocolManager() {
PROTO::xwaylandShell = makeUnique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell"); PROTO::xwaylandShell = makeUnique<CXWaylandShellProtocol>(&xwayland_shell_v1_interface, 1, "XWaylandShell");
PROTO::screencopy = makeUnique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy"); PROTO::screencopy = makeUnique<CScreencopyProtocol>(&zwlr_screencopy_manager_v1_interface, 3, "Screencopy");
PROTO::toplevelExport = makeUnique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport"); PROTO::toplevelExport = makeUnique<CToplevelExportProtocol>(&hyprland_toplevel_export_manager_v1_interface, 2, "ToplevelExport");
PROTO::toplevelMapping = makeUnique<CToplevelMappingProtocol>(&hyprland_toplevel_mapping_manager_v1_interface, 1, "ToplevelMapping");
PROTO::globalShortcuts = makeUnique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts"); PROTO::globalShortcuts = makeUnique<CGlobalShortcutsProtocol>(&hyprland_global_shortcuts_manager_v1_interface, 1, "GlobalShortcuts");
PROTO::xdgDialog = makeUnique<CXDGDialogProtocol>(&xdg_wm_dialog_v1_interface, 1, "XDGDialog"); PROTO::xdgDialog = makeUnique<CXDGDialogProtocol>(&xdg_wm_dialog_v1_interface, 1, "XDGDialog");
PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel"); PROTO::singlePixel = makeUnique<CSinglePixelProtocol>(&wp_single_pixel_buffer_manager_v1_interface, 1, "SinglePixel");
@ -262,6 +265,7 @@ CProtocolManager::~CProtocolManager() {
PROTO::xwaylandShell.reset(); PROTO::xwaylandShell.reset();
PROTO::screencopy.reset(); PROTO::screencopy.reset();
PROTO::toplevelExport.reset(); PROTO::toplevelExport.reset();
PROTO::toplevelMapping.reset();
PROTO::globalShortcuts.reset(); PROTO::globalShortcuts.reset();
PROTO::xdgDialog.reset(); PROTO::xdgDialog.reset();
PROTO::singlePixel.reset(); PROTO::singlePixel.reset();

View file

@ -6,6 +6,8 @@ CForeignToplevelHandle::CForeignToplevelHandle(SP<CExtForeignToplevelHandleV1> r
if UNLIKELY (!resource_->resource()) if UNLIKELY (!resource_->resource())
return; return;
resource->setData(this);
resource->setOnDestroy([this](CExtForeignToplevelHandleV1* h) { PROTO::foreignToplevel->destroyHandle(this); }); resource->setOnDestroy([this](CExtForeignToplevelHandleV1* h) { PROTO::foreignToplevel->destroyHandle(this); });
resource->setDestroy([this](CExtForeignToplevelHandleV1* h) { PROTO::foreignToplevel->destroyHandle(this); }); resource->setDestroy([this](CExtForeignToplevelHandleV1* h) { PROTO::foreignToplevel->destroyHandle(this); });
} }
@ -168,3 +170,8 @@ void CForeignToplevelProtocol::destroyHandle(CForeignToplevelHandle* handle) {
bool CForeignToplevelProtocol::windowValidForForeign(PHLWINDOW pWindow) { bool CForeignToplevelProtocol::windowValidForForeign(PHLWINDOW pWindow) {
return validMapped(pWindow) && !pWindow->isX11OverrideRedirect(); return validMapped(pWindow) && !pWindow->isX11OverrideRedirect();
} }
PHLWINDOW CForeignToplevelProtocol::windowFromHandleResource(wl_resource* res) {
auto data = (CForeignToplevelHandle*)(((CExtForeignToplevelHandleV1*)wl_resource_get_user_data(res))->data());
return data ? data->window() : nullptr;
}

View file

@ -3,6 +3,7 @@
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include "WaylandProtocol.hpp" #include "WaylandProtocol.hpp"
#include "desktop/DesktopTypes.hpp"
#include "ext-foreign-toplevel-list-v1.hpp" #include "ext-foreign-toplevel-list-v1.hpp"
class CForeignToplevelHandle { class CForeignToplevelHandle {
@ -18,6 +19,7 @@ class CForeignToplevelHandle {
bool closed = false; bool closed = false;
friend class CForeignToplevelList; friend class CForeignToplevelList;
friend class CForeignToplevelProtocol;
}; };
class CForeignToplevelList { class CForeignToplevelList {
@ -43,6 +45,7 @@ class CForeignToplevelList {
class CForeignToplevelProtocol : public IWaylandProtocol { class CForeignToplevelProtocol : public IWaylandProtocol {
public: public:
CForeignToplevelProtocol(const wl_interface* iface, const int& ver, const std::string& name); CForeignToplevelProtocol(const wl_interface* iface, const int& ver, const std::string& name);
PHLWINDOW windowFromHandleResource(wl_resource* res);
virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id); virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);

View file

@ -10,6 +10,8 @@ CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHand
if UNLIKELY (!resource_->resource()) if UNLIKELY (!resource_->resource())
return; return;
resource->setData(this);
resource->setOnDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); resource->setOnDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); });
resource->setDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); resource->setDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); });
@ -420,14 +422,8 @@ void CForeignToplevelWlrProtocol::destroyHandle(CForeignToplevelHandleWlr* handl
} }
PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) { PHLWINDOW CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) {
for (auto const& h : m_vHandles) { auto data = (CForeignToplevelHandleWlr*)(((CZwlrForeignToplevelHandleV1*)wl_resource_get_user_data(res))->data());
if (h->res() != res) return data ? data->window() : nullptr;
continue;
return h->window();
}
return nullptr;
} }
bool CForeignToplevelWlrProtocol::windowValidForForeign(PHLWINDOW pWindow) { bool CForeignToplevelWlrProtocol::windowValidForForeign(PHLWINDOW pWindow) {

View file

@ -0,0 +1,78 @@
#include "ToplevelMapping.hpp"
#include "hyprland-toplevel-mapping-v1.hpp"
#include "ForeignToplevelWlr.hpp"
#include "ForeignToplevel.hpp"
CToplevelWindowMappingHandle::CToplevelWindowMappingHandle(SP<CHyprlandToplevelWindowMappingHandleV1> resource_) : resource(resource_) {}
CToplevelMappingManager::CToplevelMappingManager(SP<CHyprlandToplevelMappingManagerV1> resource_) : resource(resource_) {
if UNLIKELY (!resource_->resource())
return;
resource->setOnDestroy([this](CHyprlandToplevelMappingManagerV1* h) { PROTO::toplevelMapping->onManagerResourceDestroy(this); });
resource->setDestroy([this](CHyprlandToplevelMappingManagerV1* h) { PROTO::toplevelMapping->onManagerResourceDestroy(this); });
resource->setGetWindowForToplevel([this](CHyprlandToplevelMappingManagerV1* mgr, uint32_t handle, wl_resource* toplevel) {
const auto NEWHANDLE = PROTO::toplevelMapping->m_vHandles.emplace_back(
makeShared<CToplevelWindowMappingHandle>(makeShared<CHyprlandToplevelWindowMappingHandleV1>(resource->client(), resource->version(), handle)));
if UNLIKELY (!NEWHANDLE->resource->resource()) {
LOGM(ERR, "Couldn't alloc mapping handle! (no memory)");
resource->noMemory();
return;
}
NEWHANDLE->resource->setOnDestroy([](CHyprlandToplevelWindowMappingHandleV1* h) { PROTO::toplevelMapping->destroyHandle(h); });
NEWHANDLE->resource->setDestroy([](CHyprlandToplevelWindowMappingHandleV1* h) { PROTO::toplevelMapping->destroyHandle(h); });
const auto WINDOW = PROTO::foreignToplevel->windowFromHandleResource(toplevel);
if (!WINDOW)
NEWHANDLE->resource->sendFailed();
else
NEWHANDLE->resource->sendWindowAddress((uint64_t)WINDOW.get() >> 32 & 0xFFFFFFFF, (uint64_t)WINDOW.get() & 0xFFFFFFFF);
});
resource->setGetWindowForToplevelWlr([this](CHyprlandToplevelMappingManagerV1* mgr, uint32_t handle, wl_resource* toplevel) {
const auto NEWHANDLE = PROTO::toplevelMapping->m_vHandles.emplace_back(
makeShared<CToplevelWindowMappingHandle>(makeShared<CHyprlandToplevelWindowMappingHandleV1>(resource->client(), resource->version(), handle)));
if UNLIKELY (!NEWHANDLE->resource->resource()) {
LOGM(ERR, "Couldn't alloc mapping handle! (no memory)");
resource->noMemory();
return;
}
NEWHANDLE->resource->setOnDestroy([](CHyprlandToplevelWindowMappingHandleV1* h) { PROTO::toplevelMapping->destroyHandle(h); });
NEWHANDLE->resource->setDestroy([](CHyprlandToplevelWindowMappingHandleV1* h) { PROTO::toplevelMapping->destroyHandle(h); });
const auto WINDOW = PROTO::foreignToplevelWlr->windowFromHandleResource(toplevel);
if (!WINDOW)
NEWHANDLE->resource->sendFailed();
else
NEWHANDLE->resource->sendWindowAddress((uint64_t)WINDOW.get() >> 32 & 0xFFFFFFFF, (uint64_t)WINDOW.get() & 0xFFFFFFFF);
});
}
bool CToplevelMappingManager::good() const {
return resource->resource();
}
CToplevelMappingProtocol::CToplevelMappingProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {}
void CToplevelMappingProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
const auto RESOURCE = m_vManagers.emplace_back(makeUnique<CToplevelMappingManager>(makeShared<CHyprlandToplevelMappingManagerV1>(client, ver, id))).get();
if UNLIKELY (!RESOURCE->good()) {
LOGM(ERR, "Couldn't create a toplevel mapping manager");
wl_client_post_no_memory(client);
m_vManagers.pop_back();
return;
}
}
void CToplevelMappingProtocol::onManagerResourceDestroy(CToplevelMappingManager* mgr) {
std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == mgr; });
}
void CToplevelMappingProtocol::destroyHandle(CHyprlandToplevelWindowMappingHandleV1* handle) {
std::erase_if(m_vHandles, [&](const auto& other) { return other->resource.get() == handle; });
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <vector>
#include "WaylandProtocol.hpp"
#include "hyprland-toplevel-mapping-v1.hpp"
class CToplevelWindowMappingHandle {
public:
CToplevelWindowMappingHandle(SP<CHyprlandToplevelWindowMappingHandleV1> resource_);
private:
SP<CHyprlandToplevelWindowMappingHandleV1> resource;
friend class CToplevelMappingManager;
friend class CToplevelMappingProtocol;
};
class CToplevelMappingManager {
public:
CToplevelMappingManager(SP<CHyprlandToplevelMappingManagerV1> resource_);
bool good() const;
private:
SP<CHyprlandToplevelMappingManagerV1> resource;
};
class CToplevelMappingProtocol : IWaylandProtocol {
public:
CToplevelMappingProtocol(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);
private:
void onManagerResourceDestroy(CToplevelMappingManager* mgr);
void destroyHandle(CHyprlandToplevelWindowMappingHandleV1* handle);
std::vector<UP<CToplevelMappingManager>> m_vManagers;
std::vector<SP<CToplevelWindowMappingHandle>> m_vHandles;
friend class CToplevelMappingManager;
};
namespace PROTO {
inline UP<CToplevelMappingProtocol> toplevelMapping;
};

@ -1 +1 @@
Subproject commit 755aef8dab49d0fc4663c715fa4ad221b2aedaed Subproject commit 3a5c2bda1c1a4e55cc1330c782547695a93f05b2