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"
2025-12-18 18:27:44 -07:00
/* TODO:
* - MwLLMakePopupImpl
* - MwLLShowImpl
*/
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-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 ) ;
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 ;
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 ) ) ;
2025-12-09 20:11:01 -06:00
} else {
/* printf("unknown interface %s\n", interface); */
}
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 ) {
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-24 13:31:49 -07:00
/* Recursively dispatch a draw 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
}
}
}
} ;
/* 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 ;
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 ;
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 ) {
} ;
static void wl_data_device_drop ( void * data ,
struct wl_data_device * wl_data_device ) {
} ;
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 ) {
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 ;
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 ) {
} ;
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 ;
int n ;
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 ) {
char ch ;
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 ) {
} ;
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-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-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-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-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-01-12 18:18:05 -07:00
// zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp);
2025-12-18 23:32:51 -07:00
}
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 ;
WAYLAND_EVENT_OP_START ( self ) ;
2026-03-18 23:01:39 -07:00
self - > wayland . 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 ) {
} ;
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 ) {
if ( self - > wayland . type = = MWLL_WAYLAND_TOPLEVEL & & self - > wayland . backbuffer . surface = = self - > wayland . 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 ;
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 ) {
MwLL self = data ;
MwLLMouse p ;
2026-03-24 13:31:49 -07:00
int i = 0 ;
MwWidget h = ( MwWidget ) self - > common . user ;
2025-12-09 20:11:01 -06:00
2026-01-04 11:40:34 -07:00
WAYLAND_EVENT_OP_START ( self ) ;
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 ) ;
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-01-03 18:27:34 -07:00
2026-03-17 20:28:58 -07:00
int x = self - > wayland . x ;
int y = self - > wayland . y ;
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-23 13:38:26 -07:00
// p.point.x > x && p.point.x < x + self->wayland.ww && p.point.y > y && p.point.y < y + self->wayland.wh
if (
self - > wayland . framebuffer . surface = = self - > wayland . curSurface | |
self - > wayland . backbuffer . surface = = self - > wayland . curSurface ) {
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
2025-12-30 22:26:19 -07:00
if ( ! self - > wayland . always_render ) {
MwLLDispatch ( self , draw , NULL ) ;
}
2026-01-04 11:40:34 -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 ,
MwU32 axis , wl_fixed_t value ) { } ;
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-01-04 11:40:34 -07:00
2025-12-09 20:11:01 -06:00
if ( self - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
struct _MwLLWaylandTopLevel * wayland = self - > 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 (
wayland - > xkb_context , map_shm , XKB_KEYMAP_FORMAT_TEXT_V1 ,
XKB_KEYMAP_COMPILE_NO_FLAGS ) ;
munmap ( map_shm , size ) ;
close ( fd ) ;
struct xkb_state * xkb_state = xkb_state_new ( xkb_keymap ) ;
wayland - > xkb_keymap = xkb_keymap ;
wayland - > xkb_state = xkb_state ;
}
} ;
/* `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-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-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-01-04 11:40:34 -07:00
MwLL self = data ;
WAYLAND_EVENT_OP_START ( self ) ;
2026-01-03 18:27:34 -07:00
2025-12-09 20:11:01 -06:00
if ( self - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
struct _MwLLWaylandTopLevel * wayland = self - > wayland . toplevel ;
xkb_layout_index_t layout ;
xkb_level_index_t level ;
const xkb_keysym_t * syms_out ;
MwU32 keycode = key + 8 ;
MwU64 syms_num ;
int i ;
if ( ! wayland - > xkb_keymap ) {
return ;
}
layout = xkb_state_key_get_layout ( wayland - > xkb_state , keycode ) ;
level =
xkb_keymap_num_levels_for_key ( wayland - > xkb_keymap , keycode , layout ) - 1 ;
syms_num = xkb_keymap_key_get_syms_by_level ( wayland - > xkb_keymap , keycode , layout , level , & syms_out ) ;
if ( syms_out = = NULL ) {
return ;
}
for ( i = 0 ; i < syms_num ; i + + ) {
int sym = syms_out [ i ] ;
int key ;
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 :
key = sym ;
}
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
2025-12-09 20:11:01 -06:00
if ( state = = WL_KEYBOARD_KEY_STATE_PRESSED ) {
2026-03-24 13:31:49 -07:00
recursive_dispatch_key ( self , & key ) ;
2025-12-09 20:11:01 -06:00
} else {
2026-03-24 13:31:49 -07:00
recursive_dispatch_key_released ( self , & key ) ;
2025-12-09 20:11:01 -06:00
}
}
}
2025-12-30 22:26:19 -07:00
if ( ! self - > wayland . always_render ) {
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-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
wl_seat_name ( void * data , struct wl_seat * wl_seat , const char * name ) { } ;
/* `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 ,
int32_t transform ) { } ;
static void output_mode ( void * data ,
struct wl_output * wl_output ,
uint32_t flags ,
int32_t width ,
int32_t height ,
int32_t refresh ) {
MwLL self = data ;
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 ) {
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 ) {
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 ) {
}
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 ) {
}
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 ) {
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 ) {
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-22 16:12:54 -07:00
// free(data->listener);
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-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 ;
int res ;
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 ) ;
wl_surface_commit ( wayland - > framebuffer . surface ) ;
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL )
wl_surface_commit ( wayland - > backbuffer . surface ) ;
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 ) {
int i = 0 ;
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 13:31:49 -07:00
MwLL self = data ;
int i ;
MwWidget h = ( ( MwWidget ) self - > common . user ) ;
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 ) ;
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
MwLLDispatch ( self , draw , NULL ) ;
recursive_dispatch_resize ( self ) ;
2025-12-09 20:11:01 -06:00
} ;
/* Empty function for satisfying zxdg_toplevel's requirements */
static void decoration_configure (
void * data , struct zxdg_toplevel_decoration_v1 * zxdg_toplevel_decoration_v1 ,
MwU32 mode ) {
}
/* `xdg_surface.close` callback */
static void xdg_toplevel_close (
void * data , struct xdg_toplevel * xdg_toplevel ) {
MwLL self = data ;
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 ) ;
if ( self - > wayland . configured ) {
2025-12-18 13:15:03 -07:00
wl_surface_commit ( self - > wayland . framebuffer . surface ) ;
2026-03-19 19:43:57 -07:00
wl_surface_commit ( self - > wayland . backbuffer . surface ) ;
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 ) {
}
2025-12-18 18:21:57 -07:00
static void update_buffer ( struct _MwLLWaylandShmBuffer * buffer ) {
wl_surface_attach ( buffer - > surface , buffer - > shm_buffer , 0 , 0 ) ;
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 ) {
2025-12-17 19:14:54 -07:00
int x , y ;
2025-12-18 13:15:03 -07:00
int stride = width * 4 ;
2025-12-17 19:14:54 -07:00
char temp_name [ ] = " /tmp/milsko-wl-shm-XXXXXX " ;
2025-12-18 13:15:03 -07:00
buffer - > buf_size = width * height * 4 ;
2025-12-17 19:14:54 -07:00
2025-12-18 13:15:03 -07:00
buffer - > fd = mkstemp ( temp_name ) ;
2025-12-17 19:14:54 -07:00
unlink ( temp_name ) ;
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
}
2025-12-18 13:15:03 -07:00
buffer - > buf = mmap ( NULL , buffer - > buf_size , PROT_WRITE , MAP_SHARED , buffer - > fd , 0 ) ;
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 " ) ;
}
2025-12-18 13:15:03 -07:00
buffer - > shm_buffer = wl_shm_pool_create_buffer ( buffer - > shm_pool , 0 , width , height , stride , WL_SHM_FORMAT_ARGB8888 ) ;
buffer - > setup = MwTRUE ;
}
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
}
2025-12-18 13:15:03 -07:00
wl_buffer_destroy ( buffer - > shm_buffer ) ;
wl_shm_pool_destroy ( buffer - > shm_pool ) ;
close ( buffer - > fd ) ;
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-19 19:43:57 -07:00
wayland - > front_cs = cairo_image_surface_create_for_data ( wayland - > framebuffer . buf , CAIRO_FORMAT_ARGB32 , wayland - > ww , wayland - > wh , 4 * wayland - > ww ) ;
wayland - > front_cairo = cairo_create ( wayland - > front_cs ) ;
2025-12-17 19:14:54 -07:00
2026-03-20 19:28:18 -07:00
memset ( wayland - > framebuffer . buf , 0 , wayland - > framebuffer . buf_size ) ;
2026-03-20 20:23:02 -07:00
hang_until_configured ( ( MwLL ) wayland ) ;
update_buffer ( & 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
cairo_destroy ( wayland - > front_cairo ) ;
cairo_surface_destroy ( wayland - > front_cs ) ;
} ;
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-23 15:32:28 -07:00
wayland - > back_cs = cairo_image_surface_create_for_data ( wayland - > backbuffer . buf , CAIRO_FORMAT_ARGB32 , w , h , 4 * w ) ;
2026-03-19 19:43:57 -07:00
wayland - > back_cairo = cairo_create ( wayland - > back_cs ) ;
2026-03-20 19:28:18 -07:00
memset ( wayland - > backbuffer . buf , 0 , wayland - > backbuffer . buf_size ) ;
2026-03-20 20:23:02 -07:00
hang_until_configured ( ( MwLL ) wayland ) ;
update_buffer ( & wayland - > backbuffer ) ;
2026-03-19 19:43:57 -07:00
} ;
static void backbuffer_destroy ( struct _MwLLWayland * wayland ) {
buffer_destroy ( & wayland - > backbuffer ) ;
cairo_destroy ( wayland - > back_cairo ) ;
cairo_surface_destroy ( wayland - > back_cs ) ;
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-19 15:57:20 -07:00
wl_region_add ( handle - > wayland . o_region , 0 , 0 , 1 , 1 ) ;
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 ) {
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 ) ;
2025-12-09 20:11:01 -06:00
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL ) {
WL_INTERFACE ( xdg_wm_base ) ;
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 ) {
WL_INTERFACE ( xdg_wm_base ) ;
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 ) {
int i ;
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 ;
}
2025-12-09 20:11:01 -06:00
r - > wayland . toplevel - > xkb_context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
/* 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 ) {
int i ;
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-01-12 18:18:05 -07:00
xkb_keymap_unref ( r - > wayland . toplevel - > xkb_keymap ) ;
xkb_state_unref ( r - > wayland . toplevel - > xkb_state ) ;
2025-12-18 23:32:51 -07:00
xkb_context_unref ( r - > wayland . toplevel - > xkb_context ) ;
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 ;
if ( parent - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
r - > wayland . sublevel - > parent_xdg_surface = parent - > wayland . toplevel - > xdg_surface ;
} else {
r - > wayland . sublevel - > parent_xdg_surface = parent - > wayland . sublevel - > parent_xdg_surface ;
}
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
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 ) ;
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 ) ;
}
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 ;
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 ) {
} ;
struct xdg_popup_listener popup_listener = {
. configure = popup_configure ,
. popup_done = popup_done ,
} ;
/* Popup setup function */
2026-01-04 13:01:44 -07:00
static void setup_popup ( MwLL r , int x , int y ) {
2025-12-18 23:32:51 -07:00
int i ;
struct xdg_surface * xdg_surface ;
MwLL topmost_parent = r - > wayland . parent ;
2026-01-02 14:19:30 -07:00
r - > wayland . type = MWLL_WAYLAND_POPUP ;
2026-01-04 13:01:44 -07:00
r - > wayland . x = x ;
r - > wayland . y = y ;
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
2026-01-02 14:19:30 -07:00
r - > wayland . popup = malloc ( sizeof ( struct _MwLLWaylandPopup ) ) ;
memset ( r - > wayland . popup , 0 , sizeof ( struct _MwLLWaylandPopup ) ) ;
2026-01-04 13:01:44 -07:00
r - > wayland . popup - > topmost_parent = topmost_parent ;
2025-12-18 23:32:51 -07:00
setup_callbacks ( & r - > wayland ) ;
/* 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-01-04 13:01:44 -07:00
r - > wayland . popup - > xdg_wm_base = WAYLAND_GET_INTERFACE ( topmost_parent - > 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
xdg_surface = topmost_parent - > wayland . toplevel - > xdg_surface ;
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 =
xdg_wm_base_get_xdg_surface ( r - > wayland . popup - > xdg_wm_base , r - > wayland . framebuffer . surface ) ;
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 ) ;
event_loop ( r ) ;
2026-03-17 20:28:58 -07:00
// framebuffer_destroy(&r->wayland);
framebuffer_setup ( & r - > wayland ) ;
2026-03-19 19:43:57 -07:00
backbuffer_setup ( & r - > wayland ) ;
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 ;
}
2026-03-19 19:46:58 -07:00
static void clip ( MwLL handle ) {
2026-03-20 19:33:12 -07:00
MwLL parent = handle - > wayland . parent ;
MwLL topmost = parent ;
int left_offset = 0 ;
int top_offset = 0 ;
if ( parent & & handle - > wayland . type = = MWLL_WAYLAND_SUBLEVEL ) {
2026-03-19 19:46:58 -07:00
cairo_reset_clip ( handle - > wayland . front_cairo ) ;
2026-03-20 19:33:12 -07:00
cairo_rectangle ( handle - > wayland . front_cairo , 0 , 0 , ( parent - > wayland . ww + handle - > wayland . x ) , ( parent - > wayland . wh + handle - > wayland . y ) ) ;
2026-03-20 19:28:18 -07:00
cairo_clip ( handle - > wayland . front_cairo ) ;
}
2026-03-23 14:28:49 -07:00
// if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) {
// cairo_reset_clip(handle->wayland.front_cairo);
// while(topmost->wayland.parent) topmost = topmost->wayland.parent;
// left_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT);
// top_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM);
// cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - left_offset, (topmost->wayland.wh + handle->wayland.y) - top_offset);
// cairo_clip(handle->wayland.front_cairo);
// }
2026-03-20 09:59:07 +09:00
}
2026-03-19 16:35:56 -07:00
static void wl_logger ( const char * fmt , va_list args ) {
vprintf ( fmt , args ) ;
raise ( SIGTRAP ) ;
2025-12-18 23:32:51 -07:00
}
2025-12-09 20:11:01 -06:00
static MwLL MwLLCreateImpl ( MwLL parent , int x , int y , int width , int height ) {
MwLL r ;
r = malloc ( sizeof ( * r ) ) ;
2025-12-18 13:15:03 -07:00
memset ( r , 0 , sizeof ( * r ) ) ;
2025-12-09 20:11:01 -06:00
MwLLCreateCommon ( r ) ;
2026-03-19 16:35:56 -07:00
wl_log_set_handler_client ( wl_logger ) ;
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
if ( parent = = NULL ) {
setup_toplevel ( r , x , y ) ;
} else {
setup_sublevel ( parent , r , x , y ) ;
}
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 ) ;
}
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 ) ;
}
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-03-24 13:31:49 -07:00
int i = 0 ;
MwWidget h = ( MwWidget ) handle - > common . user ;
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 ) {
2026-03-24 13:31:49 -07:00
int i = 0 ;
MwWidget widget = ( MwWidget ) handle - > common . user ;
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 */
if ( ( w < 10 | | h < 10 ) ) {
2025-12-17 19:14:54 -07:00
handle - > wayland . ww = 10 ;
handle - > wayland . wh = 10 ;
2025-12-18 11:26:51 -07:00
goto refresh ;
2025-12-09 20:11:01 -06:00
}
2026-03-23 15:32:28 -07:00
2025-12-17 19:14:54 -07:00
handle - > wayland . ww = w ;
handle - > wayland . wh = h ;
2025-12-09 20:11:01 -06: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-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 ) ;
setup_popup ( handle , handle - > wayland . x , handle - > wayland . y ) ;
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-03-20 19:28:18 -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-23 15:32:28 -07:00
int x , y ;
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-03-20 19:28:18 -07:00
cairo_set_line_width ( handle - > wayland . back_cairo , 4.0 ) ;
2026-03-23 15:32:28 -07:00
for ( x = 0 ; x < w ; x + + ) {
float placeholder = ( float ) x / ( float ) w ;
2026-03-20 19:28:18 -07:00
cairo_set_source_rgb ( handle - > wayland . back_cairo , placeholder , 0.25 , 0.25 ) ;
2026-03-23 15:32:28 -07:00
cairo_move_to ( handle - > wayland . back_cairo , w - x , 0 ) ;
cairo_line_to ( handle - > wayland . back_cairo , w - x , CSD_BORDER_FRAME_TOP ) ;
2026-03-20 19:28:18 -07:00
cairo_stroke ( handle - > wayland . back_cairo ) ;
cairo_move_to ( handle - > wayland . back_cairo , x , CSD_BORDER_FRAME_TOP ) ;
2026-03-23 15:32:28 -07:00
cairo_line_to ( handle - > wayland . back_cairo , x , h ) ;
2026-03-20 19:28:18 -07:00
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 ) ;
2026-03-23 15:32:28 -07:00
cairo_line_to ( handle - > wayland . back_cairo , 0 , h ) ;
2026-03-20 19:28:18 -07:00
cairo_stroke ( handle - > wayland . back_cairo ) ;
cairo_move_to ( handle - > wayland . back_cairo , 0 , 0 ) ;
2026-03-23 15:32:28 -07:00
cairo_line_to ( handle - > wayland . back_cairo , w , 0 ) ;
2026-03-20 19:28:18 -07:00
cairo_stroke ( handle - > wayland . back_cairo ) ;
cairo_set_source_rgba ( handle - > wayland . back_cairo , 0 , 0 , 0 , 0.5 ) ;
2026-03-23 15:32:28 -07:00
cairo_move_to ( handle - > wayland . back_cairo , 0 , h ) ;
cairo_line_to ( handle - > wayland . back_cairo , w , h ) ;
2026-03-20 19:28:18 -07:00
cairo_stroke ( handle - > wayland . back_cairo ) ;
2026-03-23 15:32:28 -07:00
cairo_move_to ( handle - > wayland . back_cairo , w , 0 ) ;
cairo_line_to ( handle - > wayland . back_cairo , w , h ) ;
2026-03-19 19:43:57 -07:00
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 ) ;
handle - > wayland . selected_cairo = handle - > wayland . back_cairo ;
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 ) ;
}
update_buffer ( & handle - > wayland . backbuffer ) ;
2026-03-20 19:42:30 -07:00
wl_surface_commit ( handle - > wayland . backbuffer . surface ) ;
2026-03-19 19:43:57 -07:00
}
2026-03-20 19:28:18 -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 ) {
update_buffer ( & handle - > wayland . framebuffer ) ;
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
}
}
2026-03-19 16:05:44 -07:00
}
2025-12-09 20:11:01 -06:00
static void MwLLPolygonImpl ( MwLL handle , MwPoint * points , int points_count , MwLLColor color ) {
2025-12-17 19:14:54 -07:00
int i ;
2026-03-20 09:59:07 +09:00
clip ( handle ) ;
2026-03-19 19:43:57 -07:00
cairo_set_source_rgb ( handle - > wayland . front_cairo , color - > common . red / 255.0 , color - > common . green / 255.0 , color - > common . blue / 255.0 ) ;
cairo_new_path ( handle - > wayland . front_cairo ) ;
2025-12-09 20:11:01 -06:00
for ( i = 0 ; i < points_count ; i + + ) {
2025-12-17 19:14:54 -07:00
if ( i = = 0 ) {
2026-03-19 19:43:57 -07:00
cairo_move_to ( handle - > wayland . front_cairo , points [ i ] . x , points [ i ] . y ) ;
2025-12-17 19:14:54 -07:00
} else {
2026-03-19 19:43:57 -07:00
cairo_line_to ( handle - > wayland . front_cairo , points [ i ] . x , points [ i ] . y ) ;
2025-12-17 19:14:54 -07:00
}
2025-12-09 20:11:01 -06:00
}
2026-03-19 19:43:57 -07:00
cairo_close_path ( handle - > wayland . front_cairo ) ;
2026-03-19 15:57:20 -07:00
2026-03-19 19:43:57 -07:00
cairo_fill ( handle - > wayland . front_cairo ) ;
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 ) {
2025-12-17 19:14:54 -07:00
int i ;
2025-12-09 20:11:01 -06:00
2026-03-19 19:43:57 -07:00
cairo_set_line_cap ( handle - > wayland . front_cairo , CAIRO_LINE_CAP_SQUARE ) ;
cairo_set_source_rgb ( handle - > wayland . front_cairo , color - > common . red / 255.0 , color - > common . green / 255.0 , color - > common . blue / 255.0 ) ;
cairo_new_path ( handle - > wayland . front_cairo ) ;
2025-12-09 20:11:01 -06:00
for ( i = 0 ; i < 2 ; i + + ) {
2025-12-17 19:14:54 -07:00
if ( i = = 0 ) {
2026-03-19 19:43:57 -07:00
cairo_move_to ( handle - > wayland . front_cairo , points [ i ] . x , points [ i ] . y ) ;
2025-12-17 19:14:54 -07:00
} else {
2026-03-19 19:43:57 -07:00
cairo_line_to ( handle - > wayland . front_cairo , points [ i ] . x , points [ i ] . y ) ;
2025-12-17 19:14:54 -07:00
}
2025-12-09 20:11:01 -06:00
}
2026-03-19 19:43:57 -07:00
cairo_close_path ( handle - > wayland . front_cairo ) ;
cairo_stroke ( handle - > wayland . front_cairo ) ;
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 ) ) ;
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 ) {
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 = {
. tv_nsec = 100 ,
. 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 ;
return 1 ;
}
2026-03-22 16:32:36 -07:00
if ( ! handle - > wayland . always_render ) wl_display_prepare_read ( handle - > wayland . display ) ;
2026-03-19 17:32:36 -07:00
if ( ! poll ( & fd , 1 , timeout . tv_nsec ) ) {
wl_display_cancel_read ( handle - > wayland . display ) ;
} else {
2026-03-22 16:32:36 -07:00
if ( ! handle - > wayland . always_render ) wl_display_read_events ( handle - > wayland . display ) ;
2026-03-19 17:32:36 -07:00
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
if ( handle - > wayland . always_render ) {
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-19 17:32:36 -07:00
wl_surface_commit ( handle - > wayland . framebuffer . surface ) ;
2026-03-19 19:43:57 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
wl_surface_commit ( handle - > wayland . backbuffer . surface ) ;
}
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 13:31:49 -07:00
int i = 0 ;
2025-12-30 22:44:04 -07:00
if ( ! handle - > wayland . always_render ) {
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 13:31:49 -07:00
if ( ! handle - > wayland . events_pending ) {
MwLLDispatch ( handle , draw , NULL ) ;
}
2026-03-19 16:35:56 -07:00
if ( handle - > wayland . configured ) update_buffer ( & 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 ) ;
}
2025-12-09 20:11:01 -06:00
}
static MwLLPixmap MwLLCreatePixmapImpl ( MwLL handle , unsigned char * data , int width , int height ) {
MwLLPixmap r = malloc ( sizeof ( * r ) ) ;
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
2025-12-17 19:14:54 -07:00
r - > wayland . cs = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 , width , height ) ;
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 ;
cairo_surface_flush ( r - > wayland . cs ) ;
d = cairo_image_surface_get_data ( r - > wayland . cs ) ;
for ( i = 0 ; i < r - > common . width * r - > common . height * 4 ; i + = 4 ) {
MwU32 * p = ( MwU32 * ) & d [ i ] ;
* p < < = 8 ;
* p | = r - > common . raw [ i + 3 ] ;
* p < < = 8 ;
* p | = r - > common . raw [ i + 0 ] ;
* p < < = 8 ;
* p | = r - > common . raw [ i + 1 ] ;
* p < < = 8 ;
* p | = r - > common . raw [ i + 2 ] ;
}
cairo_surface_mark_dirty ( r - > wayland . cs ) ;
2025-12-09 20:11:01 -06:00
}
static void MwLLDestroyPixmapImpl ( MwLLPixmap pixmap ) {
2025-12-17 19:14:54 -07:00
cairo_surface_destroy ( pixmap - > wayland . cs ) ;
free ( pixmap - > common . raw ) ;
2025-12-09 20:11:01 -06:00
free ( pixmap ) ;
}
static void MwLLDrawPixmapImpl ( MwLL handle , MwRect * rect , MwLLPixmap pixmap ) {
2025-12-17 19:14:54 -07:00
cairo_t * c ;
cairo_surface_t * cs ;
2026-03-22 16:32:36 -07:00
cairo_t * selected_cairo = handle - > wayland . selected_cairo ? handle - > wayland . selected_cairo : handle - > wayland . front_cairo ;
2025-12-09 20:11:01 -06:00
2025-12-17 19:14:54 -07:00
cs = cairo_image_surface_create ( CAIRO_FORMAT_ARGB32 , rect - > width , rect - > height ) ;
c = cairo_create ( cs ) ;
2026-03-20 09:59:07 +09:00
clip ( handle ) ;
2026-03-19 17:05:08 -07:00
2025-12-17 19:14:54 -07:00
cairo_scale ( c , ( double ) rect - > width / pixmap - > common . width , ( double ) rect - > height / pixmap - > common . height ) ;
2026-03-19 15:57:20 -07:00
2025-12-17 19:14:54 -07:00
cairo_set_source_surface ( c , pixmap - > wayland . cs , 0 , 0 ) ;
2025-12-18 12:24:06 +09:00
cairo_pattern_set_filter ( cairo_get_source ( c ) , CAIRO_FILTER_NEAREST ) ;
2026-03-19 15:57:20 -07:00
2025-12-17 19:14:54 -07:00
cairo_paint ( c ) ;
2026-03-22 16:15:50 -07:00
cairo_set_source_surface ( selected_cairo , cs , rect - > x , rect - > y ) ;
cairo_paint ( selected_cairo ) ;
2025-12-09 20:11:01 -06:00
2025-12-17 19:14:54 -07:00
cairo_destroy ( c ) ;
cairo_surface_destroy ( cs ) ;
2026-03-17 17:43:22 -07:00
MwLLForceRender ( handle ) ;
2026-03-20 19:42:30 -07:00
update_buffer ( & handle - > wayland . framebuffer ) ;
wl_surface_damage ( handle - > wayland . framebuffer . surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
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 ) {
void * map ;
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 ) ;
buffer_setup ( handle - > wayland . icon , pixmap - > common . width , pixmap - > common . height ) ;
for ( ; i < size ; i + = 2 ) {
handle - > wayland . icon - > buf [ i ] = pixmap - > common . raw [ i + 2 ] ;
handle - > wayland . icon - > buf [ i + 1 ] = pixmap - > common . raw [ i + 1 ] ;
handle - > wayland . icon - > buf [ i + 2 ] = pixmap - > common . raw [ i + 0 ] ;
handle - > wayland . icon - > buf [ i + 3 ] = 255 ;
}
2026-03-19 16:35:56 -07:00
if ( handle - > wayland . configured ) update_buffer ( handle - > wayland . icon ) ;
2025-12-18 18:21:57 -07:00
xdg_toplevel_icon_v1_add_buffer ( icon , handle - > wayland . icon - > shm_buffer , 1 ) ;
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 ) ;
memset ( handle - > wayland . cursor . buf , 0 , handle - > wayland . cursor . buf_size ) ;
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 - - ) {
int px = 0 ;
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 ) {
handle - > wayland . cursor . buf [ idx + 3 ] = 255 ;
} ;
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 ;
} ;
handle - > wayland . cursor . buf [ idx ] = px ;
handle - > wayland . cursor . buf [ idx + 1 ] = px ;
handle - > wayland . cursor . buf [ idx + 2 ] = px ;
d = d > > 1 ;
}
}
handle - > wayland . cursor . surface = wl_compositor_create_surface ( handle - > wayland . compositor ) ;
2026-03-24 04:56:08 +09:00
wl_surface_attach ( handle - > wayland . cursor . surface , handle - > wayland . cursor . shm_buffer , xs + image - > x , ys + image - > height + image - > y ) ;
2025-12-18 13:15:03 -07:00
wl_surface_commit ( handle - > wayland . cursor . surface ) ;
/* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */
if ( handle - > wayland . pointer ! = NULL ) {
wl_pointer_set_cursor ( handle - > wayland . pointer , handle - > wayland . pointer_serial , handle - > wayland . cursor . surface , 0 , 0 ) ;
}
2025-12-09 20:11:01 -06:00
}
static void MwLLDetachImpl ( MwLL handle , MwPoint * point ) {
2026-03-23 12:05:32 -07:00
handle - > wayland . detatching = MwTRUE ;
handle - > wayland . detach_point = * point ;
2025-12-09 20:11:01 -06:00
}
static void MwLLShowImpl ( MwLL handle , int show ) {
2026-03-19 17:05:08 -07:00
switch ( handle - > wayland . type ) {
case MWLL_WAYLAND_UNKNOWN :
case MWLL_WAYLAND_TOPLEVEL :
break ;
case MWLL_WAYLAND_SUBLEVEL :
break ;
case MWLL_WAYLAND_POPUP :
break ;
}
2025-12-09 20:11:01 -06:00
}
static void MwLLMakePopupImpl ( MwLL handle , MwLL parent ) {
}
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 ) {
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 ) {
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 ) {
}
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 ) {
/* no-op */
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 ) {
MwLLShow ( handle , 0 ) ;
}
static void MwLLEndStateChangeImpl ( MwLL handle ) {
2026-03-23 12:05:32 -07:00
if ( handle - > wayland . detatching ) {
switch ( handle - > wayland . type ) {
case MWLL_WAYLAND_UNKNOWN :
case MWLL_WAYLAND_TOPLEVEL :
destroy_toplevel ( handle ) ;
break ;
case MWLL_WAYLAND_SUBLEVEL :
destroy_sublevel ( handle ) ;
break ;
case MWLL_WAYLAND_POPUP :
return ;
}
wl_flush ( handle ) ;
switch ( handle - > wayland . type_to_be ) {
case MWLL_WAYLAND_POPUP :
setup_popup ( handle , handle - > wayland . detach_point . x , handle - > wayland . detach_point . y ) ;
break ;
default :
setup_toplevel ( handle , handle - > wayland . detach_point . x , handle - > wayland . detach_point . y ) ;
break ;
}
handle - > wayland . detatching = MwFALSE ;
}
2025-12-09 20:11:01 -06:00
MwLLShow ( handle , 1 ) ;
}
static int MwLLWaylandCallInitImpl ( void ) {
# ifdef __linux__
if ( strcmp ( getenv ( " XDG_SESSION_TYPE " ) , " wayland " ) ) {
return 1 ;
}
# endif
return 0 ;
}
# include "call.c"
CALL ( Wayland ) ;