mirror of
https://github.com/hyprwm/Hyprland.git
synced 2025-08-21 06:53:48 -07:00
wlr-foreign-toplevel: move to new impl
This commit is contained in:
@@ -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) {
|
||||
|
354
src/protocols/ForeignToplevelWlr.cpp
Normal file
354
src/protocols/ForeignToplevelWlr.cpp
Normal file
@@ -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;
|
||||
}
|
77
src/protocols/ForeignToplevelWlr.hpp
Normal file
77
src/protocols/ForeignToplevelWlr.hpp
Normal file
@@ -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;
|
||||
};
|
@@ -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) {
|
||||
|
@@ -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"
|
||||
|
||||
|
Reference in New Issue
Block a user