From 14915e082ac003a16a3a46a3a4a8281a48bd8c55 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 12:46:52 -0700 Subject: [PATCH 1/8] remove wayland's widget-checking stuff in an effort to remove one of the last hacks from the wayland backend --- include/Mw/LowLevel/Wayland.h | 15 +------ src/backend/wayland/wayland.c | 74 +---------------------------------- src/core.c | 10 ++++- 3 files changed, 13 insertions(+), 86 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c6d397b..02ef26e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -601,9 +601,6 @@ void MwLLWaylandRegionInvalidate(MwLL handle); void MwLLWaylandHangUntilConfigured(MwLL handle); -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); -void MwLLWaylandWidgetUndestroy(MwLL self); - /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); @@ -613,18 +610,10 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ void MwLLWaylandFlush(MwLL handle); /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) \ - if(MwLLWaylandWidgetIsDestroyed(self)) { \ - return; \ - } +#define WAYLAND_EVENT_OP_START(self) pthread_mutex_lock(&self->wayland.eventsMutex); /* Footer for WAYLAND_EVENT_OP_START */ -#define WAYLAND_EVENT_OP_END(self) - -#define WIDGET_CHECK(handle) \ - if(!handle->wayland.valid) { \ - return; \ - } +#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 3d61932..9b96097 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -18,31 +18,6 @@ static pthread_mutex_t destroyedWidgetsTableMutex; */ static MwLL* destroyedWidgetsTable; -MwBool MwLLWaylandWidgetIsDestroyed(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwTRUE; - } - } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return MwFALSE; -} -void MwLLWaylandWidgetUndestroy(MwLL self) { - int i; - pthread_mutex_lock(&destroyedWidgetsTableMutex); - for(i = 0; i < arrlen(destroyedWidgetsTable); i++) { - if(self == destroyedWidgetsTable[i]) { - arrdel(destroyedWidgetsTable, i); - break; - } - } - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - return; -} - static int event_loop(MwLL handle); /* Recursively dispatch a resize event to a widget and its children */ @@ -61,7 +36,6 @@ static void recursive_dispatch_resize(MwLL handle) { static void recursive_render(MwLL handle) { int i; - WIDGET_CHECK(handle); for(i = 0; i < arrlen(((MwWidget)handle->common.user)->children); i++) recursive_render(((MwWidget)handle->common.user)->children[i]->lowlevel); @@ -628,12 +602,7 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh r->wayland.x = x; r->wayland.y = y; r->wayland.parent = parent; - if(MwLLWaylandWidgetIsDestroyed(parent)) { - r->wayland.valid = MwFALSE; - return; - } else { - r->wayland.valid = MwTRUE; - } + r->wayland.valid = MwTRUE; if(ty == MwLL_WAYLAND_UNKNOWN) { if(parent == NULL) { @@ -657,8 +626,6 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } - WIDGET_CHECK(r); - MwLLWaylandFramebufferSetup(&r->wayland); MwLLWaylandBackbufferSetup(&r->wayland); @@ -702,10 +669,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); - if(MwLLWaylandWidgetIsDestroyed(r)) { - MwLLWaylandWidgetUndestroy(r); - } - r->wayland.is_toplevel = parent == NULL; r->wayland.is_clipping = 0; @@ -791,10 +754,6 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&destroyedWidgetsTableMutex); free(handle); - - // if(topmost_parent->wayland.currentlyHeldWidget == handle) { - // topmost_parent->wayland.currentlyHeldWidget = NULL; - // } } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { @@ -812,7 +771,6 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - WIDGET_CHECK(handle); MwLLWaylandRegionInvalidate(handle); handle->wayland.x = x; handle->wayland.y = y; @@ -863,7 +821,6 @@ static void actually_set_wh(MwLL handle) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - WIDGET_CHECK(handle); if(handle->wayland.ww == w && handle->wayland.wh == h) { return; @@ -886,7 +843,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLBeginDrawImpl(MwLL handle) { - WIDGET_CHECK(handle); cairo_save(handle->wayland.front_cairo); cairo_set_source_rgba(handle->wayland.front_cairo, 0, 0, 0, 0); cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE); @@ -995,7 +951,6 @@ static void MwLLEndDrawImpl(MwLL handle) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - WIDGET_CHECK(handle); clip(handle); @@ -1019,7 +974,6 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { int i; - WIDGET_CHECK(handle); clip(handle); @@ -1073,10 +1027,6 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(MwLLWaylandWidgetIsDestroyed(handle) || !handle->wayland.valid) { - return 0; - } - handle->wayland.resizing = 0; if(handle->wayland.setting_wh) { @@ -1128,7 +1078,6 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - WIDGET_CHECK(handle); if(!MwWaylandVulkan) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; @@ -1148,7 +1097,6 @@ static void MwLLNextEventImpl(MwLL handle) { } static void MwLLSetTitleImpl(MwLL handle, const char* title) { - WIDGET_CHECK(handle); if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); } @@ -1213,8 +1161,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { if(rect->width >= INT16_MAX) rect->width = INT16_MAX; if(rect->height >= INT16_MAX) rect->height = INT16_MAX; - WIDGET_CHECK(handle); - cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); @@ -1239,7 +1185,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - WIDGET_CHECK(handle); if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; @@ -1282,7 +1227,6 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { - WIDGET_CHECK(handle); wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); handle->wayland.force_render = MwTRUE; @@ -1294,8 +1238,6 @@ static void MwLLForceRenderImpl(MwLL handle) { static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { int x, y, xs, ys; - WIDGET_CHECK(handle); - if(handle->wayland.cursor.setup) { MwLLWaylandBufferDestroy(&handle->wayland.cursor); wl_surface_destroy(handle->wayland.cursor.surface); @@ -1346,7 +1288,6 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { static void MwLLDetachImpl(MwLL handle, MwPoint* point) { MwLL p = handle->wayland.parent; int x = 0, y = 0; - WIDGET_CHECK(handle); while(p != NULL) { x += p->wayland.x; y += p->wayland.y; @@ -1363,7 +1304,6 @@ static void MwLLShowImpl(MwLL handle, int show) { if(!handle->wayland.configured) { return; } - WIDGET_CHECK(handle); /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ if(handle->wayland.framebuffer.surface) { wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); @@ -1382,7 +1322,6 @@ static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - WIDGET_CHECK(handle); 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); @@ -1391,7 +1330,6 @@ static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { (void)toggle; - WIDGET_CHECK(handle); 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; @@ -1412,7 +1350,6 @@ static void MwLLFocusImpl(MwLL handle) { static void MwLLGrabPointerImpl(MwLL handle, int toggle) { MwLL topmost_parent = handle; - WIDGET_CHECK(handle); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; if(handle->wayland.pointer_constraints && handle->wayland.relative_pointer_manager) { if(toggle) { @@ -1439,7 +1376,6 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { int i; - WIDGET_CHECK(handle); if(handle->wayland.clipboard_buffer != NULL) { free(handle->wayland.clipboard_buffer); @@ -1466,7 +1402,6 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { int i; - WIDGET_CHECK(handle); if(clipboard_type == MwCLIPBOARD_PRIMARY) { if(handle->wayland.supports_zwp) { for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { @@ -1486,7 +1421,6 @@ static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { } static void MwLLMakeToolWindowImpl(MwLL handle) { - WIDGET_CHECK(handle); handle->wayland.type_to_be = MwLL_WAYLAND_POPUP; } @@ -1494,14 +1428,12 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { MwLL topmost_parent = handle; - WIDGET_CHECK(handle); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; *point = topmost_parent->wayland.cur_mouse_pos; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - WIDGET_CHECK(handle); rect->x = 0; rect->y = 0; @@ -1515,7 +1447,6 @@ static void MwLLBeginStateChangeImpl(MwLL handle) { } static void MwLLEndStateChangeImpl(MwLL handle) { - WIDGET_CHECK(handle); if(handle->wayland.detatching) { MwLL topmost_parent = handle->wayland.parent; @@ -1588,8 +1519,7 @@ static MwBool MwLLDoModernImpl(MwLL handle) { static void MwLLRaiseImpl(MwLL handle) { (void)handle; - /* WIDGET_CHECK(handle); - + /* if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL) { MwLL topmost_parent = handle; int children_num; diff --git a/src/core.c b/src/core.c index db81a2b..9f18d72 100644 --- a/src/core.c +++ b/src/core.c @@ -18,7 +18,7 @@ MwLLEndDraw(handle->lowlevel); \ } -static void MWAPI MwVaListApply_Internal(MwWidget handle, va_list va, int only_early); +static void MWAPI MwVaListApply_Internal(MwWidget handle, va_list va, int only_early); static MwWidget MWAPI MwCreateWidget_Internal(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height, int do_prop, va_list prop); static void lldrawhandler(MwLL handle, void* data) { @@ -392,6 +392,14 @@ void MwFreeWidget(MwWidget handle) { if(handle->root_monofont != NULL) MwFontFree(handle->root_monofont); if(handle->root_boldmonofont != NULL) MwFontFree(handle->root_boldmonofont); + if(handle->parent) { + for(i = 0; i < arrlen(handle->parent->children); i++) { + if(handle->parent->children[i] == handle) { + arrdel(handle->parent->children, i); + } + } + } + free(handle); } From 8fe9a1c168b21d3f84587bf40816f3bdc085569f Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 12:50:08 -0700 Subject: [PATCH 2/8] wayland: clean up destroyedWidgetsTableMutex remenants --- src/backend/wayland/wayland.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 9b96097..8625c60 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -10,14 +10,6 @@ wayland_call_table_t wl_call_tbl; MwBool MwWaylandVulkan = MwFALSE; #endif -static pthread_mutex_t destroyedWidgetsTableMutex; -/* - * So Wayland, bless its soul; it keeps using callbacks LONG after they should not only be destroyed but the widget doesn't even exist anymore. Naturally, this causes use after free. so we fight fire with fire in the worst code i've ever written: by storing the freed pointers here, we disallow wayland from ever using them again. if something else is created that takes this slot, we remove it from the table. - * - * TODO(IOI): FUCKING NO???? FIX THIS. - */ -static MwLL* destroyedWidgetsTable; - static int event_loop(MwLL handle); /* Recursively dispatch a resize event to a widget and its children */ @@ -749,10 +741,6 @@ static void MwLLDestroyImpl(MwLL handle) { MwLLWaylandFlush(handle); - pthread_mutex_lock(&destroyedWidgetsTableMutex); - arrput(destroyedWidgetsTable, handle); - pthread_mutex_unlock(&destroyedWidgetsTableMutex); - free(handle); } From ad7db9dcec9d91ae5f2297442ca366caf4c7366f Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 21 May 2026 04:55:00 +0900 Subject: [PATCH 3/8] maybe --- src/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core.c b/src/core.c index 9f18d72..f879661 100644 --- a/src/core.c +++ b/src/core.c @@ -354,6 +354,7 @@ void MwFreeWidget(MwWidget handle) { for(i = 0; i < arrlen(handle->children); i++) { MwFreeWidget(handle->children[i]); + i--; } arrfree(handle->children); From 70147b2716a579962c2c6d9f8e4e6634c249eaf8 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 21 May 2026 05:22:35 +0900 Subject: [PATCH 4/8] works for me --- src/core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core.c b/src/core.c index f879661..7d6cc4c 100644 --- a/src/core.c +++ b/src/core.c @@ -397,6 +397,7 @@ void MwFreeWidget(MwWidget handle) { for(i = 0; i < arrlen(handle->parent->children); i++) { if(handle->parent->children[i] == handle) { arrdel(handle->parent->children, i); + i--; } } } From 7aad2af60938a57d6cc189f070d25b4b024e245e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 13:45:35 -0700 Subject: [PATCH 5/8] wayland: merge libdecor --- include/Mw/LowLevel/Wayland.h | 70 +++++++++- src/backend/wayland/buffer.c | 2 +- src/backend/wayland/wayland.c | 254 ++++++++++++++++++---------------- 3 files changed, 202 insertions(+), 124 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 02ef26e..575c867 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -14,7 +14,13 @@ #include #include #include -#include +/* libdecor is included later on so that it's covered by the wayland dynloading. */ +struct libdecor_frame; +struct libdecor_interface; +struct libdecor_configuration; +struct libdecor_frame_interface; +enum libdecor_window_state; +struct wl_surface; #ifdef __cplusplus extern "C" { @@ -44,6 +50,8 @@ typedef struct wayland_call_table { void* lib; void* xkb_lib; void* cairo_lib; + + void* libdecor_lib; #ifdef USE_DBUS MwLLDBusFuncTable dbus; MwBool has_dbus; @@ -141,6 +149,20 @@ typedef struct wayland_call_table { void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); + MwBool has_libdecor; + struct libdecor* (*libdecor_new)(struct wl_display* display, struct libdecor_interface* iface); + struct libdecor_state* (*libdecor_state_new)(int width, int height); + void (*libdecor_frame_commit)(struct libdecor_frame* frame, struct libdecor_state* state, struct libdecor_configuration* configuration); + void (*libdecor_state_free)(struct libdecor_state* state); + struct libdecor_frame* (*libdecor_decorate)(struct libdecor* context, struct wl_surface* surface, struct libdecor_frame_interface* iface, void* user_data); + void (*libdecor_frame_set_app_id)(struct libdecor_frame* frame, const char* app_id); + void (*libdecor_frame_set_title)(struct libdecor_frame* frame, const char* title); + void (*libdecor_frame_map)(struct libdecor_frame* frame); + MwBool (*libdecor_configuration_get_content_size)(struct libdecor_configuration* configuration, struct libdecor_frame* frame, int* width, int* height); + MwBool (*libdecor_configuration_get_window_state)(struct libdecor_configuration* configuration, enum libdecor_window_state* window_state); + struct xdg_surface* (*libdecor_frame_get_xdg_surface)(struct libdecor_frame* frame); + int (*libdecor_dispatch)(struct libdecor* context, int timeout); + void (*libdecor_frame_translate_coordinate)(struct libdecor_frame* frame, int surface_x, int surface_y, int* frame_x, int* frame_y); } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; @@ -186,6 +208,17 @@ MwInline int wayland_load_funcs() { return 1; \ }; + /* i mean i pray if somebody is using thr wayland backend over apple/ios that actual decorations are supported. */ +#ifdef __APPLE__ + wl_call_tbl.libdecor_lib = MwDynamicOpen("libdecor-0.dylib"); +#else + wl_call_tbl.libdecor_lib = MwDynamicOpen("libdecor-0.so"); +#endif + wl_call_tbl.has_libdecor = (wl_call_tbl.libdecor_lib != NULL); + if(!wl_call_tbl.libdecor_lib) { + printf("(libdecor not found, window will not have any decorations.)\n"); + } + WAYLAND_FUNC(wl_display_dispatch) WAYLAND_FUNC(wl_display_dispatch_pending) WAYLAND_FUNC(wl_display_disconnect) @@ -267,6 +300,28 @@ MwInline int wayland_load_funcs() { wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); #endif + if(wl_call_tbl.has_libdecor) { +#define LIBDECOR_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.libdecor_lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Can't use libdecor because libdecor-1 doesn't export " #x ".\n"); \ + wl_call_tbl.has_libdecor = MwFALSE; \ + }; + + LIBDECOR_FUNC(libdecor_new); + LIBDECOR_FUNC(libdecor_state_new); + LIBDECOR_FUNC(libdecor_frame_commit); + LIBDECOR_FUNC(libdecor_state_free); + LIBDECOR_FUNC(libdecor_decorate); + LIBDECOR_FUNC(libdecor_frame_set_app_id); + LIBDECOR_FUNC(libdecor_frame_set_title); + LIBDECOR_FUNC(libdecor_frame_map); + LIBDECOR_FUNC(libdecor_configuration_get_content_size); + LIBDECOR_FUNC(libdecor_configuration_get_window_state); + LIBDECOR_FUNC(libdecor_frame_get_xdg_surface); + LIBDECOR_FUNC(libdecor_dispatch); + } + return 0; } @@ -342,6 +397,8 @@ MwInline int wayland_load_funcs() { #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif +#include + typedef struct wayland_protocol { void* listener; void* context; @@ -495,6 +552,11 @@ struct _MwLLWayland { MwLLDBusContext dbus; #endif + struct libdecor* decor; + struct libdecor_frame* decor_frame; + struct libdecor_interface* decor_interface; + enum libdecor_window_state decor_state; + MwBool dark_theme_detection; MwU32 dark_theme; @@ -568,8 +630,6 @@ struct _MwLLWayland { cairo_surface_t* back_cs; cairo_t* front_cairo; cairo_t* back_cairo; - /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ - cairo_t* selected_cairo; }; struct _MwLLWaylandColor { @@ -610,10 +670,10 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ void MwLLWaylandFlush(MwLL handle); /* Standard procedure before event callbacks in Wayland */ -#define WAYLAND_EVENT_OP_START(self) pthread_mutex_lock(&self->wayland.eventsMutex); +#define WAYLAND_EVENT_OP_START(self) /* Footer for WAYLAND_EVENT_OP_START */ -#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); +#define WAYLAND_EVENT_OP_END(self) /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c index a37fd34..69c375c 100644 --- a/src/backend/wayland/buffer.c +++ b/src/backend/wayland/buffer.c @@ -12,7 +12,7 @@ void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); wl_surface_commit(wayland->framebuffer.surface); - MwLLWaylandHangUntilConfigured((MwLL)wayland); + // MwLLWaylandHangUntilConfigured((MwLL)wayland); MwLLWaylandBufferUpdate((MwLL)wayland, &wayland->framebuffer); }; void MwLLWaylandFramebufferDestroy(struct _MwLLWayland* wayland) { diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 8625c60..93d0686 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -201,6 +201,96 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { } } +/* shitdecor */ +static void libdecor_error(struct libdecor* context, + enum libdecor_error error, + const char* message) { + printf("libdecor error (%d): %s\n", error, message); +} + +static void +handle_configure(struct libdecor_frame* frame, + struct libdecor_configuration* configuration, + void* user_data) { + MwLL self = user_data; + int width, height; + enum libdecor_window_state window_state; + struct libdecor_state* state; + + if(!wl_call_tbl.libdecor_configuration_get_content_size(configuration, frame, + &width, &height)) { + width = self->wayland.ww; + height = self->wayland.wh; + } + + width = (width == 0) ? 1 : width; + height = (height == 0) ? 1 : height; + + // region_invalidate(self); + self->wayland.ww = width; + self->wayland.wh = height; + + if(self->wayland.resizing == 0) { + MwLLWaylandFramebufferDestroy(&self->wayland); + MwLLWaylandFramebufferSetup(&self->wayland); + MwLLWaylandRegionSetup(self); + MwLLDispatch(self, resize, NULL); + + recursive_dispatch_resize(self); + + if(self->wayland.pointer_constrained) { + zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, 0, CSD_BORDER_FRAME_TOP); + wl_surface_commit(self->wayland.framebuffer.surface); + } + + self->wayland.resizing = 1; + } + + MwLLDispatch(self, draw, NULL); + + if(!wl_call_tbl.libdecor_configuration_get_window_state(configuration, + &window_state)) + window_state = LIBDECOR_WINDOW_STATE_NONE; + + self->wayland.decor_state = window_state; + + state = wl_call_tbl.libdecor_state_new(width, height); + wl_call_tbl.libdecor_frame_commit(frame, state, configuration); + wl_call_tbl.libdecor_state_free(state); + + self->wayland.configured = MwTRUE; +} + +static void +handle_close(struct libdecor_frame* frame, + void* user_data) { + MwLL self = user_data; + MwLLDispatch(self, close, NULL); +} + +static void +handle_commit(struct libdecor_frame* frame, + void* user_data) { + MwLL self = user_data; + wl_surface_commit(self->wayland.framebuffer.surface); +} + +static void +handle_dismiss_popup(struct libdecor_frame* frame, + const char* seat_name, + void* user_data) { +} + +static struct libdecor_frame_interface libdecor_frame_iface = { + handle_configure, + handle_close, + handle_commit, + handle_dismiss_popup, +}; + +static struct libdecor_interface libdecor_interface = { + libdecor_error}; + /* Toplevel setup function */ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.type = MwLL_WAYLAND_TOPLEVEL; @@ -234,15 +324,14 @@ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); - /* 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); - wl_subsurface_set_desync(r->wayland.toplevel->ssurface); - r->wayland.toplevel->xdg_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); + if(r->wayland.has_decorations) { + r->wayland.toplevel->xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); + 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; @@ -250,16 +339,26 @@ static void setup_toplevel(MwLL r, int x, int y) { 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); + if(r->wayland.has_decorations) { + 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"); + xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko App"); + xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); + } else { + r->wayland.decor = wl_call_tbl.libdecor_new(r->wayland.display, &libdecor_interface); + r->wayland.decor_frame = wl_call_tbl.libdecor_decorate(r->wayland.decor, r->wayland.framebuffer.surface, + &libdecor_frame_iface, r); + wl_call_tbl.libdecor_frame_set_app_id(r->wayland.decor_frame, "milsko-app"); + wl_call_tbl.libdecor_frame_set_title(r->wayland.decor_frame, "Milsko App"); + wl_call_tbl.libdecor_frame_map(r->wayland.decor_frame); + } /* 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); + wl_surface_commit(r->wayland.backbuffer.surface); + while(!r->wayland.configured) { event_loop(r); } @@ -273,8 +372,6 @@ 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); - } else { - wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); } } @@ -406,6 +503,7 @@ struct xdg_popup_listener popup_listener = { /* Popup setup function */ static void setup_popup(MwLL r, int x, int y, MwLL parent) { struct xdg_surface* xdg_surface; + struct xdg_surface* parent_xdg_surface; MwLL topmost_parent = r->wayland.parent; r->wayland.type = MwLL_WAYLAND_POPUP; @@ -437,7 +535,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { /* check now if we have decorations so that everything else can act accordingly */ if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { - r->wayland.has_decorations = MwTRUE; + // r->wayland.has_decorations = MwTRUE; } r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; @@ -455,16 +553,20 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + if(r->wayland.has_decorations) { + parent_xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; + } else { + parent_xdg_surface = wl_call_tbl.libdecor_frame_get_xdg_surface(topmost_parent->wayland.decor_frame); + } + r->wayland.popup->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.popup->xdg_popup = xdg_surface_get_popup( r->wayland.popup->xdg_surface, - xdg_surface, + parent_xdg_surface, r->wayland.popup->xdg_positioner); - uint32_t ver = wl_proxy_get_version((struct wl_proxy*)r->wayland.popup->xdg_popup); - xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; @@ -783,7 +885,11 @@ static void actually_set_wh(MwLL handle) { MwLLWaylandRegionInvalidate(handle); 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.has_decorations) { + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + } else { + xdg_surface_set_window_geometry(wl_call_tbl.libdecor_frame_get_xdg_surface(handle->wayland.decor_frame), 0, 0, handle->wayland.ww, handle->wayland.wh); + } } if(handle->wayland.type == MwLL_WAYLAND_SUBLEVEL && handle->wayland.configured && !handle->wayland.dispatching_resize) { @@ -831,101 +937,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLBeginDrawImpl(MwLL handle) { - cairo_save(handle->wayland.front_cairo); - cairo_set_source_rgba(handle->wayland.front_cairo, 0, 0, 0, 0); - cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); - cairo_fill(handle->wayland.front_cairo); - cairo_restore(handle->wayland.front_cairo); - - if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { - handle->wayland.selected_cairo = handle->wayland.front_cairo; - return; - } - - if(!handle->wayland.has_decorations) { - int x; - 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; - cairo_set_line_width(handle->wayland.back_cairo, 4.0); - for(x = 0; x < w; x++) { - float placeholder = (float)x / (float)w; - cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25); - - cairo_move_to(handle->wayland.back_cairo, w - x, 0); - cairo_line_to(handle->wayland.back_cairo, w - x, CSD_BORDER_FRAME_TOP); - cairo_stroke(handle->wayland.back_cairo); - - cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP); - cairo_line_to(handle->wayland.back_cairo, x, h); - cairo_stroke(handle->wayland.back_cairo); - } - cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5); - cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, 0, h); - cairo_stroke(handle->wayland.back_cairo); - cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, w, 0); - cairo_stroke(handle->wayland.back_cairo); - - cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5); - cairo_move_to(handle->wayland.back_cairo, 0, h); - cairo_line_to(handle->wayland.back_cairo, w, h); - cairo_stroke(handle->wayland.back_cairo); - cairo_move_to(handle->wayland.back_cairo, w, 0); - cairo_line_to(handle->wayland.back_cairo, w, h); - cairo_stroke(handle->wayland.back_cairo); - - 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); - } - MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); - } - handle->wayland.selected_cairo = handle->wayland.front_cairo; } static void MwLLEndDrawImpl(MwLL handle) { @@ -1074,6 +1085,10 @@ static void MwLLNextEventImpl(MwLL handle) { } } + if(handle->wayland.decor) { + wl_call_tbl.libdecor_dispatch(handle->wayland.decor, 0); + } + if(handle->wayland.force_render) { MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); @@ -1086,7 +1101,11 @@ static void MwLLNextEventImpl(MwLL handle) { 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) { + xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); + } else { + wl_call_tbl.libdecor_frame_set_title(handle->wayland.decor_frame, title); + } } if(!handle->wayland.has_decorations) { strncpy(handle->wayland.title, title, 255); @@ -1143,7 +1162,6 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; - cairo_t* selected_cairo = handle->wayland.selected_cairo ? handle->wayland.selected_cairo : handle->wayland.front_cairo; if(rect->width <= 0 || rect->height <= 0 || pixmap->common.width <= 0 || pixmap->common.height <= 0) return; if(rect->width >= INT16_MAX) rect->width = INT16_MAX; @@ -1163,8 +1181,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_paint(c); - cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); - cairo_paint(selected_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); From 6e2b0ff0973327d197cb5e9436e15131aa183158 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 13:52:11 -0700 Subject: [PATCH 6/8] wayland: shitdecor fixes --- src/backend/wayland/wayland.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 93d0686..768b2e3 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -386,9 +386,10 @@ static void destroy_toplevel(MwLL r) { wl_compositor_destroy(r->wayland.compositor); - xdg_surface_destroy(r->wayland.toplevel->xdg_surface); - - xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + if(r->wayland.has_decorations) { + xdg_surface_destroy(r->wayland.toplevel->xdg_surface); + xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + } xkb_keymap_unref(r->wayland.xkb_keymap); @@ -1086,7 +1087,7 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.decor) { - wl_call_tbl.libdecor_dispatch(handle->wayland.decor, 0); + // wl_call_tbl.libdecor_dispatch(handle->wayland.decor, 0); } if(handle->wayland.force_render) { @@ -1329,8 +1330,10 @@ 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); + if(handle->wayland.has_decorations) { + 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); + } } } From 4c331ad2da15c260d045b2658bf4377b2796d282 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 13:53:32 -0700 Subject: [PATCH 7/8] wayland: undo the 'has_decorations' override --- src/backend/wayland/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 768b2e3..694fbaf 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -536,7 +536,7 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { /* check now if we have decorations so that everything else can act accordingly */ if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { - // r->wayland.has_decorations = MwTRUE; + r->wayland.has_decorations = MwTRUE; } r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; From 0181a61a3d0b007326852bf7080da2c31935e862 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 20 May 2026 13:56:20 -0700 Subject: [PATCH 8/8] add libdecor cflags to perl --- include/Mw/LowLevel/Wayland.h | 2 +- pl/ostype/Linux.pl | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 575c867..2053561 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -397,7 +397,7 @@ MwInline int wayland_load_funcs() { #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif -#include +#include typedef struct wayland_protocol { void* listener; diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 75159d5..3cfdf24 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -2,6 +2,7 @@ my @enabled_backends = (); if (param_get("wayland") && not(param_get("tiny"))) { push(@enabled_backends, "wayland"); + add_cflags(`pkg-config --cflags libdecor-0`); } if (param_get("x11")) { push(@enabled_backends, "x11"); @@ -9,6 +10,7 @@ if (param_get("x11")) { add_cflags("-DUSE_DBUS"); + use_backend(@enabled_backends); 1;