[wayland_egl.c] self contained wayland setup example

main
Allen Webster 2026-03-03 12:48:49 -08:00
parent f56e3dedde
commit b5932166ae
3 changed files with 232 additions and 63 deletions

View File

@ -376,7 +376,7 @@ border_component_reallocate(struct border_component *component, int w, int h){
component->wl_buffer = 0; component->wl_buffer = 0;
} }
if (component->data != 0){ if (component->data != 0){
munmap(component->data, component->data_size); cmunmap(component->data, component->data_size);
component->data = 0; component->data = 0;
} }
component->data_size = 0; component->data_size = 0;

View File

@ -75,29 +75,78 @@ const struct xdg_wm_base_listener xdg_wm_base_listener = {
xdg_wm_base_ping xdg_wm_base_ping
}; };
#define SHADOW_MARGIN 20
#define SHADOW_THICK 10
static void static void
pointer_enter(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, pointer_enter(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y){ struct wl_surface *surface, wl_fixed_t fx, wl_fixed_t fy){
int x = ctx.p[0] = wl_fixed_to_int(fx);
int y = ctx.p[1] = wl_fixed_to_int(fy);
ctx.hover = surface;
if (surface == ctx.main_wl_surface){
printf("pointer_enter (main) %d,%d\n", x, y);
}
else if (surface == ctx.shadow_wl_surface){
printf("pointer_enter (shadow) %d,%d\n", x, y);
}
else{
printf("pointer_enter (unidentified) %d,%d\n", x, y);
ctx.hover = 0;
}
ctx.hover_serial = serial;
} }
static void static void
pointer_leave(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, pointer_leave(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
struct wl_surface *surface){ struct wl_surface *surface){
if (surface == ctx.main_wl_surface){
printf("pointer_leave (main)\n");
}
else if (surface == ctx.shadow_wl_surface){
printf("pointer_leave (shadow)\n");
}
else{
printf("pointer_leave (unidentified)\n");
}
ctx.hover = 0;
} }
static void static void
pointer_motion(void *udata, struct wl_pointer *wl_pointer, uint32_t time, pointer_motion(void *udata, struct wl_pointer *wl_pointer, uint32_t time,
wl_fixed_t surface_x, wl_fixed_t surface_y){ wl_fixed_t fx, wl_fixed_t fy){
int x = ctx.p[0] = wl_fixed_to_int(fx);
int y = ctx.p[1] = wl_fixed_to_int(fy);
printf("pointer_motion %d,%d\n", x, y);
} }
static void static void
pointer_button(void *udata, struct wl_pointer *wl_pointer, uint32_t serial, pointer_button(void *udata, struct wl_pointer *wl_pointer, uint32_t serial,
uint32_t time, uint32_t button, uint32_t state){ uint32_t time, uint32_t button, uint32_t state){
char *state_str = (state == 1?"press":"release");
if (button == BTN_LEFT){
printf("pointer_button (left) %s\n", state_str);
}
else if (button == BTN_RIGHT){
printf("pointer_button (right) %s\n", state_str);
}
else if (button == BTN_MIDDLE){
printf("pointer_button (middle) %s\n", state_str);
}
else{
printf("pointer_button (unidentified) %s\n", state_str);
}
if (state){
ctx.button = button;
ctx.button_serial = serial;
}
} }
static void static void
pointer_axis(void *udata, struct wl_pointer *wl_pointer, pointer_axis(void *udata, struct wl_pointer *wl_pointer,
uint32_t time, uint32_t axis, wl_fixed_t value){ uint32_t time, uint32_t axis, wl_fixed_t fv){
int v = wl_fixed_to_int(fv);
printf("pointer_axis %u,%d\n", axis, v);
} }
const struct wl_pointer_listener pointer_listener = { const struct wl_pointer_listener pointer_listener = {
@ -287,10 +336,10 @@ int main(){
ctx.main_xdg_toplevel = xdg_surface_get_toplevel(ctx.main_xdg_surface); ctx.main_xdg_toplevel = xdg_surface_get_toplevel(ctx.main_xdg_surface);
xdg_toplevel_add_listener(ctx.main_xdg_toplevel, &xdg_toplevel_listener, 0); xdg_toplevel_add_listener(ctx.main_xdg_toplevel, &xdg_toplevel_listener, 0);
ctx.config.dim[0] = 640;
ctx.config.dim[1] = 480;
ctx.control_flags = ~0; ctx.control_flags = ~0;
ctx.dim[0] = 640;
ctx.dim[1] = 480;
ctx.config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; ctx.config_staged.decoration_mode = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
if (ctx.zxdg_decoration_manager != 0){ if (ctx.zxdg_decoration_manager != 0){
ctx.main_zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager, ctx.main_xdg_toplevel); ctx.main_zxdg_toplevel_decoration = zxdg_decoration_manager_v1_get_toplevel_decoration(ctx.zxdg_decoration_manager, ctx.main_xdg_toplevel);
@ -313,37 +362,9 @@ int main(){
ctx.shadow_wl_surface, ctx.shadow_wl_surface,
ctx.main_wl_surface); ctx.main_wl_surface);
{
int dim[2] = {640, 25};
int stride = 4*dim[0];
uint64_t size = 4*dim[0]*dim[1];
int fd = os_create_anonymous_file(size);
if (fd >= 0){
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data != MAP_FAILED){
struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size);
struct wl_buffer *wl_buffer = wl_shm_pool_create_buffer(pool, 0, dim[0], dim[1], stride,
WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
ctx.shadow_wl_buffer = wl_buffer;
ctx.shadow_data = data;
ctx.shadow_size = size;
for (int i = 0; i < 2; i += 1){
ctx.shadow_dim[i] = dim[i];
}
}
close(fd);
}
}
/* window egl */ /* window egl */
ctx.main_wl_egl_window = wl_egl_window_create(ctx.main_wl_surface, ctx.main_wl_egl_window = wl_egl_window_create(ctx.main_wl_surface,
ctx.config.dim[0], ctx.dim[0], ctx.dim[1]);
ctx.config.dim[1]);
EGLConfig configs[64]; EGLConfig configs[64];
EGLint config_cap = sizeof(configs)/sizeof(*configs); EGLint config_cap = sizeof(configs)/sizeof(*configs);
@ -434,43 +455,155 @@ int main(){
/* window sizing */ /* window sizing */
CSD_Frame csd_frame = {0}; CSD_Frame csd_frame = {0};
int32_t csd_dim[2]; int32_t csd_dim[2] = {0};
{ {
if (csd){ if (csd){
csd_frame = csd_impl_calculate_frame(); csd_frame = csd_impl_calculate_frame();
} }
for (int i = 0; i < 2; i += 1){ for (int i = 0; i < 2; i += 1){
csd_dim[i] = csd_frame.border[i][0] + csd_frame.border[i][1]; csd_dim[i] = csd_frame.border[i][0] + csd_frame.border[i][1];
}
for (int i = 0; i < 2; i += 1){
int32_t d = ctx.config.dim[i] - csd_dim[i]; int32_t d = ctx.config.dim[i] - csd_dim[i];
if (!ctx.handled_first_size){
d = ctx.dim[i];
ctx.config.dim[i] = d + csd_dim[i];
}
d = ClampBot(d, ctx.mmbox[i][0]); d = ClampBot(d, ctx.mmbox[i][0]);
d = ClampTop(d, ctx.mmbox[i][1]); d = ClampTop(d, ctx.mmbox[i][1]);
d = ClampBot(d, csd_frame.minbox[i]); d = ClampBot(d, csd_frame.minbox[i]);
ctx.dim[i] = d; ctx.dim[i] = d;
} }
ctx.handled_first_size = 1;
}
/* frame cursor & interaction */
CursorShape cursor_shape = CursorShape_Pointer;
if (ctx.control_flags & WindowControlFlag_Resize){
static const CursorShape cursor_box[] = {
CursorShape_Resize_TopLeft, CursorShape_Resize_Top, CursorShape_Resize_TopRight,
CursorShape_Resize_Left, CursorShape_Pointer, CursorShape_Resize_Right,
CursorShape_Resize_BottomLeft, CursorShape_Resize_Bottom, CursorShape_Resize_BottomRight,
};
static const enum xdg_toplevel_resize_edge xedge_box[] = {
XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_TOP, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT,
XDG_TOPLEVEL_RESIZE_EDGE_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_NONE, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT,
XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT,
};
int l = (ctx.p[0] < SHADOW_MARGIN);
int r = (!l && ctx.p[0] >= ctx.dim[0] + SHADOW_MARGIN);
int t = (ctx.p[1] < SHADOW_MARGIN);
int b = (!t && ctx.p[1] >= ctx.dim[1] + SHADOW_MARGIN);
int loc = 3*(b - t) + (r - l);
cursor_shape = cursor_box[4 + loc];
if (ctx.button == BTN_LEFT){
ctx.button = 0;
if (loc != 0){
xdg_toplevel_resize(ctx.main_xdg_toplevel, ctx.wl_seat,
ctx.button_serial, xedge_box[4 + loc]);
}
else{
xdg_toplevel_move(ctx.main_xdg_toplevel, ctx.wl_seat,
ctx.button_serial);
}
}
} }
/* window frame render */ /* window frame render */
if (csd){ if (csd){
uint32_t *pxl = (uint32_t*)ctx.shadow_data; if (ctx.shadow_data != 0){
for (int32_t y = 0; y < ctx.shadow_dim[1]; y += 1){ munmap(ctx.shadow_data, ctx.shadow_size);
for (int32_t x = 0; x < ctx.shadow_dim[0]; x += 1){ ctx.shadow_data = 0;
*pxl = 0xFFFF0000;
pxl += 1;
} }
if (ctx.shadow_wl_buffer != 0){
wl_buffer_destroy(ctx.shadow_wl_buffer);
ctx.shadow_wl_buffer = 0;
}
{
int dim[2];
for (int i = 0; i < 2; i += 1){
dim[i] = ctx.dim[i] + SHADOW_MARGIN*2;
}
int stride = 4*dim[0];
uint64_t size = 4*dim[0]*dim[1];
int fd = os_create_anonymous_file(size);
if (fd >= 0){
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data != MAP_FAILED){
struct wl_shm_pool *pool = wl_shm_create_pool(ctx.wl_shm, fd, size);
struct wl_buffer *wl_buffer =
wl_shm_pool_create_buffer(pool, 0, dim[0], dim[1],
stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
ctx.shadow_wl_buffer = wl_buffer;
ctx.shadow_data = data;
ctx.shadow_size = size;
for (int i = 0; i < 2; i += 1){
ctx.shadow_dim[i] = dim[i];
} }
} }
/* window frame commit */ close(fd);
if (csd){ }
}
uint32_t *pxl = (uint32_t*)ctx.shadow_data;
for (int32_t y = 0; y < ctx.shadow_dim[1]; y += 1){
for (int32_t x = 0; x < ctx.shadow_dim[0]; x += 1){
*pxl = 0;
{
int x0 = SHADOW_MARGIN - SHADOW_THICK;
int y0 = SHADOW_MARGIN - SHADOW_THICK;
int x1 = x0 + ctx.dim[0] + SHADOW_THICK*2;
int y1 = y0 + ctx.dim[1] + SHADOW_THICK*2;
if (x0 <= x && x < x1 && y0 <= y && y < y1){
int xd0 = x - x0;
int xd1 = x1 - x - 1;
int yd0 = y - y0;
int yd1 = y1 - y - 1;
int d = Min(Min(xd0, xd1), Min(yd0, yd1));
if (d < SHADOW_THICK){
int c = d*0xFF/SHADOW_THICK;
((uint8_t*)pxl)[0] = 0;
((uint8_t*)pxl)[1] = 0;
((uint8_t*)pxl)[2] = 0;
((uint8_t*)pxl)[3] = c;
}
}
}
pxl += 1;
}
}
{
struct wl_region *region = wl_compositor_create_region(ctx.wl_compositor);
wl_region_add(region, 0, 0, ctx.shadow_dim[0], ctx.shadow_dim[1]);
wl_region_subtract(region, SHADOW_MARGIN, SHADOW_MARGIN,
ctx.dim[0], ctx.dim[1]);
wl_surface_set_input_region(ctx.shadow_wl_surface, region);
wl_region_destroy(region);
}
{ {
wl_surface_attach(ctx.shadow_wl_surface, ctx.shadow_wl_buffer, 0, 0); wl_surface_attach(ctx.shadow_wl_surface, ctx.shadow_wl_buffer, 0, 0);
wl_surface_set_buffer_scale(ctx.shadow_wl_surface, 1); wl_surface_set_buffer_scale(ctx.shadow_wl_surface, 1);
wl_surface_damage_buffer(ctx.shadow_wl_surface, 0, 0, wl_surface_damage_buffer(ctx.shadow_wl_surface, 0, 0,
ctx.shadow_dim[0], ctx.shadow_dim[1]); ctx.shadow_dim[0], ctx.shadow_dim[1]);
wl_subsurface_set_position(ctx.shadow_wl_subsurface, 0, -25); wl_subsurface_set_position(ctx.shadow_wl_subsurface, -SHADOW_MARGIN, -SHADOW_MARGIN);
wl_surface_commit(ctx.shadow_wl_surface); wl_surface_commit(ctx.shadow_wl_surface);
} }
}
/* window frame commit */
if (!(ctx.control_flags & WindowControlFlag_Resize)){ if (!(ctx.control_flags & WindowControlFlag_Resize)){
xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); xdg_toplevel_set_min_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]);
xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]); xdg_toplevel_set_max_size(ctx.main_xdg_toplevel, ctx.dim[0], ctx.dim[1]);
@ -487,7 +620,14 @@ int main(){
} }
} }
} }
}
xdg_surface_set_window_geometry(ctx.main_xdg_surface,
-csd_frame.border[0][0],
-csd_frame.border[1][0],
ctx.dim[0] + csd_dim[0],
ctx.dim[1] + csd_dim[1]);
wl_egl_window_resize(ctx.main_wl_egl_window, ctx.dim[0], ctx.dim[1], 0, 0);
/* app update & render */ /* app update & render */
{ {
@ -496,13 +636,29 @@ int main(){
} }
glDrawBuffer(GL_BACK); glDrawBuffer(GL_BACK);
glViewport(0, 0, ctx.config.dim[0], ctx.config.dim[1]); glViewport(0, 0, ctx.dim[0], ctx.dim[1]);
glClearColor(0.40f, 0.90f, 0.15f, 1.f); glClearColor(0.40f, 0.90f, 0.15f, 1.f);
glClear(GL_COLOR_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT);
} }
eglSwapBuffers(ctx.egl_display, ctx.main_egl_surface); eglSwapBuffers(ctx.egl_display, ctx.main_egl_surface);
wl_surface_commit(ctx.main_wl_surface); wl_surface_commit(ctx.main_wl_surface);
/* commit new cursor */
{
struct wl_cursor *cursor = ctx.wl_cursors[cursor_shape];
if (cursor != 0){
struct wl_cursor_image *cursor_image = cursor->images[0];
struct wl_buffer *cursor_buffer = wl_cursor_image_get_buffer(cursor_image);
wl_surface_set_buffer_scale(ctx.cursor_surface, 1);
wl_surface_attach(ctx.cursor_surface, cursor_buffer, 0, 0);
wl_surface_damage_buffer(ctx.cursor_surface, 0, 0,
cursor_image->width, cursor_image->height);
wl_surface_commit(ctx.cursor_surface);
wl_pointer_set_cursor(ctx.wl_pointer, ctx.hover_serial, ctx.cursor_surface,
cursor_image->hotspot_x, cursor_image->hotspot_y);
}
}
} }
return(0); return(0);
@ -515,7 +671,11 @@ csd_impl_calculate_frame(void){
CSD_Frame frame = {0}; CSD_Frame frame = {0};
bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen)); bool show_title = (!(ctx.config.flags & WindowFlag_IsFullscreen));
if (show_title){ if (show_title){
frame.border[1][0] = 25; for (int i = 0; i < 2; i += 1){
for (int j = 0; j < 2; j += 1){
frame.border[i][j] = SHADOW_MARGIN;
}
}
} }
return(frame); return(frame);
} }

View File

@ -22,7 +22,9 @@ typedef struct CursorTheme{
int size; int size;
} CursorTheme; } CursorTheme;
typedef uint32_t CursorShape;
enum{ enum{
CursorShape_Hidden,
CursorShape_Pointer, CursorShape_Pointer,
CursorShape_Resize_Top, CursorShape_Resize_Top,
CursorShape_Resize_Bottom, CursorShape_Resize_Bottom,
@ -125,6 +127,13 @@ typedef struct Ctx{
Config config_staged; Config config_staged;
int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max int32_t mmbox[2][2]; // [0][]:x [1][]:y [][0]:min [][1]:max
int32_t dim[2]; int32_t dim[2];
uint32_t hover_serial;
uint32_t button_serial;
struct wl_surface *hover;
int32_t p[2];
uint32_t button;
int handled_first_size;
} Ctx; } Ctx;