2025-11-29 17:56:33 -07:00
# include <Mw/Milsko.h>
2025-12-01 14:19:07 -07:00
# include <assert.h>
2025-11-29 20:52:56 -07:00
# include <fcntl.h>
# include <errno.h>
2025-12-07 17:25:16 -07:00
# include <linux/input-event-codes.h>
2025-11-29 20:52:56 -07:00
# include <poll.h>
2025-12-05 22:48:02 -07:00
# include <signal.h>
2025-12-01 14:19:07 -07:00
# include <stdio.h>
2025-12-01 11:45:55 -07:00
# include <stdlib.h>
2025-12-01 14:19:07 -07:00
# include <string.h>
2025-12-01 11:45:55 -07:00
# include <unistd.h>
2025-12-05 20:25:23 -07:00
# include <assert.h>
2025-12-01 11:45:55 -07:00
# include <wayland-client-protocol.h>
2025-11-29 20:52:56 -07:00
2025-11-29 17:56:33 -07:00
# include "../../external/stb_ds.h"
2025-12-01 19:12:49 -07:00
# include "Mw/BaseTypes.h"
# include "Mw/LowLevel.h"
2025-12-01 14:19:07 -07:00
# include <sys/mman.h>
2025-12-03 18:17:27 -07:00
# include <wayland-egl-core.h>
# include <wayland-util.h>
2025-12-07 17:25:16 -07:00
/* TODO: find out what FreeBSD and such wants us to include */
# include <linux/input.h>
2025-12-03 22:26:03 -07:00
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers ;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D ;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers ;
2025-12-03 18:17:27 -07:00
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer ;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer ;
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer ;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus ;
2025-11-29 17:56:33 -07:00
2025-12-07 17:25:16 -07:00
/*
callback todo :
void ( * up ) ( MwLL handle , void * data ) ;
void ( * down ) ( MwLL handle , void * data ) ;
void ( * key ) ( MwLL handle , void * data ) ;
void ( * key_released ) ( MwLL handle , void * data ) ;
void ( * focus_in ) ( MwLL handle , void * data ) ;
void ( * focus_out ) ( MwLL handle , void * data ) ;
*/
2025-11-29 20:52:56 -07:00
# define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name)
2025-11-29 17:56:33 -07:00
static void new_protocol ( void * data , struct wl_registry * registry ,
MwU32 name , const char * interface ,
MwU32 version ) {
struct _MwLLWayland * wayland = data ;
wl_setup_func * func = shget ( wayland - > wl_protocol_setup_map , interface ) ;
if ( func ! = NULL ) {
2025-11-29 20:52:56 -07:00
// printf("registering interface %s\n", interface);
2025-11-29 17:56:33 -07:00
shput ( wayland - > wl_protocol_map , interface , func ( name , data ) ) ;
2025-11-29 20:52:56 -07:00
} else {
// printf("unknown interface %s\n", interface);
2025-11-29 17:56:33 -07:00
}
} ;
static void protocol_removed ( void * data ,
struct wl_registry * registry ,
MwU32 name ) {
} ;
2025-12-07 17:25:16 -07:00
static void pointer_enter ( void * data , struct wl_pointer * wl_pointer , uint32_t serial ,
struct wl_surface * surface , wl_fixed_t surface_x ,
wl_fixed_t surface_y ) { } ;
static void pointer_leave ( void * data , struct wl_pointer * wl_pointer , uint32_t serial ,
struct wl_surface * surface ) { } ;
static void pointer_motion ( void * data , struct wl_pointer * wl_pointer , uint32_t time ,
wl_fixed_t surface_x , wl_fixed_t surface_y ) {
MwLL self = data ;
MwLLMouse p ;
self - > wayland . cur_mouse_pos . x = wl_fixed_to_double ( surface_x ) ;
self - > wayland . cur_mouse_pos . y = wl_fixed_to_double ( surface_y ) ;
p . point = self - > wayland . cur_mouse_pos ;
MwLLDispatch ( self , move , & p ) ;
} ;
static void pointer_button ( void * data , struct wl_pointer * wl_pointer , uint32_t serial , uint32_t time , uint32_t button , uint32_t state ) {
MwLL self = data ;
MwLLMouse p ;
p . point = self - > wayland . cur_mouse_pos ;
if ( p . point . x > self - > wayland . x & & p . point . x < self - > wayland . x + self - > wayland . ww & & p . point . y > self - > wayland . y & & p . point . y < self - > wayland . y + self - > wayland . wh ) {
switch ( button ) {
case BTN_LEFT :
p . button = MwLLMouseLeft ;
break ;
case BTN_MIDDLE :
p . button = MwLLMouseMiddle ;
break ;
case BTN_RIGHT :
p . button = MwLLMouseRight ;
break ;
}
switch ( state ) {
case WL_POINTER_BUTTON_STATE_PRESSED :
MwLLDispatch ( self , down , & p ) ;
break ;
case WL_POINTER_BUTTON_STATE_RELEASED :
MwLLDispatch ( self , up , & p ) ;
break ;
}
}
} ;
static void pointer_axis ( void * data , struct wl_pointer * wl_pointer , uint32_t time ,
uint32_t 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 ,
} ;
static void
wl_seat_name ( void * data , struct wl_seat * wl_seat , const char * name ) { } ;
2025-11-29 17:56:33 -07:00
static void wl_seat_capabilities ( void * data , struct wl_seat * wl_seat ,
2025-12-07 17:25:16 -07:00
MwU32 capabilities ) {
MwLL self = data ;
if ( capabilities & WL_SEAT_CAPABILITY_KEYBOARD ) {
struct wl_keyboard * keyboard = wl_seat_get_keyboard ( wl_seat ) ;
// wl_keyboard_add_listener(keyboard, const struct wl_keyboard_listener* listener, data);
}
if ( capabilities & WL_SEAT_CAPABILITY_POINTER & & ! self - > wayland . pointer ) {
self - > wayland . pointer = wl_seat_get_pointer ( wl_seat ) ;
wl_pointer_add_listener ( self - > wayland . pointer , & pointer_listener , data ) ;
return ;
}
} ;
2025-11-29 17:56:33 -07:00
void xdg_wm_base_ping ( void * data ,
struct xdg_wm_base * xdg_wm_base ,
2025-11-29 20:52:56 -07:00
MwU32 serial ) {
2025-11-29 17:56:33 -07:00
// The compositor will send us a ping event to check that we're responsive.
// We need to send back a pong request immediately.
xdg_wm_base_pong ( xdg_wm_base , serial ) ;
} ;
2025-12-07 17:25:16 -07:00
static wayland_protocol_t * wl_seat_setup ( MwU32 name , MwLL ll ) {
2025-11-29 17:56:33 -07:00
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 ;
2025-12-07 17:25:16 -07:00
proto - > context = wl_registry_bind ( ll - > wayland . registry , name , & wl_seat_interface , 1 ) ;
wl_seat_add_listener ( proto - > context , proto - > listener , ll ) ;
2025-11-29 17:56:33 -07:00
return proto ;
}
2025-11-29 20:52:56 -07:00
2025-11-29 17:56:33 -07:00
static wayland_protocol_t * wl_compositor_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
2025-11-29 20:52:56 -07:00
wayland - > compositor = wl_registry_bind ( wayland - > registry , name , & wl_compositor_interface , 1 ) ;
2025-11-29 17:56:33 -07:00
2025-11-29 20:52:56 -07:00
return NULL ;
}
static wayland_protocol_t * wl_subcompositor_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland - > subcompositor = wl_registry_bind ( wayland - > registry , name , & wl_subcompositor_interface , 1 ) ;
return NULL ;
2025-11-29 17:56:33 -07:00
}
2025-11-29 20:52:56 -07:00
2025-11-29 17:56:33 -07:00
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 ;
}
static wayland_protocol_t * wp_cursor_shape_manager_v1_setup ( MwU32 name , struct _MwLLWayland * wayland ) {
wayland_protocol_t * proto = malloc ( sizeof ( wayland_protocol_t ) ) ;
proto - > listener = NULL ;
proto - > context = wl_registry_bind ( wayland - > registry , name , & wp_cursor_shape_manager_v1_interface , 1 ) ;
return proto ;
}
typedef struct zxdg_decoration_manager_v1_context {
struct zxdg_decoration_manager_v1 * manager ;
// struct zxdg_decoration_toplevel_v1* toplevel;
struct zxdg_toplevel_decoration_v1 * decoration ;
} zxdg_decoration_manager_v1_context_t ;
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-03 18:17:27 -07:00
static MwBool egl_setup ( MwLL self , int width , int height ) {
int err ;
EGLint numConfigs ;
EGLint majorVersion ;
EGLint minorVersion ;
EGLContext context ;
EGLSurface surface ;
EGLint fbAttribs [ ] =
{
EGL_SURFACE_TYPE , EGL_WINDOW_BIT ,
EGL_RENDERABLE_TYPE , EGL_OPENGL_ES2_BIT ,
EGL_RED_SIZE , 8 ,
EGL_GREEN_SIZE , 8 ,
EGL_BLUE_SIZE , 8 ,
EGL_RENDERABLE_TYPE , EGL_OPENGL_BIT ,
EGL_NONE } ;
EGLint contextAttribs [ ] = {
EGL_CONTEXT_CLIENT_VERSION , 1 ,
EGL_CONTEXT_MAJOR_VERSION , 1 ,
EGL_CONTEXT_MINOR_VERSION , 1 ,
EGL_NONE } ;
EGLDisplay display = eglGetDisplay ( self - > wayland . display ) ;
if ( display = = EGL_NO_DISPLAY ) {
printf ( " ERROR: eglGetDisplay, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
// Initialize EGL
if ( ! eglInitialize ( display , & majorVersion , & minorVersion ) ) {
printf ( " ERROR: eglInitialize, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
// Get configs
if ( ( eglGetConfigs ( display , NULL , 0 , & numConfigs ) ! = EGL_TRUE ) | | ( numConfigs = = 0 ) ) {
printf ( " ERROR: eglGetConfigs, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
// Choose config
2025-12-05 14:50:04 -07:00
if ( ( eglChooseConfig ( display , fbAttribs , & self - > wayland . egl_config , 1 , & numConfigs ) ! = EGL_TRUE ) | | ( numConfigs ! = 1 ) ) {
2025-12-03 18:17:27 -07:00
printf ( " ERROR: eglChooseConfig, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
self - > wayland . egl_window_native =
wl_egl_window_create ( self - > wayland . surface , width , height ) ;
if ( self - > wayland . egl_window_native = = EGL_NO_SURFACE ) {
printf ( " ERROR: wl_egl_window_create, EGL_NO_SURFACE \n " ) ;
return MwFALSE ;
}
// Create a surface
2025-12-05 14:50:04 -07:00
surface = eglCreateWindowSurface ( display , self - > wayland . egl_config , self - > wayland . egl_window_native , NULL ) ;
2025-12-03 18:17:27 -07:00
if ( surface = = EGL_NO_SURFACE ) {
printf ( " ERROR: eglCreateWindowSurface, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
eglBindAPI ( EGL_OPENGL_API ) ;
// Create a GL context
2025-12-05 14:50:04 -07:00
context = eglCreateContext ( display , self - > wayland . egl_config , EGL_NO_CONTEXT , contextAttribs ) ;
2025-12-03 18:17:27 -07:00
if ( context = = EGL_NO_CONTEXT ) {
printf ( " ERROR: eglCreateContext, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
// Make the context current
if ( ! eglMakeCurrent ( display , surface , surface , context ) ) {
printf ( " ERROR: eglMakeCurrent, %0X \n " , eglGetError ( ) ) ;
return MwFALSE ;
}
glGenFramebuffers = ( PFNGLGENFRAMEBUFFERSPROC ) eglGetProcAddress ( " glGenFramebuffers " ) ;
glFramebufferTexture2D = ( PFNGLFRAMEBUFFERTEXTURE2DPROC ) eglGetProcAddress ( " glFramebufferTexture2D " ) ;
glGenRenderbuffers = ( PFNGLGENRENDERBUFFERSPROC ) eglGetProcAddress ( " glGenRenderbuffers " ) ;
// glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)eglGetProcAddress("glRenderbufferStorage");
glFramebufferRenderbuffer = ( PFNGLFRAMEBUFFERRENDERBUFFERPROC ) eglGetProcAddress ( " glFramebufferRenderbuffer " ) ;
glBindRenderbuffer = ( PFNGLBINDRENDERBUFFERPROC ) eglGetProcAddress ( " glBindRenderbuffer " ) ;
glBindFramebuffer = ( PFNGLBINDFRAMEBUFFERPROC ) eglGetProcAddress ( " glBindFramebuffer " ) ;
glCheckFramebufferStatus = ( PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC ) eglGetProcAddress ( " glCheckFramebufferStatus " ) ;
glGenTextures ( 1 , & self - > wayland . fbo_texture ) ;
glBindTexture ( GL_TEXTURE_2D , self - > wayland . fbo_texture ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , width , height , 0 , GL_RGB , GL_UNSIGNED_BYTE , NULL ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glGenFramebuffers ( 1 , & self - > wayland . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER_BINDING , self - > wayland . fbo ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , self - > wayland . fbo_texture , 0 ) ;
if ( ( err = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ) ! = GL_FRAMEBUFFER_COMPLETE ) {
printf ( " Error binding framebuffer: %0X \n " , err ) ;
return MwFALSE ;
}
glBindFramebuffer ( GL_FRAMEBUFFER_BINDING , 0 ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
2025-12-03 22:26:03 -07:00
glOrtho ( 0 , width , height , 0 , - 1 , 1 ) ;
2025-12-03 23:00:40 -07:00
glEnable ( GL_TEXTURE_2D ) ;
2025-12-05 15:18:21 -07:00
glBlendFunc ( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ) ;
glEnable ( GL_BLEND ) ;
2025-12-03 18:17:27 -07:00
self - > wayland . egl_display = display ;
self - > wayland . egl_surface = surface ;
self - > wayland . egl_context = context ;
return MwTRUE ;
}
2025-12-05 14:50:04 -07:00
static void egl_resetup ( MwLL handle ) {
int err ;
glDeleteTextures ( 1 , & handle - > wayland . fbo_texture ) ;
glGenTextures ( 1 , & handle - > wayland . fbo_texture ) ;
glBindTexture ( GL_TEXTURE_2D , handle - > wayland . fbo_texture ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGB , handle - > wayland . ww , handle - > wayland . wh , 0 , GL_RGB , GL_UNSIGNED_BYTE , NULL ) ;
glGenFramebuffers ( 1 , & handle - > wayland . fbo ) ;
glBindFramebuffer ( GL_FRAMEBUFFER_BINDING , handle - > wayland . fbo ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , handle - > wayland . fbo_texture , 0 ) ;
if ( ( err = glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ) ! = GL_FRAMEBUFFER_COMPLETE ) {
printf ( " Error binding framebuffer: %0X \n " , err ) ;
return ;
}
glBindFramebuffer ( GL_FRAMEBUFFER_BINDING , 0 ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glOrtho ( 0 , handle - > wayland . ww , handle - > wayland . wh , 0 , - 1 , 1 ) ;
glViewport ( 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
handle - > wayland . egl_do_resetup = MwFALSE ;
}
2025-12-05 20:25:23 -07:00
static void recursive_draw ( MwLL handle ) {
int i ;
if ( handle - > wayland . subwidgets ! = NULL ) {
for ( i = 0 ; i < arrlen ( handle - > wayland . subwidgets ) ; i + + ) {
MwLLDispatch ( handle - > wayland . subwidgets [ i ] , draw , NULL ) ;
recursive_draw ( handle - > wayland . subwidgets [ i ] ) ;
}
}
}
static void recursive_resize ( MwLL handle ) {
int i ;
if ( handle - > wayland . subwidgets ! = NULL ) {
for ( i = 0 ; i < arrlen ( handle - > wayland . subwidgets ) ; i + + ) {
MwLLDispatch ( handle - > wayland . subwidgets [ i ] , resize , NULL ) ;
recursive_resize ( handle - > wayland . subwidgets [ i ] ) ;
}
}
}
2025-11-29 17:56:33 -07:00
static void xdg_toplevel_configure ( void * data ,
struct xdg_toplevel * xdg_toplevel ,
2025-11-29 20:52:56 -07:00
MwI32 width , MwI32 height ,
2025-11-29 17:56:33 -07:00
struct wl_array * states ) {
2025-12-03 18:17:27 -07:00
MwLL self = data ;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = ( PFNGLFRAMEBUFFERTEXTURE2DPROC ) eglGetProcAddress ( " glFramebufferTexture2D " ) ;
2025-12-01 11:45:55 -07:00
2025-12-05 17:16:08 -07:00
if ( width = = 0 | | height = = 0 ) {
2025-12-03 18:17:27 -07:00
width = self - > wayland . ww ;
height = self - > wayland . wh ;
2025-12-05 17:16:08 -07:00
// if it's still 0 then bail
if ( width = = 0 | | height = = 0 ) {
return ;
}
2025-12-03 18:17:27 -07:00
}
self - > wayland . ww = width ;
self - > wayland . wh = height ;
2025-12-05 17:16:08 -07:00
xdg_surface_set_window_geometry ( self - > wayland . toplevel - > xdg_surface , 0 , 0 , self - > wayland . ww , self - > wayland . wh ) ;
2025-12-01 14:19:07 -07:00
2025-12-03 18:17:27 -07:00
MwLLSetWH ( self , width , height ) ;
MwLLDispatch ( self , resize , NULL ) ;
2025-12-05 20:25:23 -07:00
recursive_resize ( self ) ;
2025-12-03 18:17:27 -07:00
if ( ! self - > wayland . egl_setup ) {
self - > wayland . egl_setup = egl_setup ( self , width , height ) ;
2025-12-03 22:26:03 -07:00
MwLLForceRender ( self ) ;
2025-12-05 19:18:11 -07:00
} else {
wl_egl_window_resize ( self - > wayland . egl_window_native , width , height , 0 , 0 ) ;
self - > wayland . egl_do_resetup = MwTRUE ;
egl_resetup ( self ) ;
2025-12-03 18:17:27 -07:00
}
2025-11-29 17:56:33 -07:00
return ;
} ;
static void decoration_configure (
void * data , struct zxdg_toplevel_decoration_v1 * zxdg_toplevel_decoration_v1 ,
2025-11-29 20:52:56 -07:00
MwU32 mode ) {
2025-11-29 17:56:33 -07:00
}
static void xdg_toplevel_close (
void * data , struct xdg_toplevel * xdg_toplevel ) {
2025-12-01 11:45:55 -07:00
MwLL self = data ;
2025-12-07 17:25:16 -07:00
MwLLDispatch ( self , close , NULL ) ;
2025-11-29 17:56:33 -07:00
} ;
static void xdg_surface_configure (
2025-11-29 20:52:56 -07:00
void * data , struct xdg_surface * xdg_surface , MwU32 serial ) {
2025-12-01 11:45:55 -07:00
MwLL self = data ;
2025-11-29 17:56:33 -07:00
// The compositor configures our surface, acknowledge the configure event
xdg_surface_ack_configure ( xdg_surface , serial ) ;
2025-12-01 11:45:55 -07:00
if ( self - > wayland . configured ) {
2025-11-29 17:56:33 -07:00
// If this isn't the first configure event we've received, we already
// have a buffer attached, so no need to do anything. Commit the
// surface to apply the configure acknowledgement.
2025-11-29 20:52:56 -07:00
// wl_surface_attach(self->surface, self->buffer, 0, 0);
2025-12-01 11:45:55 -07:00
wl_surface_commit ( self - > wayland . surface ) ;
2025-11-29 17:56:33 -07:00
}
2025-12-01 11:45:55 -07:00
self - > wayland . configured = MwTRUE ;
2025-11-29 17:56:33 -07:00
}
2025-12-05 17:16:08 -07:00
static int event_loop ( MwLL handle ) {
2025-12-05 12:40:44 -07:00
enum {
DISPLAY_FD ,
KEYREPEAT_FD ,
CURSOR_FD
} ;
2025-12-05 17:16:08 -07:00
struct pollfd fd ;
2025-12-05 19:18:11 -07:00
int timeout = 100 ;
struct _MwLLWayland * wayland = & handle - > wayland ;
MwLL topmost_parent = handle - > wayland . parent ;
2025-12-05 12:40:44 -07:00
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 ) ;
2025-12-07 17:25:16 -07:00
MwLLDispatch ( handle , close , NULL ) ;
2025-12-05 12:40:44 -07:00
return 0 ;
}
}
}
/*
IOI :
I took this from ioilib which I in turn adapted from SDL . I think this is meant to be required ?
But doing this on my main machine causes the decorations manager to be null . . . ? This doesn ' t show up on the project currently using ioilib .
Race condition ? Random KDE bug ? Who knows , but it seems that not polling for this works anyways ( possibly because we already flush events above and then cancel reads when we actually need to close ) .
*/
/*
// Condition where no events are being sent.
if ( ! poll ( & fd , 1 , timeout ) ) {
wl_display_cancel_read ( wayland - > display ) ;
// In this case, we need to commit the surface for any animations, etc.
wl_surface_commit ( wayland - > surface ) ;
return 0 ;
}
*/
if ( fd . revents & POLLIN ) {
wl_display_read_events ( wayland - > display ) ;
if ( wl_display_dispatch_pending ( wayland - > display ) > 0 ) {
}
} else {
2025-12-05 17:16:08 -07:00
if ( wl_display_dispatch_pending ( wayland - > display ) = = 0 ) {
MwLLDispatch ( handle , draw , NULL ) ;
2025-12-05 20:25:23 -07:00
recursive_draw ( handle ) ;
2025-12-05 17:16:08 -07:00
}
2025-12-05 12:40:44 -07:00
}
2025-12-05 17:16:08 -07:00
2025-12-05 12:40:44 -07:00
return 0 ;
}
2025-11-29 20:52:56 -07:00
# define WL_INTERFACE(interface) \
shput ( wayland - > wl_protocol_setup_map , interface # # _interface . name , ( wl_setup_func * ) interface # # _setup ) ;
2025-11-29 17:56:33 -07:00
static void setup_callbacks ( struct _MwLLWayland * wayland ) {
wayland - > registry_listener . global = new_protocol ;
wayland - > registry_listener . global_remove = protocol_removed ;
2025-12-01 14:19:07 -07:00
wayland - > wl_protocol_setup_map = NULL ;
wayland - > wl_protocol_map = NULL ;
2025-11-29 17:56:33 -07:00
WL_INTERFACE ( wl_compositor ) ;
2025-11-29 20:52:56 -07:00
WL_INTERFACE ( wl_subcompositor ) ;
2025-12-07 17:25:16 -07:00
WL_INTERFACE ( wl_seat ) ;
2025-11-29 20:52:56 -07:00
if ( wayland - > type = = MWLL_WAYLAND_TOPLEVEL ) {
WL_INTERFACE ( xdg_wm_base ) ;
WL_INTERFACE ( zxdg_decoration_manager_v1 ) ;
WL_INTERFACE ( wp_cursor_shape_manager_v1 ) ;
}
2025-11-29 17:56:33 -07:00
}
2025-11-29 20:52:56 -07:00
# undef WL_INTERFACE
2025-11-29 17:56:33 -07:00
2025-12-05 14:50:04 -07:00
static void setup_toplevel ( MwLL r , int x , int y ) {
int i ;
struct wl_region * region ;
2025-12-05 12:40:44 -07:00
2025-12-01 11:45:55 -07:00
r - > wayland . type = MWLL_WAYLAND_TOPLEVEL ;
r - > wayland . toplevel = malloc ( sizeof ( struct _MwLLWaylandTopLevel ) ) ;
2025-11-29 17:56:33 -07: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 " ) ;
2025-12-05 22:48:02 -07:00
raise ( SIGTRAP ) ;
2025-11-29 20:52:56 -07:00
return ;
2025-11-29 17:56:33 -07:00
}
2025-11-29 20:52:56 -07:00
// Do a roundtrip to ensure all interfaces are setup.
2025-11-29 17:56:33 -07:00
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 " ) ;
2025-12-05 22:48:02 -07:00
raise ( SIGTRAP ) ;
2025-11-29 20:52:56 -07:00
return ;
2025-11-29 17:56:33 -07:00
}
// Check that all globals we require are available
if (
2025-11-29 20:52:56 -07:00
r - > wayland . compositor = = NULL | |
WAYLAND_GET_INTERFACE ( r - > wayland , xdg_wm_base ) - > context = = NULL | |
WAYLAND_GET_INTERFACE ( r - > wayland , wl_seat ) - > context = = NULL ) {
2025-11-29 17:56:33 -07:00
printf ( " no wl_shm, wl_compositor, wl_seat, or xdg_wm_base support \n " ) ;
2025-12-05 22:48:02 -07:00
raise ( SIGTRAP ) ;
2025-11-29 20:52:56 -07:00
return ;
2025-11-29 17:56:33 -07:00
}
2025-12-01 11:45:55 -07:00
r - > wayland . toplevel - > xkb_context = xkb_context_new ( XKB_CONTEXT_NO_FLAGS ) ;
2025-11-29 17:56:33 -07:00
// Create a wl_surface, a xdg_surface and a xdg_toplevel
2025-11-29 20:52:56 -07:00
r - > wayland . surface = wl_compositor_create_surface ( r - > wayland . compositor ) ;
2025-12-01 11:45:55 -07:00
r - > wayland . toplevel - > xdg_surface =
2025-11-29 20:52:56 -07:00
xdg_wm_base_get_xdg_surface ( WAYLAND_GET_INTERFACE ( r - > wayland , xdg_wm_base ) - > context , r - > wayland . surface ) ;
2025-12-01 11:45:55 -07:00
r - > wayland . toplevel - > xdg_top_level = xdg_surface_get_toplevel ( r - > wayland . toplevel - > xdg_surface ) ;
2025-11-29 17:56:33 -07:00
// setup mandatory listeners
2025-12-05 15:18:21 -07:00
r - > wayland . toplevel - > xdg_surface_listener . configure = xdg_surface_configure ;
2025-12-01 11:45:55 -07:00
r - > wayland . toplevel - > xdg_toplevel_listener . configure = xdg_toplevel_configure ;
r - > wayland . toplevel - > xdg_toplevel_listener . close = xdg_toplevel_close ;
2025-11-29 17:56:33 -07:00
2025-12-05 15:18:21 -07:00
xdg_surface_add_listener ( r - > wayland . toplevel - > xdg_surface , & r - > wayland . toplevel - > xdg_surface_listener , r ) ;
2025-12-01 11:45:55 -07:00
xdg_toplevel_add_listener ( r - > wayland . toplevel - > xdg_top_level , & r - > wayland . toplevel - > xdg_toplevel_listener ,
2025-11-29 17:56:33 -07:00
r ) ;
2025-12-05 20:27:27 -07:00
xdg_toplevel_set_title ( r - > wayland . toplevel - > xdg_top_level , " Milsko App " ) ;
2025-12-01 11:45:55 -07:00
xdg_toplevel_set_app_id ( r - > wayland . toplevel - > xdg_top_level , " MilskoWaylandApp " ) ;
2025-11-29 17:56:33 -07:00
// Perform the initial commit and wait for the first configure event
wl_surface_commit ( r - > wayland . surface ) ;
2025-12-05 17:16:08 -07:00
event_loop ( r ) ;
2025-12-05 12:40:44 -07:00
2025-11-29 17:56:33 -07:00
// setup decorations if we can
2025-12-05 12:40:44 -07:00
if ( shget ( r - > wayland . wl_protocol_map , zxdg_decoration_manager_v1_interface . name ) ! = NULL ) {
2025-11-29 20:52:56 -07:00
zxdg_decoration_manager_v1_context_t * dec = WAYLAND_GET_INTERFACE ( r - > wayland , zxdg_decoration_manager_v1 ) - > context ;
2025-11-29 17:56:33 -07:00
dec - > decoration = zxdg_decoration_manager_v1_get_toplevel_decoration (
2025-12-01 11:45:55 -07:00
dec - > manager , r - > wayland . toplevel - > xdg_top_level ) ;
2025-11-29 17:56:33 -07:00
zxdg_toplevel_decoration_v1_set_mode (
dec - > decoration , ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE ) ;
2025-11-29 20:52:56 -07:00
} else {
printf ( " zxdg null \n " ) ;
2025-11-29 17:56:33 -07:00
}
2025-12-03 18:17:27 -07:00
// buffer_setup(&r->wayland);
2025-11-29 20:52:56 -07:00
2025-12-03 22:26:03 -07:00
// glGenBuffers(1, &vertex_buffer);
2025-11-29 20:52:56 -07:00
}
2025-12-05 14:50:04 -07:00
static void setup_subsurface ( MwLL parent , MwLL r , int x , int y ) {
2025-11-29 20:52:56 -07:00
struct wl_compositor * compositor = parent - > wayland . compositor ;
struct wl_subcompositor * subcompositor = parent - > wayland . subcompositor ;
struct wl_surface * parent_surface = parent - > wayland . surface ;
2025-12-05 14:50:04 -07:00
MwLL topmost_parent = parent ;
struct wl_region * region ;
while ( topmost_parent - > wayland . type ! = MWLL_WAYLAND_TOPLEVEL ) {
topmost_parent = topmost_parent - > wayland . parent ;
}
2025-11-29 20:52:56 -07:00
r - > wayland . type = MWLL_WAYLAND_SUBSURFACE ;
2025-12-01 14:19:07 -07:00
r - > wayland . display = parent - > wayland . display ;
r - > wayland . surface = wl_compositor_create_surface ( compositor ) ;
2025-12-05 14:50:04 -07:00
region = wl_compositor_create_region ( compositor ) ;
wl_region_add ( region , 0 , 0 , r - > wayland . ww , r - > wayland . wh ) ;
wl_surface_set_opaque_region ( r - > wayland . surface , region ) ;
wl_surface_commit ( r - > wayland . surface ) ;
2025-12-05 17:16:08 -07:00
event_loop ( r ) ;
2025-12-05 14:50:04 -07:00
wl_region_destroy ( region ) ;
2025-12-01 14:19:07 -07:00
r - > wayland . subsurface = wl_subcompositor_get_subsurface ( subcompositor , r - > wayland . surface , parent_surface ) ;
wl_subsurface_set_position ( r - > wayland . subsurface , x , y ) ;
// printf("position %d %d\n", x, y);
2025-11-29 20:52:56 -07:00
setup_callbacks ( & r - > wayland ) ;
2025-12-05 14:50:04 -07:00
r - > wayland . registry = wl_display_get_registry ( topmost_parent - > wayland . display ) ;
r - > wayland . display = topmost_parent - > wayland . display ;
2025-11-29 20:52:56 -07: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-03 18:17:27 -07:00
// arrpush(parent->wayland.subsurfaces, r);
2025-11-29 20:52:56 -07:00
r - > wayland . configured = MwTRUE ;
2025-12-03 18:17:27 -07:00
2025-12-05 14:50:04 -07:00
r - > wayland . egl_context = topmost_parent - > wayland . egl_context ;
r - > wayland . egl_display = topmost_parent - > wayland . egl_display ;
r - > wayland . egl_surface = topmost_parent - > wayland . egl_surface ;
r - > wayland . fbo = topmost_parent - > wayland . fbo ;
r - > wayland . fbo_texture = topmost_parent - > wayland . fbo_texture ;
2025-12-05 19:18:11 -07:00
arrpush ( parent - > wayland . subwidgets , r ) ;
2025-12-05 14:50:04 -07:00
}
static void framebuffer_action_begin ( MwLL handle ) {
glBindFramebuffer ( GL_FRAMEBUFFER , handle - > wayland . fbo ) ;
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D , handle - > wayland . fbo_texture , 0 ) ;
}
static void framebuffer_action_end ( MwLL handle ) {
glFinish ( ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
2025-11-29 20:52:56 -07:00
}
2025-12-05 14:50:04 -07:00
2025-11-29 20:52:56 -07:00
static MwLL MwLLCreateImpl ( MwLL parent , int x , int y , int width , int height ) {
MwLL r ;
r = malloc ( sizeof ( * r ) ) ;
MwLLCreateCommon ( r ) ;
2025-12-01 19:12:49 -07:00
r - > common . type = MwLLBackendWayland ;
2025-11-29 20:52:56 -07:00
2025-12-03 18:17:27 -07:00
if ( width = = 0 ) width = 1 ;
if ( height = = 0 ) height = 1 ;
2025-12-01 14:19:07 -07:00
2025-12-05 19:18:11 -07:00
if ( x = = MwDEFAULT ) {
x = 0 ;
}
if ( y = = MwDEFAULT ) {
y = 0 ;
}
2025-12-05 17:16:08 -07:00
r - > wayland . ww = width ;
r - > wayland . wh = height ;
2025-12-05 19:18:11 -07:00
r - > wayland . x = x ;
r - > wayland . y = y ;
2025-12-03 18:17:27 -07:00
r - > wayland . parent = parent ;
2025-11-29 17:56:33 -07:00
2025-12-03 18:17:27 -07:00
r - > wayland . force_redraw = MwFALSE ;
2025-12-05 20:25:23 -07:00
r - > wayland . subwidgets = NULL ;
2025-12-07 17:25:16 -07:00
r - > wayland . pointer = NULL ;
2025-11-29 20:52:56 -07:00
if ( parent = = NULL ) {
2025-12-05 14:50:04 -07:00
setup_toplevel ( r , x , y ) ;
2025-11-29 20:52:56 -07:00
} else {
2025-12-05 14:50:04 -07:00
setup_subsurface ( parent , r , x , y ) ;
2025-11-29 20:52:56 -07:00
}
2025-11-29 17:56:33 -07:00
return r ;
}
static void MwLLDestroyImpl ( MwLL handle ) {
MwLLDestroyCommon ( handle ) ;
free ( handle ) ;
}
2025-12-01 11:45:55 -07:00
static void MwLLGetXYWHImpl ( MwLL handle , int * x , int * y , unsigned int * w , unsigned int * h ) {
* x = handle - > wayland . x ;
* y = handle - > wayland . y ;
* w = handle - > wayland . ww ;
* h = handle - > wayland . wh ;
}
static void MwLLSetXYImpl ( MwLL handle , int x , int y ) {
2025-12-03 18:17:27 -07:00
if ( handle - > wayland . type ! = MWLL_WAYLAND_TOPLEVEL ) {
handle - > wayland . x = x ;
handle - > wayland . y = y ;
wl_subsurface_set_position ( handle - > wayland . subsurface , x , y ) ;
MwLLForceRender ( handle ) ;
}
2025-12-01 11:45:55 -07:00
}
static void MwLLSetWHImpl ( MwLL handle , int w , int h ) {
2025-12-05 14:50:04 -07:00
/* Prevent an integer underflow when the w/h is too low */
2025-12-05 17:16:08 -07:00
if ( ( w < 10 | | h < 10 ) ) {
handle - > wayland . ww = 10 ;
handle - > wayland . wh = 10 ;
2025-12-05 14:50:04 -07:00
return ;
}
2025-12-01 11:45:55 -07:00
handle - > wayland . ww = w ;
handle - > wayland . wh = h ;
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
2025-12-05 17:16:08 -07:00
xdg_surface_set_window_geometry ( handle - > wayland . toplevel - > xdg_surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
2025-12-01 11:45:55 -07:00
} else {
}
}
2025-12-01 19:12:49 -07:00
2025-12-03 18:17:27 -07:00
static void MwLLPolygonImpl ( MwLL handle , MwPoint * points , int points_count , MwLLColor color ) {
2025-12-05 14:50:04 -07:00
int i , n ;
float maxX = 0 , maxY = 0 ;
float centerX , centerY ;
2025-12-05 20:25:23 -07:00
int doLoopback = MwFALSE ;
2025-12-05 14:50:04 -07:00
if ( points_count > 3 ) {
/* To avoid having to do a real triangulation algorithim:
1. ) loop through the points once to determine the bounds of the polygon
2. ) calculate the center of the polygon
*/
for ( i = 0 ; i < points_count ; i + + ) {
float x = round ( handle - > wayland . x ) + round ( points [ i ] . x ) ;
float y = round ( handle - > wayland . y ) + round ( points [ i ] . y ) ;
if ( x > = maxX ) {
maxX = x ;
}
if ( y > = maxY ) {
maxY = y ;
}
}
2025-12-03 22:26:03 -07:00
}
2025-12-05 14:50:04 -07:00
centerX = ( handle - > wayland . x + maxX / 2 ) ;
centerY = ( handle - > wayland . y + maxY / 2 ) ;
/* Efficient? No. But at the end of the day it's still not that many polygons, and if a computer can't handle 12 polygons over 6 then it should not be using Wayland anyways */
2025-12-03 18:17:27 -07:00
2025-12-05 14:50:04 -07:00
framebuffer_action_begin ( handle ) ;
2025-12-05 20:25:23 -07:00
if ( points_count = = 3 ) {
glBegin ( GL_TRIANGLES ) ;
} else if ( ( points_count % 3 ) = = 0 ) {
glBegin ( GL_POLYGON ) ;
} else {
glBegin ( GL_TRIANGLE_FAN ) ;
doLoopback = MwTRUE ;
}
2025-12-03 18:17:27 -07:00
for ( i = 0 ; i < points_count ; i + + ) {
2025-12-05 14:50:04 -07:00
float x = round ( handle - > wayland . x ) + round ( points [ i ] . x ) ;
float y = round ( handle - > wayland . y ) + round ( points [ i ] . y ) ;
2025-12-03 18:17:27 -07:00
glColor3f ( color - > common . red / 255.0 , color - > common . green / 255.0 , color - > common . blue / 255.0 ) ;
2025-12-05 14:50:04 -07:00
glVertex2f ( x , y ) ;
2025-12-05 20:25:23 -07:00
if ( doLoopback ) {
2025-12-05 14:50:04 -07:00
glVertex2f ( maxX , maxY ) ;
glVertex2f ( x , y ) ;
}
2025-12-03 18:17:27 -07:00
}
glEnd ( ) ;
2025-12-05 20:25:23 -07:00
glColor3f ( 0 , 0 , 0 ) ;
2025-12-05 14:50:04 -07:00
framebuffer_action_end ( handle ) ;
2025-12-03 23:00:40 -07:00
}
static void MwLLLineImpl ( MwLL handle , MwPoint * points , MwLLColor color ) {
2025-12-05 20:25:23 -07:00
int i ;
glLineWidth ( 1 ) ;
framebuffer_action_begin ( handle ) ;
glBegin ( GL_LINES ) ;
for ( i = 0 ; i < 2 ; i + + ) {
float x = round ( handle - > wayland . x ) + round ( points [ i ] . x ) ;
float y = round ( handle - > wayland . y ) + round ( points [ i ] . y ) ;
glColor3f ( color - > common . red / 255.0 , color - > common . green / 255.0 , color - > common . blue / 255.0 ) ;
glVertex2f ( x , y ) ;
}
glEnd ( ) ;
glColor3f ( 0 , 0 , 0 ) ;
framebuffer_action_end ( handle ) ;
2025-12-03 23:00:40 -07:00
}
static void MwLLEndDrawImpl ( MwLL handle ) {
int w , h ;
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
w = handle - > wayland . ww ;
h = handle - > wayland . wh ;
} else {
MwLL parent = handle - > wayland . parent ;
w = parent - > wayland . ww ;
h = parent - > wayland . wh ;
}
2025-12-03 18:17:27 -07:00
2025-12-07 17:25:16 -07:00
recursive_draw ( handle ) ;
2025-12-03 18:17:27 -07:00
glBindTexture ( GL_TEXTURE_2D , handle - > wayland . fbo_texture ) ;
2025-12-05 14:50:04 -07:00
// glClear(GL_COLOR_BUFFER_BIT);
2025-12-05 17:16:08 -07:00
// glClearColor(1.0, 0, 0, 1);
2025-12-03 18:17:27 -07:00
glColor3f ( 1.0 , 1.0 , 1.0 ) ;
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0.0f , 1 ) ;
glVertex2f ( 0 , 0 ) ;
glTexCoord2f ( 1 , 1 ) ;
glVertex2f ( w , 0 ) ;
glTexCoord2f ( 1 , 0.0f ) ;
glVertex2f ( w , h ) ;
glTexCoord2f ( 0.0f , 0.0f ) ;
glVertex2f ( 0 , h ) ;
glEnd ( ) ;
glFinish ( ) ;
2025-12-03 23:00:40 -07:00
wl_surface_damage ( handle - > wayland . surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
2025-12-03 18:17:27 -07:00
if ( ! eglSwapBuffers ( handle - > wayland . egl_display , handle - > wayland . egl_surface ) ) {
printf ( " error swapping buffers! %0X \n " , eglGetError ( ) ) ;
} else {
wl_surface_commit ( handle - > wayland . surface ) ;
}
2025-11-29 17:56:33 -07: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 ) {
2025-12-01 14:19:07 -07:00
free ( color ) ;
2025-11-29 17:56:33 -07:00
}
static int MwLLPendingImpl ( MwLL handle ) {
2025-12-05 17:16:08 -07:00
if ( wl_display_dispatch_pending ( handle - > wayland . display ) = = 0 ) {
}
return event_loop ( handle ) | | handle - > wayland . force_redraw ;
2025-11-29 17:56:33 -07:00
}
static void MwLLNextEventImpl ( MwLL handle ) {
2025-12-05 19:27:49 -07:00
MwBool render = handle - > wayland . force_redraw ;
if ( render ) {
handle - > wayland . force_redraw = MwFALSE ;
}
2025-11-29 17:56:33 -07:00
}
static void MwLLSetTitleImpl ( MwLL handle , const char * title ) {
2025-11-29 20:52:56 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
2025-12-01 11:45:55 -07:00
xdg_toplevel_set_title ( handle - > wayland . toplevel - > xdg_top_level , title ) ;
2025-11-29 20:52:56 -07:00
}
2025-11-29 17:56:33 -07:00
}
static MwLLPixmap MwLLCreatePixmapImpl ( MwLL handle , unsigned char * data , int width , int height ) {
MwLLPixmap r = malloc ( sizeof ( * r ) ) ;
2025-12-05 15:18:21 -07:00
r - > common . width = width ;
r - > common . height = height ;
r - > common . raw = data ;
r - > wayland . texture = 0 ;
glGenTextures ( 1 , & r - > wayland . texture ) ;
glBindTexture ( GL_TEXTURE_2D , r - > wayland . texture ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_EDGE ) ;
glTexParameterf ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_EDGE ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
MwLLPixmapUpdate ( r ) ;
2025-11-29 17:56:33 -07:00
return r ;
}
static void MwLLPixmapUpdateImpl ( MwLLPixmap r ) {
2025-12-05 15:18:21 -07:00
glBindTexture ( GL_TEXTURE_2D , r - > wayland . texture ) ;
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , r - > common . width , r - > common . height , 0 , GL_RGBA , GL_UNSIGNED_BYTE , r - > common . raw ) ;
glBindTexture ( GL_TEXTURE_2D , 0 ) ;
2025-11-29 17:56:33 -07:00
}
static void MwLLDestroyPixmapImpl ( MwLLPixmap pixmap ) {
2025-12-05 15:18:21 -07:00
glDeleteTextures ( 1 , & pixmap - > wayland . texture ) ;
2025-11-29 17:56:33 -07:00
free ( pixmap ) ;
}
static void MwLLDrawPixmapImpl ( MwLL handle , MwRect * rect , MwLLPixmap pixmap ) {
2025-12-05 15:18:21 -07:00
int x , y ;
glColor3f ( 1.0 , 1.0 , 1.0 ) ;
x = handle - > wayland . x + rect - > x ;
y = handle - > wayland . y + rect - > y ;
glBindTexture ( GL_TEXTURE_2D , pixmap - > wayland . texture ) ;
glActiveTexture ( pixmap - > wayland . texture ) ;
framebuffer_action_begin ( handle ) ;
glBegin ( GL_QUADS ) ;
glTexCoord2f ( 0.0f , 0 ) ;
glVertex2f ( x , y ) ;
glTexCoord2f ( 1 , 0 ) ;
glVertex2f ( x + rect - > width , y ) ;
glTexCoord2f ( 1 , 1 ) ;
glVertex2f ( x + rect - > width , y + rect - > height ) ;
glTexCoord2f ( 0.0f , 1 ) ;
glVertex2f ( x , y + rect - > height ) ;
glEnd ( ) ;
glFinish ( ) ;
framebuffer_action_end ( handle ) ;
2025-11-29 17:56:33 -07:00
}
static void MwLLSetIconImpl ( MwLL handle , MwLLPixmap pixmap ) {
}
static void MwLLForceRenderImpl ( MwLL handle ) {
2025-12-01 14:19:07 -07:00
wl_surface_damage ( handle - > wayland . surface , 0 , 0 , handle - > wayland . ww , handle - > wayland . wh ) ;
2025-12-03 18:17:27 -07:00
2025-12-01 14:19:07 -07:00
wl_surface_commit ( handle - > wayland . surface ) ;
2025-12-03 18:17:27 -07:00
2025-12-01 19:12:49 -07:00
handle - > wayland . force_redraw = MwTRUE ;
2025-11-29 17:56:33 -07:00
}
static void MwLLSetCursorImpl ( MwLL handle , MwCursor * image , MwCursor * mask ) {
}
static void MwLLDetachImpl ( MwLL handle , MwPoint * point ) {
}
static void MwLLShowImpl ( MwLL handle , int show ) {
}
static void MwLLMakePopupImpl ( MwLL handle , MwLL parent ) {
}
static void MwLLSetSizeHintsImpl ( MwLL handle , int minx , int miny , int maxx , int maxy ) {
2025-12-01 14:19:07 -07:00
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 ) ;
}
2025-11-29 17:56:33 -07:00
}
static void MwLLMakeBorderlessImpl ( MwLL handle , int toggle ) {
2025-12-01 14:19:07 -07:00
if ( handle - > wayland . type = = MWLL_WAYLAND_TOPLEVEL ) {
if ( WAYLAND_GET_INTERFACE ( handle - > wayland , zxdg_decoration_manager_v1 ) - > context ! = 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 ) ;
} else {
// TODO: hide our custom window decorations when we have them.
printf ( " zxdg null \n " ) ;
}
}
2025-11-29 17:56:33 -07:00
}
static void MwLLFocusImpl ( MwLL handle ) {
}
static void MwLLGrabPointerImpl ( MwLL handle , int toggle ) {
}
static void MwLLSetClipboardImpl ( MwLL handle , const char * text ) {
}
static char * MwLLGetClipboardImpl ( MwLL handle ) {
char * r = NULL ;
return r ;
}
static void MwLLMakeToolWindowImpl ( MwLL handle ) {
}
static void MwLLGetCursorCoordImpl ( MwLL handle , MwPoint * point ) {
}
static void MwLLGetScreenSizeImpl ( MwLL handle , MwRect * rect ) {
}
static void MwLLBeginStateChangeImpl ( MwLL handle ) {
MwLLShow ( handle , 0 ) ;
}
static void MwLLEndStateChangeImpl ( MwLL handle ) {
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 ) ;