wayland: malicious compliance with gnome's CSD rule

This commit is contained in:
IoI_xD 2026-03-19 19:43:57 -07:00
commit 3cf94f6651
4 changed files with 160 additions and 52 deletions

2
.clangd Normal file
View file

@ -0,0 +1,2 @@
Completion:
HeaderInsertion: Never

View file

@ -24,12 +24,21 @@ MWDECL int MwLLWaylandCallInit(void);
#ifndef WL_PROTOCOLS_DEFINED
#define WL_PROTOCOLS_DEFINED
#include "Wayland/xdg-shell-client-protocol.h"
#include "Wayland/viewporter-client-protocol.h"
#include "Wayland/xdg-decoration-client-protocol.h"
#include "Wayland/cursor-shape-client-protocol.h"
#include "Wayland/primary-selection-client-protocol.h"
#include "Wayland/xdg-toplevel-icon-client-protocol.h"
#endif
#define SSD_BORDER_FRAME_LEFT 5
#define SSD_BORDER_FRAME_RIGHT 5
#define SSD_BORDER_FRAME_TOP 24
#define SSD_BORDER_FRAME_BOTTOM 5
#define SSD_LEFT_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_LEFT
#define SSD_TOP_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_TOP
struct _MwLLWayland;
typedef struct wayland_protocol {
@ -58,6 +67,9 @@ struct _MwLLWaylandTopLevel {
MwBool compositor_created;
MwBool xdg_wm_base_created;
MwBool xdg_surface_created;
struct wl_subsurface* ssurface;
struct wl_subcompositor* scompositor;
};
struct _MwLLWaylandSublevel {
@ -143,6 +155,9 @@ struct _MwLLWayland {
MwBool always_render;
MwBool has_decorations;
char title[255];
struct wl_display* display;
struct wl_registry* registry;
struct wl_compositor* compositor;
@ -151,6 +166,8 @@ struct _MwLLWayland {
struct wl_region* region;
struct wl_output* output;
struct wp_viewport* vp;
/* clipboard related stuff.
* Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/
@ -192,6 +209,7 @@ struct _MwLLWayland {
MwBool did_event_loop_early;
struct _MwLLWaylandShmBuffer framebuffer;
struct _MwLLWaylandShmBuffer backbuffer;
struct _MwLLWaylandShmBuffer cursor;
struct _MwLLWaylandShmBuffer* icon;
@ -203,12 +221,16 @@ struct _MwLLWayland {
uint32_t last_time;
MwBool moving;
MwLL currentlyHeldWidget;
struct wl_surface* curSurface;
cairo_surface_t* cs;
cairo_t* cairo;
cairo_surface_t* front_cs;
cairo_surface_t* back_cs;
cairo_t* front_cairo;
cairo_t* back_cairo;
};
struct _MwLLWaylandColor {

View file

@ -37,6 +37,7 @@ if (grep(/^wayland$/, @backends)) {
}
scan_wayland_protocol("stable", "xdg-shell", "");
scan_wayland_protocol("stable", "viewporter", "");
scan_wayland_protocol("stable", "tablet", "-v2");
scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1");
scan_wayland_protocol("staging", "cursor-shape", "-v1");

View file

@ -1,19 +1,9 @@
#include <Mw/Milsko.h>
#include <cairo/cairo.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
#include <sys/poll.h>
#include <wayland-client-core.h>
#include <wayland-client-protocol.h>
#include <sys/mman.h>
#include "../../external/stb_ds.h"
#include "Mw/BaseTypes.h"
#include <sys/mman.h>
#include <wayland-util.h>
#include <xkbcommon/xkbcommon.h>
/* TODO:
* - MwLLMakePopupImpl
@ -49,6 +39,11 @@ static void framebuffer_setup(struct _MwLLWayland* wayland);
/* Destroy the framebuffer */
static void framebuffer_destroy(struct _MwLLWayland* handle);
/* 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);
static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer);
static void region_setup(MwLL handle);
@ -435,7 +430,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri
p.point = self->wayland.cur_mouse_pos;
if(self->wayland.framebuffer.surface == self->wayland.curSurface) {
if(self->wayland.framebuffer.surface == self->wayland.curSurface || self->wayland.backbuffer.surface == self->wayland.curSurface) {
int i;
switch(button) {
@ -798,7 +793,11 @@ static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, waylan
/* wl_subcompositor setup function */
static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1);
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);
}
return NULL;
}
@ -824,6 +823,18 @@ static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_
free(data->listener);
}
/* 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) {
free(data->listener);
}
/* the two decoration manager constructs */
typedef struct zxdg_decoration_manager_v1_context {
struct zxdg_decoration_manager_v1* manager;
@ -875,6 +886,9 @@ static void xdg_toplevel_configure(void* data,
xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh);
backbuffer_destroy(&self->wayland);
backbuffer_setup(&self->wayland);
framebuffer_destroy(&self->wayland);
framebuffer_setup(&self->wayland);
region_setup(self);
@ -910,6 +924,7 @@ static void xdg_surface_configure(
if(self->wayland.configured) {
wl_surface_commit(self->wayland.framebuffer.surface);
wl_surface_commit(self->wayland.backbuffer.surface);
}
self->wayland.configured = MwTRUE;
@ -917,8 +932,8 @@ static void xdg_surface_configure(
/* wl_shm setup function */
static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) {
wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1);
return NULL;
@ -979,16 +994,34 @@ static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) {
static void framebuffer_setup(struct _MwLLWayland* wayland) {
buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh);
wayland->cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww);
wayland->cairo = cairo_create(wayland->cs);
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);
memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size);
if(wayland->configured) update_buffer(&wayland->framebuffer);
};
static void framebuffer_destroy(struct _MwLLWayland* wayland) {
buffer_destroy(&wayland->framebuffer);
cairo_destroy(wayland->cairo);
cairo_surface_destroy(wayland->cs);
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;
}
buffer_setup(&wayland->backbuffer, wayland->ww, wayland->wh);
wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww);
wayland->back_cairo = cairo_create(wayland->back_cs);
memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size);
if(wayland->configured) update_buffer(&wayland->backbuffer);
};
static void backbuffer_destroy(struct _MwLLWayland* wayland) {
buffer_destroy(&wayland->backbuffer);
cairo_destroy(wayland->back_cairo);
cairo_surface_destroy(wayland->back_cs);
};
static void region_invalidate(MwLL handle) {
@ -1007,7 +1040,6 @@ static void region_setup(MwLL handle) {
}
wl_region_add(handle->wayland.o_region, 0, 0, 1, 1);
wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region);
if(handle->wayland.type == MWLL_WAYLAND_POPUP) {
wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y));
@ -1022,7 +1054,12 @@ static void region_setup(MwLL handle) {
}
wl_region_add(handle->wayland.region, 0, 0, width, height);
}
wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region);
wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region);
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.region);
wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region);
}
}
static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) {
@ -1076,6 +1113,8 @@ static int event_loop(MwLL handle) {
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);
@ -1109,8 +1148,10 @@ static void setup_callbacks(struct _MwLLWayland* wayland) {
WL_INTERFACE(zwp_primary_selection_device_manager_v1);
if(wayland->type == MWLL_WAYLAND_TOPLEVEL) {
WL_INTERFACE(xdg_wm_base);
WL_INTERFACE(wp_viewporter);
WL_INTERFACE(zxdg_decoration_manager_v1);
WL_INTERFACE(xdg_toplevel_icon_manager_v1);
WL_INTERFACE(wl_subcompositor);
} else if(wayland->type == MWLL_WAYLAND_POPUP) {
WL_INTERFACE(xdg_wm_base);
} else {
@ -1138,8 +1179,6 @@ static void setup_toplevel(MwLL r, int x, int y) {
return;
}
r->wayland.framebuffer.surface = NULL;
/* 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);
@ -1153,9 +1192,11 @@ static void setup_toplevel(MwLL r, int x, int y) {
/* Create a wl_surface, a xdg_surface and a xdg_toplevel */
r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor);
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);
r->wayland.toplevel->xdg_surface =
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface);
xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface);
r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface);
/* setup mandatory listeners */
@ -1172,6 +1213,7 @@ static void setup_toplevel(MwLL r, int x, int y) {
xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp");
/* Perform the initial commit and wait for the first configure event */
wl_surface_commit(r->wayland.backbuffer.surface);
wl_surface_commit(r->wayland.framebuffer.surface);
while(!r->wayland.configured) {
event_loop(r);
@ -1186,8 +1228,18 @@ static void setup_toplevel(MwLL r, int x, int y) {
zxdg_toplevel_decoration_v1_set_mode(
dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
r->wayland.has_decorations = MwTRUE;
} else {
printf("zxdg null\n");
/* otherwise set up viewporter */
struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context;
r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface);
wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh);
wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT), r->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM));
r->wayland.has_decorations = MwFALSE;
wl_subsurface_set_position(r->wayland.toplevel->ssurface, SSD_BORDER_FRAME_LEFT, SSD_BORDER_FRAME_TOP);
wl_subsurface_set_desync(r->wayland.toplevel->ssurface);
}
}
@ -1269,6 +1321,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) {
/* Sublevel setup function */
static void destroy_sublevel(MwLL r) {
backbuffer_destroy(&r->wayland);
framebuffer_destroy(&r->wayland);
wl_subsurface_destroy(r->wayland.sublevel->subsurface);
@ -1365,6 +1418,7 @@ static void setup_popup(MwLL r, int x, int y) {
// framebuffer_destroy(&r->wayland);
framebuffer_setup(&r->wayland);
backbuffer_setup(&r->wayland);
}
/* Popup destroy function */
@ -1424,6 +1478,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) {
}
framebuffer_setup(&r->wayland);
backbuffer_setup(&r->wayland);
r->wayland.region = wl_compositor_create_region(r->wayland.compositor);
r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor);
@ -1515,8 +1570,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) {
if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) {
wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y);
}
if(handle->wayland.type == MWLL_WAYLAND_POPUP) {
}
region_setup(handle);
MwLLDispatch(handle, draw, NULL);
@ -1531,17 +1584,29 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) {
handle->wayland.wh = 10;
goto refresh;
}
if(handle->wayland.parent) {
if(handle->wayland.parent->wayland.type == MWLL_WAYLAND_TOPLEVEL && !handle->wayland.parent->wayland.has_decorations) {
if(w >= handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT))
w = handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT);
if(h >= handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM))
h = handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM);
}
}
handle->wayland.ww = w;
handle->wayland.wh = h;
// if(handle->wayland.wh >= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)) {
// handle->wayland.wh -= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM);
// }
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) {
xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh);
}
if(handle->wayland.type == MWLL_WAYLAND_POPUP) {
// destroy_popup(handle);
// wl_flush(handle);
// setup_popup(handle, handle->wayland.x, handle->wayland.y);
destroy_popup(handle);
wl_flush(handle);
setup_popup(handle, handle->wayland.x, handle->wayland.y);
}
refresh:
@ -1549,31 +1614,48 @@ refresh:
framebuffer_destroy(&handle->wayland);
framebuffer_setup(&handle->wayland);
backbuffer_destroy(&handle->wayland);
backbuffer_setup(&handle->wayland);
MwLLDispatch(handle, draw, NULL);
}
static void MwLLBeginDrawImpl(MwLL handle) {
(void)handle;
if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) {
return;
}
if(!handle->wayland.has_decorations) {
cairo_set_source_rgb(handle->wayland.back_cairo, 0, 0.25, 0.25);
cairo_rectangle(handle->wayland.back_cairo, 1, 1, handle->wayland.ww - 2, handle->wayland.wh - 2);
cairo_fill_preserve(handle->wayland.back_cairo);
cairo_set_source_rgb(handle->wayland.back_cairo, 1, 1, 1);
cairo_rectangle(handle->wayland.back_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh);
cairo_stroke(handle->wayland.back_cairo);
}
}
static void MwLLEndDrawImpl(MwLL handle) {
if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer);
if(handle->wayland.configured) {
update_buffer(&handle->wayland.framebuffer);
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
update_buffer(&handle->wayland.backbuffer);
}
}
}
static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) {
int i;
cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0);
cairo_new_path(handle->wayland.cairo);
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);
for(i = 0; i < points_count; i++) {
if(i == 0) {
cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y);
cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y);
} else {
cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y);
cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y);
}
}
cairo_close_path(handle->wayland.cairo);
cairo_close_path(handle->wayland.front_cairo);
cairo_fill(handle->wayland.cairo);
cairo_fill(handle->wayland.front_cairo);
handle->wayland.events_pending = 1;
}
@ -1581,18 +1663,18 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL
static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) {
int i;
cairo_set_line_cap(handle->wayland.cairo, CAIRO_LINE_CAP_SQUARE);
cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0);
cairo_new_path(handle->wayland.cairo);
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);
for(i = 0; i < 2; i++) {
if(i == 0) {
cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y);
cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y);
} else {
cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y);
cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y);
}
}
cairo_close_path(handle->wayland.cairo);
cairo_stroke(handle->wayland.cairo);
cairo_close_path(handle->wayland.front_cairo);
cairo_stroke(handle->wayland.front_cairo);
handle->wayland.events_pending = 1;
}
@ -1638,6 +1720,9 @@ static int MwLLPendingImpl(MwLL handle) {
}
}
wl_surface_commit(handle->wayland.framebuffer.surface);
if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) {
wl_surface_commit(handle->wayland.backbuffer.surface);
}
if(handle->wayland.always_render) {
event_loop(handle);
@ -1675,6 +1760,9 @@ 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);
}
if(!handle->wayland.has_decorations) {
strncpy(handle->wayland.title, title, 255);
}
}
static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) {
@ -1726,11 +1814,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) {
cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height);
c = cairo_create(cs);
if(parent) {
cairo_rectangle(c, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y);
cairo_clip(c);
}
cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height);
cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0);
@ -1738,8 +1821,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) {
cairo_paint(c);
cairo_set_source_surface(handle->wayland.cairo, cs, rect->x, rect->y);
cairo_paint(handle->wayland.cairo);
cairo_set_source_surface(handle->wayland.front_cairo, cs, rect->x, rect->y);
cairo_paint(handle->wayland.front_cairo);
cairo_destroy(c);
cairo_surface_destroy(cs);