2022-12-05 18:05:15 +01:00
# include "ToplevelExport.hpp"
# include "../Compositor.hpp"
2024-04-25 01:58:40 +02:00
# include "ForeignToplevelWlr.hpp"
2024-05-05 23:18:10 +02:00
# include "../managers/PointerManager.hpp"
2024-06-08 10:07:59 +02:00
# include "types/WLBuffer.hpp"
# include "types/Buffer.hpp"
# include "../helpers/Format.hpp"
2022-12-05 18:05:15 +01:00
# include <algorithm>
2024-07-27 17:02:02 +02:00
CToplevelExportClient : : CToplevelExportClient ( SP < CHyprlandToplevelExportManagerV1 > resource_ ) : resource ( resource_ ) {
if ( ! good ( ) )
return ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
resource - > setOnDestroy ( [ this ] ( CHyprlandToplevelExportManagerV1 * pMgr ) { PROTO : : toplevelExport - > destroyResource ( this ) ; } ) ;
resource - > setDestroy ( [ this ] ( CHyprlandToplevelExportManagerV1 * pMgr ) { PROTO : : toplevelExport - > destroyResource ( this ) ; } ) ;
resource - > setCaptureToplevel ( [ this ] ( CHyprlandToplevelExportManagerV1 * pMgr , uint32_t frame , int32_t overlayCursor , uint32_t handle ) {
this - > captureToplevel ( pMgr , frame , overlayCursor , g_pCompositor - > getWindowFromHandle ( handle ) ) ;
} ) ;
resource - > setCaptureToplevelWithWlrToplevelHandle ( [ this ] ( CHyprlandToplevelExportManagerV1 * pMgr , uint32_t frame , int32_t overlayCursor , wl_resource * handle ) {
this - > captureToplevel ( pMgr , frame , overlayCursor , PROTO : : foreignToplevelWlr - > windowFromHandleResource ( handle ) ) ;
} ) ;
lastMeasure . reset ( ) ;
lastFrame . reset ( ) ;
tickCallback = g_pHookSystem - > hookDynamic ( " tick " , [ & ] ( void * self , SCallbackInfo & info , std : : any data ) { onTick ( ) ; } ) ;
2024-07-24 19:07:36 +02:00
}
2024-07-27 17:02:02 +02:00
void CToplevelExportClient : : captureToplevel ( CHyprlandToplevelExportManagerV1 * pMgr , uint32_t frame , int32_t overlayCursor_ , PHLWINDOW handle ) {
// create a frame
const auto FRAME = PROTO : : toplevelExport - > m_vFrames . emplace_back (
makeShared < CToplevelExportFrame > ( makeShared < CHyprlandToplevelExportFrameV1 > ( resource - > client ( ) , resource - > version ( ) , frame ) , overlayCursor_ , handle ) ) ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
if ( ! FRAME - > good ( ) ) {
LOGM ( ERR , " Couldn't alloc frame for sharing! (no memory) " ) ;
resource - > noMemory ( ) ;
PROTO : : toplevelExport - > destroyResource ( FRAME . get ( ) ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
FRAME - > self = FRAME ;
FRAME - > client = self ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
void CToplevelExportClient : : onTick ( ) {
if ( lastMeasure . getMillis ( ) < 500 )
return ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
framesInLastHalfSecond = frameCounter ;
frameCounter = 0 ;
lastMeasure . reset ( ) ;
const auto LASTFRAMEDELTA = lastFrame . getMillis ( ) / 1000.0 ;
const bool FRAMEAWAITING = std : : ranges : : any_of ( PROTO : : toplevelExport - > m_vFrames , [ & ] ( const auto & frame ) { return frame - > client . get ( ) = = this ; } ) ;
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 & & LASTFRAMEDELTA > 1.0 & & ! FRAMEAWAITING ) {
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 ;
2022-12-05 18:05:15 +01:00
}
}
2024-07-27 17:02:02 +02:00
bool CToplevelExportClient : : good ( ) {
return resource - > resource ( ) ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
CToplevelExportFrame : : ~ CToplevelExportFrame ( ) {
if ( buffer & & buffer - > locked ( ) )
buffer - > unlock ( ) ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
CToplevelExportFrame : : CToplevelExportFrame ( SP < CHyprlandToplevelExportFrameV1 > resource_ , int32_t overlayCursor_ , PHLWINDOW pWindow_ ) : resource ( resource_ ) , pWindow ( pWindow_ ) {
if ( ! good ( ) )
2022-12-05 18:05:15 +01:00
return ;
2024-07-27 17:02:02 +02:00
overlayCursor = ! ! overlayCursor_ ;
2022-12-05 18:05:15 +01:00
2024-04-27 13:43:12 +02:00
if ( ! pWindow ) {
2024-07-27 17:02:02 +02:00
LOGM ( ERR , " Client requested sharing of window handle {:x} which does not exist! " , pWindow ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-04-27 13:43:12 +02:00
if ( ! pWindow - > m_bIsMapped | | pWindow - > isHidden ( ) ) {
2024-07-27 17:02:02 +02:00
LOGM ( ERR , " Client requested sharing of window handle {:x} which is not shareable! " , pWindow ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
resource - > setOnDestroy ( [ this ] ( CHyprlandToplevelExportFrameV1 * pFrame ) { PROTO : : toplevelExport - > destroyResource ( this ) ; } ) ;
resource - > setDestroy ( [ this ] ( CHyprlandToplevelExportFrameV1 * pFrame ) { PROTO : : toplevelExport - > destroyResource ( this ) ; } ) ;
resource - > setCopy ( [ this ] ( CHyprlandToplevelExportFrameV1 * pFrame , wl_resource * res , int32_t ignoreDamage ) { this - > copy ( pFrame , res , ignoreDamage ) ; } ) ;
2022-12-05 18:05:15 +01:00
2024-04-27 13:43:12 +02:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2022-12-05 18:05:15 +01:00
2023-12-03 23:04:07 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2024-02-15 01:58:58 +01:00
2024-07-27 17:02:02 +02:00
shmFormat = g_pHyprOpenGL - > getPreferredReadFormat ( PMONITOR ) ;
if ( shmFormat = = DRM_FORMAT_INVALID ) {
LOGM ( ERR , " No format supported by renderer in capture toplevel " ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
const auto PSHMINFO = FormatUtils : : getPixelFormatFromDRM ( shmFormat ) ;
2022-12-05 18:05:15 +01:00
if ( ! PSHMINFO ) {
2024-07-27 17:02:02 +02:00
LOGM ( ERR , " No pixel format supported by renderer in capture toplevel " ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
dmabufFormat = PMONITOR - > output - > state - > state ( ) . drmFormat ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
box = { 0 , 0 , ( int ) ( pWindow - > m_vRealSize . value ( ) . x * PMONITOR - > scale ) , ( int ) ( pWindow - > m_vRealSize . value ( ) . y * PMONITOR - > scale ) } ;
2024-07-21 13:09:54 +02:00
2024-07-27 17:02:02 +02:00
box . transform ( wlTransformToHyprutils ( PMONITOR - > transform ) , PMONITOR - > vecTransformedSize . x , PMONITOR - > vecTransformedSize . y ) . round ( ) ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
shmStride = FormatUtils : : minStride ( PSHMINFO , box . w ) ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
resource - > sendBuffer ( FormatUtils : : drmToShm ( shmFormat ) , box . width , box . height , shmStride ) ;
2023-07-20 12:42:25 +02:00
2024-07-27 17:02:02 +02:00
if ( dmabufFormat ! = DRM_FORMAT_INVALID ) {
resource - > sendLinuxDmabuf ( dmabufFormat , box . width , box . height ) ;
2023-07-20 12:42:25 +02:00
}
2024-07-27 17:02:02 +02:00
resource - > sendBufferDone ( ) ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
void CToplevelExportFrame : : copy ( CHyprlandToplevelExportFrameV1 * pFrame , wl_resource * buffer_ , int32_t ignoreDamage ) {
if ( ! good ( ) ) {
LOGM ( ERR , " No frame in copyFrame?? " ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
if ( ! validMapped ( pWindow ) ) {
LOGM ( ERR , " Client requested sharing of window handle {:x} which is gone! " , pWindow ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2024-02-07 01:18:47 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
if ( ! pWindow - > m_bIsMapped | | pWindow - > isHidden ( ) ) {
LOGM ( ERR , " Client requested sharing of window handle {:x} which is not shareable (2)! " , pWindow ) ;
resource - > sendFailed ( ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
const auto PBUFFER = CWLBufferResource : : fromResource ( buffer_ ) ;
2022-12-05 18:05:15 +01:00
if ( ! PBUFFER ) {
2024-07-27 17:02:02 +02:00
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-06-08 10:07:59 +02:00
PBUFFER - > buffer - > lock ( ) ;
2024-07-27 17:02:02 +02:00
if ( PBUFFER - > buffer - > size ! = box . size ( ) ) {
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer dimensions " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
if ( buffer ) {
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_ALREADY_USED , " frame already used " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-06-08 10:07:59 +02:00
if ( auto attrs = PBUFFER - > buffer - > dmabuf ( ) ; attrs . success ) {
2024-07-27 17:02:02 +02:00
bufferDMA = true ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
if ( attrs . format ! = dmabufFormat ) {
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer format " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-06-08 10:07:59 +02:00
} else if ( auto attrs = PBUFFER - > buffer - > shm ( ) ; attrs . success ) {
2024-07-27 17:02:02 +02:00
if ( attrs . format ! = shmFormat ) {
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer format " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
2024-07-27 17:02:02 +02:00
} else if ( ( int ) attrs . stride ! = shmStride ) {
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer stride " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
} else {
2024-07-27 17:02:02 +02:00
resource - > error ( HYPRLAND_TOPLEVEL_EXPORT_FRAME_V1_ERROR_INVALID_BUFFER , " invalid buffer type " ) ;
PROTO : : toplevelExport - > destroyResource ( this ) ;
2022-12-05 18:05:15 +01:00
return ;
}
2024-07-27 17:02:02 +02:00
buffer = PBUFFER - > buffer ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
PROTO : : toplevelExport - > m_vFramesAwaitingWrite . emplace_back ( self ) ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
void CToplevelExportFrame : : share ( ) {
if ( ! buffer | | ! validMapped ( pWindow ) )
2022-12-05 18:05:15 +01:00
return ;
timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
2024-07-27 17:02:02 +02:00
if ( bufferDMA ) {
if ( ! copyDmabuf ( & now ) ) {
resource - > sendFailed ( ) ;
2022-12-05 18:05:15 +01:00
return ;
}
} else {
2024-07-27 17:02:02 +02:00
if ( ! copyShm ( & now ) ) {
resource - > sendFailed ( ) ;
2022-12-05 18:05:15 +01:00
return ;
}
}
2024-07-27 17:02:02 +02:00
resource - > sendFlags ( ( hyprlandToplevelExportFrameV1Flags ) 0 ) ;
if ( ! ignoreDamage ) {
resource - > sendDamage ( 0 , 0 , box . width , box . height ) ;
}
2022-12-05 18:05:15 +01:00
uint32_t tvSecHi = ( sizeof ( now . tv_sec ) > 4 ) ? now . tv_sec > > 32 : 0 ;
uint32_t tvSecLo = now . tv_sec & 0xFFFFFFFF ;
2024-07-27 17:02:02 +02:00
resource - > sendReady ( tvSecHi , tvSecLo , now . tv_nsec ) ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
bool CToplevelExportFrame : : copyShm ( timespec * now ) {
auto shm = buffer - > shm ( ) ;
auto [ pixelData , fmt , bufLen ] = buffer - > beginDataPtr ( 0 ) ; // no need for end, cuz it's shm
2022-12-05 18:05:15 +01:00
// render the client
2024-07-27 17:02:02 +02:00
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2023-07-19 20:09:49 +02:00
CRegion fakeDamage { 0 , 0 , PMONITOR - > vecPixelSize . x * 10 , PMONITOR - > vecPixelSize . y * 10 } ;
2022-12-05 18:05:15 +01:00
2023-11-30 11:14:35 +01:00
g_pHyprRenderer - > makeEGLCurrent ( ) ;
CFramebuffer outFB ;
2024-07-21 13:09:54 +02:00
outFB . alloc ( PMONITOR - > vecPixelSize . x , PMONITOR - > vecPixelSize . y , g_pHyprRenderer - > isNvidia ( ) ? DRM_FORMAT_XBGR8888 : PMONITOR - > output - > state - > state ( ) . drmFormat ) ;
2023-11-30 11:14:35 +01:00
2024-07-27 17:02:02 +02:00
if ( overlayCursor ) {
2024-05-05 23:18:10 +02:00
g_pPointerManager - > lockSoftwareForMonitor ( PMONITOR - > self . lock ( ) ) ;
g_pPointerManager - > damageCursor ( PMONITOR - > self . lock ( ) ) ;
}
2023-11-24 11:54:21 +01:00
2024-06-08 10:07:59 +02:00
if ( ! g_pHyprRenderer - > beginRender ( PMONITOR , fakeDamage , RENDER_MODE_FULL_FAKE , nullptr , & outFB ) )
2024-06-03 21:10:31 +02:00
return false ;
2023-01-05 19:25:45 +01:00
g_pHyprOpenGL - > clear ( CColor ( 0 , 0 , 0 , 1.0 ) ) ;
2022-12-05 18:05:15 +01:00
// render client at 0,0
2024-07-27 17:02:02 +02:00
g_pHyprRenderer - > m_bBlockSurfaceFeedback = g_pHyprRenderer - > shouldRenderWindow ( pWindow ) ; // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer - > renderWindow ( pWindow , PMONITOR , now , false , RENDER_PASS_ALL , true , true ) ;
2022-12-05 20:11:02 +01:00
g_pHyprRenderer - > m_bBlockSurfaceFeedback = false ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
if ( overlayCursor )
g_pPointerManager - > renderSoftwareCursorsFor ( PMONITOR - > self . lock ( ) , now , fakeDamage , g_pInputManager - > getMouseCoordsInternal ( ) - pWindow - > m_vRealPosition . value ( ) ) ;
2023-04-04 01:58:30 +02:00
2024-06-08 10:07:59 +02:00
const auto PFORMAT = FormatUtils : : getPixelFormatFromDRM ( shm . format ) ;
2023-12-04 04:52:54 +01:00
if ( ! PFORMAT ) {
g_pHyprRenderer - > endRender ( ) ;
return false ;
2023-12-03 23:04:07 +01:00
}
2022-12-05 18:05:15 +01:00
2024-04-03 22:35:16 +02:00
g_pHyprOpenGL - > m_RenderData . blockScreenShader = true ;
2023-12-07 18:58:13 +01:00
g_pHyprRenderer - > endRender ( ) ;
g_pHyprRenderer - > makeEGLCurrent ( ) ;
2023-12-15 22:20:13 +01:00
g_pHyprOpenGL - > m_RenderData . pMonitor = PMONITOR ;
2023-12-07 18:58:13 +01:00
outFB . bind ( ) ;
2022-12-05 18:05:15 +01:00
2023-12-15 22:04:34 +01:00
# ifndef GLES2
glBindFramebuffer ( GL_READ_FRAMEBUFFER , outFB . m_iFb ) ;
# endif
2023-12-03 23:04:07 +01:00
glPixelStorei ( GL_PACK_ALIGNMENT , 1 ) ;
2024-07-13 12:53:53 +02:00
auto glFormat = PFORMAT - > flipRB ? GL_BGRA_EXT : GL_RGBA ;
2024-07-27 17:02:02 +02:00
glReadPixels ( 0 , 0 , box . width , box . height , glFormat , PFORMAT - > glType , pixelData ) ;
2022-12-05 18:05:15 +01:00
2024-07-27 17:02:02 +02:00
if ( overlayCursor ) {
2024-05-05 23:18:10 +02:00
g_pPointerManager - > unlockSoftwareForMonitor ( PMONITOR - > self . lock ( ) ) ;
g_pPointerManager - > damageCursor ( PMONITOR - > self . lock ( ) ) ;
}
2023-04-04 01:58:30 +02:00
2022-12-05 18:05:15 +01:00
return true ;
}
2024-07-27 17:02:02 +02:00
bool CToplevelExportFrame : : copyDmabuf ( timespec * now ) {
const auto PMONITOR = g_pCompositor - > getMonitorFromID ( pWindow - > m_iMonitorID ) ;
2023-07-20 12:42:25 +02:00
2023-08-08 19:10:47 +02:00
CRegion fakeDamage { 0 , 0 , INT16_MAX , INT16_MAX } ;
2023-07-20 12:42:25 +02:00
2024-07-27 17:02:02 +02:00
if ( overlayCursor ) {
g_pPointerManager - > lockSoftwareForMonitor ( PMONITOR - > self . lock ( ) ) ;
g_pPointerManager - > damageCursor ( PMONITOR - > self . lock ( ) ) ;
}
if ( ! g_pHyprRenderer - > beginRender ( PMONITOR , fakeDamage , RENDER_MODE_TO_BUFFER , buffer . lock ( ) ) )
2023-11-24 11:54:21 +01:00
return false ;
2023-07-20 12:42:25 +02:00
2023-08-08 19:10:47 +02:00
g_pHyprOpenGL - > clear ( CColor ( 0 , 0 , 0 , 1.0 ) ) ;
2023-07-20 12:42:25 +02:00
2024-07-27 17:02:02 +02:00
g_pHyprRenderer - > m_bBlockSurfaceFeedback = g_pHyprRenderer - > shouldRenderWindow ( pWindow ) ; // block the feedback to avoid spamming the surface if it's visible
g_pHyprRenderer - > renderWindow ( pWindow , PMONITOR , now , false , RENDER_PASS_ALL , true , true ) ;
2023-07-20 12:42:25 +02:00
g_pHyprRenderer - > m_bBlockSurfaceFeedback = false ;
2024-07-27 17:02:02 +02:00
if ( overlayCursor )
g_pPointerManager - > renderSoftwareCursorsFor ( PMONITOR - > self . lock ( ) , now , fakeDamage , g_pInputManager - > getMouseCoordsInternal ( ) - pWindow - > m_vRealPosition . value ( ) ) ;
2023-07-20 12:42:25 +02:00
2024-04-03 22:35:16 +02:00
g_pHyprOpenGL - > m_RenderData . blockScreenShader = true ;
2023-11-24 11:54:21 +01:00
g_pHyprRenderer - > endRender ( ) ;
2024-07-27 17:02:02 +02:00
if ( overlayCursor ) {
g_pPointerManager - > unlockSoftwareForMonitor ( PMONITOR - > self . lock ( ) ) ;
g_pPointerManager - > damageCursor ( PMONITOR - > self . lock ( ) ) ;
}
2023-07-20 12:42:25 +02:00
return true ;
2022-12-05 18:05:15 +01:00
}
2024-07-27 17:02:02 +02:00
bool CToplevelExportFrame : : good ( ) {
return resource - > resource ( ) ;
}
CToplevelExportProtocol : : CToplevelExportProtocol ( const wl_interface * iface , const int & ver , const std : : string & name ) : IWaylandProtocol ( iface , ver , name ) {
;
}
void CToplevelExportProtocol : : bindManager ( wl_client * client , void * data , uint32_t ver , uint32_t id ) {
const auto CLIENT = m_vClients . emplace_back ( makeShared < CToplevelExportClient > ( makeShared < CHyprlandToplevelExportManagerV1 > ( client , ver , id ) ) ) ;
if ( ! CLIENT - > good ( ) ) {
LOGM ( LOG , " Failed to bind client! (out of memory) " ) ;
wl_client_post_no_memory ( client ) ;
m_vClients . pop_back ( ) ;
return ;
}
CLIENT - > self = CLIENT ;
LOGM ( LOG , " Bound client successfully! " ) ;
}
void CToplevelExportProtocol : : destroyResource ( CToplevelExportClient * client ) {
std : : erase_if ( m_vClients , [ & ] ( const auto & other ) { return other . get ( ) = = client ; } ) ;
std : : erase_if ( m_vFrames , [ & ] ( const auto & other ) { return other - > client . get ( ) = = client ; } ) ;
std : : erase_if ( m_vFramesAwaitingWrite , [ & ] ( const auto & other ) { return other - > client . get ( ) = = client ; } ) ;
}
void CToplevelExportProtocol : : destroyResource ( CToplevelExportFrame * frame ) {
std : : erase_if ( m_vFrames , [ & ] ( const auto & other ) { return other . get ( ) = = frame ; } ) ;
std : : erase_if ( m_vFramesAwaitingWrite , [ & ] ( const auto & other ) { return other . get ( ) = = frame ; } ) ;
}
void CToplevelExportProtocol : : onOutputCommit ( CMonitor * pMonitor ) {
if ( m_vFramesAwaitingWrite . empty ( ) )
return ; // nothing to share
std : : vector < WP < CToplevelExportFrame > > framesToRemove ;
// share frame if correct output
for ( auto & f : m_vFramesAwaitingWrite ) {
if ( ! f - > pWindow | | ! validMapped ( f - > pWindow ) ) {
framesToRemove . push_back ( f ) ;
continue ;
}
const auto PWINDOW = f - > pWindow ;
if ( pMonitor ! = g_pCompositor - > getMonitorFromID ( PWINDOW - > m_iMonitorID ) )
continue ;
CBox geometry = { PWINDOW - > m_vRealPosition . value ( ) . x , PWINDOW - > m_vRealPosition . value ( ) . y , PWINDOW - > m_vRealSize . value ( ) . x , PWINDOW - > m_vRealSize . value ( ) . y } ;
if ( geometry . intersection ( { pMonitor - > vecPosition , pMonitor - > vecSize } ) . empty ( ) )
continue ;
f - > share ( ) ;
f - > client - > lastFrame . reset ( ) ;
+ + f - > client - > frameCounter ;
framesToRemove . push_back ( f ) ;
}
for ( auto & f : framesToRemove ) {
destroyResource ( f . get ( ) ) ;
}
}
void CToplevelExportProtocol : : onWindowUnmap ( PHLWINDOW pWindow ) {
for ( auto & f : m_vFrames ) {
if ( f - > pWindow = = pWindow )
f - > pWindow . reset ( ) ;
2022-12-05 18:05:15 +01:00
}
2023-02-16 23:51:34 +01:00
}