2024-05-11 17:13:20 +01:00
# include "DataDevice.hpp"
# include <algorithm>
# include "../../managers/SeatManager.hpp"
# include "../../managers/PointerManager.hpp"
2024-12-14 16:19:56 +01:00
# include "../../managers/eventLoop/EventLoopManager.hpp"
2024-05-11 17:13:20 +01:00
# include "../../Compositor.hpp"
2024-12-22 17:12:09 +01:00
# include "../../render/pass/TexPassElement.hpp"
2024-05-11 17:13:20 +01:00
# include "Seat.hpp"
2024-06-08 10:07:59 +02:00
# include "Compositor.hpp"
2024-12-15 00:37:17 +01:00
# include "../../xwayland/XWayland.hpp"
# include "../../xwayland/Server.hpp"
2025-01-17 15:21:35 +00:00
# include "../../managers/input/InputManager.hpp"
# include "../../managers/HookSystemManager.hpp"
# include "../../helpers/Monitor.hpp"
# include "../../render/Renderer.hpp"
2025-02-23 21:52:10 -05:00
# include "../../xwayland/Dnd.hpp"
2025-01-30 12:30:12 +01:00
using namespace Hyprutils : : OS ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
CWLDataOfferResource : : CWLDataOfferResource ( SP < CWlDataOffer > resource_ , SP < IDataSource > source_ ) : m_source ( source_ ) , m_resource ( resource_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > setDestroy ( [ this ] ( CWlDataOffer * r ) { PROTO : : data - > destroyResource ( this ) ; } ) ;
m_resource - > setOnDestroy ( [ this ] ( CWlDataOffer * r ) { PROTO : : data - > destroyResource ( this ) ; } ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_resource - > setAccept ( [ this ] ( CWlDataOffer * r , uint32_t serial , const char * mime ) {
if ( ! m_source ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " Possible bug: Accept on an offer w/o a source " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
if ( m_dead ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " Possible bug: Accept on an offer that's dead " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
LOGM ( LOG , " Offer {:x} accepts data from source {:x} with mime {} " , ( uintptr_t ) this , ( uintptr_t ) m_source . get ( ) , mime ? mime : " null " ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_source - > accepted ( mime ? mime : " " ) ;
m_accepted = mime ;
2024-05-11 17:13:20 +01:00
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setReceive ( [ this ] ( CWlDataOffer * r , const char * mime , int fd ) {
2025-01-30 12:30:12 +01:00
CFileDescriptor sendFd { fd } ;
2025-05-03 16:02:49 +02:00
if ( ! m_source ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " Possible bug: Receive on an offer w/o a source " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
if ( m_dead ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " Possible bug: Receive on an offer that's dead " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
LOGM ( LOG , " Offer {:x} asks to send data from source {:x} " , ( uintptr_t ) this , ( uintptr_t ) m_source . get ( ) ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
if ( ! m_accepted ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " Offer was never accepted, sending accept first " ) ;
2025-05-03 16:02:49 +02:00
m_source - > accepted ( mime ? mime : " " ) ;
2024-05-11 17:13:20 +01:00
}
2025-05-03 16:02:49 +02:00
m_source - > send ( mime ? mime : " " , std : : move ( sendFd ) ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_recvd = true ;
2024-05-11 17:13:20 +01:00
// if (source->hasDnd())
// PROTO::data->completeDrag();
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setFinish ( [ this ] ( CWlDataOffer * r ) {
m_dead = true ;
if ( ! m_source | | ! m_recvd | | ! m_accepted )
2024-05-11 17:13:20 +01:00
PROTO : : data - > abortDrag ( ) ;
else
PROTO : : data - > completeDrag ( ) ;
} ) ;
}
2024-08-28 13:45:06 +02:00
CWLDataOfferResource : : ~ CWLDataOfferResource ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_source | | ! m_source - > hasDnd ( ) | | m_dead )
2024-08-28 13:45:06 +02:00
return ;
2025-05-03 16:02:49 +02:00
m_source - > sendDndFinished ( ) ;
2024-08-28 13:45:06 +02:00
}
2024-05-11 17:13:20 +01:00
bool CWLDataOfferResource : : good ( ) {
2025-05-03 16:02:49 +02:00
return m_resource - > resource ( ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataOfferResource : : sendData ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_source )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
const auto SOURCEACTIONS = m_source - > actions ( ) ;
2024-09-17 12:55:48 +01:00
2025-05-03 16:02:49 +02:00
if ( m_resource - > version ( ) > = 3 & & SOURCEACTIONS > 0 ) {
m_resource - > sendSourceActions ( SOURCEACTIONS ) ;
2024-09-17 12:55:48 +01:00
if ( SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE )
2025-05-03 16:02:49 +02:00
m_resource - > sendAction ( WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ) ;
2024-09-17 12:55:48 +01:00
else if ( SOURCEACTIONS & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY )
2025-05-03 16:02:49 +02:00
m_resource - > sendAction ( WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ) ;
2024-09-17 12:55:48 +01:00
else {
LOGM ( ERR , " Client bug? dnd source has no action move or copy. Sending move, f this. " ) ;
2025-05-03 16:02:49 +02:00
m_resource - > sendAction ( WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ) ;
2024-09-17 12:55:48 +01:00
}
}
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
for ( auto const & m : m_source - > mimes ( ) ) {
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " | offer {:x} supports mime {} " , ( uintptr_t ) this , m ) ;
2025-05-03 16:02:49 +02:00
m_resource - > sendOffer ( m . c_str ( ) ) ;
2024-05-11 17:13:20 +01:00
}
}
2024-12-15 00:37:17 +01:00
eDataSourceType CWLDataOfferResource : : type ( ) {
return DATA_SOURCE_TYPE_WAYLAND ;
}
SP < CWLDataOfferResource > CWLDataOfferResource : : getWayland ( ) {
2025-05-03 16:02:49 +02:00
return m_self . lock ( ) ;
2024-12-15 00:37:17 +01:00
}
SP < CX11DataOffer > CWLDataOfferResource : : getX11 ( ) {
return nullptr ;
}
SP < IDataSource > CWLDataOfferResource : : getSource ( ) {
2025-05-03 16:02:49 +02:00
return m_source . lock ( ) ;
2024-12-15 00:37:17 +01:00
}
2025-05-03 16:02:49 +02:00
CWLDataSourceResource : : CWLDataSourceResource ( SP < CWlDataSource > resource_ , SP < CWLDataDeviceResource > device_ ) : m_device ( device_ ) , m_resource ( resource_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > setData ( this ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_resource - > setDestroy ( [ this ] ( CWlDataSource * r ) {
2024-05-11 17:13:20 +01:00
events . destroy . emit ( ) ;
2025-05-03 16:02:49 +02:00
PROTO : : data - > onDestroyDataSource ( m_self ) ;
2024-05-11 17:13:20 +01:00
PROTO : : data - > destroyResource ( this ) ;
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setOnDestroy ( [ this ] ( CWlDataSource * r ) {
2024-05-11 17:13:20 +01:00
events . destroy . emit ( ) ;
2025-05-03 16:02:49 +02:00
PROTO : : data - > onDestroyDataSource ( m_self ) ;
2024-05-11 17:13:20 +01:00
PROTO : : data - > destroyResource ( this ) ;
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setOffer ( [ this ] ( CWlDataSource * r , const char * mime ) { m_mimeTypes . emplace_back ( mime ) ; } ) ;
m_resource - > setSetActions ( [ this ] ( CWlDataSource * r , uint32_t a ) {
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " DataSource {:x} actions {} " , ( uintptr_t ) this , a ) ;
2025-05-03 16:02:49 +02:00
m_supportedActions = a ;
2024-05-11 17:13:20 +01:00
} ) ;
}
CWLDataSourceResource : : ~ CWLDataSourceResource ( ) {
events . destroy . emit ( ) ;
2025-05-03 16:02:49 +02:00
PROTO : : data - > onDestroyDataSource ( m_self ) ;
2024-05-11 17:13:20 +01:00
}
SP < CWLDataSourceResource > CWLDataSourceResource : : fromResource ( wl_resource * res ) {
auto data = ( CWLDataSourceResource * ) ( ( ( CWlDataSource * ) wl_resource_get_user_data ( res ) ) - > data ( ) ) ;
2025-05-03 16:02:49 +02:00
return data ? data - > m_self . lock ( ) : nullptr ;
2024-05-11 17:13:20 +01:00
}
bool CWLDataSourceResource : : good ( ) {
2025-05-03 16:02:49 +02:00
return m_resource - > resource ( ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : accepted ( const std : : string & mime ) {
if ( mime . empty ( ) ) {
2025-05-03 16:02:49 +02:00
m_resource - > sendTarget ( nullptr ) ;
2024-05-11 17:13:20 +01:00
return ;
}
2025-05-03 16:02:49 +02:00
if ( std : : find ( m_mimeTypes . begin ( ) , m_mimeTypes . end ( ) , mime ) = = m_mimeTypes . end ( ) ) {
2024-05-11 17:13:20 +01:00
LOGM ( ERR , " Compositor/App bug: CWLDataSourceResource::sendAccepted with non-existent mime " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
m_resource - > sendTarget ( mime . c_str ( ) ) ;
2024-05-11 17:13:20 +01:00
}
std : : vector < std : : string > CWLDataSourceResource : : mimes ( ) {
2025-05-03 16:02:49 +02:00
return m_mimeTypes ;
2024-05-11 17:13:20 +01:00
}
2025-01-30 12:30:12 +01:00
void CWLDataSourceResource : : send ( const std : : string & mime , CFileDescriptor fd ) {
2025-05-03 16:02:49 +02:00
if ( std : : find ( m_mimeTypes . begin ( ) , m_mimeTypes . end ( ) , mime ) = = m_mimeTypes . end ( ) ) {
2024-05-11 17:13:20 +01:00
LOGM ( ERR , " Compositor/App bug: CWLDataSourceResource::sendAskSend with non-existent mime " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
m_resource - > sendSend ( mime . c_str ( ) , fd . get ( ) ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : cancelled ( ) {
2025-05-03 16:02:49 +02:00
m_resource - > sendCancelled ( ) ;
2024-05-11 17:13:20 +01:00
}
bool CWLDataSourceResource : : hasDnd ( ) {
2025-05-03 16:02:49 +02:00
return m_dnd ;
2024-05-11 17:13:20 +01:00
}
bool CWLDataSourceResource : : dndDone ( ) {
2025-05-03 16:02:49 +02:00
return m_dndSuccess ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : error ( uint32_t code , const std : : string & msg ) {
2025-05-03 16:02:49 +02:00
m_resource - > error ( code , msg ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : sendDndDropPerformed ( ) {
2025-05-03 16:02:49 +02:00
if ( m_resource - > version ( ) < 3 )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > sendDndDropPerformed ( ) ;
m_dropped = true ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : sendDndFinished ( ) {
2025-05-03 16:02:49 +02:00
if ( m_resource - > version ( ) < 3 )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > sendDndFinished ( ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataSourceResource : : sendDndAction ( wl_data_device_manager_dnd_action a ) {
2025-05-03 16:02:49 +02:00
if ( m_resource - > version ( ) < 3 )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > sendAction ( a ) ;
2024-05-11 17:13:20 +01:00
}
2024-09-17 12:55:48 +01:00
uint32_t CWLDataSourceResource : : actions ( ) {
2025-05-03 16:02:49 +02:00
return m_supportedActions ;
2024-09-17 12:55:48 +01:00
}
2024-12-15 00:37:17 +01:00
eDataSourceType CWLDataSourceResource : : type ( ) {
return DATA_SOURCE_TYPE_WAYLAND ;
}
2025-05-03 16:02:49 +02:00
CWLDataDeviceResource : : CWLDataDeviceResource ( SP < CWlDataDevice > resource_ ) : m_resource ( resource_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > setRelease ( [ this ] ( CWlDataDevice * r ) { PROTO : : data - > destroyResource ( this ) ; } ) ;
m_resource - > setOnDestroy ( [ this ] ( CWlDataDevice * r ) { PROTO : : data - > destroyResource ( this ) ; } ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_client = m_resource - > client ( ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_resource - > setSetSelection ( [ ] ( CWlDataDevice * r , wl_resource * sourceR , uint32_t serial ) {
2024-05-11 17:13:20 +01:00
auto source = sourceR ? CWLDataSourceResource : : fromResource ( sourceR ) : CSharedPointer < CWLDataSourceResource > { } ;
if ( ! source ) {
LOGM ( LOG , " Reset selection received " ) ;
g_pSeatManager - > setCurrentSelection ( nullptr ) ;
return ;
}
2025-05-03 16:02:49 +02:00
if ( source & & source - > m_used )
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this. " ) ;
source - > markUsed ( ) ;
g_pSeatManager - > setCurrentSelection ( source ) ;
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setStartDrag ( [ ] ( CWlDataDevice * r , wl_resource * sourceR , wl_resource * origin , wl_resource * icon , uint32_t serial ) {
2024-05-11 17:13:20 +01:00
auto source = CWLDataSourceResource : : fromResource ( sourceR ) ;
if ( ! source ) {
LOGM ( ERR , " No source in drag " ) ;
return ;
}
2025-05-03 16:02:49 +02:00
if ( source & & source - > m_used )
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " setSelection on a used resource. By protocol, this is a violation, but firefox et al insist on doing this. " ) ;
source - > markUsed ( ) ;
2025-05-03 16:02:49 +02:00
source - > m_dnd = true ;
2024-05-11 17:13:20 +01:00
2024-06-08 10:07:59 +02:00
PROTO : : data - > initiateDrag ( source , icon ? CWLSurfaceResource : : fromResource ( icon ) : nullptr , CWLSurfaceResource : : fromResource ( origin ) ) ;
2024-05-11 17:13:20 +01:00
} ) ;
}
bool CWLDataDeviceResource : : good ( ) {
2025-05-03 16:02:49 +02:00
return m_resource - > resource ( ) ;
2024-05-11 17:13:20 +01:00
}
wl_client * CWLDataDeviceResource : : client ( ) {
2025-05-03 16:02:49 +02:00
return m_client ;
2024-05-11 17:13:20 +01:00
}
2024-12-15 00:37:17 +01:00
void CWLDataDeviceResource : : sendDataOffer ( SP < IDataOffer > offer ) {
if ( ! offer )
2025-05-03 16:02:49 +02:00
m_resource - > sendDataOfferRaw ( nullptr ) ;
2024-12-15 00:37:17 +01:00
else if ( const auto WL = offer - > getWayland ( ) ; WL )
2025-05-03 16:02:49 +02:00
m_resource - > sendDataOffer ( WL - > m_resource . get ( ) ) ;
2024-12-15 00:37:17 +01:00
//FIXME: X11
2024-05-11 17:13:20 +01:00
}
2024-12-15 00:37:17 +01:00
void CWLDataDeviceResource : : sendEnter ( uint32_t serial , SP < CWLSurfaceResource > surf , const Vector2D & local , SP < IDataOffer > offer ) {
if ( const auto WL = offer - > getWayland ( ) ; WL )
2025-05-03 16:02:49 +02:00
m_resource - > sendEnterRaw ( serial , surf - > getResource ( ) - > resource ( ) , wl_fixed_from_double ( local . x ) , wl_fixed_from_double ( local . y ) , WL - > m_resource - > resource ( ) ) ;
2024-12-15 00:37:17 +01:00
// FIXME: X11
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceResource : : sendLeave ( ) {
2025-05-03 16:02:49 +02:00
m_resource - > sendLeave ( ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceResource : : sendMotion ( uint32_t timeMs , const Vector2D & local ) {
2025-05-03 16:02:49 +02:00
m_resource - > sendMotion ( timeMs , wl_fixed_from_double ( local . x ) , wl_fixed_from_double ( local . y ) ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceResource : : sendDrop ( ) {
2025-05-03 16:02:49 +02:00
m_resource - > sendDrop ( ) ;
2024-05-11 17:13:20 +01:00
}
2024-12-15 00:37:17 +01:00
void CWLDataDeviceResource : : sendSelection ( SP < IDataOffer > offer ) {
2024-05-11 17:13:20 +01:00
if ( ! offer )
2025-05-03 16:02:49 +02:00
m_resource - > sendSelectionRaw ( nullptr ) ;
2024-12-15 00:37:17 +01:00
else if ( const auto WL = offer - > getWayland ( ) ; WL )
2025-05-03 16:02:49 +02:00
m_resource - > sendSelection ( WL - > m_resource . get ( ) ) ;
2024-12-15 00:37:17 +01:00
}
eDataSourceType CWLDataDeviceResource : : type ( ) {
return DATA_SOURCE_TYPE_WAYLAND ;
}
SP < CWLDataDeviceResource > CWLDataDeviceResource : : getWayland ( ) {
2025-05-03 16:02:49 +02:00
return m_self . lock ( ) ;
2024-12-15 00:37:17 +01:00
}
SP < CX11DataDevice > CWLDataDeviceResource : : getX11 ( ) {
return nullptr ;
2024-05-11 17:13:20 +01:00
}
2025-05-03 16:02:49 +02:00
CWLDataDeviceManagerResource : : CWLDataDeviceManagerResource ( SP < CWlDataDeviceManager > resource_ ) : m_resource ( resource_ ) {
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! good ( ) )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_resource - > setOnDestroy ( [ this ] ( CWlDataDeviceManager * r ) { PROTO : : data - > destroyResource ( this ) ; } ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_resource - > setCreateDataSource ( [ this ] ( CWlDataDeviceManager * r , uint32_t id ) {
std : : erase_if ( m_sources , [ ] ( const auto & e ) { return e . expired ( ) ; } ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
const auto RESOURCE = PROTO : : data - > m_sources . emplace_back ( makeShared < CWLDataSourceResource > ( makeShared < CWlDataSource > ( r - > client ( ) , r - > version ( ) , id ) , m_device . lock ( ) ) ) ;
2024-05-11 17:13:20 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2024-05-11 17:13:20 +01:00
r - > noMemory ( ) ;
2025-05-03 16:02:49 +02:00
PROTO : : data - > m_sources . pop_back ( ) ;
2024-05-11 17:13:20 +01:00
return ;
}
2025-05-03 16:02:49 +02:00
if ( ! m_device )
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " New data source before a device was created " ) ;
2025-05-03 16:02:49 +02:00
RESOURCE - > m_self = RESOURCE ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_sources . emplace_back ( RESOURCE ) ;
2024-05-12 15:55:46 +01:00
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " New data source bound at {:x} " , ( uintptr_t ) RESOURCE . get ( ) ) ;
} ) ;
2025-05-03 16:02:49 +02:00
m_resource - > setGetDataDevice ( [ this ] ( CWlDataDeviceManager * r , uint32_t id , wl_resource * seat ) {
const auto RESOURCE = PROTO : : data - > m_devices . emplace_back ( makeShared < CWLDataDeviceResource > ( makeShared < CWlDataDevice > ( r - > client ( ) , r - > version ( ) , id ) ) ) ;
2024-05-11 17:13:20 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2024-05-11 17:13:20 +01:00
r - > noMemory ( ) ;
2025-05-03 16:02:49 +02:00
PROTO : : data - > m_devices . pop_back ( ) ;
2024-05-11 17:13:20 +01:00
return ;
}
2025-05-03 16:02:49 +02:00
RESOURCE - > m_self = RESOURCE ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
for ( auto const & s : m_sources ) {
2024-05-11 17:13:20 +01:00
if ( ! s )
continue ;
2025-05-03 16:02:49 +02:00
s - > m_device = RESOURCE ;
2024-05-11 17:13:20 +01:00
}
LOGM ( LOG , " New data device bound at {:x} " , ( uintptr_t ) RESOURCE . get ( ) ) ;
} ) ;
}
bool CWLDataDeviceManagerResource : : good ( ) {
2025-05-03 16:02:49 +02:00
return m_resource - > resource ( ) ;
2024-05-11 17:13:20 +01:00
}
CWLDataDeviceProtocol : : CWLDataDeviceProtocol ( const wl_interface * iface , const int & ver , const std : : string & name ) : IWaylandProtocol ( iface , ver , name ) {
2024-12-14 16:19:56 +01:00
g_pEventLoopManager - > doLater ( [ this ] ( ) {
2025-05-03 16:02:49 +02:00
m_listeners . onKeyboardFocusChange = g_pSeatManager - > m_events . keyboardFocusChange . registerListener ( [ this ] ( std : : any d ) { onKeyboardFocus ( ) ; } ) ;
m_listeners . onDndPointerFocusChange = g_pSeatManager - > m_events . dndPointerFocusChange . registerListener ( [ this ] ( std : : any d ) { onDndPointerFocus ( ) ; } ) ;
2024-12-14 16:19:56 +01:00
} ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : bindManager ( wl_client * client , void * data , uint32_t ver , uint32_t id ) {
2025-05-03 16:02:49 +02:00
const auto RESOURCE = m_managers . emplace_back ( makeShared < CWLDataDeviceManagerResource > ( makeShared < CWlDataDeviceManager > ( client , ver , id ) ) ) ;
2024-05-11 17:13:20 +01:00
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! RESOURCE - > good ( ) ) {
2024-05-11 17:13:20 +01:00
wl_client_post_no_memory ( client ) ;
2025-05-03 16:02:49 +02:00
m_managers . pop_back ( ) ;
2024-05-11 17:13:20 +01:00
return ;
}
LOGM ( LOG , " New datamgr resource bound at {:x} " , ( uintptr_t ) RESOURCE . get ( ) ) ;
}
void CWLDataDeviceProtocol : : destroyResource ( CWLDataDeviceManagerResource * seat ) {
2025-05-03 16:02:49 +02:00
std : : erase_if ( m_managers , [ & ] ( const auto & other ) { return other . get ( ) = = seat ; } ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : destroyResource ( CWLDataDeviceResource * resource ) {
2025-05-03 16:02:49 +02:00
std : : erase_if ( m_devices , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : destroyResource ( CWLDataSourceResource * resource ) {
2025-05-03 16:02:49 +02:00
std : : erase_if ( m_sources , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : destroyResource ( CWLDataOfferResource * resource ) {
2025-05-03 16:02:49 +02:00
std : : erase_if ( m_offers , [ & ] ( const auto & other ) { return other . get ( ) = = resource ; } ) ;
2024-05-11 17:13:20 +01:00
}
2024-12-15 00:37:17 +01:00
SP < IDataDevice > CWLDataDeviceProtocol : : dataDeviceForClient ( wl_client * c ) {
# ifndef NO_XWAYLAND
2025-04-09 11:08:42 -05:00
if ( g_pXWayland & & g_pXWayland - > pServer & & c = = g_pXWayland - > pServer - > xwaylandClient )
2024-12-15 00:37:17 +01:00
return g_pXWayland - > pWM - > getDataDevice ( ) ;
# endif
2025-05-03 16:02:49 +02:00
auto it = std : : find_if ( m_devices . begin ( ) , m_devices . end ( ) , [ c ] ( const auto & e ) { return e - > client ( ) = = c ; } ) ;
if ( it = = m_devices . end ( ) )
2024-05-11 17:13:20 +01:00
return nullptr ;
return * it ;
}
2024-12-15 00:37:17 +01:00
void CWLDataDeviceProtocol : : sendSelectionToDevice ( SP < IDataDevice > dev , SP < IDataSource > sel ) {
2024-05-11 17:13:20 +01:00
if ( ! sel ) {
dev - > sendSelection ( nullptr ) ;
return ;
}
2024-12-15 00:37:17 +01:00
SP < IDataOffer > offer ;
2024-05-11 17:13:20 +01:00
2024-12-15 00:37:17 +01:00
if ( const auto WL = dev - > getWayland ( ) ; WL ) {
2025-05-03 16:02:49 +02:00
const auto OFFER = m_offers . emplace_back ( makeShared < CWLDataOfferResource > ( makeShared < CWlDataOffer > ( WL - > m_resource - > client ( ) , WL - > m_resource - > version ( ) , 0 ) , sel ) ) ;
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! OFFER - > good ( ) ) {
2025-05-03 16:02:49 +02:00
WL - > m_resource - > noMemory ( ) ;
m_offers . pop_back ( ) ;
2024-12-15 00:37:17 +01:00
return ;
}
2025-05-03 16:02:49 +02:00
OFFER - > m_source = sel ;
OFFER - > m_self = OFFER ;
offer = OFFER ;
2024-12-15 00:37:17 +01:00
}
# ifndef NO_XWAYLAND
else if ( const auto X11 = dev - > getX11 ( ) ; X11 )
2025-05-02 17:07:20 +02:00
offer = g_pXWayland - > pWM - > createX11DataOffer ( g_pSeatManager - > m_state . keyboardFocus . lock ( ) , sel ) ;
2024-12-15 00:37:17 +01:00
# endif
2025-01-17 18:21:34 +01:00
if UNLIKELY ( ! offer ) {
2024-12-15 00:37:17 +01:00
LOGM ( ERR , " No offer could be created in sendSelectionToDevice " ) ;
2024-05-11 17:13:20 +01:00
return ;
}
2024-12-15 00:37:17 +01:00
LOGM ( LOG , " New {} offer {:x} for data source {:x} " , offer - > type ( ) = = DATA_SOURCE_TYPE_WAYLAND ? " wayland " : " X11 " , ( uintptr_t ) offer . get ( ) , ( uintptr_t ) sel . get ( ) ) ;
2024-05-11 17:13:20 +01:00
2024-12-15 00:37:17 +01:00
dev - > sendDataOffer ( offer ) ;
if ( const auto WL = offer - > getWayland ( ) ; WL )
WL - > sendData ( ) ;
dev - > sendSelection ( offer ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : onDestroyDataSource ( WP < CWLDataSourceResource > source ) {
2025-05-03 16:02:49 +02:00
if ( m_dnd . currentSource = = source )
2024-05-11 17:13:20 +01:00
abortDrag ( ) ;
}
void CWLDataDeviceProtocol : : setSelection ( SP < IDataSource > source ) {
2025-05-03 16:02:49 +02:00
for ( auto const & o : m_offers ) {
if ( o - > m_source & & o - > m_source - > hasDnd ( ) )
2024-05-11 17:13:20 +01:00
continue ;
2025-05-03 16:02:49 +02:00
o - > m_dead = true ;
2024-05-11 17:13:20 +01:00
}
if ( ! source ) {
LOGM ( LOG , " resetting selection " ) ;
2025-05-02 17:07:20 +02:00
if ( ! g_pSeatManager - > m_state . keyboardFocusResource )
2024-05-11 17:13:20 +01:00
return ;
2025-05-02 17:07:20 +02:00
auto DESTDEVICE = dataDeviceForClient ( g_pSeatManager - > m_state . keyboardFocusResource - > client ( ) ) ;
2024-12-15 00:37:17 +01:00
if ( DESTDEVICE & & DESTDEVICE - > type ( ) = = DATA_SOURCE_TYPE_WAYLAND )
2024-05-11 17:13:20 +01:00
sendSelectionToDevice ( DESTDEVICE , nullptr ) ;
return ;
}
LOGM ( LOG , " New selection for data source {:x} " , ( uintptr_t ) source . get ( ) ) ;
2025-05-02 17:07:20 +02:00
if ( ! g_pSeatManager - > m_state . keyboardFocusResource )
2024-05-11 17:13:20 +01:00
return ;
2025-05-02 17:07:20 +02:00
auto DESTDEVICE = dataDeviceForClient ( g_pSeatManager - > m_state . keyboardFocusResource - > client ( ) ) ;
2024-05-11 17:13:20 +01:00
if ( ! DESTDEVICE ) {
LOGM ( LOG , " CWLDataDeviceProtocol::setSelection: cannot send selection to a client without a data_device " ) ;
return ;
}
2024-12-15 00:37:17 +01:00
if ( DESTDEVICE - > type ( ) ! = DATA_SOURCE_TYPE_WAYLAND ) {
LOGM ( LOG , " CWLDataDeviceProtocol::setSelection: ignoring X11 data device " ) ;
return ;
}
2024-05-11 17:13:20 +01:00
sendSelectionToDevice ( DESTDEVICE , source ) ;
}
void CWLDataDeviceProtocol : : updateSelection ( ) {
2025-05-02 17:07:20 +02:00
if ( ! g_pSeatManager - > m_state . keyboardFocusResource )
2024-05-11 17:13:20 +01:00
return ;
2025-05-02 17:07:20 +02:00
auto DESTDEVICE = dataDeviceForClient ( g_pSeatManager - > m_state . keyboardFocusResource - > client ( ) ) ;
2024-05-11 17:13:20 +01:00
if ( ! DESTDEVICE ) {
LOGM ( LOG , " CWLDataDeviceProtocol::onKeyboardFocus: cannot send selection to a client without a data_device " ) ;
return ;
}
2025-05-02 17:07:20 +02:00
sendSelectionToDevice ( DESTDEVICE , g_pSeatManager - > m_selection . currentSelection . lock ( ) ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : onKeyboardFocus ( ) {
2025-05-03 16:02:49 +02:00
for ( auto const & o : m_offers ) {
if ( o - > m_source & & o - > m_source - > hasDnd ( ) )
2024-12-14 16:19:56 +01:00
continue ;
2025-05-03 16:02:49 +02:00
o - > m_dead = true ;
2024-05-11 17:13:20 +01:00
}
updateSelection ( ) ;
2024-12-14 16:19:56 +01:00
}
void CWLDataDeviceProtocol : : onDndPointerFocus ( ) {
2025-05-03 16:02:49 +02:00
for ( auto const & o : m_offers ) {
if ( o - > m_source & & ! o - > m_source - > hasDnd ( ) )
2024-12-14 16:19:56 +01:00
continue ;
2025-05-03 16:02:49 +02:00
o - > m_dead = true ;
2024-12-14 16:19:56 +01:00
}
2024-05-11 17:13:20 +01:00
updateDrag ( ) ;
}
2024-06-08 10:07:59 +02:00
void CWLDataDeviceProtocol : : initiateDrag ( WP < CWLDataSourceResource > currentSource , SP < CWLSurfaceResource > dragSurface , SP < CWLSurfaceResource > origin ) {
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
if ( m_dnd . currentSource ) {
2024-05-11 17:13:20 +01:00
LOGM ( WARN , " New drag started while old drag still active?? " ) ;
abortDrag ( ) ;
}
g_pInputManager - > setCursorImageUntilUnset ( " grabbing " ) ;
2025-05-03 16:02:49 +02:00
m_dnd . overriddenCursor = true ;
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " initiateDrag: source {:x}, surface: {:x}, origin: {:x} " , ( uintptr_t ) currentSource . get ( ) , ( uintptr_t ) dragSurface , ( uintptr_t ) origin ) ;
2025-05-03 16:02:49 +02:00
currentSource - > m_used = true ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . currentSource = currentSource ;
m_dnd . originSurface = origin ;
m_dnd . dndSurface = dragSurface ;
2024-05-15 16:25:56 +01:00
if ( dragSurface ) {
2025-05-03 16:02:49 +02:00
m_dnd . dndSurfaceDestroy = dragSurface - > m_events . destroy . registerListener ( [ this ] ( std : : any d ) { abortDrag ( ) ; } ) ;
m_dnd . dndSurfaceCommit = dragSurface - > m_events . commit . registerListener ( [ this ] ( std : : any d ) {
if ( m_dnd . dndSurface - > m_current . texture & & ! m_dnd . dndSurface - > m_mapped ) {
m_dnd . dndSurface - > map ( ) ;
2024-06-08 10:07:59 +02:00
return ;
}
2025-05-03 16:02:49 +02:00
if ( m_dnd . dndSurface - > m_current . texture < = 0 & & m_dnd . dndSurface - > m_mapped ) {
m_dnd . dndSurface - > unmap ( ) ;
2024-06-08 10:07:59 +02:00
return ;
}
} ) ;
2024-05-15 16:25:56 +01:00
}
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . mouseButton = g_pHookSystem - > hookDynamic ( " mouseButton " , [ this ] ( void * self , SCallbackInfo & info , std : : any e ) {
2024-05-11 17:13:20 +01:00
auto E = std : : any_cast < IPointer : : SButtonEvent > ( e ) ;
if ( E . state = = WL_POINTER_BUTTON_STATE_RELEASED ) {
LOGM ( LOG , " Dropping drag on mouseUp " ) ;
dropDrag ( ) ;
}
} ) ;
2025-05-03 16:02:49 +02:00
m_dnd . touchUp = g_pHookSystem - > hookDynamic ( " touchUp " , [ this ] ( void * self , SCallbackInfo & info , std : : any e ) {
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " Dropping drag on touchUp " ) ;
dropDrag ( ) ;
} ) ;
2025-05-03 16:02:49 +02:00
m_dnd . mouseMove = g_pHookSystem - > hookDynamic ( " mouseMove " , [ this ] ( void * self , SCallbackInfo & info , std : : any e ) {
2024-05-11 17:13:20 +01:00
auto V = std : : any_cast < const Vector2D > ( e ) ;
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice & & g_pSeatManager - > m_state . dndPointerFocus ) {
2025-05-02 17:07:20 +02:00
auto surf = CWLSurface : : fromResource ( g_pSeatManager - > m_state . dndPointerFocus . lock ( ) ) ;
2024-05-11 17:13:20 +01:00
if ( ! surf )
return ;
const auto box = surf - > getSurfaceBoxGlobal ( ) ;
if ( ! box . has_value ( ) )
return ;
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendMotion ( Time : : millis ( Time : : steadyNow ( ) ) , V - box - > pos ( ) ) ;
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " Drag motion {} " , V - box - > pos ( ) ) ;
}
} ) ;
2025-05-03 16:02:49 +02:00
m_dnd . touchMove = g_pHookSystem - > hookDynamic ( " touchMove " , [ this ] ( void * self , SCallbackInfo & info , std : : any e ) {
2024-05-11 17:13:20 +01:00
auto E = std : : any_cast < ITouch : : SMotionEvent > ( e ) ;
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice & & g_pSeatManager - > m_state . dndPointerFocus ) {
2025-05-02 17:07:20 +02:00
auto surf = CWLSurface : : fromResource ( g_pSeatManager - > m_state . dndPointerFocus . lock ( ) ) ;
2024-05-11 17:13:20 +01:00
if ( ! surf )
return ;
const auto box = surf - > getSurfaceBoxGlobal ( ) ;
if ( ! box . has_value ( ) )
return ;
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendMotion ( E . timeMs , E . pos ) ;
2024-05-11 17:13:20 +01:00
LOGM ( LOG , " Drag motion {} " , E . pos ) ;
}
} ) ;
2024-06-16 16:23:35 +02:00
// unfocus the pointer from the surface, this is part of """standard""" wayland procedure and gtk will freak out if this isn't happening.
// BTW, the spec does NOT require this explicitly...
// Fuck you gtk.
2025-05-02 17:07:20 +02:00
const auto LASTDNDFOCUS = g_pSeatManager - > m_state . dndPointerFocus ;
2024-06-16 16:23:35 +02:00
g_pSeatManager - > setPointerFocus ( nullptr , { } ) ;
2025-05-02 17:07:20 +02:00
g_pSeatManager - > m_state . dndPointerFocus = LASTDNDFOCUS ;
2024-06-16 16:23:35 +02:00
2024-05-11 17:13:20 +01:00
// make a new offer, etc
updateDrag ( ) ;
}
void CWLDataDeviceProtocol : : updateDrag ( ) {
2024-06-17 16:14:45 +02:00
if ( ! dndActive ( ) )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice )
m_dnd . focusedDevice - > sendLeave ( ) ;
2024-05-11 17:13:20 +01:00
2025-05-02 17:07:20 +02:00
if ( ! g_pSeatManager - > m_state . dndPointerFocus )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice = dataDeviceForClient ( g_pSeatManager - > m_state . dndPointerFocus - > client ( ) ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . focusedDevice )
2024-05-11 17:13:20 +01:00
return ;
2024-12-15 00:37:17 +01:00
SP < IDataOffer > offer ;
2025-05-03 16:02:49 +02:00
if ( const auto WL = m_dnd . focusedDevice - > getWayland ( ) ; WL ) {
2024-12-15 00:37:17 +01:00
const auto OFFER =
2025-05-03 16:02:49 +02:00
m_offers . emplace_back ( makeShared < CWLDataOfferResource > ( makeShared < CWlDataOffer > ( WL - > m_resource - > client ( ) , WL - > m_resource - > version ( ) , 0 ) , m_dnd . currentSource . lock ( ) ) ) ;
2024-12-15 00:37:17 +01:00
if ( ! OFFER - > good ( ) ) {
2025-05-03 16:02:49 +02:00
WL - > m_resource - > noMemory ( ) ;
m_offers . pop_back ( ) ;
2024-12-15 00:37:17 +01:00
return ;
}
2025-05-03 16:02:49 +02:00
OFFER - > m_source = m_dnd . currentSource ;
OFFER - > m_self = OFFER ;
offer = OFFER ;
2024-12-15 00:37:17 +01:00
}
# ifndef NO_XWAYLAND
2025-05-03 16:02:49 +02:00
else if ( const auto X11 = m_dnd . focusedDevice - > getX11 ( ) ; X11 )
offer = g_pXWayland - > pWM - > createX11DataOffer ( g_pSeatManager - > m_state . keyboardFocus . lock ( ) , m_dnd . currentSource . lock ( ) ) ;
2024-12-15 00:37:17 +01:00
# endif
2024-05-11 17:13:20 +01:00
2024-12-15 00:37:17 +01:00
if ( ! offer ) {
LOGM ( ERR , " No offer could be created in updateDrag " ) ;
2024-05-11 17:13:20 +01:00
return ;
}
2024-12-15 00:37:17 +01:00
LOGM ( LOG , " New {} dnd offer {:x} for data source {:x} " , offer - > type ( ) = = DATA_SOURCE_TYPE_WAYLAND ? " wayland " : " X11 " , ( uintptr_t ) offer . get ( ) ,
2025-05-03 16:02:49 +02:00
( uintptr_t ) m_dnd . currentSource . get ( ) ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendDataOffer ( offer ) ;
2024-12-15 00:37:17 +01:00
if ( const auto WL = offer - > getWayland ( ) ; WL )
WL - > sendData ( ) ;
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendEnter ( wl_display_next_serial ( g_pCompositor - > m_wlDisplay ) , g_pSeatManager - > m_state . dndPointerFocus . lock ( ) ,
g_pSeatManager - > m_state . dndPointerFocus - > m_current . size / 2.F , offer ) ;
2024-05-11 17:13:20 +01:00
}
2025-02-23 21:52:10 -05:00
void CWLDataDeviceProtocol : : cleanupDndState ( bool resetDevice , bool resetSource , bool simulateInput ) {
2025-05-03 16:02:49 +02:00
m_dnd . dndSurface . reset ( ) ;
m_dnd . dndSurfaceCommit . reset ( ) ;
m_dnd . dndSurfaceDestroy . reset ( ) ;
m_dnd . mouseButton . reset ( ) ;
m_dnd . mouseMove . reset ( ) ;
m_dnd . touchUp . reset ( ) ;
m_dnd . touchMove . reset ( ) ;
2025-02-23 21:52:10 -05:00
if ( resetDevice )
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice . reset ( ) ;
2025-02-23 21:52:10 -05:00
if ( resetSource )
2025-05-03 16:02:49 +02:00
m_dnd . currentSource . reset ( ) ;
2025-02-23 21:52:10 -05:00
if ( simulateInput ) {
g_pInputManager - > simulateMouseMovement ( ) ;
g_pSeatManager - > resendEnterEvents ( ) ;
}
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : dropDrag ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . focusedDevice | | ! m_dnd . currentSource ) {
if ( m_dnd . currentSource )
2024-05-11 17:13:20 +01:00
abortDrag ( ) ;
return ;
}
2024-06-15 17:33:21 +02:00
if ( ! wasDragSuccessful ( ) ) {
abortDrag ( ) ;
return ;
}
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendDrop ( ) ;
2024-05-11 17:13:20 +01:00
2025-02-23 21:52:10 -05:00
# ifndef NO_XWAYLAND
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice - > getX11 ( ) ) {
m_dnd . focusedDevice - > sendLeave ( ) ;
if ( m_dnd . overriddenCursor )
2025-02-23 21:52:10 -05:00
g_pInputManager - > unsetCursorImage ( ) ;
2025-05-03 16:02:49 +02:00
m_dnd . overriddenCursor = false ;
2025-02-23 21:52:10 -05:00
cleanupDndState ( true , true , true ) ;
return ;
}
# endif
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendLeave ( ) ;
if ( m_dnd . overriddenCursor )
2024-05-11 17:13:20 +01:00
g_pInputManager - > unsetCursorImage ( ) ;
2025-05-03 16:02:49 +02:00
m_dnd . overriddenCursor = false ;
2025-02-23 21:52:10 -05:00
cleanupDndState ( false , false , false ) ;
2024-05-11 17:13:20 +01:00
}
2024-06-15 17:33:21 +02:00
bool CWLDataDeviceProtocol : : wasDragSuccessful ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . currentSource )
2024-06-15 17:33:21 +02:00
return false ;
2025-05-03 16:02:49 +02:00
for ( auto const & o : m_offers ) {
if ( o - > m_dead | | o - > m_source ! = m_dnd . currentSource )
2024-06-15 17:33:21 +02:00
continue ;
2025-05-03 16:02:49 +02:00
if ( o - > m_recvd | | o - > m_accepted )
2024-06-15 17:33:21 +02:00
return true ;
}
2024-12-15 00:37:17 +01:00
# ifndef NO_XWAYLAND
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice - > getX11 ( ) )
2025-02-23 21:52:10 -05:00
return true ;
2024-12-15 00:37:17 +01:00
# endif
2024-06-15 17:33:21 +02:00
return false ;
}
2024-05-11 17:13:20 +01:00
void CWLDataDeviceProtocol : : completeDrag ( ) {
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . focusedDevice & & ! m_dnd . currentSource )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
if ( m_dnd . currentSource ) {
m_dnd . currentSource - > sendDndDropPerformed ( ) ;
m_dnd . currentSource - > sendDndFinished ( ) ;
2024-06-17 16:14:45 +02:00
}
2024-05-11 17:13:20 +01:00
2025-02-23 21:52:10 -05:00
cleanupDndState ( true , true , true ) ;
2024-05-11 17:13:20 +01:00
}
void CWLDataDeviceProtocol : : abortDrag ( ) {
2025-02-23 21:52:10 -05:00
cleanupDndState ( false , false , false ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
if ( m_dnd . overriddenCursor )
2024-05-11 17:13:20 +01:00
g_pInputManager - > unsetCursorImage ( ) ;
2025-05-03 16:02:49 +02:00
m_dnd . overriddenCursor = false ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . focusedDevice & & ! m_dnd . currentSource )
2024-05-11 17:13:20 +01:00
return ;
2025-05-03 16:02:49 +02:00
if ( m_dnd . focusedDevice ) {
2025-02-23 21:52:10 -05:00
# ifndef NO_XWAYLAND
2025-05-03 16:02:49 +02:00
if ( auto x11Device = m_dnd . focusedDevice - > getX11 ( ) ; x11Device )
2025-02-23 21:52:10 -05:00
x11Device - > forceCleanupDnd ( ) ;
# endif
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice - > sendLeave ( ) ;
2025-02-23 21:52:10 -05:00
}
2025-05-03 16:02:49 +02:00
if ( m_dnd . currentSource )
m_dnd . currentSource - > cancelled ( ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . focusedDevice . reset ( ) ;
m_dnd . currentSource . reset ( ) ;
2024-05-11 17:13:20 +01:00
2024-06-16 16:23:35 +02:00
g_pInputManager - > simulateMouseMovement ( ) ;
2024-06-16 20:36:55 +02:00
g_pSeatManager - > resendEnterEvents ( ) ;
2024-05-11 17:13:20 +01:00
}
2025-04-16 01:37:48 +01:00
void CWLDataDeviceProtocol : : renderDND ( PHLMONITOR pMonitor , const Time : : steady_tp & when ) {
2025-05-03 16:02:49 +02:00
if ( ! m_dnd . dndSurface | | ! m_dnd . dndSurface - > m_current . texture )
2024-05-11 17:13:20 +01:00
return ;
const auto POS = g_pInputManager - > getMouseCoordsInternal ( ) ;
2025-04-06 17:24:14 -04:00
Vector2D surfacePos = POS ;
2025-05-03 16:02:49 +02:00
surfacePos + = m_dnd . dndSurface - > m_current . offset ;
2025-04-06 17:24:14 -04:00
2025-05-03 16:02:49 +02:00
CBox box = CBox { surfacePos , m_dnd . dndSurface - > m_current . size } . translate ( - pMonitor - > m_position ) . scale ( pMonitor - > m_scale ) ;
2024-12-22 17:12:09 +01:00
CTexPassElement : : SRenderData data ;
2025-05-03 16:02:49 +02:00
data . tex = m_dnd . dndSurface - > m_current . texture ;
2024-12-22 17:12:09 +01:00
data . box = box ;
g_pHyprRenderer - > m_sRenderPass . add ( makeShared < CTexPassElement > ( data ) ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
CBox damageBox = CBox { surfacePos , m_dnd . dndSurface - > m_current . size } . expand ( 5 ) ;
2025-04-06 17:24:14 -04:00
g_pHyprRenderer - > damageBox ( damageBox ) ;
2024-05-11 17:13:20 +01:00
2025-05-03 16:02:49 +02:00
m_dnd . dndSurface - > frame ( when ) ;
2024-05-11 17:13:20 +01:00
}
bool CWLDataDeviceProtocol : : dndActive ( ) {
2025-05-03 16:02:49 +02:00
return m_dnd . currentSource ;
2024-05-11 17:13:20 +01:00
}
2025-01-24 13:37:23 +00:00
void CWLDataDeviceProtocol : : abortDndIfPresent ( ) {
if ( ! dndActive ( ) )
return ;
abortDrag ( ) ;
}