diff options
Diffstat (limited to 'src/protocols')
| -rw-r--r-- | src/protocols/ForeignToplevel.cpp | 2 | ||||
| -rw-r--r-- | src/protocols/ForeignToplevelWlr.cpp | 354 | ||||
| -rw-r--r-- | src/protocols/ForeignToplevelWlr.hpp | 77 | ||||
| -rw-r--r-- | src/protocols/ToplevelExport.cpp | 8 | ||||
| -rw-r--r-- | src/protocols/ToplevelExport.hpp | 1 |
5 files changed, 435 insertions, 7 deletions
diff --git a/src/protocols/ForeignToplevel.cpp b/src/protocols/ForeignToplevel.cpp index c502029c..5aaede1a 100644 --- a/src/protocols/ForeignToplevel.cpp +++ b/src/protocols/ForeignToplevel.cpp @@ -62,6 +62,8 @@ void CForeignToplevelList::onMap(CWindow* pWindow) { NEWHANDLE->resource->sendAppId(pWindow->m_szInitialClass.c_str()); NEWHANDLE->resource->sendTitle(pWindow->m_szInitialTitle.c_str()); NEWHANDLE->resource->sendDone(); + + handles.push_back(NEWHANDLE); } SP<CForeignToplevelHandle> CForeignToplevelList::handleForWindow(CWindow* pWindow) { diff --git a/src/protocols/ForeignToplevelWlr.cpp b/src/protocols/ForeignToplevelWlr.cpp new file mode 100644 index 00000000..436bf1d2 --- /dev/null +++ b/src/protocols/ForeignToplevelWlr.cpp @@ -0,0 +1,354 @@ +#include "ForeignToplevelWlr.hpp" +#include <algorithm> +#include "../Compositor.hpp" + +#define LOGM PROTO::foreignToplevelWlr->protoLog + +CForeignToplevelHandleWlr::CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHandleV1> resource_, CWindow* pWindow_) : resource(resource_), pWindow(pWindow_) { + if (!resource_->resource()) + return; + + resource->setOnDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); + resource->setDestroy([this](CZwlrForeignToplevelHandleV1* h) { PROTO::foreignToplevelWlr->destroyHandle(this); }); + + resource->setActivate([this](CZwlrForeignToplevelHandleV1* p, wl_resource* seat) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_ACTIVATE) + return; + + pWindow->activate(); + }); + + resource->setSetFullscreen([this](CZwlrForeignToplevelHandleV1* p, wl_resource* output) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + return; + + if (!pWindow->m_bIsMapped) { + pWindow->m_bWantsInitialFullscreen = true; + return; + } + + g_pCompositor->setWindowFullscreen(pWindow, true); + }); + + resource->setUnsetFullscreen([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_FULLSCREEN) + return; + + g_pCompositor->setWindowFullscreen(pWindow, false); + }); + + resource->setSetMaximized([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + return; + + if (!pWindow->m_bIsMapped) { + pWindow->m_bWantsInitialFullscreen = true; + return; + } + + g_pCompositor->setWindowFullscreen(pWindow, true, FULLSCREEN_MAXIMIZED); + }); + + resource->setUnsetMaximized([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + if (pWindow->m_eSuppressedEvents & SUPPRESS_MAXIMIZE) + return; + + g_pCompositor->setWindowFullscreen(pWindow, false); + }); + + resource->setClose([this](CZwlrForeignToplevelHandleV1* p) { + if (!pWindow) + return; + + g_pCompositor->closeWindow(pWindow); + }); +} + +bool CForeignToplevelHandleWlr::good() { + return resource->resource(); +} + +CWindow* CForeignToplevelHandleWlr::window() { + return pWindow; +} + +wl_resource* CForeignToplevelHandleWlr::res() { + return resource->resource(); +} + +void CForeignToplevelHandleWlr::sendMonitor(CMonitor* pMonitor) { + if (lastMonitorID == (int64_t)pMonitor->ID) + return; + + const auto CLIENT = wl_resource_get_client(resource->resource()); + + struct wl_resource* outputResource; + + if (const auto PLASTMONITOR = g_pCompositor->getMonitorFromID(lastMonitorID); PLASTMONITOR) { + wl_resource_for_each(outputResource, &PLASTMONITOR->output->resources) { + if (wl_resource_get_client(outputResource) != CLIENT) + continue; + + resource->sendOutputLeave(outputResource); + } + } + + wl_resource_for_each(outputResource, &pMonitor->output->resources) { + if (wl_resource_get_client(outputResource) != CLIENT) + continue; + + resource->sendOutputEnter(outputResource); + } + + lastMonitorID = pMonitor->ID; +} + +void CForeignToplevelHandleWlr::sendState() { + if (!pWindow || !pWindow->m_pWorkspace || !pWindow->m_bIsMapped) + return; + + wl_array state; + wl_array_init(&state); + + if (pWindow == g_pCompositor->m_pLastWindow) { + auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_ACTIVATED; + } + + if (pWindow->m_bIsFullscreen) { + auto p = (uint32_t*)wl_array_add(&state, sizeof(uint32_t)); + if (pWindow->m_pWorkspace->m_efFullscreenMode == FULLSCREEN_FULL) + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_FULLSCREEN; + else + *p = ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_STATE_MAXIMIZED; + } + + resource->sendState(&state); + + wl_array_release(&state); +} + +CForeignToplevelWlrManager::CForeignToplevelWlrManager(SP<CZwlrForeignToplevelManagerV1> resource_) : resource(resource_) { + if (!resource_->resource()) + return; + + resource->setOnDestroy([this](CZwlrForeignToplevelManagerV1* h) { PROTO::foreignToplevelWlr->onManagerResourceDestroy(this); }); + + resource->setStop([this](CZwlrForeignToplevelManagerV1* h) { + resource->sendFinished(); + finished = true; + LOGM(LOG, "CForeignToplevelWlrManager: finished"); + PROTO::foreignToplevelWlr->onManagerResourceDestroy(this); + }); + + for (auto& w : g_pCompositor->m_vWindows) { + if (!w->m_bIsMapped || w->m_bFadingOut) + continue; + + onMap(w.get()); + } + + lastFocus = g_pCompositor->m_pLastWindow; +} + +void CForeignToplevelWlrManager::onMap(CWindow* pWindow) { + if (finished) + return; + + const auto NEWHANDLE = PROTO::foreignToplevelWlr->m_vHandles.emplace_back(std::make_shared<CForeignToplevelHandleWlr>( + std::make_shared<CZwlrForeignToplevelHandleV1>(wl_resource_get_client(resource->resource()), wl_resource_get_version(resource->resource()), 0), pWindow)); + + if (!NEWHANDLE->good()) { + LOGM(ERR, "Couldn't create a foreign handle"); + wl_resource_post_no_memory(resource->resource()); + PROTO::foreignToplevelWlr->m_vHandles.pop_back(); + return; + } + + LOGM(LOG, "Newly mapped window {:016x}", (uintptr_t)pWindow); + resource->sendToplevel(NEWHANDLE->resource.get()); + NEWHANDLE->resource->sendAppId(pWindow->m_szInitialClass.c_str()); + NEWHANDLE->resource->sendTitle(pWindow->m_szInitialTitle.c_str()); + if (const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); PMONITOR) + NEWHANDLE->sendMonitor(PMONITOR); + NEWHANDLE->sendState(); + NEWHANDLE->resource->sendDone(); + + handles.push_back(NEWHANDLE); +} + +SP<CForeignToplevelHandleWlr> CForeignToplevelWlrManager::handleForWindow(CWindow* pWindow) { + std::erase_if(handles, [](const auto& wp) { return !wp.lock(); }); + const auto IT = std::find_if(handles.begin(), handles.end(), [pWindow](const auto& h) { return h.lock()->window() == pWindow; }); + return IT == handles.end() ? SP<CForeignToplevelHandleWlr>{} : IT->lock(); +} + +void CForeignToplevelWlrManager::onTitle(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->resource->sendTitle(pWindow->m_szTitle.c_str()); +} + +void CForeignToplevelWlrManager::onClass(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->resource->sendAppId(g_pXWaylandManager->getAppIDClass(pWindow).c_str()); +} + +void CForeignToplevelWlrManager::onUnmap(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H) + return; + + H->resource->sendClosed(); + H->closed = true; +} + +void CForeignToplevelWlrManager::onMoveMonitor(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID); + + if (!PMONITOR) + return; + + H->sendMonitor(PMONITOR); +} + +void CForeignToplevelWlrManager::onFullscreen(CWindow* pWindow) { + if (finished) + return; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->sendState(); +} + +void CForeignToplevelWlrManager::onNewFocus(CWindow* pWindow) { + if (finished) + return; + + if (const auto HOLD = handleForWindow(lastFocus); HOLD) + HOLD->sendState(); + + lastFocus = pWindow; + + const auto H = handleForWindow(pWindow); + if (!H || H->closed) + return; + + H->sendState(); +} + +bool CForeignToplevelWlrManager::good() { + return resource->resource(); +} + +CForeignToplevelWlrProtocol::CForeignToplevelWlrProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + static auto P = g_pHookSystem->hookDynamic("openWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onMap(PWINDOW); + } + }); + + static auto P1 = g_pHookSystem->hookDynamic("closeWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onUnmap(PWINDOW); + } + }); + + static auto P2 = g_pHookSystem->hookDynamic("windowTitle", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onTitle(PWINDOW); + } + }); + + static auto P3 = g_pHookSystem->hookDynamic("activeWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onNewFocus(PWINDOW); + } + }); + + static auto P4 = g_pHookSystem->hookDynamic("moveWindow", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onMoveMonitor(PWINDOW); + } + }); + + static auto P5 = g_pHookSystem->hookDynamic("fullscreen", [this](void* self, SCallbackInfo& info, std::any data) { + const auto PWINDOW = std::any_cast<CWindow*>(data); + for (auto& m : m_vManagers) { + m->onFullscreen(PWINDOW); + } + }); +} + +void CForeignToplevelWlrProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { + const auto RESOURCE = m_vManagers.emplace_back(std::make_unique<CForeignToplevelWlrManager>(std::make_shared<CZwlrForeignToplevelManagerV1>(client, ver, id))).get(); + + if (!RESOURCE->good()) { + LOGM(ERR, "Couldn't create a foreign list"); + wl_client_post_no_memory(client); + m_vManagers.pop_back(); + return; + } +} + +void CForeignToplevelWlrProtocol::onManagerResourceDestroy(CForeignToplevelWlrManager* mgr) { + std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == mgr; }); +} + +void CForeignToplevelWlrProtocol::destroyHandle(CForeignToplevelHandleWlr* handle) { + std::erase_if(m_vHandles, [&](const auto& other) { return other.get() == handle; }); +} + +CWindow* CForeignToplevelWlrProtocol::windowFromHandleResource(wl_resource* res) { + for (auto& h : m_vHandles) { + if (h->res() != res) + continue; + + return h->window(); + } + + return nullptr; +}
\ No newline at end of file diff --git a/src/protocols/ForeignToplevelWlr.hpp b/src/protocols/ForeignToplevelWlr.hpp new file mode 100644 index 00000000..c22a71cd --- /dev/null +++ b/src/protocols/ForeignToplevelWlr.hpp @@ -0,0 +1,77 @@ +#pragma once + +#include <memory> +#include <vector> +#include "WaylandProtocol.hpp" +#include "wlr-foreign-toplevel-management-unstable-v1.hpp" + +class CWindow; +class CMonitor; + +class CForeignToplevelHandleWlr { + public: + CForeignToplevelHandleWlr(SP<CZwlrForeignToplevelHandleV1> resource_, CWindow* pWindow); + + bool good(); + CWindow* window(); + wl_resource* res(); + + private: + SP<CZwlrForeignToplevelHandleV1> resource; + CWindow* pWindow = nullptr; + bool closed = false; + int64_t lastMonitorID = -1; + + void sendMonitor(CMonitor* pMonitor); + void sendState(); + + friend class CForeignToplevelWlrManager; +}; + +class CForeignToplevelWlrManager { + public: + CForeignToplevelWlrManager(SP<CZwlrForeignToplevelManagerV1> resource_); + + void onMap(CWindow* pWindow); + void onTitle(CWindow* pWindow); + void onClass(CWindow* pWindow); + void onMoveMonitor(CWindow* pWindow); + void onFullscreen(CWindow* pWindow); + void onNewFocus(CWindow* pWindow); + void onUnmap(CWindow* pWindow); + + bool good(); + + private: + SP<CZwlrForeignToplevelManagerV1> resource; + bool finished = false; + CWindow* lastFocus = nullptr; // READ-ONLY + + SP<CForeignToplevelHandleWlr> handleForWindow(CWindow* pWindow); + + std::vector<WP<CForeignToplevelHandleWlr>> handles; +}; + +class CForeignToplevelWlrProtocol : public IWaylandProtocol { + public: + CForeignToplevelWlrProtocol(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); + + CWindow* windowFromHandleResource(wl_resource* res); + + private: + void onManagerResourceDestroy(CForeignToplevelWlrManager* mgr); + void destroyHandle(CForeignToplevelHandleWlr* handle); + + // + std::vector<UP<CForeignToplevelWlrManager>> m_vManagers; + std::vector<SP<CForeignToplevelHandleWlr>> m_vHandles; + + friend class CForeignToplevelWlrManager; + friend class CForeignToplevelHandleWlr; +}; + +namespace PROTO { + inline UP<CForeignToplevelWlrProtocol> foreignToplevelWlr; +}; diff --git a/src/protocols/ToplevelExport.cpp b/src/protocols/ToplevelExport.cpp index e2006afb..166ba1af 100644 --- a/src/protocols/ToplevelExport.cpp +++ b/src/protocols/ToplevelExport.cpp @@ -1,5 +1,6 @@ #include "ToplevelExport.hpp" #include "../Compositor.hpp" +#include "ForeignToplevelWlr.hpp" #include <algorithm> @@ -39,17 +40,12 @@ CToplevelExportProtocolManager::CToplevelExportProtocolManager() { Debug::log(LOG, "ToplevelExportManager started successfully!"); } -wlr_foreign_toplevel_handle_v1* zwlrHandleFromResource(wl_resource* resource) { - // we can't assert here, but it doesnt matter. - return (wlr_foreign_toplevel_handle_v1*)wl_resource_get_user_data(resource); -} - static void handleCaptureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, uint32_t handle) { g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromHandle(handle)); } static void handleCaptureToplevelWithWlr(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, wl_resource* handle) { - g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, g_pCompositor->getWindowFromZWLRHandle(handle)); + g_pProtocolManager->m_pToplevelExportProtocolManager->captureToplevel(client, resource, frame, overlay_cursor, PROTO::foreignToplevelWlr->windowFromHandleResource(handle)); } static void handleDestroy(wl_client* client, wl_resource* resource) { diff --git a/src/protocols/ToplevelExport.hpp b/src/protocols/ToplevelExport.hpp index 50b967ed..199a26dd 100644 --- a/src/protocols/ToplevelExport.hpp +++ b/src/protocols/ToplevelExport.hpp @@ -1,7 +1,6 @@ #pragma once #include "../defines.hpp" -#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h" #include "hyprland-toplevel-export-v1-protocol.h" #include "Screencopy.hpp" |
