mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-08 09:45:58 +01:00
Screencopy: unify frame and client between impls + event
Adds a new event to both hooks and ipc: screencopy
This commit is contained in:
parent
12604b7676
commit
edad24c257
4 changed files with 90 additions and 63 deletions
|
@ -85,9 +85,9 @@ static const struct zwlr_screencopy_frame_v1_interface screencopyFrameImpl = {
|
||||||
.copy_with_damage = handleCopyWithDamage,
|
.copy_with_damage = handleCopyWithDamage,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SScreencopyClient* clientFromResource(wl_resource* resource) {
|
static CScreencopyClient* clientFromResource(wl_resource* resource) {
|
||||||
ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl));
|
ASSERT(wl_resource_instance_of(resource, &zwlr_screencopy_manager_v1_interface, &screencopyMgrImpl));
|
||||||
return (SScreencopyClient*)wl_resource_get_user_data(resource);
|
return (CScreencopyClient*)wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
||||||
|
@ -95,7 +95,7 @@ static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
||||||
return (SScreencopyFrame*)wl_resource_get_user_data(resource);
|
return (SScreencopyFrame*)wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScreencopyProtocolManager::removeClient(SScreencopyClient* client, bool force) {
|
void CScreencopyProtocolManager::removeClient(CScreencopyClient* client, bool force) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!client || client->ref <= 0)
|
if (!client || client->ref <= 0)
|
||||||
return;
|
return;
|
||||||
|
@ -113,6 +113,36 @@ static void handleManagerResourceDestroy(wl_resource* resource) {
|
||||||
g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true);
|
g_pProtocolManager->m_pScreencopyProtocolManager->removeClient(PCLIENT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CScreencopyClient::~CScreencopyClient() {
|
||||||
|
g_pHookSystem->unhook(tickCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
CScreencopyClient::CScreencopyClient() {
|
||||||
|
lastMeasure = std::chrono::system_clock::now();
|
||||||
|
tickCallback = g_pHookSystem->hookDynamic("tick", [&](void* self, std::any data) { onTick(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScreencopyClient::onTick() {
|
||||||
|
const auto SINCELAST = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - lastMeasure).count() / 1000.0;
|
||||||
|
|
||||||
|
if (SINCELAST < 0.5)
|
||||||
|
return;
|
||||||
|
|
||||||
|
framesInLastHalfSecond = frameCounter;
|
||||||
|
frameCounter = 0;
|
||||||
|
lastMeasure = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
if (framesInLastHalfSecond > 3 && !sentScreencast) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{1, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "1," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = true;
|
||||||
|
} else if (framesInLastHalfSecond < 4 && sentScreencast) {
|
||||||
|
EMIT_HOOK_EVENT("screencast", (std::vector<uint64_t>{0, (uint64_t)framesInLastHalfSecond, (uint64_t)clientOwner}));
|
||||||
|
g_pEventManager->postEvent(SHyprIPCEvent{"screencast", "0," + std::to_string(clientOwner)});
|
||||||
|
sentScreencast = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
void CScreencopyProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||||
const auto PCLIENT = &m_lClients.emplace_back();
|
const auto PCLIENT = &m_lClients.emplace_back();
|
||||||
|
|
||||||
|
@ -320,6 +350,8 @@ void CScreencopyProtocolManager::shareAllFrames(CMonitor* pMonitor, bool dmabuf)
|
||||||
|
|
||||||
shareFrame(f);
|
shareFrame(f);
|
||||||
|
|
||||||
|
++f->client->frameCounter;
|
||||||
|
|
||||||
framesToRemove.push_back(f);
|
framesToRemove.push_back(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,42 @@
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "../managers/HookSystemManager.hpp"
|
||||||
|
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
|
|
||||||
struct SScreencopyClient {
|
enum eClientOwners
|
||||||
int ref = 0;
|
{
|
||||||
wl_resource* resource = nullptr;
|
CLIENT_SCREENCOPY = 0,
|
||||||
|
CLIENT_TOPLEVEL_EXPORT
|
||||||
|
};
|
||||||
|
|
||||||
bool operator==(const SScreencopyClient& other) const {
|
class CScreencopyClient {
|
||||||
|
public:
|
||||||
|
CScreencopyClient();
|
||||||
|
~CScreencopyClient();
|
||||||
|
|
||||||
|
int ref = 0;
|
||||||
|
wl_resource* resource = nullptr;
|
||||||
|
|
||||||
|
eClientOwners clientOwner = CLIENT_SCREENCOPY;
|
||||||
|
|
||||||
|
int frameCounter = 0;
|
||||||
|
int framesInLastHalfSecond = 0;
|
||||||
|
std::chrono::system_clock::time_point lastMeasure;
|
||||||
|
bool sentScreencast = false;
|
||||||
|
|
||||||
|
void onTick();
|
||||||
|
HOOK_CALLBACK_FN* tickCallback = nullptr;
|
||||||
|
|
||||||
|
bool operator==(const CScreencopyClient& other) const {
|
||||||
return resource == other.resource;
|
return resource == other.resource;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SScreencopyFrame {
|
struct SScreencopyFrame {
|
||||||
wl_resource* resource = nullptr;
|
wl_resource* resource = nullptr;
|
||||||
SScreencopyClient* client = nullptr;
|
CScreencopyClient* client = nullptr;
|
||||||
|
|
||||||
uint32_t shmFormat = 0;
|
uint32_t shmFormat = 0;
|
||||||
uint32_t dmabufFormat = 0;
|
uint32_t dmabufFormat = 0;
|
||||||
|
@ -34,6 +55,7 @@ struct SScreencopyFrame {
|
||||||
wlr_buffer* buffer = nullptr;
|
wlr_buffer* buffer = nullptr;
|
||||||
|
|
||||||
CMonitor* pMonitor = nullptr;
|
CMonitor* pMonitor = nullptr;
|
||||||
|
CWindow* pWindow = nullptr;
|
||||||
|
|
||||||
bool operator==(const SScreencopyFrame& other) const {
|
bool operator==(const SScreencopyFrame& other) const {
|
||||||
return resource == other.resource && client == other.client;
|
return resource == other.resource && client == other.client;
|
||||||
|
@ -45,7 +67,7 @@ class CScreencopyProtocolManager {
|
||||||
CScreencopyProtocolManager();
|
CScreencopyProtocolManager();
|
||||||
|
|
||||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
void removeClient(SScreencopyClient* client, bool force = false);
|
void removeClient(CScreencopyClient* client, bool force = false);
|
||||||
void removeFrame(SScreencopyFrame* frame, bool force = false);
|
void removeFrame(SScreencopyFrame* frame, bool force = false);
|
||||||
void displayDestroy();
|
void displayDestroy();
|
||||||
|
|
||||||
|
@ -59,7 +81,7 @@ class CScreencopyProtocolManager {
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
wl_global* m_pGlobal = nullptr;
|
||||||
std::list<SScreencopyFrame> m_lFrames;
|
std::list<SScreencopyFrame> m_lFrames;
|
||||||
std::list<SScreencopyClient> m_lClients;
|
std::list<CScreencopyClient> m_lClients;
|
||||||
|
|
||||||
wl_listener m_liDisplayDestroy;
|
wl_listener m_liDisplayDestroy;
|
||||||
|
|
||||||
|
|
|
@ -75,17 +75,17 @@ static const struct hyprland_toplevel_export_manager_v1_interface toplevelExport
|
||||||
|
|
||||||
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame};
|
static const struct hyprland_toplevel_export_frame_v1_interface toplevelFrameImpl = {.copy = handleCopyFrame, .destroy = handleDestroyFrame};
|
||||||
|
|
||||||
static SToplevelClient* clientFromResource(wl_resource* resource) {
|
static CScreencopyClient* clientFromResource(wl_resource* resource) {
|
||||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
|
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_manager_v1_interface, &toplevelExportManagerImpl));
|
||||||
return (SToplevelClient*)wl_resource_get_user_data(resource);
|
return (CScreencopyClient*)wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
static SToplevelFrame* frameFromResource(wl_resource* resource) {
|
static SScreencopyFrame* frameFromResource(wl_resource* resource) {
|
||||||
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
|
ASSERT(wl_resource_instance_of(resource, &hyprland_toplevel_export_frame_v1_interface, &toplevelFrameImpl));
|
||||||
return (SToplevelFrame*)wl_resource_get_user_data(resource);
|
return (SScreencopyFrame*)wl_resource_get_user_data(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::removeClient(SToplevelClient* client, bool force) {
|
void CToplevelExportProtocolManager::removeClient(CScreencopyClient* client, bool force) {
|
||||||
if (!force) {
|
if (!force) {
|
||||||
if (!client || client->ref <= 0)
|
if (!client || client->ref <= 0)
|
||||||
return;
|
return;
|
||||||
|
@ -106,7 +106,8 @@ static void handleManagerResourceDestroy(wl_resource* resource) {
|
||||||
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
void CToplevelExportProtocolManager::bindManager(wl_client* client, void* data, uint32_t version, uint32_t id) {
|
||||||
const auto PCLIENT = &m_lClients.emplace_back();
|
const auto PCLIENT = &m_lClients.emplace_back();
|
||||||
|
|
||||||
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id);
|
PCLIENT->clientOwner = CLIENT_TOPLEVEL_EXPORT;
|
||||||
|
PCLIENT->resource = wl_resource_create(client, &hyprland_toplevel_export_manager_v1_interface, version, id);
|
||||||
|
|
||||||
if (!PCLIENT->resource) {
|
if (!PCLIENT->resource) {
|
||||||
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
|
Debug::log(ERR, "ToplevelExportManager could not bind! (out of memory?)");
|
||||||
|
@ -128,7 +129,7 @@ static void handleFrameResourceDestroy(wl_resource* resource) {
|
||||||
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
|
g_pProtocolManager->m_pToplevelExportProtocolManager->removeFrame(PFRAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::removeFrame(SToplevelFrame* frame, bool force) {
|
void CToplevelExportProtocolManager::removeFrame(SScreencopyFrame* frame, bool force) {
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -283,7 +284,7 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||||
if (m_vFramesAwaitingWrite.empty())
|
if (m_vFramesAwaitingWrite.empty())
|
||||||
return; // nothing to share
|
return; // nothing to share
|
||||||
|
|
||||||
std::vector<SToplevelFrame*> framesToRemove;
|
std::vector<SScreencopyFrame*> framesToRemove;
|
||||||
|
|
||||||
// share frame if correct output
|
// share frame if correct output
|
||||||
for (auto& f : m_vFramesAwaitingWrite) {
|
for (auto& f : m_vFramesAwaitingWrite) {
|
||||||
|
@ -299,6 +300,8 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||||
|
|
||||||
shareFrame(f);
|
shareFrame(f);
|
||||||
|
|
||||||
|
++f->client->frameCounter;
|
||||||
|
|
||||||
framesToRemove.push_back(f);
|
framesToRemove.push_back(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -307,7 +310,7 @@ void CToplevelExportProtocolManager::onMonitorRender(CMonitor* pMonitor) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) {
|
void CToplevelExportProtocolManager::shareFrame(SScreencopyFrame* frame) {
|
||||||
if (!frame->buffer) {
|
if (!frame->buffer) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -337,7 +340,7 @@ void CToplevelExportProtocolManager::shareFrame(SToplevelFrame* frame) {
|
||||||
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
hyprland_toplevel_export_frame_v1_send_ready(frame->resource, tvSecHi, tvSecLo, now.tv_nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespec* now) {
|
bool CToplevelExportProtocolManager::copyFrameShm(SScreencopyFrame* frame, timespec* now) {
|
||||||
void* data;
|
void* data;
|
||||||
uint32_t format;
|
uint32_t format;
|
||||||
size_t stride;
|
size_t stride;
|
||||||
|
@ -423,7 +426,7 @@ bool CToplevelExportProtocolManager::copyFrameShm(SToplevelFrame* frame, timespe
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CToplevelExportProtocolManager::copyFrameDmabuf(SToplevelFrame* frame) {
|
bool CToplevelExportProtocolManager::copyFrameDmabuf(SScreencopyFrame* frame) {
|
||||||
// todo
|
// todo
|
||||||
Debug::log(ERR, "DMABUF copying not impl'd!");
|
Debug::log(ERR, "DMABUF copying not impl'd!");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../defines.hpp"
|
#include "../defines.hpp"
|
||||||
#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h"
|
#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h"
|
||||||
#include "hyprland-toplevel-export-v1-protocol.h"
|
#include "hyprland-toplevel-export-v1-protocol.h"
|
||||||
|
#include "Screencopy.hpp"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -10,61 +11,30 @@
|
||||||
class CMonitor;
|
class CMonitor;
|
||||||
class CWindow;
|
class CWindow;
|
||||||
|
|
||||||
struct SToplevelClient {
|
|
||||||
int ref = 0;
|
|
||||||
wl_resource* resource = nullptr;
|
|
||||||
|
|
||||||
bool operator==(const SToplevelClient& other) const {
|
|
||||||
return resource == other.resource;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SToplevelFrame {
|
|
||||||
wl_resource* resource = nullptr;
|
|
||||||
SToplevelClient* client = nullptr;
|
|
||||||
|
|
||||||
uint32_t shmFormat = 0;
|
|
||||||
uint32_t dmabufFormat = 0;
|
|
||||||
wlr_box box = {0};
|
|
||||||
int shmStride = 0;
|
|
||||||
|
|
||||||
bool overlayCursor = false;
|
|
||||||
|
|
||||||
wlr_buffer_cap bufferCap = WLR_BUFFER_CAP_SHM;
|
|
||||||
|
|
||||||
wlr_buffer* buffer = nullptr;
|
|
||||||
|
|
||||||
CWindow* pWindow = nullptr;
|
|
||||||
|
|
||||||
bool operator==(const SToplevelFrame& other) const {
|
|
||||||
return resource == other.resource && client == other.client;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class CToplevelExportProtocolManager {
|
class CToplevelExportProtocolManager {
|
||||||
public:
|
public:
|
||||||
CToplevelExportProtocolManager();
|
CToplevelExportProtocolManager();
|
||||||
|
|
||||||
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
void bindManager(wl_client* client, void* data, uint32_t version, uint32_t id);
|
||||||
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* handle);
|
void captureToplevel(wl_client* client, wl_resource* resource, uint32_t frame, int32_t overlay_cursor, CWindow* handle);
|
||||||
void removeClient(SToplevelClient* client, bool force = false);
|
void removeClient(CScreencopyClient* client, bool force = false);
|
||||||
void removeFrame(SToplevelFrame* frame, bool force = false);
|
void removeFrame(SScreencopyFrame* frame, bool force = false);
|
||||||
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
void copyFrame(wl_client* client, wl_resource* resource, wl_resource* buffer, int32_t ignore_damage);
|
||||||
void displayDestroy();
|
void displayDestroy();
|
||||||
void onWindowUnmap(CWindow* pWindow);
|
void onWindowUnmap(CWindow* pWindow);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
wl_global* m_pGlobal = nullptr;
|
wl_global* m_pGlobal = nullptr;
|
||||||
std::list<SToplevelFrame> m_lFrames;
|
std::list<SScreencopyFrame> m_lFrames;
|
||||||
std::list<SToplevelClient> m_lClients;
|
std::list<CScreencopyClient> m_lClients;
|
||||||
|
|
||||||
wl_listener m_liDisplayDestroy;
|
wl_listener m_liDisplayDestroy;
|
||||||
|
|
||||||
std::vector<SToplevelFrame*> m_vFramesAwaitingWrite;
|
std::vector<SScreencopyFrame*> m_vFramesAwaitingWrite;
|
||||||
|
|
||||||
void shareFrame(SToplevelFrame* frame);
|
void shareFrame(SScreencopyFrame* frame);
|
||||||
bool copyFrameDmabuf(SToplevelFrame* frame);
|
bool copyFrameDmabuf(SScreencopyFrame* frame);
|
||||||
bool copyFrameShm(SToplevelFrame* frame, timespec* now);
|
bool copyFrameShm(SScreencopyFrame* frame, timespec* now);
|
||||||
|
|
||||||
void onMonitorRender(CMonitor* pMonitor);
|
void onMonitorRender(CMonitor* pMonitor);
|
||||||
};
|
};
|
Loading…
Reference in a new issue