2025-12-09 20:11:01 -06:00
# include <Mw/Milsko.h>
2026-03-19 17:32:36 -07:00
# include <sys/poll.h>
2026-03-19 19:43:57 -07:00
# include <sys/mman.h>
2025-12-09 20:11:01 -06:00
# include "../../external/stb_ds.h"
2026-04-08 14:18:13 -07:00
# include "pixman.h"
2025-12-09 20:11:01 -06:00
/* TODO: find out what FreeBSD and such wants us to include */
# ifdef __FreeBSD__
/* XXX: Untested (nishi) */
# include <evdev/input.h>
# else
# include <linux/input.h>
# include <linux/input-event-codes.h>
# endif
2026-03-24 17:38:21 -07:00
wayland_call_table_t wl_call_tbl ;
2026-03-24 23:24:20 -07:00
MwBool MwWaylandAlwaysRender = MwFALSE ;
2026-03-24 17:38:21 -07:00
2026-01-04 11:40:34 -07:00
/* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */
# define WAYLAND_EVENT_OP_START(self) \
do { \
struct timespec t ; \
t . tv_sec = 0 ; \
t . tv_nsec = 250 ; \
if ( pthread_mutex_timedlock ( & self - > wayland . eventsMutex , & t ) ! = 0 ) { \
/*printf("deadlock at line %d\n", __LINE__);*/ \
return ; \
} ; \
} while ( 0 ) ;
/* Footer for WAYLAND_EVENT_OP_START */
# define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex);
2025-12-18 13:15:03 -07:00
/* Setup the framebuffer with the saved width/height */
static void framebuffer_setup ( struct _MwLLWayland * wayland ) ;
/* Destroy the framebuffer */
static void framebuffer_destroy ( struct _MwLLWayland * handle ) ;
2025-12-17 19:41:05 -07:00
2026-03-19 19:43:57 -07:00
/* Setup the framebuffer with the saved width/height */
static void backbuffer_setup ( struct _MwLLWayland * wayland ) ;
/* Destroy the backbuffer */
static void backbuffer_destroy ( struct _MwLLWayland * handle ) ;
2025-12-18 23:32:51 -07:00
static void buffer_destroy ( struct _MwLLWaylandShmBuffer * buffer ) ;
2025-12-18 11:26:51 -07:00
static void region_setup ( MwLL handle ) ;
static void region_invalidate ( MwLL handle ) ;
2026-03-26 17:48:22 -07:00
static void update_buffer ( MwLL self , struct _MwLLWaylandShmBuffer * buffer ) ;
2025-12-09 20:11:01 -06:00
/* Get the registered interface from r, or NULL if it doesn't currently have it. */
# define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name)
/* `wl_registry.global` callback */
static void new_protocol ( void * data , struct wl_registry * registry ,
MwU32 name , const char * interface ,
MwU32 version ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) version ;
( void ) registry ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-09 20:11:01 -06:00
2026-01-04 11:40:34 -07:00
wayland_protocol_callback_table_t * cb = shget ( self - > wayland . wl_protocol_setup_map , interface ) ;
2025-12-18 23:32:51 -07:00
if ( cb ! = NULL ) {
2025-12-30 22:26:19 -07:00
char * inter = malloc ( strlen ( interface ) + 1 ) ;
2025-12-18 17:46:23 -07:00
strcpy ( inter , interface ) ;
2026-01-04 11:40:34 -07:00
shput ( self - > wayland . wl_protocol_map , inter , cb - > setup ( name , data ) ) ;
2026-03-26 17:48:22 -07:00
/* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */
} else if ( strcmp ( interface , " wp_alpha_modifier_v1 " ) = = 0 ) {
self - > common . supports_transparency = MwTRUE ;
2025-12-09 20:11:01 -06:00
} else {
2026-03-26 17:48:22 -07:00
// printf("unknown interface %s\n", interface);
2025-12-09 20:11:01 -06:00
}
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_registry.global_remove` callback */
static void protocol_removed ( void * data ,
struct wl_registry * registry ,
MwU32 name ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) registry ;
( void ) name ;
2025-12-18 23:32:51 -07:00
printf ( " %d destroyed \n " , name ) ;
2025-12-09 20:11:01 -06:00
} ;
2025-12-30 17:12:12 -07:00
/* Flush Wayland events */
static void wl_flush ( MwLL handle ) {
struct pollfd pfd ;
int rc ;
pfd . fd = wl_display_get_fd ( handle - > wayland . display ) ;
pfd . events = POLLIN ;
while ( MwTRUE ) {
rc = wl_display_flush ( handle - > wayland . display ) ;
if ( errno ! = EAGAIN | | rc ! = - 1 ) {
break ;
}
if ( poll ( & pfd , 1 , - 1 ) = = - 1 ) {
break ;
}
}
}
2026-03-27 15:14:04 -07:00
/* Recursively dispatch a resize event to a widget and its children */
2026-03-24 14:43:38 -07:00
static void recursive_dispatch_resize ( MwLL handle ) {
2026-03-24 13:31:49 -07:00
MwWidget h = ( MwWidget ) handle - > common . user ;
if ( h ) {
int i ;
for ( i = 0 ; i < arrlen ( h - > children ) ; i + + ) {
MwDispatch ( h - > children [ i ] , resize ) ;
if ( arrlen ( h - > children [ i ] - > children ) > 0 ) {
2026-03-24 14:43:38 -07:00
recursive_dispatch_resize ( h - > children [ i ] - > lowlevel ) ;
2026-03-24 13:31:49 -07:00
}
}
}
} ;
2026-03-27 17:15:59 -07:00
/* Recursively dispatch a move event to a widget and its children */
static void recursive_dispatch_move ( MwLL handle , MwLLMouse * p ) {
2026-03-27 15:14:04 -07:00
MwWidget h = ( MwWidget ) handle - > common . user ;
if ( h ) {
int i ;
for ( i = 0 ; i < arrlen ( h - > children ) ; i + + ) {
2026-03-27 17:15:59 -07:00
MwLLDispatch ( h - > children [ i ] - > lowlevel , move , p ) ;
2026-03-27 15:14:04 -07:00
if ( arrlen ( h - > children [ i ] - > children ) > 0 ) {
2026-03-27 17:15:59 -07:00
recursive_dispatch_move ( h - > children [ i ] - > lowlevel , p ) ;
2026-03-27 15:14:04 -07:00
}
}
}
} ;
2026-03-24 13:31:49 -07:00
/* Recursively dispatch a key event to a widget and its children */
static void recursive_dispatch_key ( MwLL handle , int * k ) {
MwWidget h = ( MwWidget ) handle - > common . user ;
MwLLDispatch ( handle , key , k ) ;
if ( h ) {
int i ;
for ( i = 0 ; i < arrlen ( h - > children ) ; i + + ) {
MwLLDispatch ( h - > children [ i ] - > lowlevel , key , k ) ;
if ( arrlen ( h - > children [ i ] - > children ) > 0 ) {
recursive_dispatch_key ( h - > children [ i ] - > lowlevel , k ) ;
}
}
}
} ;
/* Recursively dispatch a key released event to a widget and its children */
static void recursive_dispatch_key_released ( MwLL handle , int * k ) {
MwWidget h = ( MwWidget ) handle - > common . user ;
MwLLDispatch ( handle , key_released , k ) ;
if ( h ) {
int i ;
for ( i = 0 ; i < arrlen ( h - > children ) ; i + + ) {
MwLLDispatch ( h - > children [ i ] - > lowlevel , key_released , k ) ;
if ( arrlen ( h - > children [ i ] - > children ) > 0 ) {
recursive_dispatch_key_released ( h - > children [ i ] - > lowlevel , k ) ;
}
}
}
} ;
2025-12-30 17:12:12 -07:00
static void wl_offer ( void * data ,
struct wl_data_offer * wl_data_offer ,
const char * mime_type ) {
wl_clipboard_device_context_t * self = data ;
wl_data_offer_accept ( wl_data_offer , self - > ll - > wayland . clipboard_serial , mime_type ) ;
2025-12-18 17:46:23 -07:00
} ;
2025-12-30 17:12:12 -07:00
struct wl_data_offer_listener offer_listener = {
. offer = wl_offer ,
2025-12-18 17:46:23 -07:00
} ;
2025-12-30 17:12:12 -07:00
static void wl_data_device_data_offer ( void * data ,
struct wl_data_device * wl_data_device ,
struct wl_data_offer * offer ) {
wl_clipboard_device_context_t * self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_data_device ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
wl_data_offer_add_listener ( offer , & offer_listener , data ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
self - > offer . wl = offer ;
} ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
static void wl_data_device_enter ( void * data ,
struct wl_data_device * wl_data_device ,
uint32_t serial ,
struct wl_surface * surface ,
wl_fixed_t x ,
wl_fixed_t y ,
struct wl_data_offer * id ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_data_device ;
( void ) surface ;
( void ) x ;
( void ) y ;
( void ) id ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
self - > wayland . clipboard_serial = serial ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
static void wl_data_device_leave ( void * data ,
struct wl_data_device * wl_data_device ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
wl_data_device_destroy ( wl_data_device ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
static void wl_data_device_motion ( void * data ,
struct wl_data_device * wl_data_device ,
uint32_t time ,
wl_fixed_t x ,
wl_fixed_t y ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) wl_data_device ;
( void ) time ;
( void ) x ;
( void ) y ;
2025-12-30 17:12:12 -07:00
} ;
static void wl_data_device_drop ( void * data ,
struct wl_data_device * wl_data_device ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) wl_data_device ;
2025-12-30 17:12:12 -07:00
} ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
static void wl_data_device_selection ( void * data ,
struct wl_data_device * wl_data_device ,
struct wl_data_offer * id ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) wl_data_device ;
( void ) id ;
2025-12-18 17:46:23 -07:00
} ;
2025-12-30 17:12:12 -07:00
struct wl_data_device_listener wl_data_device_listener = {
. data_offer = wl_data_device_data_offer ,
. enter = wl_data_device_enter ,
. leave = wl_data_device_leave ,
. motion = wl_data_device_motion ,
. drop = wl_data_device_drop ,
. selection = wl_data_device_selection ,
2025-12-18 17:46:23 -07:00
} ;
2025-12-30 17:12:12 -07:00
static void zwp_primary_selection_device_v1_data_offer ( void * data ,
struct zwp_primary_selection_device_v1 * zwp_primary_selection_device_v1 ,
struct zwp_primary_selection_offer_v1 * offer ) {
wl_clipboard_device_context_t * self = data ;
2026-03-24 17:38:21 -07:00
( void ) zwp_primary_selection_device_v1 ;
2025-12-30 17:12:12 -07:00
self - > offer . zwp = offer ;
} ;
static void zwp_primary_selection_device_v1_selection ( void * data ,
struct zwp_primary_selection_device_v1 * zwp_primary_selection_device_v1 ,
struct zwp_primary_selection_offer_v1 * id ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) zwp_primary_selection_device_v1 ;
( void ) id ;
2025-12-30 17:12:12 -07:00
} ;
struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = {
. data_offer = zwp_primary_selection_device_v1_data_offer ,
. selection = zwp_primary_selection_device_v1_selection ,
} ;
static void wl_clipboard_read ( wl_clipboard_device_context_t * ctx ) {
int fds [ 2 ] ;
fd_set set ;
char * buf = NULL ;
struct timeval timeout ;
int rc = 0 ;
if ( pipe ( fds ) ! = 0 ) {
return ;
}
FD_ZERO ( & set ) ;
FD_SET ( fds [ 0 ] , & set ) ;
timeout . tv_sec = 0 ;
timeout . tv_usec = 100 ;
if ( ctx - > ll - > wayland . supports_zwp ) {
zwp_primary_selection_offer_v1_receive ( ctx - > offer . zwp , " text/plain " , fds [ 1 ] ) ;
2026-03-23 15:45:48 -07:00
} else if ( ctx - > offer . wl ) {
2025-12-30 17:12:12 -07:00
wl_data_offer_receive ( ctx - > offer . wl , " text/plain " , fds [ 1 ] ) ;
}
close ( fds [ 1 ] ) ;
wl_flush ( ctx - > ll ) ;
wl_display_roundtrip ( ctx - > ll - > wayland . display ) ;
while ( MwTRUE ) {
rc = select ( fds [ 0 ] + 1 , & set , NULL , NULL , & timeout ) ;
if ( rc < = 0 ) {
break ;
} else {
char b ;
ssize_t n = read ( fds [ 0 ] , & b , sizeof ( b ) ) ;
if ( n < = 0 ) {
break ;
}
arrpush ( buf , b ) ;
}
}
arrpush ( buf , 0 ) ;
close ( fds [ 0 ] ) ;
MwLLDispatch ( ctx - > ll , clipboard , buf ) ;
arrfree ( buf ) ;
2026-03-23 12:05:32 -07:00
ctx - > ll - > wayland . events_pending = 1 ;
2025-12-30 17:12:12 -07:00
}
static void wl_data_source_listener_target ( void * data ,
struct wl_data_source * wl_data_source ,
const char * mime_type ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) wl_data_source ;
( void ) mime_type ;
2025-12-30 17:12:12 -07:00
} ;
static void wl_data_source_listener_send ( void * data ,
struct wl_data_source * wl_data_source ,
const char * mime_type ,
int32_t fd ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_data_source ;
( void ) mime_type ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
if ( self - > wayland . clipboard_buffer ! = NULL ) {
write ( fd , self - > wayland . clipboard_buffer , strlen ( self - > wayland . clipboard_buffer ) ) ;
close ( fd ) ;
}
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
static void wl_data_source_listener_cancelled ( void * data ,
struct wl_data_source * wl_data_source ) ;
struct wl_data_source_listener wl_data_source_listener = {
. target = wl_data_source_listener_target ,
. send = wl_data_source_listener_send ,
. cancelled = wl_data_source_listener_cancelled ,
} ;
static void wl_data_source_listener_cancelled ( void * data ,
struct wl_data_source * wl_data_source ) {
MwLL self = data ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
wl_data_source_destroy ( wl_data_source ) ;
self - > wayland . clipboard_source . wl = wl_data_device_manager_create_data_source ( self - > wayland . clipboard_manager . wl ) ;
wl_data_source_offer ( self - > wayland . clipboard_source . wl , " text/plain " ) ;
wl_data_source_offer ( self - > wayland . clipboard_source . wl , " text/plain;charset=utf-8 " ) ;
wl_data_source_offer ( self - > wayland . clipboard_source . wl , " TEXT " ) ;
wl_data_source_offer ( self - > wayland . clipboard_source . wl , " STRING " ) ;
wl_data_source_offer ( self - > wayland . clipboard_source . wl , " UTF8_STRING " ) ;
wl_data_source_add_listener ( self - > wayland . clipboard_source . wl , & wl_data_source_listener , self ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
static void zwp_primary_selection_source_v1_send ( void * data ,
struct zwp_primary_selection_source_v1 * wl_data_source ,
const char * mime_type ,
int32_t fd ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_data_source ;
( void ) mime_type ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
if ( self - > wayland . clipboard_buffer ! = NULL ) {
write ( fd , self - > wayland . clipboard_buffer , strlen ( self - > wayland . clipboard_buffer ) ) ;
close ( fd ) ;
}
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
static void zwp_primary_selection_source_v1_cancelled ( void * data ,
struct zwp_primary_selection_source_v1 * wl_data_source ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_data_source ;
2025-12-30 17:12:12 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-30 17:12:12 -07:00
zwp_primary_selection_source_v1_destroy ( self - > wayland . clipboard_source . zwp ) ;
self - > wayland . clipboard_source . zwp = zwp_primary_selection_device_manager_v1_create_source ( self - > wayland . clipboard_manager . zwp ) ;
zwp_primary_selection_source_v1_offer ( self - > wayland . clipboard_source . zwp , " text/plain " ) ;
zwp_primary_selection_source_v1_offer ( self - > wayland . clipboard_source . zwp , " text/plain;charset=utf-8 " ) ;
zwp_primary_selection_source_v1_offer ( self - > wayland . clipboard_source . zwp , " TEXT " ) ;
zwp_primary_selection_source_v1_offer ( self - > wayland . clipboard_source . zwp , " STRING " ) ;
zwp_primary_selection_source_v1_offer ( self - > wayland . clipboard_source . zwp , " UTF8_STRING " ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-30 17:12:12 -07:00
} ;
struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = {
. send = zwp_primary_selection_source_v1_send ,
. cancelled = zwp_primary_selection_source_v1_cancelled ,
} ;
/* wl_data_device_manager setup function */
static wayland_protocol_t * wl_data_device_manager_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland - > clipboard_manager . wl = wl_registry_bind ( wayland - > registry , name , & wl_data_device_manager_interface , 2 ) ;
wayland - > clipboard_source . wl = wl_data_device_manager_create_data_source ( wayland - > clipboard_manager . wl ) ;
wl_data_source_offer ( wayland - > clipboard_source . wl , " text/plain " ) ;
wl_data_source_offer ( wayland - > clipboard_source . wl , " text/plain;charset=utf-8 " ) ;
wl_data_source_offer ( wayland - > clipboard_source . wl , " TEXT " ) ;
wl_data_source_offer ( wayland - > clipboard_source . wl , " STRING " ) ;
wl_data_source_offer ( wayland - > clipboard_source . wl , " UTF8_STRING " ) ;
wl_data_source_add_listener ( wayland - > clipboard_source . wl , & wl_data_source_listener , wayland ) ;
return NULL ;
}
static void wl_data_device_manager_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
2026-01-02 14:19:30 -07:00
if ( wayland - > clipboard_manager . wl ! = NULL & & ! wayland - > supports_zwp ) {
wl_data_device_manager_destroy ( wayland - > clipboard_manager . wl ) ;
wl_data_source_destroy ( wayland - > clipboard_source . wl ) ;
wayland - > clipboard_manager . wl = NULL ;
}
2025-12-30 17:12:12 -07:00
}
2025-12-18 17:46:23 -07:00
/* zwp_primary_selection_device_manager_v1 setup function */
static wayland_protocol_t * zwp_primary_selection_device_manager_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
2025-12-30 17:12:12 -07:00
if ( wayland - > clipboard_manager . wl ! = NULL ) {
wl_data_device_manager_interface_destroy ( wayland , NULL ) ;
}
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
wayland - > clipboard_manager . zwp = wl_registry_bind ( wayland - > registry , name , & zwp_primary_selection_device_manager_v1_interface , 1 ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
wayland - > clipboard_source . zwp = zwp_primary_selection_device_manager_v1_create_source ( wayland - > clipboard_manager . zwp ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
zwp_primary_selection_source_v1_offer ( wayland - > clipboard_source . zwp , " text/plain " ) ;
zwp_primary_selection_source_v1_offer ( wayland - > clipboard_source . zwp , " text/plain;charset=utf-8 " ) ;
zwp_primary_selection_source_v1_offer ( wayland - > clipboard_source . zwp , " TEXT " ) ;
zwp_primary_selection_source_v1_offer ( wayland - > clipboard_source . zwp , " STRING " ) ;
zwp_primary_selection_source_v1_offer ( wayland - > clipboard_source . zwp , " UTF8_STRING " ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
zwp_primary_selection_source_v1_add_listener ( wayland - > clipboard_source . zwp , & zwp_primary_selection_source_v1_listener , wayland ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
wayland - > supports_zwp = MwTRUE ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
return NULL ;
2025-12-18 17:46:23 -07:00
}
2025-12-18 23:32:51 -07:00
static void zwp_primary_selection_device_manager_v1_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2025-12-18 23:32:51 -07:00
}
2026-03-24 23:44:30 -07:00
/* zwp_primary_selection_device_manager_v1 setup function */
static wayland_protocol_t * zwp_pointer_constraints_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland - > pointer_constraints = wl_registry_bind ( wayland - > registry , name , & zwp_pointer_constraints_v1_interface , 1 ) ;
return NULL ;
}
static void zwp_pointer_constraints_v1_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
( void ) wayland ;
( void ) data ;
}
2026-03-24 22:40:36 -07:00
static struct wl_surface * curSurface ;
2025-12-09 20:11:01 -06:00
/* `wl_pointer.enter` callback */
static void pointer_enter ( void * data , struct wl_pointer * wl_pointer , MwU32 serial ,
struct wl_surface * surface , wl_fixed_t surface_x ,
2025-12-18 11:26:51 -07:00
wl_fixed_t surface_y ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) surface_x ;
( void ) surface_y ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2026-03-24 22:40:36 -07:00
curSurface = surface ;
2026-01-03 18:27:34 -07:00
2025-12-18 13:15:03 -07:00
self - > wayland . pointer_serial = serial ;
wl_pointer_set_cursor ( wl_pointer , serial , self - > wayland . cursor . surface , 0 , 0 ) ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-18 11:26:51 -07:00
} ;
2025-12-09 20:11:01 -06:00
/* `wl_pointer.leave` callback */
static void pointer_leave ( void * data , struct wl_pointer * wl_pointer , MwU32 serial ,
2025-12-18 11:26:51 -07:00
struct wl_surface * surface ) {
2026-03-27 15:14:04 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_pointer ;
( void ) serial ;
( void ) surface ;
2026-03-27 15:14:04 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
curSurface = NULL ;
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-18 11:26:51 -07:00
} ;
2025-12-09 20:11:01 -06:00
2026-03-20 19:28:18 -07:00
static void xdg_borderless_step ( MwLL self , MwLLMouse p , MwU32 serial ) {
2026-03-24 22:40:36 -07:00
if ( self - > wayland . type = = MWLL_WAYLAND_TOPLEVEL & & self - > wayland . backbuffer . surface = = curSurface ) {
2026-03-23 15:45:48 -07:00
if ( p . point . y > = ( self - > wayland . wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM ) - 5 ) {
if ( p . point . x > = ( self - > wayland . ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ) - 5 ) {
2026-03-20 19:28:18 -07:00
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT ) ;
} else {
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM ) ;
}
} else if ( p . point . y < = 5 ) {
2026-03-23 15:45:48 -07:00
if ( p . point . x > = ( self - > wayland . ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ) - 5 ) {
2026-03-20 19:28:18 -07:00
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT ) ;
} else {
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_TOP ) ;
}
2026-03-23 15:45:48 -07:00
} else if ( p . point . x > = ( self - > wayland . ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ) - 5 ) {
2026-03-20 19:28:18 -07:00
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_RIGHT ) ;
} else if ( p . point . x < = 5 ) {
xdg_toplevel_resize ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial , XDG_TOPLEVEL_RESIZE_EDGE_LEFT ) ;
} else if ( p . point . y < = CSD_BORDER_FRAME_TOP ) {
xdg_toplevel_move ( self - > wayland . toplevel - > xdg_top_level , self - > wayland . pointer_seat , serial ) ;
}
} ;
}
2026-03-23 12:05:32 -07:00
static MwLL currentlyHeldWidget = NULL ;
2026-03-27 17:15:59 -07:00
static void relative_pointer_motion ( void * data ,
struct zwp_relative_pointer_v1 * pointer ,
uint32_t timeHi ,
uint32_t timeLo ,
wl_fixed_t dx ,
wl_fixed_t dy ,
wl_fixed_t dxUnaccel ,
wl_fixed_t dyUnaccel ) {
MwLL self = data ;
MwLLMouse p ;
WAYLAND_EVENT_OP_START ( self ) ;
p . point . x = wl_fixed_to_int ( dxUnaccel ) ;
p . point . y = wl_fixed_to_int ( dyUnaccel ) ;
recursive_dispatch_move ( self , & p ) ;
2026-03-27 18:06:17 -07:00
if ( self - > wayland . locked_pointer ) zwp_locked_pointer_v1_set_cursor_position_hint ( self - > wayland . locked_pointer , 0 , CSD_BORDER_FRAME_TOP ) ;
2026-03-27 17:15:59 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
}
struct zwp_relative_pointer_v1_listener relative_pointer_listener =
{
relative_pointer_motion } ;
/* zwp_primary_selection_device_manager_v1 setup function */
static wayland_protocol_t * zwp_relative_pointer_manager_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland - > relative_pointer_manager = wl_registry_bind ( wayland - > registry , name , & zwp_relative_pointer_manager_v1_interface , 1 ) ;
return NULL ;
}
static void zwp_relative_pointer_manager_v1_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
( void ) wayland ;
( void ) data ;
}
2025-12-09 20:11:01 -06:00
/* `wl_pointer.motion` callback */
static void pointer_motion ( void * data , struct wl_pointer * wl_pointer , MwU32 time ,
wl_fixed_t surface_x , wl_fixed_t surface_y ) {
2026-03-27 18:06:17 -07:00
MwLL self = data ;
MwLL topmost_parent = self ;
2025-12-09 20:11:01 -06:00
MwLLMouse p ;
2026-03-24 17:38:21 -07:00
( void ) time ;
( void ) wl_pointer ;
2025-12-09 20:11:01 -06:00
2026-03-27 18:06:17 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
while ( topmost_parent - > wayland . parent ) topmost_parent = topmost_parent - > wayland . parent ;
2026-01-03 18:27:34 -07:00
2026-03-17 20:28:58 -07:00
self - > wayland . cur_mouse_pos . x = wl_fixed_to_int ( surface_x ) ;
self - > wayland . cur_mouse_pos . y = wl_fixed_to_int ( surface_y ) ;
2026-03-27 18:06:17 -07:00
p . point = self - > wayland . cur_mouse_pos ;
2025-12-09 20:11:01 -06:00
MwLLDispatch ( self , move , & p ) ;
2025-12-30 22:26:19 -07:00
2026-03-23 12:05:32 -07:00
if ( currentlyHeldWidget ) {
MwLLDispatch ( currentlyHeldWidget , down , & p ) ;
2026-03-17 20:28:58 -07:00
}
2026-03-23 12:05:32 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_pointer.button` callback */
static void pointer_button ( void * data , struct wl_pointer * wl_pointer , MwU32 serial , MwU32 time , MwU32 button , MwU32 state ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
MwLLMouse p ;
2026-03-27 15:14:04 -07:00
MwBool inArea = MwFALSE ;
2026-01-03 18:27:34 -07:00
2026-03-24 17:38:21 -07:00
( void ) wl_pointer ;
( void ) serial ;
( void ) time ;
2026-03-17 20:28:58 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2026-01-03 18:27:34 -07:00
2025-12-09 20:11:01 -06:00
p . point = self - > wayland . cur_mouse_pos ;
2026-03-17 20:28:58 -07:00
2026-03-27 15:14:04 -07:00
if ( self - > wayland . framebuffer . surface ) {
inArea | = self - > wayland . framebuffer . surface = = curSurface ;
}
if ( self - > wayland . backbuffer . surface ) {
inArea | = self - > wayland . backbuffer . surface = = curSurface ;
}
if ( inArea ) {
2026-02-02 23:02:42 +09:00
int i ;
2026-03-17 17:43:22 -07:00
2025-12-09 20:11:01 -06:00
switch ( button ) {
case BTN_LEFT :
p . button = MwLLMouseLeft ;
break ;
case BTN_MIDDLE :
p . button = MwLLMouseMiddle ;
2026-02-02 23:02:42 +09:00
for ( i = 0 ; i < arrlen ( self - > wayland . clipboard_devices ) ; i + + ) {
2025-12-30 17:12:12 -07:00
wl_clipboard_read (
self - > wayland . clipboard_devices [ i ] ) ;
}
2025-12-09 20:11:01 -06:00
break ;
case BTN_RIGHT :
p . button = MwLLMouseRight ;
break ;
}
2026-03-20 19:28:18 -07:00
self - > wayland . held_down = state = = WL_POINTER_BUTTON_STATE_PRESSED ;
2025-12-09 20:11:01 -06:00
switch ( state ) {
case WL_POINTER_BUTTON_STATE_PRESSED :
MwLLDispatch ( self , down , & p ) ;
2026-03-23 12:05:32 -07:00
currentlyHeldWidget = self ;
2026-03-20 19:28:18 -07:00
2025-12-09 20:11:01 -06:00
break ;
case WL_POINTER_BUTTON_STATE_RELEASED :
2026-03-23 12:05:32 -07:00
if ( currentlyHeldWidget ! = NULL ) {
MwLLDispatch ( currentlyHeldWidget , up , & p ) ;
currentlyHeldWidget = NULL ;
2026-01-12 18:50:33 -07:00
} else {
MwLLDispatch ( self , up , & p ) ;
2026-01-12 18:18:05 -07:00
}
2025-12-09 20:11:01 -06:00
break ;
}
}
2025-12-17 19:14:54 -07:00
2026-03-20 19:28:18 -07:00
if ( ! self - > wayland . has_decorations ) {
xdg_borderless_step ( self , p , serial ) ;
}
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_pointer.axis` callback */
static void pointer_axis ( void * data , struct wl_pointer * wl_pointer , MwU32 time ,
2026-03-24 17:38:21 -07:00
MwU32 axis , wl_fixed_t value ) {
( void ) data ;
( void ) wl_pointer ;
( void ) time ;
( void ) axis ;
( void ) value ;
} ;
2025-12-09 20:11:01 -06:00
struct wl_pointer_listener pointer_listener = {
. enter = pointer_enter ,
. leave = pointer_leave ,
. motion = pointer_motion ,
. button = pointer_button ,
. axis = pointer_axis ,
} ;
/* `wl_keyboard.keymap` callback */
static void keyboard_keymap ( void * data ,
struct wl_keyboard * wl_keyboard ,
MwU32 format ,
int32_t fd ,
MwU32 size ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_keyboard ;
2026-01-04 11:40:34 -07:00
2025-12-09 20:11:01 -06:00
if ( self - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
assert ( format = = WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 ) ;
char * map_shm = ( char * ) mmap ( NULL , size , PROT_READ , MAP_SHARED , fd , 0 ) ;
assert ( map_shm ! = MAP_FAILED ) ;
struct xkb_keymap * xkb_keymap = xkb_keymap_new_from_string (
2026-03-27 15:14:04 -07:00
self - > wayland . xkb_context , map_shm , XKB_KEYMAP_FORMAT_TEXT_V1 ,
2025-12-09 20:11:01 -06:00
XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
munmap ( map_shm , size ) ;
close ( fd ) ;
struct xkb_state * xkb_state = xkb_state_new ( xkb_keymap ) ;
2026-03-27 15:14:04 -07:00
self - > wayland . xkb_keymap = xkb_keymap ;
self - > wayland . xkb_state = xkb_state ;
} else {
self - > wayland . xkb_keymap = self - > wayland . parent - > wayland . xkb_keymap ;
self - > wayland . xkb_state = self - > wayland . parent - > wayland . xkb_state ;
2025-12-09 20:11:01 -06:00
}
} ;
/* `wl_keyboard.enter` callback */
static void keyboard_enter ( void * data ,
struct wl_keyboard * wl_keyboard ,
MwU32 serial ,
struct wl_surface * surface ,
struct wl_array * keys ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_keyboard ;
( void ) surface ;
( void ) keys ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2026-01-03 18:27:34 -07:00
2025-12-30 17:12:12 -07:00
self - > wayland . keyboard_serial = serial ;
2025-12-09 20:11:01 -06:00
MwLLDispatch ( self , focus_in , NULL ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_keyboard.leave` callback */
static void keyboard_leave ( void * data ,
struct wl_keyboard * wl_keyboard ,
MwU32 serial ,
struct wl_surface * surface ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_keyboard ;
( void ) serial ;
( void ) surface ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2026-01-03 18:27:34 -07:00
2025-12-09 20:11:01 -06:00
MwLLDispatch ( self , focus_out , NULL ) ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_keyboard.key` callback */
static void keyboard_key ( void * data ,
struct wl_keyboard * wl_keyboard ,
MwU32 serial ,
MwU32 time ,
MwU32 key ,
MwU32 state ) {
2026-03-27 15:14:04 -07:00
MwLL self = data ;
MwBool inArea ;
2026-03-24 17:38:21 -07:00
( void ) wl_keyboard ;
( void ) serial ;
( void ) time ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2026-01-03 18:27:34 -07:00
2026-03-27 15:14:04 -07:00
if ( self - > wayland . framebuffer . surface ) {
inArea | = self - > wayland . framebuffer . surface = = curSurface ;
}
2026-03-27 18:06:17 -07:00
if ( self - > wayland . backbuffer . surface ) {
inArea | = self - > wayland . backbuffer . surface = = curSurface ;
}
2026-03-27 15:14:04 -07:00
if ( inArea ) {
xkb_layout_index_t layout ;
MwU32 levels ;
xkb_level_index_t level ;
const xkb_keysym_t * syms_out ;
MwU32 keycode = key + 8 ;
MwU64 syms_num ;
int i ;
if ( ! self - > wayland . xkb_keymap ) {
2025-12-09 20:11:01 -06:00
return ;
}
2026-03-27 15:14:04 -07:00
layout = xkb_state_key_get_layout ( self - > wayland . xkb_state , keycode ) ;
levels =
xkb_keymap_num_levels_for_key ( self - > wayland . xkb_keymap , keycode , layout ) ;
if ( ( ( ( self - > wayland . mod_state & 1 ) = = 1 ) | | ( ( self - > wayland . mod_state & 2 ) = = 2 ) ) & & levels > = 2 ) {
level = 1 ;
} else if ( levels > = 1 ) {
level = 0 ;
}
syms_num = xkb_keymap_key_get_syms_by_level ( self - > wayland . xkb_keymap , keycode , layout , level , & syms_out ) ;
2025-12-09 20:11:01 -06:00
if ( syms_out = = NULL ) {
return ;
}
for ( i = 0 ; i < syms_num ; i + + ) {
2026-03-27 15:14:04 -07:00
int sym = syms_out [ i ] ;
int key = - 1 ;
const char * name ;
2025-12-09 20:11:01 -06:00
switch ( sym ) {
case XKB_KEY_BackSpace :
key = MwLLKeyBackSpace ;
break ;
case XKB_KEY_Left :
key = MwLLKeyLeft ;
break ;
case XKB_KEY_Right :
key = MwLLKeyRight ;
break ;
case XKB_KEY_Up :
key = MwLLKeyUp ;
break ;
case XKB_KEY_Down :
key = MwLLKeyDown ;
break ;
case XKB_KEY_Return :
key = MwLLKeyEnter ;
break ;
case XKB_KEY_Escape :
key = MwLLKeyEscape ;
break ;
case XKB_KEY_Shift_L :
key = MwLLKeyLeftShift ;
break ;
case XKB_KEY_Shift_R :
key = MwLLKeyRightShift ;
break ;
case XKB_KEY_Alt_L :
case XKB_KEY_Alt_R :
key = MwLLKeyAlt ;
break ;
case XKB_KEY_Control_L :
case XKB_KEY_Control_R :
key = MwLLKeyControl ;
break ;
default :
2026-03-31 12:36:31 -07:00
if ( MwStringIsKeyUTF8 ( sym ) ) {
2026-03-27 15:14:04 -07:00
key = sym ;
}
2025-12-09 20:11:01 -06:00
}
2026-03-27 15:14:04 -07:00
2025-12-18 11:36:04 -07:00
if ( ( self - > wayland . mod_state & 4 ) = = 4 ) {
2025-12-30 17:12:12 -07:00
/* clipboard paste */
if ( key = = ' V ' ) {
2026-02-02 23:02:42 +09:00
int i ;
for ( i = 0 ; i < arrlen ( self - > wayland . clipboard_devices ) ; i + + ) {
2025-12-30 17:12:12 -07:00
wl_clipboard_read (
self - > wayland . clipboard_devices [ i ] ) ;
}
}
2025-12-18 11:36:04 -07:00
key | = MwLLControlMask ;
}
if ( ( self - > wayland . mod_state & 8 ) = = 8 ) {
key | = MwLLAltMask ;
}
2025-12-30 17:12:12 -07:00
2026-03-27 15:14:04 -07:00
if ( key ! = - 1 ) {
if ( state = = WL_KEYBOARD_KEY_STATE_PRESSED ) {
MwLLDispatch ( self , key , & key ) ;
} else {
MwLLDispatch ( self , key_released , & key ) ;
}
2025-12-09 20:11:01 -06:00
}
}
}
2025-12-30 22:26:19 -07:00
2026-03-24 23:24:20 -07:00
if ( ! MwWaylandAlwaysRender ) {
2025-12-30 22:26:19 -07:00
MwLLDispatch ( self , draw , NULL ) ;
}
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `wl_keyboard.modifiers` callback */
static void keyboard_modifiers ( void * data ,
struct wl_keyboard * wl_keyboard ,
MwU32 serial ,
MwU32 mods_depressed ,
MwU32 mods_latched ,
MwU32 mods_locked ,
2025-12-18 11:36:04 -07:00
MwU32 group ) {
2026-01-04 11:40:34 -07:00
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) wl_keyboard ;
( void ) serial ;
( void ) group ;
( void ) mods_latched ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-18 11:36:04 -07:00
self - > wayland . mod_state = 0 ;
self - > wayland . mod_state | = mods_depressed ;
self - > wayland . mod_state | = mods_locked ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-18 11:36:04 -07:00
} ;
2025-12-09 20:11:01 -06:00
struct wl_keyboard_listener keyboard_listener = {
. keymap = keyboard_keymap ,
. enter = keyboard_enter ,
. leave = keyboard_leave ,
. key = keyboard_key ,
. modifiers = keyboard_modifiers ,
} ;
/* `wl_seat.name` callback */
static void
2026-03-24 17:38:21 -07:00
wl_seat_name ( void * data , struct wl_seat * wl_seat , const char * name ) {
( void ) data ;
( void ) wl_seat ;
( void ) name ;
} ;
2025-12-09 20:11:01 -06:00
/* `wl_seat.capabilities` callback */
static void wl_seat_capabilities ( void * data , struct wl_seat * wl_seat ,
MwU32 capabilities ) {
2025-12-30 17:12:12 -07:00
MwLL self = data ;
wl_clipboard_device_context_t * device_ctx = malloc ( sizeof ( wl_clipboard_device_context_t ) ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-09 20:11:01 -06:00
if ( capabilities & WL_SEAT_CAPABILITY_KEYBOARD ) {
2025-12-18 23:32:51 -07:00
self - > wayland . keyboard = wl_seat_get_keyboard ( wl_seat ) ;
wl_keyboard_add_listener ( self - > wayland . keyboard , & keyboard_listener , data ) ;
2025-12-09 20:11:01 -06:00
}
if ( capabilities & WL_SEAT_CAPABILITY_POINTER ) {
2026-03-20 19:28:18 -07:00
self - > wayland . pointer_seat = wl_seat ;
self - > wayland . pointer = wl_seat_get_pointer ( wl_seat ) ;
2025-12-18 13:15:03 -07:00
wl_pointer_add_listener ( self - > wayland . pointer , & pointer_listener , data ) ;
2025-12-09 20:11:01 -06:00
}
2025-12-18 17:46:23 -07:00
2026-01-02 14:19:30 -07:00
if ( self - > wayland . clipboard_manager . wl ! = NULL ) {
if ( self - > wayland . supports_zwp ) {
device_ctx - > device . zwp = zwp_primary_selection_device_manager_v1_get_device ( self - > wayland . clipboard_manager . zwp , wl_seat ) ;
} else {
device_ctx - > device . wl = wl_data_device_manager_get_data_device ( self - > wayland . clipboard_manager . wl , wl_seat ) ;
}
device_ctx - > ll = self ;
device_ctx - > seat = wl_seat ;
device_ctx - > capabilities = capabilities ;
2025-12-18 23:32:51 -07:00
2026-01-02 14:19:30 -07:00
if ( self - > wayland . supports_zwp ) {
zwp_primary_selection_device_v1_add_listener ( device_ctx - > device . zwp , & zwp_primary_selection_device_v1_listener , device_ctx ) ;
} else {
wl_data_device_add_listener ( device_ctx - > device . wl , & wl_data_device_listener , device_ctx ) ;
}
2025-12-30 17:12:12 -07:00
2026-01-02 14:19:30 -07:00
arrpush ( self - > wayland . clipboard_devices , device_ctx ) ;
}
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
2025-12-18 13:43:45 -07:00
static void output_geometry ( void * data ,
struct wl_output * wl_output ,
int32_t x ,
int32_t y ,
int32_t physical_width ,
int32_t physical_height ,
int32_t subpixel ,
const char * make ,
const char * model ,
2026-03-24 17:38:21 -07:00
int32_t transform ) {
( void ) data ;
( void ) wl_output ;
( void ) x ;
( void ) y ;
( void ) physical_width ;
( void ) physical_height ;
( void ) subpixel ;
( void ) make ;
( void ) model ;
( void ) transform ;
} ;
2025-12-18 13:43:45 -07:00
static void output_mode ( void * data ,
struct wl_output * wl_output ,
uint32_t flags ,
int32_t width ,
int32_t height ,
int32_t refresh ) {
2026-03-24 17:38:21 -07:00
MwLL self = data ;
( void ) wl_output ;
( void ) flags ;
( void ) refresh ;
2025-12-18 13:43:45 -07:00
self - > wayland . mw = width ;
self - > wayland . mh = height ;
} ;
struct wl_output_listener output_listener = {
. geometry = output_geometry ,
. mode = output_mode ,
} ;
2025-12-09 20:11:01 -06:00
/* `xdg_wm_base.ping` callback */
void xdg_wm_base_ping ( void * data ,
struct xdg_wm_base * xdg_wm_base ,
MwU32 serial ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
2025-12-09 20:11:01 -06:00
xdg_wm_base_pong ( xdg_wm_base , serial ) ;
} ;
/* wl_seat setup function */
static wayland_protocol_t * wl_seat_setup ( MwU32 name , MwLL ll ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
proto - > listener = malloc ( sizeof ( struct wl_seat_listener ) ) ;
( ( struct wl_seat_listener * ) proto - > listener ) - > name = wl_seat_name ;
( ( struct wl_seat_listener * ) proto - > listener ) - > capabilities = wl_seat_capabilities ;
2026-01-12 18:18:05 -07:00
wl_seat_add_listener ( wl_registry_bind ( ll - > wayland . registry , name , & wl_seat_interface , 1 ) , proto - > listener , ll ) ;
2025-12-09 20:11:01 -06:00
return proto ;
}
2025-12-18 23:32:51 -07:00
static void wl_seat_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
2025-12-18 23:32:51 -07:00
free ( data - > listener ) ;
}
2025-12-18 13:43:45 -07:00
/* wl_output setup function */
static wayland_protocol_t * wl_output_setup ( MwU32 name , MwLL ll ) {
ll - > wayland . output = wl_registry_bind ( ll - > wayland . registry , name , & wl_output_interface , 1 ) ;
wl_output_add_listener ( ll - > wayland . output , & output_listener , ll ) ;
return NULL ;
}
2025-12-18 23:32:51 -07:00
static void wl_output_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2025-12-18 23:32:51 -07:00
}
2025-12-09 20:11:01 -06:00
/* wl_compositor setup function */
static wayland_protocol_t * wl_compositor_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland - > compositor = wl_registry_bind ( wayland - > registry , name , & wl_compositor_interface , 1 ) ;
return NULL ;
}
2025-12-18 23:32:51 -07:00
static void wl_compositor_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2025-12-18 23:32:51 -07:00
}
2025-12-09 20:11:01 -06:00
/* wl_subcompositor setup function */
static wayland_protocol_t * wl_subcompositor_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
2026-03-19 19:43:57 -07:00
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL ) {
wayland - > toplevel - > scompositor = wl_registry_bind ( wayland - > registry , name , & wl_subcompositor_interface , 1 ) ;
} else {
wayland - > sublevel - > subcompositor = wl_registry_bind ( wayland - > registry , name , & wl_subcompositor_interface , 1 ) ;
}
2025-12-09 20:11:01 -06:00
return NULL ;
}
2025-12-18 23:32:51 -07:00
static void wl_subcompositor_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
2025-12-18 23:32:51 -07:00
wl_subcompositor_destroy ( wayland - > sublevel - > subcompositor ) ;
}
2025-12-09 20:11:01 -06:00
/* xdg_wm_base setup function */
static wayland_protocol_t * xdg_wm_base_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
proto - > listener = malloc ( sizeof ( struct xdg_wm_base_listener ) ) ;
( ( struct xdg_wm_base_listener * ) proto - > listener ) - > ping = xdg_wm_base_ping ;
proto - > context = wl_registry_bind ( wayland - > registry , name , & xdg_wm_base_interface , 1 ) ;
xdg_wm_base_add_listener ( proto - > context , proto - > listener , wayland ) ;
return proto ;
}
2025-12-18 23:32:51 -07:00
static void xdg_wm_base_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
2025-12-18 23:32:51 -07:00
free ( data - > listener ) ;
}
2026-03-19 19:43:57 -07:00
/* xdg_wm_base setup function */
static wayland_protocol_t * wp_viewporter_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
proto - > context = wl_registry_bind ( wayland - > registry , name , & wp_viewporter_interface , 1 ) ;
return proto ;
}
static void wp_viewporter_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2026-03-19 19:43:57 -07:00
}
2025-12-09 20:11:01 -06:00
/* the two decoration manager constructs */
typedef struct zxdg_decoration_manager_v1_context {
struct zxdg_decoration_manager_v1 * manager ;
struct zxdg_toplevel_decoration_v1 * decoration ;
} zxdg_decoration_manager_v1_context_t ;
/* zxdg_decoration_manager_v1 setup function */
static wayland_protocol_t * zxdg_decoration_manager_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
zxdg_decoration_manager_v1_context_t * ctx = malloc ( sizeof ( zxdg_decoration_manager_v1_context_t ) ) ;
proto - > listener = NULL ;
ctx - > manager = wl_registry_bind ( wayland - > registry , name , & zxdg_decoration_manager_v1_interface , 1 ) ;
;
proto - > context = ctx ;
return proto ;
}
2025-12-18 23:32:51 -07:00
static void zxdg_decoration_manager_v1_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2025-12-18 23:32:51 -07:00
}
2026-03-20 20:23:02 -07:00
/* Standard Wayland event loop. */
static int event_loop ( MwLL handle ) {
struct pollfd fd ;
struct timespec timeout ;
struct _MwLLWayland * wayland = & handle - > wayland ;
timeout . tv_nsec = 1 ;
timeout . tv_sec = 0 ;
if ( wayland - > display = = NULL ) {
return 0 ;
}
fd . fd = wl_display_get_fd ( wayland - > display ) ;
fd . events = POLLIN ;
/* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */
while ( wl_display_flush ( wayland - > display ) = = - 1 ) {
if ( errno ! = EAGAIN ) {
return MwFALSE ;
}
while ( poll ( & fd , 1 , - 1 ) = = - 1 ) {
if ( errno ! = EINTR & & errno ! = EAGAIN ) {
wl_display_cancel_read ( wayland - > display ) ;
MwLLDispatch ( handle , close , NULL ) ;
return 0 ;
}
}
}
wl_display_prepare_read ( handle - > wayland . display ) ;
/* Condition where no events are being sent. */
if ( ! poll ( & fd , 1 , timeout . tv_nsec ) ) {
wl_display_cancel_read ( wayland - > display ) ;
2026-03-26 17:48:22 -07:00
update_buffer ( handle , & wayland - > framebuffer ) ;
2026-03-20 20:23:02 -07:00
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL )
2026-03-26 17:48:22 -07:00
update_buffer ( handle , & wayland - > backbuffer ) ;
2026-03-20 20:23:02 -07:00
return 0 ;
}
wl_display_read_events ( wayland - > display ) ;
if ( wl_display_dispatch_pending ( wayland - > display ) < 0 ) {
wl_display_cancel_read ( wayland - > display ) ;
}
return 1 ;
}
/* make the fuck sure that we're configurd */
static void hang_until_configured ( MwLL handle ) {
while ( ! handle - > wayland . configured ) {
if ( wl_display_roundtrip ( handle - > wayland . display ) = = - 1 ) {
printf ( " roundtrip failed \n " ) ;
raise ( SIGTRAP ) ;
return ;
}
event_loop ( handle ) ;
}
}
2026-03-19 16:35:56 -07:00
/* `xdg_toplevel.configure` callback */
2025-12-09 20:11:01 -06:00
static void xdg_toplevel_configure ( void * data ,
struct xdg_toplevel * xdg_toplevel ,
MwI32 width , MwI32 height ,
struct wl_array * states ) {
2026-03-24 17:38:21 -07:00
MwLL self = data ;
( void ) states ;
( void ) xdg_toplevel ;
2025-12-09 20:11:01 -06:00
2025-12-30 17:12:12 -07:00
/* Yes, somehow this can get called before */
if ( ! self - > wayland . configured ) {
return ;
}
2025-12-09 20:11:01 -06:00
if ( width = = 0 | | height = = 0 ) {
width = self - > wayland . ww ;
height = self - > wayland . wh ;
/* if it's still 0 then bail */
if ( width = = 0 | | height = = 0 ) {
return ;
}
}
2025-12-18 11:26:51 -07:00
region_invalidate ( self ) ;
2025-12-09 20:11:01 -06:00
self - > wayland . ww = width ;
self - > wayland . wh = height ;
2026-03-19 16:35:56 -07:00
2025-12-09 20:11:01 -06:00
xdg_surface_set_window_geometry ( self - > wayland . toplevel - > xdg_surface , 0 , 0 , self - > wayland . ww , self - > wayland . wh ) ;
2026-03-19 19:43:57 -07:00
backbuffer_destroy ( & self - > wayland ) ;
backbuffer_setup ( & self - > wayland ) ;
2025-12-18 13:15:03 -07:00
framebuffer_destroy ( & self - > wayland ) ;
framebuffer_setup ( & self - > wayland ) ;
2026-03-24 22:40:36 -07:00
2025-12-18 11:26:51 -07:00
region_setup ( self ) ;
2026-03-24 14:43:38 -07:00
MwLLDispatch ( self , resize , NULL ) ;
2025-12-17 19:14:54 -07:00
2026-03-24 14:43:38 -07:00
recursive_dispatch_resize ( self ) ;
2026-03-25 00:31:23 -07:00
if ( self - > wayland . pointer_constrained ) {
2026-03-27 18:06:17 -07:00
zwp_locked_pointer_v1_set_cursor_position_hint ( self - > wayland . locked_pointer , 0 , CSD_BORDER_FRAME_TOP ) ;
2026-03-25 00:31:23 -07:00
wl_surface_commit ( self - > wayland . framebuffer . surface ) ;
}
2025-12-09 20:11:01 -06:00
} ;
/* `xdg_surface.close` callback */
static void xdg_toplevel_close (
void * data , struct xdg_toplevel * xdg_toplevel ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) xdg_toplevel ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
2025-12-09 20:11:01 -06:00
MwLLDispatch ( self , close , NULL ) ;
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_END ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* `xdg_surface.configure` callback */
static void xdg_surface_configure (
void * data , struct xdg_surface * xdg_surface , MwU32 serial ) {
MwLL self = data ;
xdg_surface_ack_configure ( xdg_surface , serial ) ;
2026-03-27 15:14:04 -07:00
MwLLDispatch ( self , draw , NULL ) ;
2025-12-09 20:11:01 -06:00
if ( self - > wayland . configured ) {
2026-03-26 17:48:22 -07:00
update_buffer ( self , & self - > wayland . framebuffer ) ;
update_buffer ( self , & self - > wayland . backbuffer ) ;
2025-12-09 20:11:01 -06:00
}
self - > wayland . configured = MwTRUE ;
}
2025-12-17 19:14:54 -07:00
/* wl_shm setup function */
static wayland_protocol_t * wl_shm_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
2025-12-18 13:15:03 -07:00
wayland - > framebuffer . shm = wl_registry_bind ( wayland - > registry , name , & wl_shm_interface , 1 ) ;
2026-03-19 19:43:57 -07:00
wayland - > backbuffer . shm = wl_registry_bind ( wayland - > registry , name , & wl_shm_interface , 1 ) ;
2025-12-18 13:15:03 -07:00
wayland - > cursor . shm = wl_registry_bind ( wayland - > registry , name , & wl_shm_interface , 1 ) ;
2025-12-17 19:41:05 -07:00
return NULL ;
}
2025-12-18 23:32:51 -07:00
static void wl_shm_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
( void ) data ;
2025-12-18 23:32:51 -07:00
}
2026-03-25 00:31:23 -07:00
static void update_buffer ( MwLL self , struct _MwLLWaylandShmBuffer * buffer ) {
2026-03-27 15:14:04 -07:00
( void ) self ;
2026-03-26 16:54:40 -07:00
memcpy ( buffer - > buf , buffer - > buf_back , buffer - > buf_size ) ;
2026-04-08 14:39:26 -07:00
2026-04-08 12:36:18 -07:00
// Yes this is needed every time, it's how we fix weston.
wl_surface_attach ( buffer - > surface , buffer - > shm_buffer , 0 , 0 ) ;
2026-04-08 14:39:26 -07:00
2026-04-08 14:18:13 -07:00
wl_surface_commit ( buffer - > surface ) ;
2025-12-17 19:41:05 -07:00
}
2025-12-18 13:15:03 -07:00
static void buffer_setup ( struct _MwLLWaylandShmBuffer * buffer , MwU32 width , MwU32 height ) {
2026-03-26 16:54:40 -07:00
int stride = width * 4 ;
char temp_name [ ] = " /tmp/milsko-wl-shm-XXXXXX " ;
char temp_name_back [ ] = " /tmp/milsko-wl-shm-back-XXXXXX " ;
2025-12-17 19:14:54 -07:00
2026-04-08 14:18:13 -07:00
buffer - > buf_size = ( width * height * 4 ) * sizeof ( MwU32 ) ;
2025-12-17 19:14:54 -07:00
2026-04-08 14:45:55 -07:00
buffer - > fd = mkstemp ( temp_name ) ;
2025-12-17 19:14:54 -07:00
unlink ( temp_name ) ;
2026-03-26 16:54:40 -07:00
unlink ( temp_name_back ) ;
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
if ( posix_fallocate ( buffer - > fd , 0 , buffer - > buf_size ) ! = 0 ) {
2025-12-17 19:14:54 -07:00
printf ( " failure setting up wl_shm: could not fallocate. %s. \n " , strerror ( errno ) ) ;
2025-12-18 13:15:03 -07:00
close ( buffer - > fd ) ;
2025-12-17 19:41:05 -07:00
return ;
2025-12-17 19:14:54 -07:00
}
2025-12-18 13:15:03 -07:00
if ( ftruncate ( buffer - > fd , buffer - > buf_size ) ! = 0 ) {
2025-12-17 19:14:54 -07:00
printf ( " failure setting up wl_shm: could not truncate. %s. \n " , strerror ( errno ) ) ;
2025-12-18 13:15:03 -07:00
close ( buffer - > fd ) ;
2025-12-17 19:41:05 -07:00
return ;
2025-12-17 19:14:54 -07:00
}
2026-03-26 16:54:40 -07:00
buffer - > buf = mmap ( NULL , buffer - > buf_size , PROT_WRITE , MAP_SHARED , buffer - > fd , 0 ) ;
2026-04-08 14:45:55 -07:00
buffer - > buf_back = malloc ( buffer - > buf_size ) ;
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
fsync ( buffer - > fd ) ;
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
if ( ! ( buffer - > shm_pool = wl_shm_create_pool ( buffer - > shm , buffer - > fd , buffer - > buf_size ) ) ) {
2025-12-17 19:14:54 -07:00
printf ( " failure setting up wl_shm: could not create pool. \n " ) ;
}
2026-04-08 14:45:55 -07:00
buffer - > shm_buffer = wl_shm_pool_create_buffer ( buffer - > shm_pool , 0 , width , height , stride , WL_SHM_FORMAT_ARGB8888 ) ;
2026-04-08 14:18:13 -07:00
2026-04-08 14:39:26 -07:00
buffer - > pixman_fb = pixman_image_create_bits ( PIXMAN_a8r8g8b8 ,
width , height , buffer - > buf_back , stride ) ;
buffer - > width = width ;
buffer - > height = height ;
2026-04-08 14:18:13 -07:00
buffer - > setup = MwTRUE ;
2025-12-18 13:15:03 -07:00
}
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
static void buffer_destroy ( struct _MwLLWaylandShmBuffer * buffer ) {
if ( ! buffer - > setup ) {
return ;
2025-12-17 19:14:54 -07:00
}
2026-03-27 17:15:59 -07:00
if ( buffer - > shm_buffer ) wl_buffer_destroy ( buffer - > shm_buffer ) ;
if ( buffer - > shm_pool ) wl_shm_pool_destroy ( buffer - > shm_pool ) ;
2026-04-08 14:45:55 -07:00
munmap ( buffer - > buf , buffer - > buf_size ) ;
free ( buffer - > buf_back ) ;
2025-12-18 13:15:03 -07:00
close ( buffer - > fd ) ;
2026-04-08 14:39:26 -07:00
pixman_image_unref ( buffer - > pixman_fb ) ;
2026-04-08 14:18:13 -07:00
2025-12-18 13:15:03 -07:00
buffer - > setup = MwFALSE ;
}
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
static void framebuffer_setup ( struct _MwLLWayland * wayland ) {
buffer_setup ( & wayland - > framebuffer , wayland - > ww , wayland - > wh ) ;
2025-12-17 19:14:54 -07:00
2026-03-26 16:54:40 -07:00
memset ( wayland - > framebuffer . buf_back , 0 , wayland - > framebuffer . buf_size ) ;
2026-03-26 21:36:57 -07:00
wl_surface_attach ( wayland - > framebuffer . surface , wayland - > framebuffer . shm_buffer , 0 , 0 ) ;
wl_surface_commit ( wayland - > framebuffer . surface ) ;
2026-03-20 20:23:02 -07:00
hang_until_configured ( ( MwLL ) wayland ) ;
2026-03-25 00:31:23 -07:00
update_buffer ( ( MwLL ) wayland , & wayland - > framebuffer ) ;
2025-12-18 13:15:03 -07:00
} ;
static void framebuffer_destroy ( struct _MwLLWayland * wayland ) {
buffer_destroy ( & wayland - > framebuffer ) ;
2026-03-19 19:43:57 -07:00
} ;
static void backbuffer_setup ( struct _MwLLWayland * wayland ) {
if ( wayland - > type ! = MWLL_WAYLAND_TOPLEVEL ) {
return ;
}
2026-03-23 15:32:28 -07:00
MwU32 w = wayland - > ww ;
MwU32 h = wayland - > wh ;
if ( ! wayland - > has_decorations ) {
w + = ( CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ) ;
h + = ( CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM ) ;
}
buffer_setup ( & wayland - > backbuffer , w , h ) ;
2026-03-19 19:43:57 -07:00
2026-03-26 16:54:40 -07:00
memset ( wayland - > backbuffer . buf_back , 255 , wayland - > backbuffer . buf_size ) ;
2026-03-26 21:36:57 -07:00
wl_surface_attach ( wayland - > backbuffer . surface , wayland - > backbuffer . shm_buffer , 0 , 0 ) ;
wl_surface_commit ( wayland - > backbuffer . surface ) ;
2026-03-20 20:23:02 -07:00
hang_until_configured ( ( MwLL ) wayland ) ;
2026-03-25 00:31:23 -07:00
update_buffer ( ( MwLL ) wayland , & wayland - > backbuffer ) ;
2026-03-19 19:43:57 -07:00
} ;
static void backbuffer_destroy ( struct _MwLLWayland * wayland ) {
buffer_destroy ( & wayland - > backbuffer ) ;
2025-12-18 13:15:03 -07:00
} ;
2025-12-17 19:14:54 -07:00
2025-12-18 11:26:51 -07:00
static void region_invalidate ( MwLL handle ) {
if ( ! handle - > wayland . configured ) {
return ;
}
2026-03-17 20:28:58 -07:00
wl_region_subtract ( handle - > wayland . region , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
2025-12-18 11:26:51 -07:00
}
static void region_setup ( MwLL handle ) {
2026-03-19 15:57:20 -07:00
MwLL parent = handle - > wayland . parent ;
int width = handle - > wayland . ww ;
int height = handle - > wayland . wh ;
2026-03-19 16:01:32 -07:00
if ( ! handle - > wayland . configured ) {
return ;
}
2026-03-24 22:40:36 -07:00
wl_region_add ( handle - > wayland . o_region , 0 , 0 , width , height ) ;
2026-03-17 20:28:58 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_POPUP ) {
2026-03-19 15:57:20 -07:00
wl_region_add ( handle - > wayland . region , 0 , 0 , width + abs ( handle - > wayland . x ) , height + abs ( handle - > wayland . y ) ) ;
2026-03-17 20:28:58 -07:00
} else {
2026-03-19 15:57:20 -07:00
if ( parent ) {
if ( width - handle - > wayland . x > parent - > wayland . ww ) {
width = parent - > wayland . ww - handle - > wayland . x ;
}
if ( height - handle - > wayland . y > parent - > wayland . wh ) {
height = parent - > wayland . wh - handle - > wayland . y ;
}
2026-03-23 15:45:48 -07:00
} else {
if ( ! handle - > wayland . has_decorations ) {
width + = CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ;
height + = CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM ;
}
2026-03-19 15:57:20 -07:00
}
wl_region_add ( handle - > wayland . region , 0 , 0 , width , height ) ;
2026-03-17 20:28:58 -07:00
}
2026-03-23 15:45:48 -07:00
2026-03-19 19:43:57 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
2026-03-23 14:28:49 -07:00
wl_surface_set_opaque_region ( handle - > wayland . backbuffer . surface , handle - > wayland . o_region ) ;
2026-03-19 19:43:57 -07:00
wl_surface_set_input_region ( handle - > wayland . backbuffer . surface , handle - > wayland . region ) ;
}
2026-03-23 14:28:49 -07:00
wl_surface_set_opaque_region ( handle - > wayland . framebuffer . surface , handle - > wayland . o_region ) ;
2026-03-20 19:28:18 -07:00
wl_surface_set_input_region ( handle - > wayland . framebuffer . surface , handle - > wayland . region ) ;
2025-12-18 11:26:51 -07:00
}
2025-12-18 18:21:57 -07:00
static wayland_protocol_t * xdg_toplevel_icon_manager_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
proto - > context = wl_registry_bind ( wayland - > registry , name , & xdg_toplevel_icon_manager_v1_interface , 1 ) ;
proto - > listener = NULL ;
return proto ;
}
2025-12-18 23:32:51 -07:00
static void xdg_toplevel_icon_manager_v1_interface_destroy ( struct _MwLLWayland * wayland , wayland_protocol_t * data ) {
2026-03-24 17:38:21 -07:00
( void ) wayland ;
2025-12-18 23:32:51 -07:00
free ( data - > listener ) ;
}
2025-12-09 20:11:01 -06:00
/* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */
static void setup_callbacks ( struct _MwLLWayland * wayland ) {
/* Convience macro for adding the interface functions to the setup map */
# define WL_INTERFACE(interface) \
2025-12-18 23:32:51 -07:00
do { \
wayland_protocol_callback_table_t * cb = malloc ( sizeof ( wayland_protocol_callback_table_t ) ) ; \
cb - > setup = ( wl_setup_func * ) interface # # _setup ; \
cb - > destroy = ( wl_destroy_func * ) interface # # _interface_destroy ; \
shput ( wayland - > wl_protocol_setup_map , interface # # _interface . name , cb ) ; \
} while ( 0 ) ;
2025-12-09 20:11:01 -06:00
wayland - > registry_listener . global = new_protocol ;
wayland - > registry_listener . global_remove = protocol_removed ;
wayland - > wl_protocol_setup_map = NULL ;
wayland - > wl_protocol_map = NULL ;
2025-12-17 19:14:54 -07:00
WL_INTERFACE ( wl_shm ) ;
2025-12-09 20:11:01 -06:00
WL_INTERFACE ( wl_compositor ) ;
WL_INTERFACE ( wl_seat ) ;
2025-12-18 13:43:45 -07:00
WL_INTERFACE ( wl_output ) ;
2025-12-30 17:12:12 -07:00
WL_INTERFACE ( wl_data_device_manager ) ;
2025-12-18 17:46:23 -07:00
WL_INTERFACE ( zwp_primary_selection_device_manager_v1 ) ;
2026-03-24 23:44:30 -07:00
WL_INTERFACE ( zwp_pointer_constraints_v1 ) ;
2026-03-27 17:15:59 -07:00
WL_INTERFACE ( zwp_relative_pointer_manager_v1 ) ;
2026-03-27 15:14:04 -07:00
WL_INTERFACE ( xdg_wm_base ) ;
2025-12-09 20:11:01 -06:00
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL ) {
2026-03-19 19:43:57 -07:00
WL_INTERFACE ( wp_viewporter ) ;
2025-12-09 20:11:01 -06:00
WL_INTERFACE ( zxdg_decoration_manager_v1 ) ;
2025-12-18 18:21:57 -07:00
WL_INTERFACE ( xdg_toplevel_icon_manager_v1 ) ;
2026-03-19 19:43:57 -07:00
WL_INTERFACE ( wl_subcompositor ) ;
2025-12-18 23:32:51 -07:00
} else if ( wayland - > type = = MWLL_WAYLAND_POPUP ) {
2025-12-17 19:14:54 -07:00
} else {
WL_INTERFACE ( wl_subcompositor ) ;
2025-12-09 20:11:01 -06:00
}
# undef WL_INTERFACE
}
/* Toplevel setup function */
static void setup_toplevel ( MwLL r , int x , int y ) {
2025-12-17 19:14:54 -07:00
r - > wayland . type = MWLL_WAYLAND_TOPLEVEL ;
r - > wayland . toplevel = malloc ( sizeof ( struct _MwLLWaylandTopLevel ) ) ;
2026-03-17 20:28:58 -07:00
r - > wayland . x = x ;
r - > wayland . y = y ;
2025-12-09 20:11:01 -06:00
setup_callbacks ( & r - > wayland ) ;
/* Connect to the Wayland compositor */
r - > wayland . display = wl_display_connect ( NULL ) ;
if ( r - > wayland . display = = NULL ) {
printf ( " wayland: failed to create display \n " ) ;
raise ( SIGTRAP ) ;
return ;
}
/* Do a roundtrip to ensure all interfaces are setup. */
r - > wayland . registry = wl_display_get_registry ( r - > wayland . display ) ;
wl_registry_add_listener ( r - > wayland . registry , & r - > wayland . registry_listener , r ) ;
if ( wl_display_roundtrip ( r - > wayland . display ) = = - 1 ) {
printf ( " roundtrip failed \n " ) ;
raise ( SIGTRAP ) ;
return ;
}
2026-03-23 14:28:49 -07:00
/* check now if we have decorations so that everything else can act accordingly */
if ( shget ( r - > wayland . wl_protocol_map , zxdg_decoration_manager_v1_interface . name ) ! = NULL ) {
r - > wayland . has_decorations = MwTRUE ;
}
2026-03-27 15:14:04 -07:00
r - > wayland . xkb_context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
2025-12-09 20:11:01 -06:00
/* Create a wl_surface, a xdg_surface and a xdg_toplevel */
2025-12-18 13:15:03 -07:00
r - > wayland . framebuffer . surface = wl_compositor_create_surface ( r - > wayland . compositor ) ;
2026-03-19 19:43:57 -07:00
r - > wayland . backbuffer . surface = wl_compositor_create_surface ( r - > wayland . compositor ) ;
r - > wayland . toplevel - > ssurface = wl_subcompositor_get_subsurface ( r - > wayland . toplevel - > scompositor , r - > wayland . framebuffer . surface , r - > wayland . backbuffer . surface ) ;
2026-03-20 19:28:18 -07:00
wl_subsurface_set_desync ( r - > wayland . toplevel - > ssurface ) ;
2025-12-18 13:43:45 -07:00
2025-12-09 20:11:01 -06:00
r - > wayland . toplevel - > xdg_surface =
2026-03-19 19:43:57 -07:00
xdg_wm_base_get_xdg_surface ( WAYLAND_GET_INTERFACE ( r - > wayland , xdg_wm_base ) - > context , r - > wayland . backbuffer . surface ) ;
2025-12-09 20:11:01 -06:00
r - > wayland . toplevel - > xdg_top_level = xdg_surface_get_toplevel ( r - > wayland . toplevel - > xdg_surface ) ;
/* setup mandatory listeners */
r - > wayland . toplevel - > xdg_surface_listener . configure = xdg_surface_configure ;
r - > wayland . toplevel - > xdg_toplevel_listener . configure = xdg_toplevel_configure ;
r - > wayland . toplevel - > xdg_toplevel_listener . close = xdg_toplevel_close ;
xdg_surface_add_listener ( r - > wayland . toplevel - > xdg_surface , & r - > wayland . toplevel - > xdg_surface_listener , r ) ;
xdg_toplevel_add_listener ( r - > wayland . toplevel - > xdg_top_level , & r - > wayland . toplevel - > xdg_toplevel_listener ,
r ) ;
xdg_toplevel_set_title ( r - > wayland . toplevel - > xdg_top_level , " Milsko App " ) ;
xdg_toplevel_set_app_id ( r - > wayland . toplevel - > xdg_top_level , " MilskoWaylandApp " ) ;
/* Perform the initial commit and wait for the first configure event */
2026-03-19 19:43:57 -07:00
wl_surface_commit ( r - > wayland . backbuffer . surface ) ;
2025-12-18 13:15:03 -07:00
wl_surface_commit ( r - > wayland . framebuffer . surface ) ;
2025-12-30 17:12:12 -07:00
while ( ! r - > wayland . configured ) {
2026-01-12 18:18:05 -07:00
event_loop ( r ) ;
2025-12-30 17:12:12 -07:00
}
2025-12-09 20:11:01 -06:00
/* setup decorations if we can */
2026-03-23 14:28:49 -07:00
if ( r - > wayland . has_decorations ) {
2025-12-09 20:11:01 -06:00
zxdg_decoration_manager_v1_context_t * dec = WAYLAND_GET_INTERFACE ( r - > wayland , zxdg_decoration_manager_v1 ) - > context ;
dec - > decoration = zxdg_decoration_manager_v1_get_toplevel_decoration (
dec - > manager , r - > wayland . toplevel - > xdg_top_level ) ;
zxdg_toplevel_decoration_v1_set_mode (
dec - > decoration , ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE ) ;
} else {
2026-03-20 19:28:18 -07:00
wl_subsurface_set_position ( r - > wayland . toplevel - > ssurface , CSD_BORDER_FRAME_LEFT , CSD_BORDER_FRAME_TOP ) ;
2025-12-09 20:11:01 -06:00
}
2025-12-18 23:32:51 -07:00
}
/* Toplevel destroy function */
static void destroy_toplevel ( MwLL r ) {
if ( shget ( r - > wayland . wl_protocol_map , zxdg_decoration_manager_v1_interface . name ) ! = NULL ) {
zxdg_decoration_manager_v1_context_t * dec = WAYLAND_GET_INTERFACE ( r - > wayland , zxdg_decoration_manager_v1 ) - > context ;
zxdg_decoration_manager_v1_destroy ( dec - > manager ) ;
}
2025-12-09 20:11:01 -06:00
2026-01-02 14:19:30 -07:00
wl_surface_destroy ( r - > wayland . framebuffer . surface ) ;
2025-12-18 23:32:51 -07:00
wl_compositor_destroy ( r - > wayland . compositor ) ;
xdg_surface_destroy ( r - > wayland . toplevel - > xdg_surface ) ;
xdg_toplevel_destroy ( r - > wayland . toplevel - > xdg_top_level ) ;
2026-03-27 15:14:04 -07:00
xkb_keymap_unref ( r - > wayland . xkb_keymap ) ;
2026-01-12 18:18:05 -07:00
2026-03-27 15:14:04 -07:00
xkb_state_unref ( r - > wayland . xkb_state ) ;
2026-01-12 18:18:05 -07:00
2026-03-27 15:14:04 -07:00
xkb_context_unref ( r - > wayland . xkb_context ) ;
2025-12-18 23:32:51 -07:00
2026-01-12 18:18:05 -07:00
free ( r - > wayland . toplevel ) ;
2025-12-18 23:32:51 -07:00
wl_registry_destroy ( r - > wayland . registry ) ;
wl_display_disconnect ( r - > wayland . display ) ;
2026-03-19 16:35:56 -07:00
r - > wayland . configured = MwFALSE ;
2025-12-09 20:11:01 -06:00
}
/* Sublevel setup function */
static void setup_sublevel ( MwLL parent , MwLL r , int x , int y ) {
2025-12-17 19:14:54 -07:00
struct wl_compositor * compositor = parent - > wayland . compositor ;
2025-12-18 13:15:03 -07:00
struct wl_surface * parent_surface = parent - > wayland . framebuffer . surface ;
2025-12-17 19:14:54 -07:00
2025-12-18 23:32:51 -07:00
r - > wayland . sublevel = malloc ( sizeof ( struct _MwLLWaylandSublevel ) ) ;
r - > wayland . sublevel - > parent = parent ;
2025-12-09 20:11:01 -06:00
r - > wayland . type = MWLL_WAYLAND_SUBLEVEL ;
r - > wayland . display = parent - > wayland . display ;
setup_callbacks ( & r - > wayland ) ;
2025-12-17 19:14:54 -07:00
r - > wayland . registry = wl_display_get_registry ( parent - > wayland . display ) ;
r - > wayland . display = parent - > wayland . display ;
2025-12-09 20:11:01 -06:00
2026-03-27 17:15:59 -07:00
if ( parent - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
r - > wayland . sublevel - > xdg_surface = parent - > wayland . toplevel - > xdg_surface ;
} else {
r - > wayland . sublevel - > xdg_surface = parent - > wayland . sublevel - > xdg_surface ;
}
2025-12-09 20:11:01 -06:00
wl_registry_add_listener ( r - > wayland . registry , & r - > wayland . registry_listener , r ) ;
if ( wl_display_roundtrip ( r - > wayland . display ) = = - 1 ) {
printf ( " roundtrip failed \n " ) ;
raise ( SIGTRAP ) ;
return ;
}
2025-12-30 17:12:12 -07:00
r - > wayland . framebuffer . surface = wl_compositor_create_surface ( compositor ) ;
2026-03-26 23:32:24 -07:00
2025-12-18 13:15:03 -07:00
r - > wayland . sublevel - > subsurface = wl_subcompositor_get_subsurface ( r - > wayland . sublevel - > subcompositor , r - > wayland . framebuffer . surface , parent_surface ) ;
2025-12-09 20:11:01 -06:00
2026-03-18 23:01:39 -07:00
wl_subsurface_set_desync ( r - > wayland . sublevel - > subsurface ) ;
2025-12-17 19:14:54 -07:00
wl_subsurface_set_position ( r - > wayland . sublevel - > subsurface , x , y ) ;
2025-12-09 20:11:01 -06:00
2026-03-19 15:57:20 -07:00
if ( parent ) {
wl_subsurface_place_above ( r - > wayland . sublevel - > subsurface , parent - > wayland . framebuffer . surface ) ;
}
2026-03-27 15:14:04 -07:00
r - > wayland . xkb_keymap = parent - > wayland . xkb_keymap ;
r - > wayland . xkb_state = parent - > wayland . xkb_state ;
2025-12-17 19:14:54 -07:00
r - > wayland . configured = MwTRUE ;
2025-12-09 20:11:01 -06:00
}
2025-12-18 23:32:51 -07:00
/* Sublevel setup function */
static void destroy_sublevel ( MwLL r ) {
2026-03-19 19:43:57 -07:00
backbuffer_destroy ( & r - > wayland ) ;
2026-03-17 20:28:58 -07:00
framebuffer_destroy ( & r - > wayland ) ;
2025-12-18 23:32:51 -07:00
2026-03-17 20:28:58 -07:00
wl_subsurface_destroy ( r - > wayland . sublevel - > subsurface ) ;
2025-12-18 23:32:51 -07:00
free ( r - > wayland . sublevel ) ;
2026-03-19 16:35:56 -07:00
r - > wayland . configured = MwFALSE ;
2025-12-18 23:32:51 -07:00
}
static void popup_configure ( void * data ,
struct xdg_popup * xdg_popup ,
int32_t x ,
int32_t y ,
int32_t width ,
int32_t height ) {
MwLL self = data ;
2026-03-24 17:38:21 -07:00
( void ) xdg_popup ;
2025-12-18 23:32:51 -07:00
self - > wayland . x = x ;
self - > wayland . y = y ;
self - > wayland . ww = width ;
self - > wayland . wh = height ;
} ;
static void popup_done ( void * data ,
struct xdg_popup * xdg_popup ) {
2026-03-24 17:38:21 -07:00
( void ) data ;
( void ) xdg_popup ;
2025-12-18 23:32:51 -07:00
} ;
struct xdg_popup_listener popup_listener = {
. configure = popup_configure ,
. popup_done = popup_done ,
} ;
/* Popup setup function */
2026-03-24 23:08:43 -07:00
static void setup_popup ( MwLL r , int x , int y , MwLL parent ) {
2025-12-18 23:32:51 -07:00
struct xdg_surface * xdg_surface ;
MwLL topmost_parent = r - > wayland . parent ;
2026-03-24 23:08:43 -07:00
r - > wayland . type = MWLL_WAYLAND_POPUP ;
r - > wayland . x = x ;
r - > wayland . y = y ;
r - > wayland . popup = malloc ( sizeof ( struct _MwLLWaylandPopup ) ) ;
2026-01-02 14:19:30 -07:00
2025-12-18 23:32:51 -07:00
while ( topmost_parent - > wayland . type ! = MWLL_WAYLAND_TOPLEVEL ) {
topmost_parent = topmost_parent - > wayland . parent ;
}
2026-03-20 19:42:30 -07:00
if ( ! topmost_parent - > wayland . has_decorations ) {
r - > wayland . x + = ceil ( ( float ) CSD_BORDER_FRAME_LEFT / 2. ) ;
r - > wayland . y + = ceil ( ( float ) CSD_BORDER_FRAME_TOP / 2. ) ;
}
2025-12-18 23:32:51 -07:00
setup_callbacks ( & r - > wayland ) ;
2026-03-24 23:08:43 -07:00
/* Connect to the Wayland compositor */
r - > wayland . display = parent - > wayland . display ;
2025-12-18 23:32:51 -07:00
/* Do a roundtrip to ensure all interfaces are setup. */
r - > wayland . registry = wl_display_get_registry ( r - > wayland . display ) ;
wl_registry_add_listener ( r - > wayland . registry , & r - > wayland . registry_listener , r ) ;
if ( wl_display_roundtrip ( r - > wayland . display ) = = - 1 ) {
printf ( " roundtrip failed \n " ) ;
raise ( SIGTRAP ) ;
return ;
}
2026-03-24 23:08:43 -07:00
/* check now if we have decorations so that everything else can act accordingly */
if ( shget ( r - > wayland . wl_protocol_map , zxdg_decoration_manager_v1_interface . name ) ! = NULL ) {
r - > wayland . has_decorations = MwTRUE ;
}
r - > wayland . popup - > xdg_wm_base = WAYLAND_GET_INTERFACE ( r - > wayland , xdg_wm_base ) - > context ;
2025-12-18 23:32:51 -07:00
r - > wayland . popup - > xdg_positioner = xdg_wm_base_create_positioner ( r - > wayland . popup - > xdg_wm_base ) ;
xdg_positioner_set_size ( r - > wayland . popup - > xdg_positioner , r - > wayland . ww , r - > wayland . wh ) ;
xdg_positioner_set_anchor_rect (
2026-03-17 20:28:58 -07:00
r - > wayland . popup - > xdg_positioner ,
2026-03-20 19:42:30 -07:00
r - > wayland . x , r - > wayland . y , r - > wayland . ww , r - > wayland . wh ) ;
2025-12-18 23:32:51 -07:00
2026-03-27 15:14:04 -07:00
xdg_surface = topmost_parent - > wayland . toplevel - > xdg_surface ;
r - > wayland . xkb_keymap = topmost_parent - > wayland . xkb_keymap ;
r - > wayland . xkb_state = topmost_parent - > wayland . xkb_state ;
2025-12-18 23:32:51 -07:00
2026-01-02 14:19:30 -07:00
r - > wayland . framebuffer . surface = wl_compositor_create_surface ( r - > wayland . compositor ) ;
2025-12-18 23:32:51 -07:00
r - > wayland . popup - > xdg_surface =
2026-03-24 23:08:43 -07:00
xdg_wm_base_get_xdg_surface ( WAYLAND_GET_INTERFACE ( r - > wayland , xdg_wm_base ) - > context , r - > wayland . framebuffer . surface ) ;
2025-12-18 23:32:51 -07:00
r - > wayland . popup - > xdg_popup = xdg_surface_get_popup (
r - > wayland . popup - > xdg_surface ,
xdg_surface ,
r - > wayland . popup - > xdg_positioner ) ;
xdg_popup_add_listener ( r - > wayland . popup - > xdg_popup , & popup_listener , r ) ;
r - > wayland . popup - > xdg_surface_listener . configure = xdg_surface_configure ;
xdg_surface_add_listener ( r - > wayland . popup - > xdg_surface , & r - > wayland . popup - > xdg_surface_listener , r ) ;
/* Perform the initial commit and wait for the first configure event */
wl_surface_commit ( r - > wayland . framebuffer . surface ) ;
2026-03-24 23:08:43 -07:00
while ( ! r - > wayland . configured ) {
event_loop ( r ) ;
}
2025-12-18 23:32:51 -07:00
}
2025-12-30 17:12:12 -07:00
2025-12-18 23:32:51 -07:00
/* Popup destroy function */
static void destroy_popup ( MwLL r ) {
xdg_popup_destroy ( r - > wayland . popup - > xdg_popup ) ;
xdg_surface_destroy ( r - > wayland . popup - > xdg_surface ) ;
xdg_positioner_destroy ( r - > wayland . popup - > xdg_positioner ) ;
wl_surface_destroy ( r - > wayland . framebuffer . surface ) ;
wl_registry_destroy ( r - > wayland . registry ) ;
2026-03-19 16:35:56 -07:00
r - > wayland . configured = MwFALSE ;
}
static void wl_logger ( const char * fmt , va_list args ) {
vprintf ( fmt , args ) ;
raise ( SIGTRAP ) ;
2025-12-18 23:32:51 -07:00
}
2026-03-24 22:40:36 -07:00
static void widget_setup ( MwLL r , MwLL parent , int x , int y , int width , int height , enum _MwLLWaylandType ty ) {
2026-01-04 13:06:36 -07:00
/* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this.
*/
r - > common . coordinate_type = MwCoordinatesLocal ;
2025-12-09 20:11:01 -06:00
r - > common . type = MwLLBackendWayland ;
2025-12-17 19:14:54 -07:00
if ( width < 2 ) width = 2 ;
if ( height < 2 ) height = 2 ;
2025-12-09 20:11:01 -06:00
if ( x = = MwDEFAULT ) {
x = 0 ;
}
if ( y = = MwDEFAULT ) {
y = 0 ;
}
2025-12-18 23:32:51 -07:00
r - > wayland . ww = width ;
r - > wayland . wh = height ;
r - > wayland . x = x ;
r - > wayland . y = y ;
r - > wayland . parent = parent ;
2025-12-09 20:11:01 -06:00
2026-03-24 22:40:36 -07:00
if ( ty = = MWLL_WAYLAND_UNKNOWN ) {
if ( parent = = NULL ) {
setup_toplevel ( r , x , y ) ;
} else {
setup_sublevel ( parent , r , x , y ) ;
}
2025-12-09 20:11:01 -06:00
} else {
2026-03-24 22:40:36 -07:00
switch ( ty ) {
case MWLL_WAYLAND_UNKNOWN :
break ;
case MWLL_WAYLAND_TOPLEVEL :
setup_toplevel ( r , x , y ) ;
break ;
case MWLL_WAYLAND_SUBLEVEL :
setup_sublevel ( parent , r , x , y ) ;
break ;
case MWLL_WAYLAND_POPUP :
2026-03-24 23:08:43 -07:00
setup_popup ( r , x , y , parent ) ;
2026-03-24 22:40:36 -07:00
break ;
}
2025-12-09 20:11:01 -06:00
}
2025-12-18 13:15:03 -07:00
framebuffer_setup ( & r - > wayland ) ;
2026-03-19 19:43:57 -07:00
backbuffer_setup ( & r - > wayland ) ;
2025-12-17 19:14:54 -07:00
2026-03-19 15:57:20 -07:00
r - > wayland . region = wl_compositor_create_region ( r - > wayland . compositor ) ;
r - > wayland . o_region = wl_compositor_create_region ( r - > wayland . compositor ) ;
2025-12-18 11:26:51 -07:00
region_setup ( r ) ;
2025-12-17 19:14:54 -07:00
MwLLForceRender ( r ) ;
2026-01-12 18:50:33 -07:00
if ( parent ! = NULL ) {
MwLLForceRender ( parent ) ;
}
2026-03-26 17:48:22 -07:00
if ( ! r - > wayland . has_decorations ) {
MwLLBeginDraw ( r ) ;
MwLLEndDraw ( r ) ;
}
2026-03-24 22:40:36 -07:00
}
static MwLL MwLLCreateImpl ( MwLL parent , int x , int y , int width , int height ) {
MwLL r ;
r = malloc ( sizeof ( * r ) ) ;
memset ( r , 0 , sizeof ( * r ) ) ;
MwLLCreateCommon ( r ) ;
widget_setup ( r , parent , x , y , width , height , MWLL_WAYLAND_UNKNOWN ) ;
2025-12-17 19:14:54 -07:00
2025-12-09 20:11:01 -06:00
return r ;
}
static void MwLLDestroyImpl ( MwLL handle ) {
2026-01-04 11:40:34 -07:00
int i ;
struct timeval tv ;
struct timespec t = {
. tv_sec = 0 ,
2026-03-18 23:07:16 -07:00
. tv_nsec = 0 ,
2026-01-04 11:40:34 -07:00
} ;
int select_ret ;
2026-01-03 18:27:34 -07:00
2026-01-04 11:40:34 -07:00
if ( pthread_mutex_timedlock ( & handle - > wayland . eventsMutex , & t ) ! = 0 ) {
printf ( " WARNING: Couldn't call MwLLDestroyImpl due to deadlock. \n " ) ;
return ;
} ;
2025-12-18 23:32:51 -07:00
2025-12-09 20:11:01 -06:00
MwLLDestroyCommon ( handle ) ;
2026-01-02 14:19:30 -07:00
event_loop ( handle ) ;
2026-01-12 18:18:05 -07:00
/* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */
tv . tv_sec = 0 ;
tv . tv_usec = 1000 ;
do {
select_ret = select ( 1 , NULL , NULL , NULL , & tv ) ;
} while ( ( select_ret = = - 1 ) & & ( errno = = EINTR ) ) ;
pthread_mutex_unlock ( & handle - > wayland . eventsMutex ) ;
pthread_mutex_destroy ( & handle - > wayland . eventsMutex ) ;
2026-03-17 20:28:58 -07:00
// framebuffer_destroy(&handle->wayland);
2025-12-18 13:15:03 -07:00
buffer_destroy ( & handle - > wayland . cursor ) ;
2025-12-18 11:26:51 -07:00
wl_region_destroy ( handle - > wayland . region ) ;
2025-12-17 19:14:54 -07:00
2025-12-30 17:12:12 -07:00
if ( handle - > wayland . supports_zwp ) {
zwp_primary_selection_source_v1_destroy ( handle - > wayland . clipboard_source . zwp ) ;
} else {
wl_data_source_destroy ( handle - > wayland . clipboard_source . wl ) ;
2025-12-18 17:46:23 -07:00
}
2025-12-18 18:21:57 -07:00
if ( handle - > wayland . icon ! = NULL ) {
buffer_destroy ( handle - > wayland . icon ) ;
wl_surface_destroy ( handle - > wayland . icon - > surface ) ;
}
2025-12-18 23:32:51 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
destroy_toplevel ( handle ) ;
} else if ( handle - > wayland . type = = MWLL_WAYLAND_SUBLEVEL ) {
destroy_sublevel ( handle ) ;
} else if ( handle - > wayland . type = = MWLL_WAYLAND_POPUP ) {
destroy_popup ( handle ) ;
}
for ( i = 0 ; i < shlen ( handle - > wayland . wl_protocol_setup_map ) ; i + + ) {
void * ctx = shget ( handle - > wayland . wl_protocol_map , handle - > wayland . wl_protocol_setup_map [ i ] . key ) ;
2026-01-12 18:18:05 -07:00
if ( ctx ! = NULL ) {
handle - > wayland . wl_protocol_setup_map [ i ] . value - > destroy ( & handle - > wayland , ctx ) ;
}
2026-01-02 14:19:30 -07:00
shdel ( handle - > wayland . wl_protocol_map , handle - > wayland . wl_protocol_setup_map [ i ] . value ) ;
2025-12-18 23:32:51 -07:00
}
shfree ( handle - > wayland . wl_protocol_map ) ;
shfree ( handle - > wayland . wl_protocol_setup_map ) ;
2025-12-09 20:11:01 -06:00
free ( handle ) ;
2026-03-24 23:08:43 -07:00
if ( currentlyHeldWidget = = handle ) {
currentlyHeldWidget = NULL ;
}
2025-12-09 20:11:01 -06:00
}
static void MwLLGetXYWHImpl ( MwLL handle , int * x , int * y , unsigned int * w , unsigned int * h ) {
* x = handle - > wayland . x ;
* y = handle - > wayland . y ;
* w = handle - > wayland . ww ;
* h = handle - > wayland . wh ;
}
static void MwLLSetXYImpl ( MwLL handle , int x , int y ) {
2026-01-04 13:01:44 -07:00
region_invalidate ( handle ) ;
handle - > wayland . x = x ;
handle - > wayland . y = y ;
2026-01-02 14:19:30 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_SUBLEVEL ) {
2025-12-17 19:14:54 -07:00
wl_subsurface_set_position ( handle - > wayland . sublevel - > subsurface , x , y ) ;
2025-12-09 20:11:01 -06:00
}
2026-01-04 13:01:44 -07:00
region_setup ( handle ) ;
2025-12-18 11:26:51 -07:00
2025-12-17 19:14:54 -07:00
MwLLDispatch ( handle , draw , NULL ) ;
2025-12-09 20:11:01 -06:00
}
static void MwLLSetWHImpl ( MwLL handle , int w , int h ) {
2025-12-18 11:26:51 -07:00
region_invalidate ( handle ) ;
2025-12-30 17:12:12 -07:00
2025-12-09 20:11:01 -06:00
/* Prevent an integer underflow when the w/h is too low */
2026-03-27 15:14:04 -07:00
if ( ( w < 2 | | h < 2 ) ) {
handle - > wayland . ww = 2 ;
handle - > wayland . wh = 2 ;
} else {
handle - > wayland . ww = w ;
handle - > wayland . wh = h ;
2025-12-09 20:11:01 -06:00
}
2026-03-23 15:32:28 -07:00
2025-12-30 17:12:12 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL & & handle - > wayland . configured ) {
2025-12-09 20:11:01 -06:00
xdg_surface_set_window_geometry ( handle - > wayland . toplevel - > xdg_surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
}
2025-12-18 11:26:51 -07:00
2026-03-27 15:14:04 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_SUBLEVEL & & handle - > wayland . configured & & ! handle - > wayland . dispatching_resize ) {
handle - > wayland . dispatching_resize = MwTRUE ;
MwLLDispatch ( handle , resize , NULL ) ;
handle - > wayland . dispatching_resize = MwFALSE ;
}
2026-03-17 20:28:58 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_POPUP ) {
2026-03-19 19:43:57 -07:00
destroy_popup ( handle ) ;
wl_flush ( handle ) ;
2026-03-24 23:08:43 -07:00
setup_popup ( handle , handle - > wayland . x , handle - > wayland . y , handle - > wayland . parent ) ;
2026-03-17 20:28:58 -07:00
}
2025-12-18 11:26:51 -07:00
refresh :
region_setup ( handle ) ;
2025-12-18 13:15:03 -07:00
framebuffer_destroy ( & handle - > wayland ) ;
framebuffer_setup ( & handle - > wayland ) ;
2026-03-19 19:43:57 -07:00
backbuffer_destroy ( & handle - > wayland ) ;
backbuffer_setup ( & handle - > wayland ) ;
2026-01-12 18:48:22 -07:00
MwLLDispatch ( handle , draw , NULL ) ;
2026-03-23 15:45:48 -07:00
handle - > wayland . events_pending = 1 ;
2025-12-09 20:11:01 -06:00
}
2026-03-19 16:05:44 -07:00
static void MwLLBeginDrawImpl ( MwLL handle ) {
2026-03-19 19:43:57 -07:00
if ( handle - > wayland . type ! = MWLL_WAYLAND_TOPLEVEL ) {
2026-04-08 14:18:13 -07:00
// handle->wayland.selected_cairo = handle->wayland.front_cairo;
2026-03-19 19:43:57 -07:00
return ;
}
2026-03-23 15:45:48 -07:00
2026-03-19 19:43:57 -07:00
if ( ! handle - > wayland . has_decorations ) {
2026-03-24 17:38:21 -07:00
int x ;
2026-03-23 15:32:28 -07:00
MwU32 w = handle - > wayland . ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT ;
MwU32 h = handle - > wayland . wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM ;
2026-04-08 14:18:13 -07:00
// cairo_set_line_width(handle->wayland.back_cairo, 4.0);
// for(x = 0; x < w; x++) {
// float placeholder = (float)x / (float)w;
// cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25);
// cairo_move_to(handle->wayland.back_cairo, w - x, 0);
// cairo_line_to(handle->wayland.back_cairo, w - x, CSD_BORDER_FRAME_TOP);
// cairo_stroke(handle->wayland.back_cairo);
// cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP);
// cairo_line_to(handle->wayland.back_cairo, x, h);
// cairo_stroke(handle->wayland.back_cairo);
// }
// cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5);
// cairo_move_to(handle->wayland.back_cairo, 0, 0);
// cairo_line_to(handle->wayland.back_cairo, 0, h);
// cairo_stroke(handle->wayland.back_cairo);
// cairo_move_to(handle->wayland.back_cairo, 0, 0);
// cairo_line_to(handle->wayland.back_cairo, w, 0);
// cairo_stroke(handle->wayland.back_cairo);
// cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5);
// cairo_move_to(handle->wayland.back_cairo, 0, h);
// cairo_line_to(handle->wayland.back_cairo, w, h);
// cairo_stroke(handle->wayland.back_cairo);
// cairo_move_to(handle->wayland.back_cairo, w, 0);
// cairo_line_to(handle->wayland.back_cairo, w, h);
// cairo_stroke(handle->wayland.back_cairo);
2026-03-20 19:28:18 -07:00
if ( strlen ( handle - > wayland . title ) ! = 0 ) {
int y , x ;
int i = 0 , sx = 0 , sy = 0 ;
int tw , th ;
unsigned char * px ;
MwRect r ;
MwLLPixmap p ;
tw = strlen ( handle - > wayland . title ) * 7 ;
th = 14 ;
px = malloc ( tw * th * 4 ) ;
assert ( px ) ;
memset ( px , 0 , tw * th * 4 ) ;
2026-04-08 14:18:13 -07:00
// handle->wayland.selected_cairo = handle->wayland.back_cairo;
2026-03-20 19:28:18 -07:00
while ( handle - > wayland . title [ i ] ) {
int out ;
i + = MwUTF8ToUTF32 ( handle - > wayland . title + i , & out ) ;
if ( out > 0xff ) {
out = 0 ;
}
for ( y = 0 ; y < 14 ; y + + ) {
for ( x = 0 ; x < 7 ; x + + ) {
unsigned char * ppx = & px [ ( ( sy + y ) * tw + sx + x ) * 4 ] ;
int col = MwFontData [ out ] . data [ y ] & ( 1 < < ( ( 7 - 1 ) - x ) ) ? 255 : 0 ;
ppx [ 0 ] = col ;
ppx [ 1 ] = col ;
ppx [ 2 ] = col ;
ppx [ 3 ] = col ;
}
}
sx + = 7 ;
}
p = MwLLCreatePixmap ( handle , px , tw , th ) ;
r . x = 5 ;
r . y = 5 ;
r . width = tw ;
r . height = th ;
MwLLDrawPixmap ( handle , & r , p ) ;
MwLLDestroyPixmap ( p ) ;
free ( px ) ;
}
2026-03-25 00:31:23 -07:00
update_buffer ( handle , & handle - > wayland . backbuffer ) ;
2026-03-19 19:43:57 -07:00
}
2026-04-08 14:18:13 -07:00
// handle->wayland.selected_cairo = handle->wayland.front_cairo;
2026-03-19 16:05:44 -07:00
}
static void MwLLEndDrawImpl ( MwLL handle ) {
2026-03-19 19:43:57 -07:00
if ( handle - > wayland . configured ) {
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
2026-03-25 00:31:23 -07:00
update_buffer ( handle , & handle - > wayland . backbuffer ) ;
2026-03-19 19:43:57 -07:00
}
2026-03-25 00:31:23 -07:00
update_buffer ( handle , & handle - > wayland . framebuffer ) ;
2026-03-19 19:43:57 -07:00
}
2026-03-19 16:05:44 -07:00
}
2026-04-08 17:58:10 -07:00
# define MAXPTS 512
# define MAXTRI (MAXPTS * 4)
# define EPS 1e-7
# define PACK(dst, pts, idx) \
do { \
( dst ) . x = pixman_int_to_fixed ( ( pts ) [ ( idx ) ] . x ) ; \
( dst ) . y = pixman_int_to_fixed ( ( pts ) [ ( idx ) ] . y ) ; \
} while ( 0 )
typedef struct {
int a , b , c ;
double cx , cy , r2 ; /* circumcircle centre + radius^2 */
} triangle ;
typedef struct {
MwPoint pts [ MAXPTS + 3 ] ;
int npts ;
triangle tris [ MAXTRI ] ;
int ntris ;
int bad [ MAXTRI ] ;
int nbad ;
MwPoint edges [ MAXTRI * 3 ] ;
int nedges ;
} triangulation_state ;
static void circumcircle ( triangulation_state * s , int t ) {
double ax = s - > pts [ s - > tris [ t ] . a ] . x , ay = s - > pts [ s - > tris [ t ] . a ] . y ;
double bx = s - > pts [ s - > tris [ t ] . b ] . x , by = s - > pts [ s - > tris [ t ] . b ] . y ;
double cx = s - > pts [ s - > tris [ t ] . c ] . x , cy = s - > pts [ s - > tris [ t ] . c ] . y ;
double D = 2.0 * ( ax * ( by - cy ) + bx * ( cy - ay ) + cx * ( ay - by ) ) ;
double ux , uy ;
if ( fabs ( D ) < EPS ) {
s - > tris [ t ] . r2 = 1e30 ;
return ;
}
ux = ( ( ax * ax + ay * ay ) * ( by - cy ) + ( bx * bx + by * by ) * ( cy - ay ) + ( cx * cx + cy * cy ) * ( ay - by ) ) / D ;
uy = ( ( ax * ax + ay * ay ) * ( cx - bx ) + ( bx * bx + by * by ) * ( ax - cx ) + ( cx * cx + cy * cy ) * ( bx - ax ) ) / D ;
s - > tris [ t ] . cx = ux ;
s - > tris [ t ] . cy = uy ;
s - > tris [ t ] . r2 = ( ax - ux ) * ( ax - ux ) + ( ay - uy ) * ( ay - uy ) ;
}
static int in_circumcircle ( triangulation_state * s , int t , int p ) {
double dx = s - > pts [ p ] . x - s - > tris [ t ] . cx ;
double dy = s - > pts [ p ] . y - s - > tris [ t ] . cy ;
return dx * dx + dy * dy < s - > tris [ t ] . r2 - EPS ;
}
static void add_tri ( triangulation_state * s , int a , int b , int c ) {
s - > tris [ s - > ntris ] . a = a ;
s - > tris [ s - > ntris ] . b = b ;
s - > tris [ s - > ntris ] . c = c ;
circumcircle ( s , s - > ntris ) ;
s - > ntris + + ;
}
static void remove_tri ( triangulation_state * s , int i ) {
s - > tris [ i ] = s - > tris [ - - s - > ntris ] ;
}
2026-04-08 18:12:11 -07:00
static int delaunay ( MwPoint * src , int npts ,
2026-04-08 17:58:10 -07:00
pixman_triangle_t * out , int out_size ) {
triangulation_state s ;
int si , i , j , k ;
double mnx , mxx , mny , mxy , dx , dy , dmx , mx , my ;
if ( npts < 3 | | npts > MAXPTS ) return - 1 ;
s . npts = npts ;
2026-04-08 18:12:11 -07:00
memcpy ( s . pts , src , npts * sizeof ( MwPoint ) ) ;
2026-04-08 17:58:10 -07:00
/* super-triangle */
mnx = mxx = s . pts [ 0 ] . x ;
mny = mxy = s . pts [ 0 ] . y ;
for ( i = 1 ; i < npts ; i + + ) {
if ( s . pts [ i ] . x < mnx ) mnx = s . pts [ i ] . x ;
if ( s . pts [ i ] . x > mxx ) mxx = s . pts [ i ] . x ;
if ( s . pts [ i ] . y < mny ) mny = s . pts [ i ] . y ;
if ( s . pts [ i ] . y > mxy ) mxy = s . pts [ i ] . y ;
}
dx = mxx - mnx ;
dy = mxy - mny ;
dmx = ( dx > dy ) ? dx : dy ;
mx = ( mnx + mxx ) * 0.5 ;
my = ( mny + mxy ) * 0.5 ;
si = npts ;
s . pts [ si ] . x = mx - 20.0 * dmx ;
s . pts [ si ] . y = my - dmx ;
s . pts [ si + 1 ] . x = mx ;
s . pts [ si + 1 ] . y = my + 20.0 * dmx ;
s . pts [ si + 2 ] . x = mx + 20.0 * dmx ;
s . pts [ si + 2 ] . y = my - dmx ;
s . ntris = 0 ;
add_tri ( & s , si , si + 1 , si + 2 ) ;
/* insert each point */
for ( i = 0 ; i < npts ; i + + ) {
s . nbad = 0 ;
for ( j = 0 ; j < s . ntris ; j + + )
if ( in_circumcircle ( & s , j , i ) )
s . bad [ s . nbad + + ] = j ;
s . nedges = 0 ;
for ( j = 0 ; j < s . nbad ; j + + ) {
int ea [ 3 ] [ 2 ] ;
ea [ 0 ] [ 0 ] = s . tris [ s . bad [ j ] ] . a ;
ea [ 0 ] [ 1 ] = s . tris [ s . bad [ j ] ] . b ;
ea [ 1 ] [ 0 ] = s . tris [ s . bad [ j ] ] . b ;
ea [ 1 ] [ 1 ] = s . tris [ s . bad [ j ] ] . c ;
ea [ 2 ] [ 0 ] = s . tris [ s . bad [ j ] ] . c ;
ea [ 2 ] [ 1 ] = s . tris [ s . bad [ j ] ] . a ;
for ( k = 0 ; k < 3 ; k + + ) {
int m , shared = 0 ;
for ( m = 0 ; m < s . nbad ; m + + ) {
if ( m = = j ) continue ;
if ( ( s . tris [ s . bad [ m ] ] . a = = ea [ k ] [ 0 ] | | s . tris [ s . bad [ m ] ] . b = = ea [ k ] [ 0 ] | | s . tris [ s . bad [ m ] ] . c = = ea [ k ] [ 0 ] ) & &
( s . tris [ s . bad [ m ] ] . a = = ea [ k ] [ 1 ] | | s . tris [ s . bad [ m ] ] . b = = ea [ k ] [ 1 ] | | s . tris [ s . bad [ m ] ] . c = = ea [ k ] [ 1 ] ) ) {
shared = 1 ;
break ;
}
}
if ( ! shared ) {
s . edges [ s . nedges ] . x = ea [ k ] [ 0 ] ;
s . edges [ s . nedges ] . y = ea [ k ] [ 1 ] ;
s . nedges + + ;
}
}
}
for ( j = s . nbad - 1 ; j > = 0 ; j - - )
remove_tri ( & s , s . bad [ j ] ) ;
for ( j = 0 ; j < s . nedges ; j + + )
add_tri ( & s , s . edges [ j ] . x , s . edges [ j ] . y , i ) ;
}
/* remove triangles touching the super-triangle */
for ( i = s . ntris - 1 ; i > = 0 ; i - - )
if ( s . tris [ i ] . a > = npts | | s . tris [ i ] . b > = npts | | s . tris [ i ] . c > = npts )
remove_tri ( & s , i ) ;
if ( s . ntris > out_size ) return - 1 ;
2026-04-08 17:06:29 -07:00
2026-04-08 17:58:10 -07:00
/* pack into pixman_triangle_t */
for ( i = 0 ; i < s . ntris ; i + + ) {
PACK ( out [ i ] . p1 , s . pts , s . tris [ i ] . a ) ;
PACK ( out [ i ] . p2 , s . pts , s . tris [ i ] . b ) ;
PACK ( out [ i ] . p3 , s . pts , s . tris [ i ] . c ) ;
2025-12-09 20:11:01 -06:00
}
2026-04-08 17:58:10 -07:00
return s . ntris ;
}
static void MwLLPolygonImpl ( MwLL handle , MwPoint * points , int points_count , MwLLColor color ) {
int n , i ;
pixman_color_t col = { color - > common . red * 0xFF , color - > common . green * 0xFF , color - > common . blue * 0xFF , 0xffff } ;
pixman_image_t * image = pixman_image_create_solid_fill ( & col ) ;
pixman_triangle_t out [ MAXTRI ] ;
2026-04-08 18:12:11 -07:00
n = delaunay ( points , points_count , out , MAXTRI ) ;
2026-04-08 17:58:10 -07:00
pixman_composite_triangles ( PIXMAN_OP_ATOP_REVERSE , image , handle - > wayland . framebuffer . pixman_fb , PIXMAN_a8 , 0 , 0 , 0 , 0 , points_count , out ) ;
2026-03-19 15:57:20 -07:00
2026-04-08 14:18:13 -07:00
pixman_image_unref ( image ) ;
2025-12-30 22:26:19 -07:00
2026-03-18 19:24:51 -07:00
handle - > wayland . events_pending = 1 ;
2025-12-09 20:11:01 -06:00
}
static void MwLLLineImpl ( MwLL handle , MwPoint * points , MwLLColor color ) {
2026-04-08 17:58:10 -07:00
int i ;
pixman_color_t col = { color - > common . red * 0xFF , color - > common . green * 0xFF , color - > common . blue * 0xFF , 0xffff } ;
pixman_image_t * image = pixman_image_create_solid_fill ( & col ) ;
2026-04-08 14:18:13 -07:00
pixman_image_unref ( image ) ;
2025-12-30 22:26:19 -07:00
2026-03-18 19:24:51 -07:00
handle - > wayland . events_pending = 1 ;
2025-12-09 20:11:01 -06:00
}
static MwLLColor MwLLAllocColorImpl ( MwLL handle , int r , int g , int b ) {
MwLLColor c = malloc ( sizeof ( * c ) ) ;
2026-03-24 17:38:21 -07:00
( void ) handle ;
2025-12-09 20:11:01 -06:00
c - > common . red = r ;
c - > common . blue = b ;
c - > common . green = g ;
return c ;
}
static void MwLLColorUpdateImpl ( MwLL handle , MwLLColor c , int r , int g , int b ) {
2026-03-24 17:38:21 -07:00
( void ) handle ;
2025-12-09 20:11:01 -06:00
c - > common . red = r ;
c - > common . blue = b ;
c - > common . green = g ;
}
static void MwLLFreeColorImpl ( MwLLColor color ) {
free ( color ) ;
}
2025-12-30 19:15:33 -07:00
static int MwLLPendingImpl ( MwLL handle ) {
2026-03-23 12:05:32 -07:00
struct timespec timeout = {
2026-03-24 14:52:53 -07:00
. tv_nsec = 1 ,
2026-03-23 12:05:32 -07:00
. tv_sec = 0 ,
} ;
struct pollfd fd = {
. fd = wl_display_get_fd ( handle - > wayland . display ) ,
. events = POLLOUT ,
} ;
int pending = 0 ;
2026-03-19 17:32:36 -07:00
2026-03-23 14:28:49 -07:00
if ( ! handle - > wayland . did_initial_resize ) {
2026-03-24 14:43:38 -07:00
recursive_dispatch_resize ( handle ) ;
2026-03-23 14:28:49 -07:00
handle - > wayland . did_initial_resize = 1 ;
}
2026-03-25 00:43:35 -07:00
if ( ! MwWaylandAlwaysRender ) {
wl_display_prepare_read ( handle - > wayland . display ) ;
if ( ! poll ( & fd , 1 , timeout . tv_nsec ) ) {
wl_display_cancel_read ( handle - > wayland . display ) ;
} else {
wl_display_read_events ( handle - > wayland . display ) ;
if ( ( pending = wl_display_dispatch_pending ( handle - > wayland . display ) ) < 0 ) {
wl_display_cancel_read ( handle - > wayland . display ) ;
}
}
2026-03-19 17:32:36 -07:00
} else {
if ( ( pending = wl_display_dispatch_pending ( handle - > wayland . display ) ) < 0 ) {
wl_display_cancel_read ( handle - > wayland . display ) ;
}
}
2026-03-22 16:32:36 -07:00
2026-03-24 23:24:20 -07:00
if ( MwWaylandAlwaysRender ) {
2026-03-23 12:05:32 -07:00
handle - > wayland . did_event_loop_early = MwTRUE ;
event_loop ( handle ) ;
2026-03-22 16:32:36 -07:00
return pending ;
}
2026-03-25 00:31:23 -07:00
update_buffer ( handle , & handle - > wayland . framebuffer ) ;
2026-03-19 19:43:57 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
2026-03-25 00:31:23 -07:00
update_buffer ( handle , & handle - > wayland . backbuffer ) ;
2026-03-19 19:43:57 -07:00
}
2026-03-17 17:43:22 -07:00
2026-03-23 12:05:32 -07:00
return handle - > wayland . force_render | | handle - > wayland . events_pending | | pending ;
2025-12-09 20:11:01 -06:00
}
static void MwLLNextEventImpl ( MwLL handle ) {
2026-03-24 23:24:20 -07:00
if ( ! MwWaylandAlwaysRender ) {
2026-03-17 17:43:22 -07:00
if ( handle - > wayland . did_event_loop_early ) {
handle - > wayland . did_event_loop_early = MwFALSE ;
} else {
event_loop ( handle ) ;
}
2025-12-30 22:44:04 -07:00
}
2026-03-23 12:05:32 -07:00
2025-12-30 22:38:01 -07:00
if ( handle - > wayland . force_render ) {
2026-03-24 14:52:53 -07:00
MwLLDispatch ( handle , draw , NULL ) ;
2026-03-25 00:31:23 -07:00
if ( handle - > wayland . configured ) update_buffer ( handle , & handle - > wayland . framebuffer ) ;
2025-12-30 22:38:01 -07:00
handle - > wayland . force_render = 0 ;
2025-12-18 23:50:03 -07:00
}
2026-03-23 12:05:32 -07:00
if ( handle - > wayland . events_pending ) {
handle - > wayland . events_pending = 0 ;
}
2025-12-09 20:11:01 -06:00
}
static void MwLLSetTitleImpl ( MwLL handle , const char * title ) {
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
xdg_toplevel_set_title ( handle - > wayland . toplevel - > xdg_top_level , title ) ;
}
2026-03-19 19:43:57 -07:00
if ( ! handle - > wayland . has_decorations ) {
strncpy ( handle - > wayland . title , title , 255 ) ;
2026-03-26 17:48:22 -07:00
MwLLBeginDraw ( handle ) ;
MwLLEndDraw ( handle ) ;
2026-03-19 19:43:57 -07:00
}
2025-12-09 20:11:01 -06:00
}
static MwLLPixmap MwLLCreatePixmapImpl ( MwLL handle , unsigned char * data , int width , int height ) {
2026-04-08 14:18:13 -07:00
MwLLPixmap r = malloc ( sizeof ( * r ) ) ;
pixman_transform_t transform ;
2026-03-24 17:38:21 -07:00
( void ) handle ;
2026-04-08 14:18:13 -07:00
int stride = width * 4 ;
2025-12-09 20:11:01 -06:00
2025-12-17 19:14:54 -07:00
r - > common . width = width ;
r - > common . height = height ;
r - > common . raw = malloc ( 4 * width * height ) ;
memcpy ( r - > common . raw , data , 4 * width * height ) ;
2025-12-09 20:11:01 -06:00
2026-04-08 14:18:13 -07:00
r - > wayland . img = NULL ;
2025-12-09 20:11:01 -06:00
MwLLPixmapUpdate ( r ) ;
return r ;
}
static void MwLLPixmapUpdateImpl ( MwLLPixmap r ) {
2025-12-17 19:14:54 -07:00
int i ;
unsigned char * d ;
2026-04-08 14:18:13 -07:00
if ( r - > wayland . img ) {
pixman_image_unref ( r - > wayland . img ) ;
2025-12-17 19:14:54 -07:00
}
2026-04-08 17:58:10 -07:00
r - > wayland . img = pixman_image_create_bits ( PIXMAN_a8b8g8r8 , r - > common . width , r - > common . height , ( MwU32 * ) r - > common . raw , r - > common . width * 4 ) ;
2025-12-09 20:11:01 -06:00
}
static void MwLLDestroyPixmapImpl ( MwLLPixmap pixmap ) {
2025-12-17 19:14:54 -07:00
free ( pixmap - > common . raw ) ;
2025-12-09 20:11:01 -06:00
free ( pixmap ) ;
}
static void MwLLDrawPixmapImpl ( MwLL handle , MwRect * rect , MwLLPixmap pixmap ) {
2026-04-08 18:04:25 -07:00
int width , height ;
pixman_transform_t transform ;
pixman_transform_t reverse ;
2026-04-08 17:58:10 -07:00
pixman_transform_init_identity ( & transform ) ;
pixman_transform_scale ( & transform , & reverse , pixman_double_to_fixed ( ( double ) pixmap - > common . width / ( double ) rect - > width ) , pixman_double_to_fixed ( ( double ) pixmap - > common . height / ( double ) rect - > height ) ) ;
pixman_image_set_transform ( pixmap - > wayland . img , & transform ) ;
2026-04-08 14:18:13 -07:00
width = pixman_image_get_width ( pixmap - > wayland . img ) ;
height = pixman_image_get_height ( pixmap - > wayland . img ) ;
2026-04-08 17:58:10 -07:00
pixman_image_composite ( PIXMAN_OP_OVER ,
pixmap - > wayland . img , /* src */
NULL /* mask */ ,
handle - > wayland . framebuffer . pixman_fb , /* dest */
0 , 0 , /* src_x, src_y */
0 , 0 , /* mask_x, mask_y */
rect - > x , rect - > y , /* dest_x, dest_y */
rect - > width , rect - > height /* height */ ) ;
2025-12-09 20:11:01 -06:00
}
static void MwLLSetIconImpl ( MwLL handle , MwLLPixmap pixmap ) {
2025-12-18 18:21:57 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
if ( WAYLAND_GET_INTERFACE ( handle - > wayland , xdg_toplevel_icon_manager_v1 ) ! = NULL ) {
struct xdg_toplevel_icon_manager_v1 * icon_manager = WAYLAND_GET_INTERFACE ( handle - > wayland , xdg_toplevel_icon_manager_v1 ) - > context ;
struct xdg_toplevel_icon_v1 * icon = xdg_toplevel_icon_manager_v1_create_icon ( icon_manager ) ;
MwU64 size = pixmap - > common . width * pixmap - > common . height * 4 ;
int i = 0 ;
if ( handle - > wayland . icon = = NULL ) {
2026-01-02 14:19:30 -07:00
handle - > wayland . icon = malloc ( sizeof ( struct _MwLLWaylandShmBuffer ) ) ;
memset ( handle - > wayland . icon , 0 , sizeof ( struct _MwLLWaylandShmBuffer ) ) ;
2025-12-18 18:21:57 -07:00
handle - > wayland . icon - > shm = handle - > wayland . framebuffer . shm ;
}
if ( handle - > wayland . icon - > setup ) {
buffer_destroy ( handle - > wayland . icon ) ;
wl_surface_destroy ( handle - > wayland . icon - > surface ) ;
}
handle - > wayland . icon - > surface = wl_compositor_create_surface ( handle - > wayland . compositor ) ;
2026-03-26 21:36:57 -07:00
wl_surface_attach ( handle - > wayland . icon - > surface , handle - > wayland . icon - > shm_buffer , 0 , 0 ) ;
wl_surface_commit ( handle - > wayland . icon - > surface ) ;
2025-12-18 18:21:57 -07:00
buffer_setup ( handle - > wayland . icon , pixmap - > common . width , pixmap - > common . height ) ;
for ( ; i < size ; i + = 2 ) {
2026-03-26 16:54:40 -07:00
handle - > wayland . icon - > buf_back [ i ] = pixmap - > common . raw [ i + 2 ] ;
handle - > wayland . icon - > buf_back [ i + 1 ] = pixmap - > common . raw [ i + 1 ] ;
handle - > wayland . icon - > buf_back [ i + 2 ] = pixmap - > common . raw [ i + 0 ] ;
handle - > wayland . icon - > buf_back [ i + 3 ] = 255 ;
2025-12-18 18:21:57 -07:00
}
2026-03-25 00:31:23 -07:00
if ( handle - > wayland . configured ) update_buffer ( handle , handle - > wayland . icon ) ;
2025-12-18 18:21:57 -07:00
2026-04-08 14:45:55 -07:00
xdg_toplevel_icon_v1_add_buffer ( icon , handle - > wayland . icon - > shm_buffer , 1 ) ;
2025-12-18 18:21:57 -07:00
xdg_toplevel_icon_manager_v1_set_icon ( icon_manager , handle - > wayland . toplevel - > xdg_top_level , icon ) ;
}
}
2025-12-09 20:11:01 -06:00
}
static void MwLLForceRenderImpl ( MwLL handle ) {
2025-12-18 13:15:03 -07:00
wl_surface_damage ( handle - > wayland . framebuffer . surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
2025-12-09 20:11:01 -06:00
2025-12-30 22:26:19 -07:00
handle - > wayland . force_render = MwTRUE ;
2026-03-23 12:05:32 -07:00
if ( handle - > wayland . parent ) {
handle - > wayland . parent - > wayland . force_render = MwTRUE ;
}
2025-12-09 20:11:01 -06:00
}
static void MwLLSetCursorImpl ( MwLL handle , MwCursor * image , MwCursor * mask ) {
2026-03-23 12:35:29 -07:00
int x , y , xs , ys ;
2025-12-18 13:15:03 -07:00
if ( handle - > wayland . cursor . setup ) {
buffer_destroy ( & handle - > wayland . cursor ) ;
wl_surface_destroy ( handle - > wayland . cursor . surface ) ;
}
buffer_setup ( & handle - > wayland . cursor , image - > width , image - > height ) ;
2026-03-26 16:54:40 -07:00
memset ( handle - > wayland . cursor . buf_back , 0 , handle - > wayland . cursor . buf_size ) ;
2025-12-18 13:15:03 -07:00
2026-03-23 12:35:29 -07:00
xs = - mask - > x + image - > x ;
2026-03-24 04:56:08 +09:00
ys = mask - > height + mask - > y ;
ys = image - > height + image - > y - ys ;
2026-03-23 12:35:29 -07:00
2025-12-18 13:15:03 -07:00
for ( y = 0 ; y < mask - > height ; y + + ) {
unsigned int d = mask - > data [ y ] ;
for ( x = mask - > width - 1 ; x > = 0 ; x - - ) {
2026-03-24 04:56:08 +09:00
int idx = ( ( y * image - > width ) + x ) * 4 ;
2025-12-18 13:15:03 -07:00
if ( d & 1 ) {
2026-03-26 16:54:40 -07:00
handle - > wayland . cursor . buf_back [ idx + 3 ] = 255 ;
2025-12-18 13:15:03 -07:00
} ;
d = d > > 1 ;
}
}
for ( y = 0 ; y < image - > height ; y + + ) {
unsigned int d = image - > data [ y ] ;
for ( x = image - > width - 1 ; x > = 0 ; x - - ) {
int px = 0 ;
2026-03-23 12:35:29 -07:00
int idx = ( ( ( y + ys ) * image - > width ) + ( x + xs ) ) * 4 ;
2025-12-18 13:15:03 -07:00
if ( d & 1 ) {
px = 255 ;
} ;
2026-03-26 16:54:40 -07:00
handle - > wayland . cursor . buf_back [ idx ] = px ;
handle - > wayland . cursor . buf_back [ idx + 1 ] = px ;
handle - > wayland . cursor . buf_back [ idx + 2 ] = px ;
d = d > > 1 ;
2025-12-18 13:15:03 -07:00
}
}
handle - > wayland . cursor . surface = wl_compositor_create_surface ( handle - > wayland . compositor ) ;
2026-03-26 21:36:57 -07:00
wl_surface_attach ( handle - > wayland . cursor . surface , handle - > wayland . cursor . shm_buffer , 0 , 0 ) ;
2025-12-18 13:15:03 -07:00
wl_surface_commit ( handle - > wayland . cursor . surface ) ;
2026-03-26 21:36:57 -07:00
update_buffer ( handle , & handle - > wayland . cursor ) ;
2025-12-18 13:15:03 -07:00
/* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */
if ( handle - > wayland . pointer ! = NULL ) {
2026-03-27 15:14:04 -07:00
// wl_pointer_set_cursor(handle->wayland.pointer, handle->wayland.pointer_serial, handle->wayland.cursor.surface, 0, 0);
2025-12-18 13:15:03 -07:00
}
2025-12-09 20:11:01 -06:00
}
static void MwLLDetachImpl ( MwLL handle , MwPoint * point ) {
2026-03-26 21:36:57 -07:00
MwLL p = handle - > wayland . parent ;
int x = 0 , y = 0 ;
while ( p ! = NULL ) {
x + = p - > wayland . x ;
y + = p - > wayland . y ;
p = p - > wayland . parent ;
}
2026-03-23 12:05:32 -07:00
handle - > wayland . detatching = MwTRUE ;
handle - > wayland . detach_point = * point ;
2026-03-26 21:36:57 -07:00
handle - > wayland . detach_point . x + = x ;
handle - > wayland . detach_point . y + = y ;
2025-12-09 20:11:01 -06:00
}
static void MwLLShowImpl ( MwLL handle , int show ) {
2026-03-26 23:32:24 -07:00
/* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */
if ( handle - > wayland . framebuffer . surface ) {
wl_surface_attach ( handle - > wayland . framebuffer . surface , show ? handle - > wayland . framebuffer . shm_buffer : NULL , 0 , 0 ) ;
wl_surface_commit ( handle - > wayland . framebuffer . surface ) ;
}
if ( handle - > wayland . backbuffer . surface ) {
wl_surface_attach ( handle - > wayland . backbuffer . surface , show ? handle - > wayland . backbuffer . shm_buffer : NULL , 0 , 0 ) ;
wl_surface_commit ( handle - > wayland . backbuffer . surface ) ;
2026-03-19 17:05:08 -07:00
}
2025-12-09 20:11:01 -06:00
}
static void MwLLMakePopupImpl ( MwLL handle , MwLL parent ) {
2026-03-24 17:38:21 -07:00
( void ) handle ;
( void ) parent ;
/* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */
2025-12-09 20:11:01 -06:00
}
static void MwLLSetSizeHintsImpl ( MwLL handle , int minx , int miny , int maxx , int maxy ) {
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
xdg_toplevel_set_min_size ( handle - > wayland . toplevel - > xdg_top_level , minx , miny ) ;
xdg_toplevel_set_max_size ( handle - > wayland . toplevel - > xdg_top_level , maxx , maxy ) ;
}
}
static void MwLLMakeBorderlessImpl ( MwLL handle , int toggle ) {
2026-03-24 17:38:21 -07:00
( void ) toggle ;
2025-12-09 20:11:01 -06:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
if ( WAYLAND_GET_INTERFACE ( handle - > wayland , zxdg_decoration_manager_v1 ) ! = NULL ) {
zxdg_decoration_manager_v1_context_t * dec = WAYLAND_GET_INTERFACE ( handle - > wayland , zxdg_decoration_manager_v1 ) - > context ;
dec - > decoration = zxdg_decoration_manager_v1_get_toplevel_decoration (
dec - > manager , handle - > wayland . toplevel - > xdg_top_level ) ;
zxdg_toplevel_decoration_v1_set_mode (
dec - > decoration , ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE ) ;
}
}
}
static void MwLLFocusImpl ( MwLL handle ) {
2026-03-24 17:38:21 -07:00
( void ) handle ;
2025-12-18 19:59:40 -07:00
printf ( " [WARNING] MwLLFocus not supported on Wayland \n " ) ;
2025-12-09 20:11:01 -06:00
}
static void MwLLGrabPointerImpl ( MwLL handle , int toggle ) {
2026-03-27 17:15:59 -07:00
MwLL topmost_parent = handle ;
while ( topmost_parent - > wayland . parent ) topmost_parent = topmost_parent - > wayland . parent ;
if ( handle - > wayland . pointer_constraints & & handle - > wayland . relative_pointer_manager ) {
if ( toggle ) {
topmost_parent - > wayland . locked_pointer = zwp_pointer_constraints_v1_lock_pointer ( topmost_parent - > wayland . pointer_constraints , topmost_parent - > wayland . backbuffer . surface , topmost_parent - > wayland . pointer , topmost_parent - > wayland . region , ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT ) ;
wl_surface_commit ( topmost_parent - > wayland . backbuffer . surface ) ;
2026-03-27 18:06:17 -07:00
zwp_locked_pointer_v1_set_cursor_position_hint ( topmost_parent - > wayland . locked_pointer , 0 , CSD_BORDER_FRAME_TOP ) ;
2026-03-27 17:15:59 -07:00
handle - > wayland . relative_pointer = zwp_relative_pointer_manager_v1_get_relative_pointer ( handle - > wayland . relative_pointer_manager , handle - > wayland . pointer ) ;
zwp_relative_pointer_v1_add_listener ( handle - > wayland . relative_pointer , & relative_pointer_listener , topmost_parent ) ;
} else {
if ( topmost_parent - > wayland . locked_pointer ) {
zwp_locked_pointer_v1_destroy ( topmost_parent - > wayland . locked_pointer ) ;
topmost_parent - > wayland . locked_pointer = NULL ;
}
if ( topmost_parent - > wayland . relative_pointer ) {
zwp_relative_pointer_v1_destroy ( topmost_parent - > wayland . relative_pointer ) ;
topmost_parent - > wayland . relative_pointer = NULL ;
}
}
2026-03-25 00:31:23 -07:00
handle - > wayland . do_lock_pointer = toggle ;
2026-03-24 23:44:30 -07:00
} else {
2026-03-27 17:15:59 -07:00
printf ( " [WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 and relative_pointer_manager_v1 are required. \n " ) ;
2026-03-24 23:44:30 -07:00
}
2025-12-09 20:11:01 -06:00
}
static void MwLLSetClipboardImpl ( MwLL handle , const char * text ) {
2025-12-30 17:12:12 -07:00
if ( handle - > wayland . clipboard_buffer ! = NULL ) {
free ( handle - > wayland . clipboard_buffer ) ;
}
handle - > wayland . clipboard_buffer = malloc ( strlen ( text ) ) ;
strcpy ( handle - > wayland . clipboard_buffer , text ) ;
2025-12-18 17:46:23 -07:00
2025-12-30 17:12:12 -07:00
if ( handle - > wayland . supports_zwp ) {
2026-02-02 23:02:42 +09:00
int i ;
for ( i = 0 ; i < arrlen ( handle - > wayland . clipboard_devices ) ; i + + ) {
2025-12-30 17:12:12 -07:00
wl_clipboard_device_context_t * device = handle - > wayland . clipboard_devices [ i ] ;
zwp_primary_selection_device_v1_set_selection ( device - > device . zwp , handle - > wayland . clipboard_source . zwp , handle - > wayland . keyboard_serial ) ;
2025-12-18 17:46:23 -07:00
}
2025-12-30 17:12:12 -07:00
} else {
2026-02-02 23:02:42 +09:00
int i ;
for ( i = 0 ; i < arrlen ( handle - > wayland . clipboard_devices ) ; i + + ) {
2025-12-30 17:12:12 -07:00
wl_clipboard_device_context_t * device = handle - > wayland . clipboard_devices [ i ] ;
wl_data_device_set_selection ( device - > device . wl , handle - > wayland . clipboard_source . wl , handle - > wayland . keyboard_serial ) ;
2025-12-18 17:46:23 -07:00
}
}
2025-12-30 17:12:12 -07:00
}
static void MwLLGetClipboardImpl ( MwLL handle ) {
2026-03-26 21:58:47 -07:00
int i ;
for ( i = 0 ; i < arrlen ( handle - > wayland . clipboard_devices ) ; i + + ) {
wl_clipboard_read (
handle - > wayland . clipboard_devices [ i ] ) ;
}
2025-12-30 17:12:12 -07:00
return ;
2025-12-09 20:11:01 -06:00
}
static void MwLLMakeToolWindowImpl ( MwLL handle ) {
2025-12-18 23:32:51 -07:00
handle - > wayland . type_to_be = MWLL_WAYLAND_POPUP ;
2025-12-09 20:11:01 -06:00
}
static void MwLLGetCursorCoordImpl ( MwLL handle , MwPoint * point ) {
2025-12-18 13:16:16 -07:00
* point = handle - > wayland . cur_mouse_pos ;
2025-12-09 20:11:01 -06:00
}
static void MwLLGetScreenSizeImpl ( MwLL handle , MwRect * rect ) {
2025-12-18 13:43:45 -07:00
rect - > x = 0 ;
rect - > y = 0 ;
rect - > width = handle - > wayland . mw ;
rect - > height = handle - > wayland . mh ;
2025-12-09 20:11:01 -06:00
}
static void MwLLBeginStateChangeImpl ( MwLL handle ) {
2026-03-27 15:14:04 -07:00
( void ) handle ;
/* no-op */
2025-12-09 20:11:01 -06:00
}
static void MwLLEndStateChangeImpl ( MwLL handle ) {
2026-03-23 12:05:32 -07:00
if ( handle - > wayland . detatching ) {
2026-03-24 23:08:43 -07:00
MwLL topmost_parent = handle - > wayland . parent ;
while ( topmost_parent - > wayland . type ! = MWLL_WAYLAND_TOPLEVEL ) {
topmost_parent = topmost_parent - > wayland . parent ;
}
2026-03-23 12:05:32 -07:00
switch ( handle - > wayland . type ) {
case MWLL_WAYLAND_UNKNOWN :
2026-03-24 22:40:36 -07:00
break ;
2026-03-23 12:05:32 -07:00
case MWLL_WAYLAND_TOPLEVEL :
destroy_toplevel ( handle ) ;
break ;
case MWLL_WAYLAND_SUBLEVEL :
destroy_sublevel ( handle ) ;
break ;
case MWLL_WAYLAND_POPUP :
2026-03-24 22:40:36 -07:00
destroy_popup ( handle ) ;
break ;
2026-03-23 12:05:32 -07:00
}
wl_flush ( handle ) ;
2026-03-24 22:40:36 -07:00
widget_setup ( handle , handle - > wayland . parent , handle - > wayland . detach_point . x , handle - > wayland . detach_point . y , handle - > wayland . ww , handle - > wayland . wh , handle - > wayland . type_to_be ) ;
2026-03-24 18:01:55 -07:00
2026-03-24 23:08:43 -07:00
if ( handle - > common . user ) {
MwWidget w = handle - > common . user ;
int i ;
for ( i = 0 ; i < arrlen ( w - > children ) ; i + + ) {
if ( w - > children [ i ] - > lowlevel - > wayland . type = = MWLL_WAYLAND_SUBLEVEL ) {
2026-03-27 15:14:04 -07:00
MwLL child = w - > children [ i ] - > lowlevel ;
child - > wayland . sublevel - > xdg_surface = handle - > wayland . popup - > xdg_surface ;
2026-03-24 23:08:43 -07:00
wl_subsurface_destroy ( child - > wayland . sublevel - > subsurface ) ;
wl_flush ( handle ) ;
child - > wayland . sublevel - > subsurface = wl_subcompositor_get_subsurface ( child - > wayland . sublevel - > subcompositor , child - > wayland . framebuffer . surface , handle - > wayland . framebuffer . surface ) ;
wl_subsurface_set_desync ( child - > wayland . sublevel - > subsurface ) ;
wl_subsurface_set_position ( child - > wayland . sublevel - > subsurface , child - > wayland . x , child - > wayland . y ) ;
wl_subsurface_place_above ( child - > wayland . sublevel - > subsurface , handle - > wayland . framebuffer . surface ) ;
MwLLEndStateChangeImpl ( w - > children [ i ] - > lowlevel ) ;
currentlyHeldWidget = NULL ;
}
}
}
2026-03-24 18:01:55 -07:00
MwLLForceRender ( handle ) ;
if ( handle - > wayland . parent ! = NULL ) {
MwLLForceRender ( handle - > wayland . parent ) ;
}
handle - > wayland . events_pending = 1 ;
2026-03-23 12:05:32 -07:00
handle - > wayland . detatching = MwFALSE ;
}
2025-12-09 20:11:01 -06:00
}
static int MwLLWaylandCallInitImpl ( void ) {
2026-04-08 11:59:05 -07:00
/*
* Order of precedence :
* - MILSKO_BACKEND
* - XDG_SESSION_TYPE
* - manually checking environment variables
*/
2025-12-09 20:11:01 -06:00
# ifdef __linux__
2026-04-08 14:18:13 -07:00
MwBool loadWayland = MwFALSE ;
2026-04-08 11:59:05 -07:00
if ( getenv ( " MILSKO_BACKEND " ) ) {
2026-04-08 14:18:13 -07:00
loadWayland =
2026-04-08 11:59:05 -07:00
( strcmp ( getenv ( " MILSKO_BACKEND " ) , " wayland " ) = = 0 ) ;
2026-04-08 14:18:13 -07:00
} else if ( getenv ( " WAYLAND_DISPLAY " ) & & ! loadWayland ) {
loadWayland = ( getenv ( " WAYLAND_DISPLAY " ) ! = NULL ) ;
2026-04-08 11:59:05 -07:00
}
if ( loadWayland ) {
2026-03-24 17:38:21 -07:00
if ( wayland_load_funcs ( ) ) {
return 1 ;
}
wl_log_set_handler_client ( wl_logger ) ;
return 0 ;
2025-12-09 20:11:01 -06:00
}
# endif
2026-03-24 17:38:21 -07:00
return 1 ;
2025-12-09 20:11:01 -06:00
}
# include "call.c"
CALL ( Wayland ) ;