mirror of
https://github.com/hyprwm/xdg-desktop-portal-hyprland.git
synced 2025-10-29 03:23:43 +00:00
core: Implement hyprland-toplevel-mapping-v1 protocol (#322)
* feat: start toplevel-mapping-v1 implementation * feat: finished toplevel-mapping-v1 implementation * fix: rename unordered map member variable * chore: fix formatting * fix: update share picker for new env * chore: hyprland protocol version bump * chore: implement review * chore: implement feedback * chore: implemented feedback
This commit is contained in:
parent
be6771e754
commit
76bbf1a6b1
@ -130,7 +130,10 @@ protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
|
||||
true)
|
||||
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
|
||||
true)
|
||||
protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1"
|
||||
true)
|
||||
protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
|
||||
protocolnew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false)
|
||||
|
||||
# Installation
|
||||
install(TARGETS hyprland-share-picker)
|
||||
|
||||
@ -61,13 +61,17 @@ std::vector<SWindowEntry> getWindows(const char* env) {
|
||||
const auto TITLESEPPOS = rolling.find("[HE>]");
|
||||
const auto TITLESTR = rolling.substr(CLASSSEPPOS + 5, TITLESEPPOS - 5 - CLASSSEPPOS);
|
||||
|
||||
// window address
|
||||
const auto WINDOWSEPPOS = rolling.find("[HA>]");
|
||||
const auto WINDOWADDR = rolling.substr(TITLESEPPOS + 5, WINDOWSEPPOS - 5 - TITLESEPPOS);
|
||||
|
||||
try {
|
||||
result.push_back({TITLESTR, CLASSSTR, std::stoull(IDSTR)});
|
||||
} catch (std::exception& e) {
|
||||
// silent err
|
||||
}
|
||||
|
||||
rolling = rolling.substr(TITLESEPPOS + 5);
|
||||
rolling = rolling.substr(WINDOWSEPPOS + 5);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -4,7 +4,7 @@ wayland_protos = dependency('wayland-protocols',
|
||||
)
|
||||
|
||||
hyprland_protos = dependency('hyprland-protocols',
|
||||
version: '>=0.2',
|
||||
version: '>=0.6.4',
|
||||
fallback: 'hyprland-protocols',
|
||||
)
|
||||
|
||||
@ -21,8 +21,10 @@ client_protocols = [
|
||||
'wlr-screencopy-unstable-v1.xml',
|
||||
'wlr-foreign-toplevel-management-unstable-v1.xml',
|
||||
hl_protocol_dir / 'protocols/hyprland-toplevel-export-v1.xml',
|
||||
hl_protocol_dir / 'protocols/hyprland-toplevel-mapping-v1.xml',
|
||||
hl_protocol_dir / 'protocols/hyprland-global-shortcuts-v1.xml',
|
||||
wl_protocol_dir / 'stable/linux-dmabuf/linux-dmabuf-v1.xml',
|
||||
wl_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
||||
]
|
||||
|
||||
wl_proto_files = []
|
||||
|
||||
@ -192,6 +192,11 @@ void CPortalManager::onGlobal(uint32_t name, const char* interface, uint32_t ver
|
||||
if (!std::any_cast<Hyprlang::INT>(m_sConfig.config->getConfigValue("general:toplevel_dynamic_bind")))
|
||||
m_sHelpers.toplevel->activate();
|
||||
}
|
||||
|
||||
else if (INTERFACE == hyprland_toplevel_mapping_manager_v1_interface.name) {
|
||||
m_sHelpers.toplevelMapping = std::make_unique<CToplevelMappingManager>(makeShared<CCHyprlandToplevelMappingManagerV1>(
|
||||
(wl_proxy*)wl_registry_bind((wl_registry*)m_sWaylandConnection.registry->resource(), name, &hyprland_toplevel_mapping_manager_v1_interface, version)));
|
||||
}
|
||||
}
|
||||
|
||||
void CPortalManager::onGlobalRemoved(uint32_t name) {
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
#include "../portals/GlobalShortcuts.hpp"
|
||||
#include "../helpers/Timer.hpp"
|
||||
#include "../shared/ToplevelManager.hpp"
|
||||
#include "../shared/ToplevelMappingManager.hpp"
|
||||
#include <gbm.h>
|
||||
#include <xf86drm.h>
|
||||
|
||||
@ -63,7 +64,8 @@ class CPortalManager {
|
||||
} m_sPortals;
|
||||
|
||||
struct {
|
||||
std::unique_ptr<CToplevelManager> toplevel;
|
||||
std::unique_ptr<CToplevelManager> toplevel;
|
||||
std::unique_ptr<CToplevelMappingManager> toplevelMapping;
|
||||
} m_sHelpers;
|
||||
|
||||
struct {
|
||||
|
||||
@ -31,8 +31,9 @@ std::string buildWindowList() {
|
||||
return result;
|
||||
|
||||
for (auto& e : g_pPortalManager->m_sHelpers.toplevel->m_vToplevels) {
|
||||
result += std::format("{}[HC>]{}[HT>]{}[HE>]", (uint32_t)(((uint64_t)e->handle->resource()) & 0xFFFFFFFF), sanitizeNameForWindowList(e->windowClass),
|
||||
sanitizeNameForWindowList(e->windowTitle));
|
||||
result += std::format("{}[HC>]{}[HT>]{}[HE>]{}[HA>]", (uint32_t)(((uint64_t)e->handle->resource()) & 0xFFFFFFFF), sanitizeNameForWindowList(e->windowClass),
|
||||
sanitizeNameForWindowList(e->windowTitle),
|
||||
g_pPortalManager->m_sHelpers.toplevelMapping ? g_pPortalManager->m_sHelpers.toplevelMapping->getWindowForToplevel(e->handle) : 0);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@ -19,6 +19,8 @@ SToplevelHandle::SToplevelHandle(SP<CCZwlrForeignToplevelHandleV1> handle_) : ha
|
||||
Debug::log(TRACE, "[toplevel] toplevel at {} closed", (void*)this);
|
||||
|
||||
std::erase_if(g_pPortalManager->m_sHelpers.toplevel->m_vToplevels, [&](const auto& e) { return e.get() == this; });
|
||||
if (g_pPortalManager->m_sHelpers.toplevelMapping)
|
||||
g_pPortalManager->m_sHelpers.toplevelMapping->m_muAddresses.erase(this->handle);
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,9 +43,15 @@ void CToplevelManager::activate() {
|
||||
m_pManager->setToplevel([this](CCZwlrForeignToplevelManagerV1* r, wl_proxy* newHandle) {
|
||||
Debug::log(TRACE, "[toplevel] New toplevel at {}", (void*)newHandle);
|
||||
|
||||
m_vToplevels.emplace_back(makeShared<SToplevelHandle>(makeShared<CCZwlrForeignToplevelHandleV1>(newHandle)));
|
||||
const auto HANDLE = m_vToplevels.emplace_back(makeShared<SToplevelHandle>(makeShared<CCZwlrForeignToplevelHandleV1>(newHandle)));
|
||||
if (g_pPortalManager->m_sHelpers.toplevelMapping)
|
||||
g_pPortalManager->m_sHelpers.toplevelMapping->fetchWindowForToplevel(HANDLE->handle);
|
||||
});
|
||||
m_pManager->setFinished([this](CCZwlrForeignToplevelManagerV1* r) {
|
||||
m_vToplevels.clear();
|
||||
if (g_pPortalManager->m_sHelpers.toplevelMapping)
|
||||
g_pPortalManager->m_sHelpers.toplevelMapping->m_muAddresses.clear();
|
||||
});
|
||||
m_pManager->setFinished([this](CCZwlrForeignToplevelManagerV1* r) { m_vToplevels.clear(); });
|
||||
|
||||
wl_display_roundtrip(g_pPortalManager->m_sWaylandConnection.display);
|
||||
|
||||
@ -60,6 +68,8 @@ void CToplevelManager::deactivate() {
|
||||
|
||||
m_pManager.reset();
|
||||
m_vToplevels.clear();
|
||||
if (g_pPortalManager->m_sHelpers.toplevelMapping)
|
||||
g_pPortalManager->m_sHelpers.toplevelMapping->m_muAddresses.clear();
|
||||
|
||||
Debug::log(LOG, "[toplevel] unbound manager");
|
||||
}
|
||||
|
||||
39
src/shared/ToplevelMappingManager.cpp
Normal file
39
src/shared/ToplevelMappingManager.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "ToplevelMappingManager.hpp"
|
||||
#include "../helpers/Log.hpp"
|
||||
|
||||
CToplevelMappingManager::CToplevelMappingManager(SP<CCHyprlandToplevelMappingManagerV1> mgr) : m_pManager(mgr) {
|
||||
Debug::log(LOG, "[toplevel mapping] registered manager");
|
||||
}
|
||||
|
||||
void CToplevelMappingManager::fetchWindowForToplevel(SP<CCZwlrForeignToplevelHandleV1> handle) {
|
||||
if (!handle)
|
||||
return;
|
||||
|
||||
Debug::log(TRACE, "[toplevel mapping] fetching window for toplevel at {}", (void*)handle.get());
|
||||
auto const HANDLE = makeShared<CCHyprlandToplevelWindowMappingHandleV1>(m_pManager->sendGetWindowForToplevelWlr(handle->resource()));
|
||||
|
||||
m_vHandles.push_back(HANDLE);
|
||||
|
||||
HANDLE->setWindowAddress([this, handle](CCHyprlandToplevelWindowMappingHandleV1* h, uint32_t address_hi, uint32_t address) {
|
||||
const auto ADDRESS = (uint64_t)address_hi << 32 | address;
|
||||
m_muAddresses.insert_or_assign(handle, ADDRESS);
|
||||
Debug::log(TRACE, "[toplevel mapping] mapped toplevel at {} to window {}", (void*)handle.get(), ADDRESS);
|
||||
std::erase_if(m_vHandles, [&](const auto& other) { return other.get() == h; });
|
||||
});
|
||||
|
||||
HANDLE->setFailed([this, handle](CCHyprlandToplevelWindowMappingHandleV1* h) {
|
||||
Debug::log(TRACE, "[toplevel mapping] failed to map toplevel at {} to window", (void*)handle.get());
|
||||
std::erase_if(m_vHandles, [&](const auto& other) { return other.get() == h; });
|
||||
});
|
||||
}
|
||||
|
||||
uint64_t CToplevelMappingManager::getWindowForToplevel(CSharedPointer<CCZwlrForeignToplevelHandleV1> handle) {
|
||||
auto iter = m_muAddresses.find(handle);
|
||||
if (iter != m_muAddresses.end())
|
||||
return iter->second;
|
||||
|
||||
if (handle)
|
||||
Debug::log(TRACE, "[toplevel mapping] did not find window address for toplevel at {}", (void*)handle.get());
|
||||
|
||||
return 0;
|
||||
}
|
||||
24
src/shared/ToplevelMappingManager.hpp
Normal file
24
src/shared/ToplevelMappingManager.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "wayland.hpp"
|
||||
#include "hyprland-toplevel-mapping-v1.hpp"
|
||||
#include "wlr-foreign-toplevel-management-unstable-v1.hpp"
|
||||
#include <memory>
|
||||
#include "../includes.hpp"
|
||||
|
||||
class CToplevelMappingManager {
|
||||
public:
|
||||
CToplevelMappingManager(SP<CCHyprlandToplevelMappingManagerV1> mgr);
|
||||
|
||||
uint64_t getWindowForToplevel(SP<CCZwlrForeignToplevelHandleV1> handle);
|
||||
|
||||
private:
|
||||
SP<CCHyprlandToplevelMappingManagerV1> m_pManager = nullptr;
|
||||
|
||||
std::unordered_map<SP<CCZwlrForeignToplevelHandleV1>, uint64_t> m_muAddresses;
|
||||
std::vector<SP<CCHyprlandToplevelWindowMappingHandleV1>> m_vHandles;
|
||||
void fetchWindowForToplevel(SP<CCZwlrForeignToplevelHandleV1> handle);
|
||||
|
||||
friend struct SToplevelHandle;
|
||||
friend class CToplevelManager;
|
||||
};
|
||||
@ -1 +1 @@
|
||||
Subproject commit 4d29e48433270a2af06b8bc711ca1fe5109746cd
|
||||
Subproject commit 3a5c2bda1c1a4e55cc1330c782547695a93f05b2
|
||||
Loading…
x
Reference in New Issue
Block a user