From 843cc74c4c01375e04d53330f4d45d8ea92e2a24 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sat, 29 Nov 2025 17:56:33 -0700 Subject: [PATCH 01/16] wayland backend init commit --- .gitignore | 3 + include/Mw/LowLevel.h | 16 +- include/Mw/LowLevel/Wayland.h | 84 +++++ include/Mw/LowLevel/Wayland/.gitignore | 1 + include/Mw/LowLevel/Wayland/README.md | 1 + pl/ostype/Linux.pl | 7 +- pl/rules.pl | 13 + pl/utils.pl | 17 + src/backend/.gitignore | 1 + src/backend/wayland.c | 437 +++++++++++++++++++++++++ src/backend/x11.c | 1 - src/core.c | 3 + 12 files changed, 581 insertions(+), 3 deletions(-) create mode 100644 include/Mw/LowLevel/Wayland.h create mode 100644 include/Mw/LowLevel/Wayland/.gitignore create mode 100644 include/Mw/LowLevel/Wayland/README.md create mode 100644 src/backend/.gitignore create mode 100644 src/backend/wayland.c diff --git a/.gitignore b/.gitignore index 7b0e56d33..814f7b348 100644 --- a/.gitignore +++ b/.gitignore @@ -3,8 +3,11 @@ examples/* examples/*.exe examples/*/* +examples/*/*.o examples/*/*.exe !examples/*/ !examples/*.* !examples/*/*.* compile_flags.txt +*.a +Makefile diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index cb9c1e66b..c3f7fe977 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -26,13 +26,15 @@ typedef void* MwLLPixmap; enum MwLLBackends { MwLLBackendX11 = 0, - MwLLBackendGDI + MwLLBackendGDI, + MwLLBackendWayland, }; struct _MwLLCommon { void* user; int copy_buffer; int type; + int success; MwLLHandler handler; }; @@ -56,6 +58,9 @@ struct _MwLLCommonPixmap { #ifdef USE_GDI #include #endif +#ifdef USE_WAYLAND +#include +#endif union _MwLL { struct _MwLLCommon common; @@ -65,6 +70,9 @@ union _MwLL { #ifdef USE_GDI struct _MwLLGDI gdi; #endif +#ifdef USE_WAYLAND + struct _MwLLWayland wayland; +#endif }; union _MwLLColor { @@ -75,6 +83,9 @@ union _MwLLColor { #ifdef USE_GDI struct _MwLLGDIColor gdi; #endif +#ifdef USE_WAYLAND + struct _MwLLWaylandColor wayland; +#endif }; union _MwLLPixmap { @@ -85,6 +96,9 @@ union _MwLLPixmap { #ifdef USE_GDI struct _MwLLGDIPixmap gdi; #endif +#ifdef USE_WAYLAND + struct _MwLLWaylandPixmap wayland; +#endif }; #endif #include diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h new file mode 100644 index 000000000..5fd1e7a87 --- /dev/null +++ b/include/Mw/LowLevel/Wayland.h @@ -0,0 +1,84 @@ +/* $Id$ */ +/*! + * @file Mw/LowLevel/Wayland.h + * @brief Wayland Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_WAYLAND_H__ +#define __MW_LOWLEVEL_WAYLAND_H__ + +#include +#include +#include + +#include +#include + +MWDECL int MwLLWaylandCallInit(void); + +#ifndef WL_PROTOCOLS_DEFINED +#define WL_PROTOCOLS_DEFINED +#include "Wayland/xdg-shell-client-protocol.h" +#include "Wayland/xdg-decoration-client-protocol.h" +#include "Wayland/cursor-shape-client-protocol.h" +#endif + +typedef struct wayland_protocol { + void* listener; + void* context; +} wayland_protocol_t; + +typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*); + +struct _MwLLWayland { + struct _MwLLCommon common; + + // struct wl_shm* shm; + struct wl_display* display; + struct wl_registry* registry; + // struct wl_compositor* compositor; + // struct wl_seat* seat; + struct wl_surface* surface; + struct xdg_surface* xdg_surface; + // struct xdg_wm_base* xdg_wm_base; + struct xdg_toplevel* xdg_top_level; + + struct wl_registry_listener registry_listener; + + // struct zxdg_decoration_manager_v1* decoration_manager; + // struct zxdg_toplevel_decoration_v1* toplevel_decoration; + + struct xdg_toplevel_listener xdg_toplevel_listener; + // struct xdg_wm_base_listener xdg_wm_base_listener; + struct xdg_surface_listener xdg_surface_listener; + // struct wl_pointer_listener pointer_listener; + // struct wl_seat_listener seat_listener; + // struct wl_keyboard_listener keyboard_listener; + // struct wl_shell_surface_listener shell_surface_listener; + // struct zxdg_toplevel_decoration_v1_listener decoration_listener; + + struct { + const char* key; + wl_setup_func* value; + }* wl_protocol_setup_map; + + struct { + const char* key; + wayland_protocol_t* value; + }* wl_protocol_map; + + struct xkb_context* xkb_context; + + MwBool configured; + MwBool running; +}; + +struct _MwLLWaylandColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLWaylandPixmap { + struct _MwLLCommonPixmap common; +}; + +#endif diff --git a/include/Mw/LowLevel/Wayland/.gitignore b/include/Mw/LowLevel/Wayland/.gitignore new file mode 100644 index 000000000..25a4663fa --- /dev/null +++ b/include/Mw/LowLevel/Wayland/.gitignore @@ -0,0 +1 @@ +*protocol.h diff --git a/include/Mw/LowLevel/Wayland/README.md b/include/Mw/LowLevel/Wayland/README.md new file mode 100644 index 000000000..e0c17e81f --- /dev/null +++ b/include/Mw/LowLevel/Wayland/README.md @@ -0,0 +1 @@ +Folder for wayland-scanner to place any of its files. diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 980b11975..f3befce02 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,4 +1,9 @@ # $Id$ -use_backend("x11"); + +if(system("wayland-scanner -v >/dev/null 2>&1") == 0){ + use_backend("wayland", "x11"); +} else { + use_backend("x11"); +} 1; diff --git a/pl/rules.pl b/pl/rules.pl index 90778b949..e1bd49997 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -27,6 +27,19 @@ if (grep(/^gdi$/, @backends)) { $gl_libs = "-lopengl32 -lglu32"; } +if (grep(/^wayland$/, @backends)) { + add_cflags("-DUSE_WAYLAND"); + new_object("src/backend/wayland.c"); + add_libs("-lwayland-client -lxkbcommon"); + + scan_wayland_protocol("stable", "xdg-shell",""); + scan_wayland_protocol("stable", "tablet","-v2"); + scan_wayland_protocol("staging", "cursor-shape","-v1"); + scan_wayland_protocol("unstable", "xdg-decoration","-unstable-v1"); + + $gl_libs = "-lGL -lGLU"; +} + if (param_get("stb-image")) { add_cflags("-DUSE_STB_IMAGE"); } diff --git a/pl/utils.pl b/pl/utils.pl index 218f50504..5887e74c8 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -55,6 +55,23 @@ sub use_backend { } } +sub scan_wayland_protocol { + my $tier = $_[0]; + my $proto = $_[1]; + my $ver = $_[2]; + + my $proto_c = "src/backend/wayland-${proto}-protocol.c"; + + if(system("wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c}") != 0) { + print("^ Error on getting private code for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n"); + } else { + new_object($proto_c); + }; + if(system("wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml include/Mw/LowLevel/Wayland/${proto}-client-protocol.h")) { + print("^ Error on getting client header for /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml\n"); + }; +} + our %params = (); sub param_set { diff --git a/src/backend/.gitignore b/src/backend/.gitignore new file mode 100644 index 000000000..137387c58 --- /dev/null +++ b/src/backend/.gitignore @@ -0,0 +1 @@ +wayland*protocol.c diff --git a/src/backend/wayland.c b/src/backend/wayland.c new file mode 100644 index 000000000..f9640378b --- /dev/null +++ b/src/backend/wayland.c @@ -0,0 +1,437 @@ +/* $Id$ */ + +/** + TODO: + + - would fit with Milsko's goal to support older compositors using wl_shell. would also suck to test because most compositors outright removed that around 2021... + + */ + +#include + +#include "../../external/stb_ds.h" + +#define WAYLAND_GET_INTERFACE(r, inter) shget(r->wayland.wl_protocol_map, inter##_interface.name) + +// REGISTRY +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) { + shput(wayland->wl_protocol_map, interface, func(name, data)); + } +}; + +static void protocol_removed(void* data, + struct wl_registry* registry, + MwU32 name) { + +}; + +// SEAT +static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; +static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, + uint32_t capabilities) {}; + +// XDG SHELL +void xdg_wm_base_ping(void* data, + struct xdg_wm_base* xdg_wm_base, + uint32_t serial) { + // 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); +}; + +// XDG SHELL SURFACE +static void wl_shell_surface_ping(void* data, + struct wl_shell_surface* wl_shell_surface, + uint32_t serial) {}; +static void wl_shell_surface_configure(void* data, + struct wl_shell_surface* wl_shell_surface, + uint32_t edges, + int32_t width, + int32_t height) {}; + +static void wl_shell_surface_popup_done(void* data, + struct wl_shell_surface* wl_shell_surface) {}; + +static wayland_protocol_t* wl_shm_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, &wl_shm_interface, 1); + return proto; +} +static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) { + 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; + + proto->context = wl_registry_bind(wayland->registry, name, &wl_seat_interface, 1); + wl_seat_add_listener(proto->context, proto->listener, wayland); + + return proto; +} +static wayland_protocol_t* wl_compositor_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, &wl_compositor_interface, 1); + + return proto; +} +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* wl_shell_surface_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + proto->listener = malloc(sizeof(struct wl_shell_surface_listener)); + + ((struct wl_shell_surface_listener*)proto->listener)->ping = wl_shell_surface_ping; + ((struct wl_shell_surface_listener*)proto->listener)->configure = wl_shell_surface_configure; + ((struct wl_shell_surface_listener*)proto->listener)->popup_done = wl_shell_surface_popup_done; + + proto->context = wl_registry_bind(wayland->registry, name, &wl_shell_surface_interface, 1); + wl_shell_surface_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; +} + +static void xdg_toplevel_configure(void* data, + struct xdg_toplevel* xdg_toplevel, + int32_t width, int32_t height, + struct wl_array* states) { + struct _MwLLWayland* self = (struct _MwLLWayland*)data; + + wl_surface_commit(self->surface); + + return; +}; + +static void decoration_configure( + void* data, struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, + uint32_t mode) { +} + +static void xdg_toplevel_close( + void* data, struct xdg_toplevel* xdg_toplevel) { + struct _MwLLWayland* self = (struct _MwLLWayland*)data; + // Stop running if the user requests to close the toplevel + self->running = MwFALSE; +}; + +static void xdg_surface_configure( + void* data, struct xdg_surface* xdg_surface, uint32_t serial) { + struct _MwLLWayland* self = (struct _MwLLWayland*)data; + + // The compositor configures our surface, acknowledge the configure event + xdg_surface_ack_configure(xdg_surface, serial); + + if(self->configured) { + // 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. + wl_surface_commit(self->surface); + } + + self->configured = MwTRUE; +} + +static void shell_surface_ping(void* data, + struct wl_shell_surface* shell_surface, + uint32_t serial) {}; +static void shell_surface_configure( + void* data, struct wl_shell_surface* shell_surface, uint32_t edges, + int32_t width, int32_t height) {}; + +static void shell_surface_popup_done( + void* data, struct wl_shell_surface* shell_surface) {}; + +static void setup_callbacks(struct _MwLLWayland* wayland) { + wayland->registry_listener.global = new_protocol; + wayland->registry_listener.global_remove = protocol_removed; + +#define WL_INTERFACE(interface) \ + shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); + + WL_INTERFACE(wl_shm); + WL_INTERFACE(wl_seat); + WL_INTERFACE(wl_compositor); + WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(wl_shell_surface); + WL_INTERFACE(zxdg_decoration_manager_v1); + WL_INTERFACE(wp_cursor_shape_manager_v1); +} + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + MwLLCreateCommon(r); + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendWayland; + + 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"); + r->common.success = MwFALSE; + return r; + } + + // Obtain the wl_registry and fetch the list of globals + 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"); + r->common.success = MwFALSE; + return r; + } + + // Check that all globals we require are available + if( + WAYLAND_GET_INTERFACE(r, wl_compositor)->context == NULL || + WAYLAND_GET_INTERFACE(r, xdg_wm_base)->context == NULL || + WAYLAND_GET_INTERFACE(r, wl_seat)->context == NULL) { + + printf("no wl_shm, wl_compositor, wl_seat, or xdg_wm_base support\n"); + r->common.success = MwFALSE; + return r; + } + + // wl_log_set_handler_client(_MwLLWayland::logger); + + r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + + // Create a wl_surface, a xdg_surface and a xdg_toplevel + r->wayland.surface = wl_compositor_create_surface(WAYLAND_GET_INTERFACE(r, wl_compositor)->context); + r->wayland.xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r, xdg_wm_base)->context, r->wayland.surface); + r->wayland.xdg_top_level = xdg_surface_get_toplevel(r->wayland.xdg_surface); + + // setup mandatory listeners + r->wayland.xdg_surface_listener.configure = xdg_surface_configure; + r->wayland.xdg_toplevel_listener.configure = xdg_toplevel_configure; + r->wayland.xdg_toplevel_listener.close = xdg_toplevel_close; + + xdg_surface_add_listener(r->wayland.xdg_surface, &r->wayland.xdg_surface_listener, r); + xdg_toplevel_add_listener(r->wayland.xdg_top_level, &r->wayland.xdg_toplevel_listener, + r); + + xdg_toplevel_set_title(r->wayland.xdg_top_level, "Milsko Wayland App"); + xdg_toplevel_set_app_id(r->wayland.xdg_top_level, "Milsko Wayland App"); + + // if (!mFlags.windowResizable) { + // xdg_toplevel_set_min_size(mXDGTopLevel, mWidth, mHeight); + // xdg_toplevel_set_max_size(mXDGTopLevel, mWidth, mHeight); + // } + + // Perform the initial commit and wait for the first configure event + wl_surface_commit(r->wayland.surface); + while(wl_display_dispatch(r->wayland.display) != -1 && !r->wayland.configured) { + } + + // setup decorations if we can + if(WAYLAND_GET_INTERFACE(r, zxdg_decoration_manager_v1)->context != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r, zxdg_decoration_manager_v1)->context; + + dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( + dec->manager, r->wayland.xdg_top_level); + + // zxdg_toplevel_decoration_v1_add_listener(dec->decoration, + // dec->listener, r); + + zxdg_toplevel_decoration_v1_set_mode( + dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } + + wl_surface_commit(r->wayland.surface); + + r->common.success = MwTRUE; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { +} + +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 MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + *x = 0; + *y = 0; + *w = 0; + *h = 0; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { +} + +static void MwLLFreeColorImpl(MwLLColor color) { +} + +static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { +} + +static int MwLLPendingImpl(MwLL handle) { + return 0; +} + +static void MwLLNextEventImpl(MwLL handle) { +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + MwLLPixmap r = malloc(sizeof(*r)); + + r->common.width = width; + r->common.height = height; + r->common.raw = data; + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { +} + +static void MwLLForceRenderImpl(MwLL handle) { +} + +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) { +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { +} + +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); diff --git a/src/backend/x11.c b/src/backend/x11.c index f75adfb95..a7bea2fd7 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1019,7 +1019,6 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static int MwLLX11CallInitImpl(void) { - /* TODO: check properly */ return 0; } diff --git a/src/core.c b/src/core.c index 77c6d9a40..6bb49798c 100644 --- a/src/core.c +++ b/src/core.c @@ -687,6 +687,9 @@ MwWidget MwGetParent(MwWidget handle) { typedef int (*call_t)(void); int MwLibraryInit(void) { call_t calls[] = { +#ifdef USE_WAYLAND + MwLLWaylandCallInit, +#endif #ifdef USE_X11 MwLLX11CallInit, #endif From 5a9a33e87395753e5b1c09c7c95ea3468050d779 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sat, 29 Nov 2025 20:52:56 -0700 Subject: [PATCH 02/16] wayland: we now have subsurfaces working --- .gitignore | 9 +- include/Mw/LowLevel/Wayland.h | 55 +++--- src/backend/wayland.c | 318 ++++++++++++++++++++++++++-------- 3 files changed, 275 insertions(+), 107 deletions(-) diff --git a/.gitignore b/.gitignore index 814f7b348..06c431e48 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,8 @@ *.o *.so -examples/* -examples/*.exe examples/*/* -examples/*/*.o -examples/*/*.exe -!examples/*/ -!examples/*.* -!examples/*/*.* +!examples/*/*.c +!examples/*/*.spv compile_flags.txt *.a Makefile diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 5fd1e7a87..da610b45e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -30,33 +30,41 @@ typedef struct wayland_protocol { typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*); +struct _MwLLWaylandTopLevel { + struct xdg_surface* xdg_surface; + struct xdg_toplevel* xdg_top_level; + struct xdg_toplevel_listener xdg_toplevel_listener; + struct xdg_surface_listener xdg_surface_listener; + + struct xkb_context* xkb_context; + + MwBool running; + MwBool compositor_created; + MwBool xdg_wm_base_created; + MwBool xdg_surface_created; +}; + struct _MwLLWayland { struct _MwLLCommon common; + union { + struct _MwLLWaylandTopLevel toplevel; + struct wl_subsurface* subsurface; + }; + enum { + MWLL_WAYLAND_TOPLEVEL = 0, + MWLL_WAYLAND_SUBSURFACE = 1, + } type; + MwU32 ww; + MwU32 wh; - // struct wl_shm* shm; - struct wl_display* display; - struct wl_registry* registry; - // struct wl_compositor* compositor; - // struct wl_seat* seat; - struct wl_surface* surface; - struct xdg_surface* xdg_surface; - // struct xdg_wm_base* xdg_wm_base; - struct xdg_toplevel* xdg_top_level; - + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_subcompositor* subcompositor; + struct wl_surface* surface; + struct wl_shm* shm; struct wl_registry_listener registry_listener; - // struct zxdg_decoration_manager_v1* decoration_manager; - // struct zxdg_toplevel_decoration_v1* toplevel_decoration; - - struct xdg_toplevel_listener xdg_toplevel_listener; - // struct xdg_wm_base_listener xdg_wm_base_listener; - struct xdg_surface_listener xdg_surface_listener; - // struct wl_pointer_listener pointer_listener; - // struct wl_seat_listener seat_listener; - // struct wl_keyboard_listener keyboard_listener; - // struct wl_shell_surface_listener shell_surface_listener; - // struct zxdg_toplevel_decoration_v1_listener decoration_listener; - struct { const char* key; wl_setup_func* value; @@ -67,10 +75,7 @@ struct _MwLLWayland { wayland_protocol_t* value; }* wl_protocol_map; - struct xkb_context* xkb_context; - MwBool configured; - MwBool running; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f9640378b..e8e735875 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -9,9 +9,13 @@ #include +#include +#include +#include + #include "../../external/stb_ds.h" -#define WAYLAND_GET_INTERFACE(r, inter) shget(r->wayland.wl_protocol_map, inter##_interface.name) +#define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) // REGISTRY static void new_protocol(void* data, struct wl_registry* registry, @@ -21,7 +25,10 @@ static void new_protocol(void* data, struct wl_registry* registry, wl_setup_func* func = shget(wayland->wl_protocol_setup_map, interface); if(func != NULL) { + // printf("registering interface %s\n", interface); shput(wayland->wl_protocol_map, interface, func(name, data)); + } else { + // printf("unknown interface %s\n", interface); } }; @@ -34,12 +41,12 @@ static void protocol_removed(void* data, // SEAT static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, - uint32_t capabilities) {}; + MwU32 capabilities) {}; // XDG SHELL void xdg_wm_base_ping(void* data, struct xdg_wm_base* xdg_wm_base, - uint32_t serial) { + MwU32 serial) { // 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); @@ -48,22 +55,76 @@ void xdg_wm_base_ping(void* data, // XDG SHELL SURFACE static void wl_shell_surface_ping(void* data, struct wl_shell_surface* wl_shell_surface, - uint32_t serial) {}; + MwU32 serial) {}; static void wl_shell_surface_configure(void* data, struct wl_shell_surface* wl_shell_surface, - uint32_t edges, - int32_t width, - int32_t height) {}; + MwU32 edges, + MwI32 width, + MwI32 height) {}; static void wl_shell_surface_popup_done(void* data, struct wl_shell_surface* wl_shell_surface) {}; static wayland_protocol_t* wl_shm_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, &wl_shm_interface, 1); - return proto; + wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + return NULL; } +static void buffer_setup(struct _MwLLWayland* wayland) { + struct wl_shm_pool* pool; + struct wl_buffer* buffer; + int x, y; + + int fd; + MwU32 size = wayland->ww * wayland->wh * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + + fd = mkstemp(temp_name); + + unlink(temp_name); + + if(posix_fallocate(fd, 0, size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(fd); + return; + } + if(ftruncate(fd, size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(fd); + return; + } + + for(y = 0; y < wayland->wh; y++) { + for(x = 0; x < wayland->ww; x++) { +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + MwU8 a = 0xFF; + MwU8 r = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); + MwU8 g = MIN((x * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); + MwU8 b = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, (y * 0xFF) / wayland->wh); + write(fd, &b, 1); + write(fd, &g, 1); + write(fd, &r, 1); + write(fd, &a, 1); +#undef MIN + } + } + + fsync(fd); + + if(!(pool = wl_shm_create_pool(wayland->shm, fd, size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + + buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, wayland->ww * 4, WL_SHM_FORMAT_ARGB8888); + + if(wayland->configured) { + wl_surface_attach(wayland->surface, buffer, 0, 0); + wl_surface_commit(wayland->surface); + } + + wl_buffer_destroy(buffer); + close(fd); +} + static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); proto->listener = malloc(sizeof(struct wl_seat_listener)); @@ -76,13 +137,19 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* waylan return proto; } -static wayland_protocol_t* wl_compositor_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, &wl_compositor_interface, 1); - return proto; +static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); + + return NULL; } + +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; +} + 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)); @@ -138,7 +205,7 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, - int32_t width, int32_t height, + MwI32 width, MwI32 height, struct wl_array* states) { struct _MwLLWayland* self = (struct _MwLLWayland*)data; @@ -149,18 +216,18 @@ static void xdg_toplevel_configure(void* data, static void decoration_configure( void* data, struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - uint32_t mode) { + MwU32 mode) { } static void xdg_toplevel_close( void* data, struct xdg_toplevel* xdg_toplevel) { struct _MwLLWayland* self = (struct _MwLLWayland*)data; // Stop running if the user requests to close the toplevel - self->running = MwFALSE; + self->toplevel.running = MwFALSE; }; static void xdg_surface_configure( - void* data, struct xdg_surface* xdg_surface, uint32_t serial) { + void* data, struct xdg_surface* xdg_surface, MwU32 serial) { struct _MwLLWayland* self = (struct _MwLLWayland*)data; // The compositor configures our surface, acknowledge the configure event @@ -170,45 +237,94 @@ static void xdg_surface_configure( // 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. + // wl_surface_attach(self->surface, self->buffer, 0, 0); wl_surface_commit(self->surface); } self->configured = MwTRUE; } -static void shell_surface_ping(void* data, - struct wl_shell_surface* shell_surface, - uint32_t serial) {}; -static void shell_surface_configure( - void* data, struct wl_shell_surface* shell_surface, uint32_t edges, - int32_t width, int32_t height) {}; - -static void shell_surface_popup_done( - void* data, struct wl_shell_surface* shell_surface) {}; +#define WL_INTERFACE(interface) \ + shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); static void setup_callbacks(struct _MwLLWayland* wayland) { wayland->registry_listener.global = new_protocol; wayland->registry_listener.global_remove = protocol_removed; -#define WL_INTERFACE(interface) \ - shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); - WL_INTERFACE(wl_shm); - WL_INTERFACE(wl_seat); WL_INTERFACE(wl_compositor); - WL_INTERFACE(xdg_wm_base); - WL_INTERFACE(wl_shell_surface); - WL_INTERFACE(zxdg_decoration_manager_v1); - WL_INTERFACE(wp_cursor_shape_manager_v1); + WL_INTERFACE(wl_subcompositor); + if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { + WL_INTERFACE(wl_seat); + WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(wl_shell_surface); + WL_INTERFACE(zxdg_decoration_manager_v1); + WL_INTERFACE(wp_cursor_shape_manager_v1); + } } -static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - r = malloc(sizeof(*r)); - MwLLCreateCommon(r); +#undef WL_INTERFACE - r->common.copy_buffer = 1; - r->common.type = MwLLBackendWayland; +static MwBool flush_display(struct wl_display* display) { + while(wl_display_flush(display) == -1) { + if(errno != EAGAIN) { + return MwFALSE; + } + + struct pollfd fd = {wl_display_get_fd(display), POLL_OUT}; + + while(poll(&fd, 1, -1) == -1) { + if(errno != EINTR && errno != EAGAIN) + return MwFALSE; + } + } + return MwTRUE; +} + +static void event_loop(MwLL handle) { + enum { + DISPLAY_FD, + KEYREPEAT_FD, + CURSOR_FD, + LIBDECOR_FD + }; + if(handle->wayland.display == NULL) { + return; + } + struct pollfd fd = {wl_display_get_fd(handle->wayland.display), POLLIN}; + int timeout = 500; + + while(wl_display_prepare_read(handle->wayland.display) != 0) { + if(wl_display_dispatch_pending(handle->wayland.display) > 0) { + return; + } + } + + // If an error other than EAGAIN happens, we have likely been disconnected + // from the Wayland session + if(!flush_display(handle->wayland.display)) { + wl_display_cancel_read(handle->wayland.display); + + handle->wayland.toplevel.running = MwFALSE; + return; + } + + if(!poll(&fd, 1, timeout)) { + wl_display_cancel_read(handle->wayland.display); + return; + } + + if(fd.revents & POLLIN) { + wl_display_read_events(handle->wayland.display); + if(wl_display_dispatch_pending(handle->wayland.display) > 0) { + } + } else { + wl_display_cancel_read(handle->wayland.display); + } +} + +static void setup_toplevel(MwLL r, int x, int y, int width, int height) { + r->wayland.type = MWLL_WAYLAND_TOPLEVEL; setup_callbacks(&r->wayland); @@ -217,55 +333,48 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(r->wayland.display == NULL) { printf("wayland: failed to create display\n"); r->common.success = MwFALSE; - return r; + return; } - // Obtain the wl_registry and fetch the list of globals + // Do a roundtrip to ensure all interfaces are setup. r->wayland.registry = wl_display_get_registry(r->wayland.display); wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); if(wl_display_roundtrip(r->wayland.display) == -1) { printf("roundtrip failed\n"); r->common.success = MwFALSE; - return r; + return; } // Check that all globals we require are available if( - WAYLAND_GET_INTERFACE(r, wl_compositor)->context == NULL || - WAYLAND_GET_INTERFACE(r, xdg_wm_base)->context == NULL || - WAYLAND_GET_INTERFACE(r, wl_seat)->context == NULL) { + r->wayland.compositor == NULL || + WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context == NULL || + WAYLAND_GET_INTERFACE(r->wayland, wl_seat)->context == NULL) { printf("no wl_shm, wl_compositor, wl_seat, or xdg_wm_base support\n"); r->common.success = MwFALSE; - return r; + return; } - // wl_log_set_handler_client(_MwLLWayland::logger); - - r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + r->wayland.toplevel.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); // Create a wl_surface, a xdg_surface and a xdg_toplevel - r->wayland.surface = wl_compositor_create_surface(WAYLAND_GET_INTERFACE(r, wl_compositor)->context); - r->wayland.xdg_surface = - xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r, xdg_wm_base)->context, r->wayland.surface); - r->wayland.xdg_top_level = xdg_surface_get_toplevel(r->wayland.xdg_surface); + r->wayland.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.toplevel.xdg_surface = + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.surface); + r->wayland.toplevel.xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel.xdg_surface); // setup mandatory listeners - r->wayland.xdg_surface_listener.configure = xdg_surface_configure; - r->wayland.xdg_toplevel_listener.configure = xdg_toplevel_configure; - r->wayland.xdg_toplevel_listener.close = xdg_toplevel_close; + r->wayland.toplevel.xdg_surface_listener.configure = xdg_surface_configure; + r->wayland.toplevel.xdg_toplevel_listener.configure = xdg_toplevel_configure; + r->wayland.toplevel.xdg_toplevel_listener.close = xdg_toplevel_close; - xdg_surface_add_listener(r->wayland.xdg_surface, &r->wayland.xdg_surface_listener, r); - xdg_toplevel_add_listener(r->wayland.xdg_top_level, &r->wayland.xdg_toplevel_listener, + 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.xdg_top_level, "Milsko Wayland App"); - xdg_toplevel_set_app_id(r->wayland.xdg_top_level, "Milsko Wayland App"); - - // if (!mFlags.windowResizable) { - // xdg_toplevel_set_min_size(mXDGTopLevel, mWidth, mHeight); - // xdg_toplevel_set_max_size(mXDGTopLevel, mWidth, mHeight); - // } + xdg_toplevel_set_title(r->wayland.toplevel.xdg_top_level, "Milsko Wayland App"); + 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.surface); @@ -273,23 +382,76 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } // setup decorations if we can - if(WAYLAND_GET_INTERFACE(r, zxdg_decoration_manager_v1)->context != NULL) { - zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r, zxdg_decoration_manager_v1)->context; + if(WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context != NULL) { + zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - dec->manager, r->wayland.xdg_top_level); - - // zxdg_toplevel_decoration_v1_add_listener(dec->decoration, - // dec->listener, r); + dec->manager, r->wayland.toplevel.xdg_top_level); zxdg_toplevel_decoration_v1_set_mode( dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + } else { + printf("zxdg null\n"); } + buffer_setup(&r->wayland); + wl_surface_commit(r->wayland.surface); +} + +static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int height) { + struct wl_compositor* compositor = parent->wayland.compositor; + struct wl_subcompositor* subcompositor = parent->wayland.subcompositor; + struct wl_surface* parent_surface = parent->wayland.surface; + + r->wayland.type = MWLL_WAYLAND_SUBSURFACE; + + setup_callbacks(&r->wayland); + + r->wayland.registry = wl_display_get_registry(parent->wayland.display); + r->wayland.display = parent->wayland.display; + + wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); + if(wl_display_roundtrip(r->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + r->wayland.display = parent->wayland.display; + + r->wayland.surface = wl_compositor_create_surface(compositor); + + 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); + + r->wayland.configured = MwTRUE; + + buffer_setup(&r->wayland); + + wl_surface_commit(parent->wayland.surface); +} +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + MwLLCreateCommon(r); + + r->common.copy_buffer = 1; + r->common.type = MwLLBackendWayland; + + r->wayland.ww = width; + r->wayland.wh = height; r->common.success = MwTRUE; + if(parent == NULL) { + setup_toplevel(r, x, y, width, height); + } else { + setup_subsurface(parent, r, x, y, width, height); + } + return r; } @@ -341,13 +503,18 @@ static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { + event_loop(handle); return 0; } static void MwLLNextEventImpl(MwLL handle) { + event_loop(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); + } } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { @@ -373,6 +540,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { + // event_loop(handle); } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { From 43b0b86a0f9fb4abb2e9169c17055116252bc737 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sat, 29 Nov 2025 21:04:01 -0700 Subject: [PATCH 03/16] changed my mind, removing wl_shell stuff makes the resulting library smaller and i don't actually feel like supporting a feature that's been obsolete since 2013 --- src/backend/wayland.c | 37 ------------------------------------- 1 file changed, 37 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index e8e735875..656ed764d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,12 +1,5 @@ /* $Id$ */ -/** - TODO: - - - would fit with Milsko's goal to support older compositors using wl_shell. would also suck to test because most compositors outright removed that around 2021... - - */ - #include #include @@ -17,7 +10,6 @@ #define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) -// REGISTRY static void new_protocol(void* data, struct wl_registry* registry, MwU32 name, const char* interface, MwU32 version) { @@ -38,12 +30,10 @@ static void protocol_removed(void* data, }; -// SEAT static void wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) {}; -// XDG SHELL void xdg_wm_base_ping(void* data, struct xdg_wm_base* xdg_wm_base, MwU32 serial) { @@ -52,19 +42,6 @@ void xdg_wm_base_ping(void* data, xdg_wm_base_pong(xdg_wm_base, serial); }; -// XDG SHELL SURFACE -static void wl_shell_surface_ping(void* data, - struct wl_shell_surface* wl_shell_surface, - MwU32 serial) {}; -static void wl_shell_surface_configure(void* data, - struct wl_shell_surface* wl_shell_surface, - MwU32 edges, - MwI32 width, - MwI32 height) {}; - -static void wl_shell_surface_popup_done(void* data, - struct wl_shell_surface* wl_shell_surface) {}; - static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); return NULL; @@ -161,19 +138,6 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa return proto; } -static wayland_protocol_t* wl_shell_surface_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - proto->listener = malloc(sizeof(struct wl_shell_surface_listener)); - - ((struct wl_shell_surface_listener*)proto->listener)->ping = wl_shell_surface_ping; - ((struct wl_shell_surface_listener*)proto->listener)->configure = wl_shell_surface_configure; - ((struct wl_shell_surface_listener*)proto->listener)->popup_done = wl_shell_surface_popup_done; - - proto->context = wl_registry_bind(wayland->registry, name, &wl_shell_surface_interface, 1); - wl_shell_surface_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)); @@ -257,7 +221,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(wl_seat); WL_INTERFACE(xdg_wm_base); - WL_INTERFACE(wl_shell_surface); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(wp_cursor_shape_manager_v1); } From b2ea14c3540b7def64d911d7bf50fb6c3f77afee Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 1 Dec 2025 11:45:55 -0700 Subject: [PATCH 04/16] handle resizing, turn _MwLLWaylandToplevel into a pointer --- include/Mw/LowLevel/Wayland.h | 7 +- src/backend/wayland.c | 135 ++++++++++++++++++++++------------ 2 files changed, 89 insertions(+), 53 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index da610b45e..843c60449 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -47,15 +47,13 @@ struct _MwLLWaylandTopLevel { struct _MwLLWayland { struct _MwLLCommon common; union { - struct _MwLLWaylandTopLevel toplevel; - struct wl_subsurface* subsurface; + struct _MwLLWaylandTopLevel* toplevel; + struct wl_subsurface* subsurface; }; enum { MWLL_WAYLAND_TOPLEVEL = 0, MWLL_WAYLAND_SUBSURFACE = 1, } type; - MwU32 ww; - MwU32 wh; struct wl_display* display; struct wl_registry* registry; @@ -76,6 +74,7 @@ struct _MwLLWayland { }* wl_protocol_map; MwBool configured; + MwU32 x, y, ww, wh; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 656ed764d..17df5cfe2 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,8 +5,14 @@ #include #include #include +#include +#include +#include +#include #include "../../external/stb_ds.h" +#include "Mw/LowLevel.h" +#include "Mw/LowLevel/Wayland/xdg-shell-client-protocol.h" #define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) @@ -54,6 +60,8 @@ static void buffer_setup(struct _MwLLWayland* wayland) { int fd; MwU32 size = wayland->ww * wayland->wh * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + void* map; + MwU8 data = 0xFF; fd = mkstemp(temp_name); @@ -70,20 +78,23 @@ static void buffer_setup(struct _MwLLWayland* wayland) { return; } - for(y = 0; y < wayland->wh; y++) { - for(x = 0; x < wayland->ww; x++) { -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - MwU8 a = 0xFF; - MwU8 r = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); - MwU8 g = MIN((x * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); - MwU8 b = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, (y * 0xFF) / wayland->wh); - write(fd, &b, 1); - write(fd, &g, 1); - write(fd, &r, 1); - write(fd, &a, 1); -#undef MIN - } - } + map = mmap(NULL, wayland->wh * wayland->ww * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + memset(map, 0xFF, wayland->wh * wayland->ww * 4); + + // for(y = 0; y < wayland->wh; y++) { + // for(x = 0; x < wayland->ww; x++) { + // #define MIN(a, b) (((a) < (b)) ? (a) : (b)) + // MwU8 a = 0xFF; + // MwU8 r = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); + // MwU8 g = MIN((x * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); + // MwU8 b = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, (y * 0xFF) / wayland->wh); + // write(fd, &b, 1); + // write(fd, &g, 1); + // write(fd, &r, 1); + // write(fd, &a, 1); + // #undef MIN + // } + // } fsync(fd); @@ -171,9 +182,17 @@ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, struct wl_array* states) { - struct _MwLLWayland* self = (struct _MwLLWayland*)data; + MwLL self = data; - wl_surface_commit(self->surface); + if(width != 0 && height != 0) { + self->wayland.ww = width; + self->wayland.wh = height; + MwLLDispatch(self, resize, NULL); + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); + buffer_setup(&self->wayland); + }; + + wl_surface_commit(self->wayland.surface); return; }; @@ -185,27 +204,28 @@ static void decoration_configure( static void xdg_toplevel_close( void* data, struct xdg_toplevel* xdg_toplevel) { - struct _MwLLWayland* self = (struct _MwLLWayland*)data; + MwLL self = data; + // Stop running if the user requests to close the toplevel - self->toplevel.running = MwFALSE; + self->wayland.toplevel->running = MwFALSE; }; static void xdg_surface_configure( void* data, struct xdg_surface* xdg_surface, MwU32 serial) { - struct _MwLLWayland* self = (struct _MwLLWayland*)data; + MwLL self = data; // The compositor configures our surface, acknowledge the configure event xdg_surface_ack_configure(xdg_surface, serial); - if(self->configured) { + if(self->wayland.configured) { // 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. // wl_surface_attach(self->surface, self->buffer, 0, 0); - wl_surface_commit(self->surface); + wl_surface_commit(self->wayland.surface); } - self->configured = MwTRUE; + self->wayland.configured = MwTRUE; } #define WL_INTERFACE(interface) \ @@ -268,7 +288,7 @@ static void event_loop(MwLL handle) { if(!flush_display(handle->wayland.display)) { wl_display_cancel_read(handle->wayland.display); - handle->wayland.toplevel.running = MwFALSE; + handle->wayland.toplevel->running = MwFALSE; return; } @@ -287,7 +307,8 @@ static void event_loop(MwLL handle) { } static void setup_toplevel(MwLL r, int x, int y, int width, int height) { - r->wayland.type = MWLL_WAYLAND_TOPLEVEL; + r->wayland.type = MWLL_WAYLAND_TOPLEVEL; + r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); setup_callbacks(&r->wayland); @@ -319,25 +340,25 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { return; } - r->wayland.toplevel.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + r->wayland.toplevel->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); // Create a wl_surface, a xdg_surface and a xdg_toplevel r->wayland.surface = wl_compositor_create_surface(r->wayland.compositor); - r->wayland.toplevel.xdg_surface = + r->wayland.toplevel->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.surface); - r->wayland.toplevel.xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel.xdg_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; - r->wayland.toplevel.xdg_toplevel_listener.configure = xdg_toplevel_configure; - r->wayland.toplevel.xdg_toplevel_listener.close = xdg_toplevel_close; + r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; + r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; - xdg_surface_add_listener(r->wayland.toplevel.xdg_surface, &r->wayland.toplevel.xdg_surface_listener, r); - xdg_toplevel_add_listener(r->wayland.toplevel.xdg_top_level, &r->wayland.toplevel.xdg_toplevel_listener, + 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 Wayland App"); - xdg_toplevel_set_app_id(r->wayland.toplevel.xdg_top_level, "MilskoWaylandApp"); + xdg_toplevel_set_title(r->wayland.toplevel->xdg_top_level, "Milsko Wayland App"); + 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.surface); @@ -349,7 +370,7 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( - dec->manager, r->wayland.toplevel.xdg_top_level); + dec->manager, r->wayland.toplevel->xdg_top_level); zxdg_toplevel_decoration_v1_set_mode( dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); @@ -424,6 +445,35 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { + *x = handle->wayland.x; + *y = handle->wayland.y; + *w = handle->wayland.ww; + *h = handle->wayland.wh; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + handle->wayland.x = x; + handle->wayland.y = y; + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + } else { + wl_subsurface_set_position(handle->wayland.subsurface, x, y); + } +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + handle->wayland.ww = w; + handle->wayland.wh = h; + + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + } else { + // setup the buffer again with the new size. + buffer_setup(&handle->wayland); + } +} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { } @@ -446,19 +496,6 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { c->common.green = g; } -static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { - *x = 0; - *y = 0; - *w = 0; - *h = 0; -} - -static void MwLLSetXYImpl(MwLL handle, int x, int y) { -} - -static void MwLLSetWHImpl(MwLL handle, int w, int h) { -} - static void MwLLFreeColorImpl(MwLLColor color) { } @@ -476,7 +513,7 @@ 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); + xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); } } From 5ad21381c5def03b3f558055be7260b9dc178f08 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 1 Dec 2025 14:19:07 -0700 Subject: [PATCH 05/16] more wayland impls --- src/backend/wayland.c | 80 +++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 33 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 17df5cfe2..18d4a18fe 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2,17 +2,19 @@ #include +#include #include #include #include +#include #include +#include #include -#include #include #include "../../external/stb_ds.h" -#include "Mw/LowLevel.h" -#include "Mw/LowLevel/Wayland/xdg-shell-client-protocol.h" + +#include #define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) @@ -61,7 +63,6 @@ static void buffer_setup(struct _MwLLWayland* wayland) { MwU32 size = wayland->ww * wayland->wh * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; void* map; - MwU8 data = 0xFF; fd = mkstemp(temp_name); @@ -78,23 +79,9 @@ static void buffer_setup(struct _MwLLWayland* wayland) { return; } - map = mmap(NULL, wayland->wh * wayland->ww * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - memset(map, 0xFF, wayland->wh * wayland->ww * 4); - - // for(y = 0; y < wayland->wh; y++) { - // for(x = 0; x < wayland->ww; x++) { - // #define MIN(a, b) (((a) < (b)) ? (a) : (b)) - // MwU8 a = 0xFF; - // MwU8 r = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); - // MwU8 g = MIN((x * 0xFF) / wayland->ww, ((wayland->wh - y) * 0xFF) / wayland->wh); - // MwU8 b = MIN(((wayland->ww - x) * 0xFF) / wayland->ww, (y * 0xFF) / wayland->wh); - // write(fd, &b, 1); - // write(fd, &g, 1); - // write(fd, &r, 1); - // write(fd, &a, 1); - // #undef MIN - // } - // } + lseek(fd, 0, SEEK_SET); + map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); + memset(map, 0xFF, size); fsync(fd); @@ -108,8 +95,8 @@ static void buffer_setup(struct _MwLLWayland* wayland) { wl_surface_attach(wayland->surface, buffer, 0, 0); wl_surface_commit(wayland->surface); } - wl_buffer_destroy(buffer); + wl_shm_pool_destroy(pool); close(fd); } @@ -187,9 +174,9 @@ static void xdg_toplevel_configure(void* data, if(width != 0 && height != 0) { self->wayland.ww = width; self->wayland.wh = height; - MwLLDispatch(self, resize, NULL); xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); - buffer_setup(&self->wayland); + + MwLLDispatch(self, resize, NULL); }; wl_surface_commit(self->wayland.surface); @@ -234,6 +221,8 @@ static void xdg_surface_configure( static void setup_callbacks(struct _MwLLWayland* wayland) { wayland->registry_listener.global = new_protocol; wayland->registry_listener.global_remove = protocol_removed; + wayland->wl_protocol_setup_map = NULL; + wayland->wl_protocol_map = NULL; WL_INTERFACE(wl_shm); WL_INTERFACE(wl_compositor); @@ -390,6 +379,16 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h r->wayland.type = MWLL_WAYLAND_SUBSURFACE; + r->wayland.display = parent->wayland.display; + + r->wayland.surface = wl_compositor_create_surface(compositor); + + 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); + setup_callbacks(&r->wayland); r->wayland.registry = wl_display_get_registry(parent->wayland.display); @@ -401,15 +400,6 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h raise(SIGTRAP); return; } - r->wayland.display = parent->wayland.display; - - r->wayland.surface = wl_compositor_create_surface(compositor); - - 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); r->wayland.configured = MwTRUE; @@ -425,6 +415,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.copy_buffer = 1; r->common.type = MwLLBackendWayland; + if(width == 0) width = parent->wayland.ww; + if(height == 0) height = parent->wayland.wh; + r->wayland.ww = width; r->wayland.wh = height; @@ -497,6 +490,7 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { } static void MwLLFreeColorImpl(MwLLColor color) { + free(color); } static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { @@ -541,6 +535,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { static void MwLLForceRenderImpl(MwLL handle) { // event_loop(handle); + wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + wl_surface_commit(handle->wayland.surface); } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { @@ -556,9 +552,27 @@ static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + xdg_toplevel_set_min_size(handle->wayland.toplevel->xdg_top_level, minx, miny); + xdg_toplevel_set_max_size(handle->wayland.toplevel->xdg_top_level, maxx, maxy); + } } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->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"); + } + } } static void MwLLFocusImpl(MwLL handle) { From 37fe636c75528c7c47bef44d507eaf385524430e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 1 Dec 2025 19:12:49 -0700 Subject: [PATCH 06/16] more wayland work --- examples/basic/rotate.c | 6 +- include/Mw/LowLevel.h | 2 - include/Mw/LowLevel/Wayland.h | 5 + src/backend/call.c | 2 - src/backend/gdi.c | 5 - src/backend/wayland.c | 193 ++++++++++++++++++++++++---------- src/backend/x11.c | 4 - src/core.c | 10 +- src/draw.c | 1 + src/lowlevel.c | 2 - 10 files changed, 152 insertions(+), 78 deletions(-) diff --git a/examples/basic/rotate.c b/examples/basic/rotate.c index c3b85d739..835993dc5 100644 --- a/examples/basic/rotate.c +++ b/examples/basic/rotate.c @@ -56,13 +56,13 @@ void resize(MwWidget w, void* user, void* client) { int main() { MwWidget window; - int i; + int i; MwLibraryInit(); window = MwVaCreateWidget(MwWindowClass, "window", NULL, MwDEFAULT, MwDEFAULT, (ww = 500), (wh = 500), - MwNtitle, "rotate", - NULL); + MwNtitle, "rotate", + NULL); for(i = 0; i < (int)(sizeof(buttons) / sizeof(buttons[0])); i++) { const char* color = ""; diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index c3f7fe977..49c1cc7fe 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -198,8 +198,6 @@ MWDECL void (*MwLLMakePopup)(MwLL handle, MwLL parent); MWDECL void (*MwLLBeginStateChange)(MwLL handle); MWDECL void (*MwLLEndStateChange)(MwLL handle); -MWDECL void (*MwLLSetBackground)(MwLL handle, MwLLColor color); - MWDECL void (*MwLLFocus)(MwLL handle); MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 843c60449..c502a533a 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -7,6 +7,7 @@ #ifndef __MW_LOWLEVEL_WAYLAND_H__ #define __MW_LOWLEVEL_WAYLAND_H__ +#include "Mw/BaseTypes.h" #include #include #include @@ -63,6 +64,9 @@ struct _MwLLWayland { struct wl_shm* shm; struct wl_registry_listener registry_listener; + MwU8* mapped_buffer; + int mapped_buffer_size; + struct { const char* key; wl_setup_func* value; @@ -74,6 +78,7 @@ struct _MwLLWayland { }* wl_protocol_map; MwBool configured; + MwBool force_redraw; MwU32 x, y, ww, wh; }; diff --git a/src/backend/call.c b/src/backend/call.c index bace30c1b..de4b7f085 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -44,8 +44,6 @@ \ MwLLBeginStateChange = MwLLBeginStateChangeImpl; \ MwLLEndStateChange = MwLLEndStateChangeImpl; \ -\ - MwLLSetBackground = MwLLSetBackgroundImpl; \ \ MwLLFocus = MwLLFocusImpl; \ MwLLGrabPointer = MwLLGrabPointerImpl; \ diff --git a/src/backend/gdi.c b/src/backend/gdi.c index f466dfd17..d366d6b18 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -342,11 +342,6 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { - (void)handle; - (void)color; -} - static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { RECT rc; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 18d4a18fe..d14cada54 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -13,6 +13,8 @@ #include #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include @@ -62,7 +64,6 @@ static void buffer_setup(struct _MwLLWayland* wayland) { int fd; MwU32 size = wayland->ww * wayland->wh * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - void* map; fd = mkstemp(temp_name); @@ -80,8 +81,9 @@ static void buffer_setup(struct _MwLLWayland* wayland) { } lseek(fd, 0, SEEK_SET); - map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); - memset(map, 0xFF, size); + wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); + memset(wayland->mapped_buffer, 0xFF, size); + wayland->mapped_buffer_size = size; fsync(fd); @@ -176,10 +178,11 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); + MwLLSetWH(self, width, height); MwLLDispatch(self, resize, NULL); }; - wl_surface_commit(self->wayland.surface); + MwLLForceRender(self); return; }; @@ -253,48 +256,6 @@ static MwBool flush_display(struct wl_display* display) { return MwTRUE; } -static void event_loop(MwLL handle) { - enum { - DISPLAY_FD, - KEYREPEAT_FD, - CURSOR_FD, - LIBDECOR_FD - }; - if(handle->wayland.display == NULL) { - return; - } - struct pollfd fd = {wl_display_get_fd(handle->wayland.display), POLLIN}; - int timeout = 500; - - while(wl_display_prepare_read(handle->wayland.display) != 0) { - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - return; - } - } - - // If an error other than EAGAIN happens, we have likely been disconnected - // from the Wayland session - if(!flush_display(handle->wayland.display)) { - wl_display_cancel_read(handle->wayland.display); - - handle->wayland.toplevel->running = MwFALSE; - return; - } - - if(!poll(&fd, 1, timeout)) { - wl_display_cancel_read(handle->wayland.display); - return; - } - - if(fd.revents & POLLIN) { - wl_display_read_events(handle->wayland.display); - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - } - } else { - wl_display_cancel_read(handle->wayland.display); - } -} - static void setup_toplevel(MwLL r, int x, int y, int width, int height) { r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); @@ -412,8 +373,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r = malloc(sizeof(*r)); MwLLCreateCommon(r); - r->common.copy_buffer = 1; - r->common.type = MwLLBackendWayland; + // r->common.copy_buffer = 1; + r->common.type = MwLLBackendWayland; if(width == 0) width = parent->wayland.ww; if(height == 0) height = parent->wayland.wh; @@ -467,10 +428,76 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } } +// fractional part of x +static float fpart(float x) { + return x - floor(x); +} +static float rfpart(float x) { + return x - fpart(x); +} + +#define IMAGE_POS_GET(x, y, o) handle->wayland.mapped_buffer[(((y * handle->wayland.ww) + x) * 4) + o] + +#define IMAGE_POS_SET(x, y, o, v) IMAGE_POS_GET(x, y, o) = v; +#define IMAGE_PLOT(x, y, color) \ + IMAGE_POS_SET(x, y, 0, color->common.blue); \ + IMAGE_POS_SET(x, y, 1, color->common.green); \ + IMAGE_POS_SET(x, y, 2, color->common.red); \ + IMAGE_POS_SET(x, y, 3, 255); + +static void +line_draw(MwLL handle, int x0, int y0, int x1, int y1, MwLLColor color) { + int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; + int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; + int err = dx + dy, e2; + + for(;;) { + IMAGE_PLOT(x0, y0, color); + if(x0 == x1 && y0 == y1) break; + e2 = 2 * err; + if(e2 >= dy) { + err += dy; + x0 += sx; + } + if(e2 <= dx) { + err += dx; + y0 += sy; + } + } +} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; + int lx = 65536, ly = 65536; + int hx = 0, hy = 0; + int x, y; + + for(i = 0; i < points_count - 1; i++) { + MwPoint p1 = points[i]; + MwPoint p2 = points[i + 1]; + if(p1.x < lx) lx = p1.x; + if(p1.y < ly) ly = p1.y; + if(p1.x > hx) hx = p1.x; + if(p1.y > hy) hy = p1.y; + } + // for(y = ly; y < hy; y++) { + // for(x = lx; x < hx; x++) { + // IMAGE_PLOT(x, y, color); + // } + // } + for(i = 0; i < points_count - 1; i++) { + MwPoint p1 = points[i]; + MwPoint p2 = points[i + 1]; + + line_draw(handle, p1.x, p1.y, p2.x, p2.y, color); + } } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MwPoint p1 = points[0]; + MwPoint p2 = points[1]; + + line_draw(handle, p1.x, p1.y, p2.x, p2.y, color); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -493,16 +520,73 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { -} - static int MwLLPendingImpl(MwLL handle) { - event_loop(handle); - return 0; + enum { + DISPLAY_FD, + KEYREPEAT_FD, + CURSOR_FD + }; + struct pollfd fd; + int timeout = 1; + + if(handle->wayland.force_redraw) { + return 1; + } + + if(handle->wayland.display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(handle->wayland.display); + fd.events = POLLIN; + + while(wl_display_prepare_read(handle->wayland.display) != 0) { + if(wl_display_dispatch_pending(handle->wayland.display) > 0) { + return 0; + } + } + + // If an error other than EAGAIN happens, we have likely been disconnected + // from the Wayland session + if(!flush_display(handle->wayland.display)) { + wl_display_cancel_read(handle->wayland.display); + + handle->wayland.toplevel->running = MwFALSE; + return 0; + } + + // Condition where no events are being sent. + if(!poll(&fd, 1, timeout)) { + wl_display_cancel_read(handle->wayland.display); + // In this case, we need to commit the surface for any animations, etc. + wl_surface_commit(handle->wayland.surface); + return 0; + } + + if(fd.revents & POLLIN) { + wl_display_read_events(handle->wayland.display); + if(wl_display_dispatch_pending(handle->wayland.display) > 0) { + } + } else { + wl_display_cancel_read(handle->wayland.display); + } + + return 1; } static void MwLLNextEventImpl(MwLL handle) { - event_loop(handle); + MwBool render; + + render = handle->wayland.force_redraw; + + if(render) { + int x, y; + unsigned int w, h; + + MwLLGetXYWH(handle, &x, &y, &w, &h); + + MwLLDispatch(handle, draw, NULL); + handle->wayland.force_redraw = MwFALSE; + } } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -537,6 +621,7 @@ static void MwLLForceRenderImpl(MwLL handle) { // event_loop(handle); wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); wl_surface_commit(handle->wayland.surface); + handle->wayland.force_redraw = MwTRUE; } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { diff --git a/src/backend/x11.c b/src/backend/x11.c index a7bea2fd7..ec50ad21b 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -395,10 +395,6 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { - XSetWindowBackground(handle->x11.display, handle->x11.window, color->x11.pixel); -} - static int MwLLPendingImpl(MwLL handle) { XEvent ev; if(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { diff --git a/src/core.c b/src/core.c index 6bb49798c..19eaaa8db 100644 --- a/src/core.c +++ b/src/core.c @@ -295,7 +295,9 @@ int MwStep(MwWidget handle) { arrfree(widgets); handle->prop_event = 0; - if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel)) MwLLNextEvent(handle->lowlevel); + if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel)) + MwLLNextEvent(handle->lowlevel); + handle->prop_event = 1; clean_destroy_queue(handle); @@ -378,11 +380,7 @@ void MwSetText(MwWidget handle, const char* key, const char* value) { shput(handle->text, key, v); } if(handle->prop_event) MwDispatch3(handle, prop_change, key); - if(strcmp(key, MwNbackground) == 0) { - MwLLColor c = MwParseColor(handle, value); - MwLLSetBackground(handle->lowlevel, c); - MwLLFreeColor(c); - } + if(strcmp(key, MwNbackground) == 0 || strcmp(key, MwNforeground) == 0 || strcmp(key, MwNsubBackground) == 0 || strcmp(key, MwNsubForeground) == 0) { MwForceRender(handle); } diff --git a/src/draw.c b/src/draw.c index fd3541f24..deaa7e846 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,5 +1,6 @@ /* $Id$ */ #include +#include #ifdef USE_STB_IMAGE #include "../external/stb_image.h" diff --git a/src/lowlevel.c b/src/lowlevel.c index 70dd50f2a..f8a4ccac1 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -40,8 +40,6 @@ void (*MwLLMakePopup)(MwLL handle, MwLL parent); void (*MwLLBeginStateChange)(MwLL handle); void (*MwLLEndStateChange)(MwLL handle); -void (*MwLLSetBackground)(MwLL handle, MwLLColor color); - void (*MwLLFocus)(MwLL handle); void (*MwLLGrabPointer)(MwLL handle, int toggle); From be2eb6483c1d7f4f8f4188a457fa5205758dce08 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 1 Dec 2025 20:05:03 -0700 Subject: [PATCH 07/16] throw in the towel and switch to cairo lmao --- include/Mw/LowLevel/Wayland.h | 5 +- pl/rules.pl | 2 +- src/backend/wayland.c | 92 +++++++++++++---------------------- 3 files changed, 38 insertions(+), 61 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c502a533a..bc2aa25a9 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -15,6 +15,8 @@ #include #include +#include + MWDECL int MwLLWaylandCallInit(void); #ifndef WL_PROTOCOLS_DEFINED @@ -64,8 +66,9 @@ struct _MwLLWayland { struct wl_shm* shm; struct wl_registry_listener registry_listener; + cairo_surface_t* cairo_surface; + MwU8* mapped_buffer; - int mapped_buffer_size; struct { const char* key; diff --git a/pl/rules.pl b/pl/rules.pl index e1bd49997..5f2b0edb4 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -30,7 +30,7 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - add_libs("-lwayland-client -lxkbcommon"); + add_libs("-lcairo -lwayland-client -lxkbcommon"); scan_wayland_protocol("stable", "xdg-shell",""); scan_wayland_protocol("stable", "tablet","-v2"); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d14cada54..589c48d25 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -60,6 +60,7 @@ static void buffer_setup(struct _MwLLWayland* wayland) { struct wl_shm_pool* pool; struct wl_buffer* buffer; int x, y; + int stride = wayland->ww * 4; int fd; MwU32 size = wayland->ww * wayland->wh * 4; @@ -80,10 +81,15 @@ static void buffer_setup(struct _MwLLWayland* wayland) { return; } - lseek(fd, 0, SEEK_SET); wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); memset(wayland->mapped_buffer, 0xFF, size); - wayland->mapped_buffer_size = size; + // wayland->mapped_buffer_size = size; + + wayland->cairo_surface = cairo_image_surface_create_for_data(wayland->mapped_buffer, + CAIRO_FORMAT_ARGB32, + wayland->ww, + wayland->wh, + stride); fsync(fd); @@ -91,7 +97,7 @@ static void buffer_setup(struct _MwLLWayland* wayland) { printf("failure setting up wl_shm: could not create pool.\n"); } - buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, wayland->ww * 4, WL_SHM_FORMAT_ARGB8888); + buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); if(wayland->configured) { wl_surface_attach(wayland->surface, buffer, 0, 0); @@ -428,76 +434,41 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } } -// fractional part of x -static float fpart(float x) { - return x - floor(x); -} -static float rfpart(float x) { - return x - fpart(x); -} - -#define IMAGE_POS_GET(x, y, o) handle->wayland.mapped_buffer[(((y * handle->wayland.ww) + x) * 4) + o] - -#define IMAGE_POS_SET(x, y, o, v) IMAGE_POS_GET(x, y, o) = v; -#define IMAGE_PLOT(x, y, color) \ - IMAGE_POS_SET(x, y, 0, color->common.blue); \ - IMAGE_POS_SET(x, y, 1, color->common.green); \ - IMAGE_POS_SET(x, y, 2, color->common.red); \ - IMAGE_POS_SET(x, y, 3, 255); - -static void -line_draw(MwLL handle, int x0, int y0, int x1, int y1, MwLLColor color) { - int dx = abs(x1 - x0), sx = x0 < x1 ? 1 : -1; - int dy = -abs(y1 - y0), sy = y0 < y1 ? 1 : -1; - int err = dx + dy, e2; - - for(;;) { - IMAGE_PLOT(x0, y0, color); - if(x0 == x1 && y0 == y1) break; - e2 = 2 * err; - if(e2 >= dy) { - err += dy; - x0 += sx; - } - if(e2 <= dx) { - err += dx; - y0 += sy; - } - } -} - static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - int lx = 65536, ly = 65536; - int hx = 0, hy = 0; - int x, y; - for(i = 0; i < points_count - 1; i++) { - MwPoint p1 = points[i]; - MwPoint p2 = points[i + 1]; - if(p1.x < lx) lx = p1.x; - if(p1.y < ly) ly = p1.y; - if(p1.x > hx) hx = p1.x; - if(p1.y > hy) hy = p1.y; - } - // for(y = ly; y < hy; y++) { - // for(x = lx; x < hx; x++) { - // IMAGE_PLOT(x, y, color); - // } - // } + cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + cairo_set_line_width(cairo, 1); + cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); + cairo_paint(cairo); + for(i = 0; i < points_count - 1; i++) { MwPoint p1 = points[i]; MwPoint p2 = points[i + 1]; - line_draw(handle, p1.x, p1.y, p2.x, p2.y, color); + cairo_move_to(cairo, p1.x, p1.y); + cairo_line_to(cairo, p2.x, p2.y); } + cairo_fill(cairo); + cairo_destroy(cairo); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { MwPoint p1 = points[0]; MwPoint p2 = points[1]; + int i; - line_draw(handle, p1.x, p1.y, p2.x, p2.y, color); + cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); + cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); + cairo_set_line_width(cairo, 1); + cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); + cairo_paint(cairo); + + cairo_move_to(cairo, p1.x, p1.y); + cairo_line_to(cairo, p2.x, p2.y); + cairo_fill(cairo); + cairo_destroy(cairo); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -520,6 +491,9 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } +static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { +} + static int MwLLPendingImpl(MwLL handle) { enum { DISPLAY_FD, From 8cbde42de36c50dce40a3a792bd1aed1a9c610c9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 1 Dec 2025 20:45:21 -0700 Subject: [PATCH 08/16] have cairo fill in lines idk --- include/Mw/LowLevel/Wayland.h | 3 +++ src/backend/wayland.c | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index bc2aa25a9..d5eb32d71 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -66,7 +66,10 @@ struct _MwLLWayland { struct wl_shm* shm; struct wl_registry_listener registry_listener; + int mapped_buffer_size; + cairo_surface_t* cairo_surface; + // cairo_t* cairo; MwU8* mapped_buffer; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 589c48d25..91e46d709 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -433,24 +434,26 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { buffer_setup(&handle->wayland); } } - static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - cairo_set_line_width(cairo, 1); cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_paint(cairo); + cairo_set_line_width(cairo, 1); + cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD); - for(i = 0; i < points_count - 1; i++) { - MwPoint p1 = points[i]; - MwPoint p2 = points[i + 1]; - - cairo_move_to(cairo, p1.x, p1.y); - cairo_line_to(cairo, p2.x, p2.y); + cairo_new_path(cairo); + for(i = 0; i < points_count + 1; i++) { + cairo_line_to(cairo, points[i].x, points[i].y); } + if(points[0].x != points[i].x && points[0].y != points[i].y) { + cairo_line_to(cairo, points[0].x, points[0].y); + } + cairo_close_path(cairo); + + cairo_stroke_preserve(cairo); cairo_fill(cairo); + // cairo_paint(cairo); cairo_destroy(cairo); } @@ -491,9 +494,6 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static void MwLLSetBackgroundImpl(MwLL handle, MwLLColor color) { -} - static int MwLLPendingImpl(MwLL handle) { enum { DISPLAY_FD, From c50e9201236e83088a2a6bacbff317d86cd4b27c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 2 Dec 2025 23:42:55 -0700 Subject: [PATCH 09/16] cairo about to make me give up on the wayland port --- src/backend/wayland.c | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 91e46d709..abec1b9eb 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -370,10 +370,6 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h } r->wayland.configured = MwTRUE; - - buffer_setup(&r->wayland); - - wl_surface_commit(parent->wayland.surface); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; @@ -397,6 +393,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_subsurface(parent, r, x, y, width, height); } + buffer_setup(&r->wayland); + return r; } @@ -414,13 +412,6 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - handle->wayland.x = x; - handle->wayland.y = y; - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); - } else { - wl_subsurface_set_position(handle->wayland.subsurface, x, y); - } } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -431,29 +422,26 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); } else { // setup the buffer again with the new size. - buffer_setup(&handle->wayland); + // buffer_setup(&handle->wayland); } } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i; + int i = 0; cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_set_line_width(cairo, 1); + cairo_set_line_width(cairo, 0.1); cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD); cairo_new_path(cairo); - for(i = 0; i < points_count + 1; i++) { + for(; i < points_count; i++) { cairo_line_to(cairo, points[i].x, points[i].y); } - if(points[0].x != points[i].x && points[0].y != points[i].y) { - cairo_line_to(cairo, points[0].x, points[0].y); - } cairo_close_path(cairo); + // cairo_paint(cairo); cairo_stroke_preserve(cairo); cairo_fill(cairo); - // cairo_paint(cairo); cairo_destroy(cairo); } From 0adc98a2a2cdc6ca6d7aa84a848177de55dabd56 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 3 Dec 2025 18:17:27 -0700 Subject: [PATCH 10/16] wayland: give up on cairo and switch to OpenGL --- include/Mw/LowLevel/Wayland.h | 45 ++-- pl/rules.pl | 2 +- src/backend/wayland.c | 376 +++++++++++++++++++++++++--------- src/backend/x11.c | 1 + src/core.c | 3 + src/draw.c | 2 + 6 files changed, 310 insertions(+), 119 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index d5eb32d71..c13e9bf77 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -12,11 +12,14 @@ #include #include +#include +#include +#include +#include + #include #include -#include - MWDECL int MwLLWaylandCallInit(void); #ifndef WL_PROTOCOLS_DEFINED @@ -58,21 +61,6 @@ struct _MwLLWayland { MWLL_WAYLAND_SUBSURFACE = 1, } type; - struct wl_display* display; - struct wl_registry* registry; - struct wl_compositor* compositor; - struct wl_subcompositor* subcompositor; - struct wl_surface* surface; - struct wl_shm* shm; - struct wl_registry_listener registry_listener; - - int mapped_buffer_size; - - cairo_surface_t* cairo_surface; - // cairo_t* cairo; - - MwU8* mapped_buffer; - struct { const char* key; wl_setup_func* value; @@ -83,9 +71,32 @@ struct _MwLLWayland { wayland_protocol_t* value; }* wl_protocol_map; + /*MwLL* subsurfaces;*/ + + struct wl_display* display; + struct wl_registry* registry; + struct wl_compositor* compositor; + struct wl_subcompositor* subcompositor; + struct wl_surface* surface; + struct wl_shm* shm; + struct wl_registry_listener registry_listener; + // cairo_surface_t* cairo_surface; MwBool configured; MwBool force_redraw; + MwBool do_clear; MwU32 x, y, ww, wh; + + MwLL parent; + + GLuint fbo; + unsigned int fbo_texture; + unsigned int rbo; + + MwBool egl_setup; + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; }; struct _MwLLWaylandColor { diff --git a/pl/rules.pl b/pl/rules.pl index 5f2b0edb4..4927a10ef 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -30,7 +30,7 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - add_libs("-lcairo -lwayland-client -lxkbcommon"); + add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon"); scan_wayland_protocol("stable", "xdg-shell",""); scan_wayland_protocol("stable", "tablet","-v2"); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index abec1b9eb..b860f7f49 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,5 +1,6 @@ /* $Id$ */ +#include #include #include @@ -18,6 +19,17 @@ #include "Mw/LowLevel.h" #include +#include +#include + +PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; +// PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; +PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; +PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatus; #define WAYLAND_GET_INTERFACE(r, inter) shget(r.wl_protocol_map, inter##_interface.name) @@ -57,57 +69,8 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); return NULL; } -static void buffer_setup(struct _MwLLWayland* wayland) { - struct wl_shm_pool* pool; - struct wl_buffer* buffer; - int x, y; - int stride = wayland->ww * 4; - - int fd; - MwU32 size = wayland->ww * wayland->wh * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - - fd = mkstemp(temp_name); - - unlink(temp_name); - - if(posix_fallocate(fd, 0, size) != 0) { - printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(fd); - return; - } - if(ftruncate(fd, size) != 0) { - printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(fd); - return; - } - - wayland->mapped_buffer = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0); - memset(wayland->mapped_buffer, 0xFF, size); - // wayland->mapped_buffer_size = size; - - wayland->cairo_surface = cairo_image_surface_create_for_data(wayland->mapped_buffer, - CAIRO_FORMAT_ARGB32, - wayland->ww, - wayland->wh, - stride); - - fsync(fd); - - if(!(pool = wl_shm_create_pool(wayland->shm, fd, size))) { - printf("failure setting up wl_shm: could not create pool.\n"); - } - - buffer = wl_shm_pool_create_buffer(pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); - - if(wayland->configured) { - wl_surface_attach(wayland->surface, buffer, 0, 0); - wl_surface_commit(wayland->surface); - } - wl_buffer_destroy(buffer); - wl_shm_pool_destroy(pool); - close(fd); -} +// static void buffer_setup(struct _MwLLWayland* wayland) { +// } static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -174,20 +137,171 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ return proto; } +static MwBool egl_setup(MwLL self, int width, int height) { + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLConfig config; + 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 + if((eglChooseConfig(display, fbAttribs, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + 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 + surface = eglCreateWindowSurface(display, config, self->wayland.egl_window_native, NULL); + if(surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return MwFALSE; + } + + eglBindAPI(EGL_OPENGL_API); + + // Create a GL context + context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + 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); + 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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + glBindTexture(GL_TEXTURE_2D, 0); + + glGenRenderbuffers(1, &self->wayland.rbo); + // glBindRenderbuffer(GL_RENDERBUFFER, self->wayland.rbo)); + // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 768, 1024); + // glBindRenderbuffer(GL_RENDERBUFFER, 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); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self->wayland.rbo); + + 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(); + glOrtho(0, width, height, -13, -1, 1); + + self->wayland.egl_display = display; + self->wayland.egl_surface = surface; + self->wayland.egl_context = context; + printf("EGL success\n"); + return MwTRUE; +} + static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, struct wl_array* states) { - MwLL self = data; + MwLL self = data; + PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D"); - if(width != 0 && height != 0) { - self->wayland.ww = width; - self->wayland.wh = height; - xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); + if(width == 0 && height == 0) { + width = self->wayland.ww; + height = self->wayland.wh; + } + self->wayland.ww = width; + self->wayland.wh = height; + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); - MwLLSetWH(self, width, height); - MwLLDispatch(self, resize, NULL); - }; + MwLLSetWH(self, width, height); + MwLLDispatch(self, resize, NULL); + + if(!self->wayland.egl_setup) { + self->wayland.egl_setup = egl_setup(self, width, height); + } else { + wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, width, height, -13, -1, 1); + self->wayland.do_clear = MwTRUE; + + // glDeleteTextures(1, &self->wayland.fbo_texture); + // 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); + // 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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + + // glBindTexture(GL_TEXTURE_2D, 0); + } MwLLForceRender(self); @@ -335,7 +449,7 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { printf("zxdg null\n"); } - buffer_setup(&r->wayland); + // buffer_setup(&r->wayland); wl_surface_commit(r->wayland.surface); } @@ -369,23 +483,34 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h return; } + // arrpush(parent->wayland.subsurfaces, r); + r->wayland.configured = MwTRUE; + + r->wayland.egl_context = parent->wayland.egl_context; + r->wayland.egl_display = parent->wayland.egl_display; + r->wayland.egl_surface = parent->wayland.egl_surface; + r->wayland.fbo = parent->wayland.fbo; + r->wayland.fbo_texture = parent->wayland.fbo_texture; + r->wayland.rbo = parent->wayland.rbo; } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); MwLLCreateCommon(r); - // r->common.copy_buffer = 1; r->common.type = MwLLBackendWayland; - if(width == 0) width = parent->wayland.ww; - if(height == 0) height = parent->wayland.wh; + if(width == 0) width = 1; + if(height == 0) height = 1; - r->wayland.ww = width; - r->wayland.wh = height; + r->wayland.ww = width; + r->wayland.wh = height; + r->wayland.parent = parent; - r->common.success = MwTRUE; + r->wayland.force_redraw = MwFALSE; + r->wayland.do_clear = MwFALSE; + r->common.success = MwTRUE; if(parent == NULL) { setup_toplevel(r, x, y, width, height); @@ -393,7 +518,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_subsurface(parent, r, x, y, width, height); } - buffer_setup(&r->wayland); + // buffer_setup(&r->wayland); return r; } @@ -412,6 +537,13 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { + + 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); + } } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -421,45 +553,82 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); } else { - // setup the buffer again with the new size. - // buffer_setup(&handle->wayland); } } + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i = 0; + /* + * TODO: this function sucks shit, ioi needs to make it not suck shit :) + */ + int i; + PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer"); + PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer"); + int w, h; - cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); - cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_set_line_width(cairo, 0.1); - cairo_set_fill_rule(cairo, CAIRO_FILL_RULE_EVEN_ODD); - - cairo_new_path(cairo); - for(; i < points_count; i++) { - cairo_line_to(cairo, points[i].x, points[i].y); + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + w = handle->wayland.ww; + h = handle->wayland.wh; + } else { + MwLL parent = handle->wayland.parent; + while(parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + parent = parent->wayland.parent; + } + w = parent->wayland.ww; + h = parent->wayland.wh; } - cairo_close_path(cairo); - // cairo_paint(cairo); - cairo_stroke_preserve(cairo); - cairo_fill(cairo); - cairo_destroy(cairo); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); + + glBegin(GL_TRIANGLE_FAN); + for(i = 0; i < points_count; i++) { + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + glVertex2f( + (handle->wayland.x + points[i].x), + (handle->wayland.y + points[i].y)); + + if((i % 3) == 0 && i != 0) { + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + glVertex2f( + (handle->wayland.x + points[i].x), + (handle->wayland.y + points[i].y)); + } + } + glEnd(); + glFinish(); + + glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(0, 0, 0, 1); + + 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(); + + if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { + printf("error swapping buffers! %0X\n", eglGetError()); + } else { + wl_surface_commit(handle->wayland.surface); + } + glDisable(GL_TEXTURE_2D); + handle->wayland.do_clear = MwFALSE; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MwPoint p1 = points[0]; - MwPoint p2 = points[1]; - int i; - - cairo_t* cairo = cairo_create(handle->wayland.cairo_surface); - cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); - cairo_set_line_width(cairo, 1); - cairo_set_source_rgb(cairo, color->common.red / 255., color->common.green / 255., color->common.blue / 255.); - cairo_paint(cairo); - - cairo_move_to(cairo, p1.x, p1.y); - cairo_line_to(cairo, p2.x, p2.y); - cairo_fill(cairo); - cairo_destroy(cairo); + // } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -536,9 +705,7 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - MwBool render; - - render = handle->wayland.force_redraw; + MwBool render = handle->wayland.force_redraw; if(render) { int x, y; @@ -580,9 +747,16 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } static void MwLLForceRenderImpl(MwLL handle) { - // event_loop(handle); wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + + if(handle->wayland.egl_setup) { + if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { + printf("error swapping buffers! %0X\n", eglGetError()); + } + } + wl_surface_commit(handle->wayland.surface); + handle->wayland.force_redraw = MwTRUE; } diff --git a/src/backend/x11.c b/src/backend/x11.c index ec50ad21b..b6d22c0a4 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -131,6 +131,7 @@ static XVisualInfo* get_visual_info(Display* display) { } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + printf("%d %d\n", width, height); MwLL r; Window p; XVisualInfo* xvi; diff --git a/src/core.c b/src/core.c index 19eaaa8db..cb7c6fd08 100644 --- a/src/core.c +++ b/src/core.c @@ -1,7 +1,9 @@ /* $Id$ */ #include +#include #include "../external/stb_ds.h" +#include "Mw/LowLevel.h" static void lldrawhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; @@ -295,6 +297,7 @@ int MwStep(MwWidget handle) { arrfree(widgets); handle->prop_event = 0; + if(handle->lowlevel != NULL && MwLLPending(handle->lowlevel)) MwLLNextEvent(handle->lowlevel); diff --git a/src/draw.c b/src/draw.c index deaa7e846..6229a889e 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,4 +1,5 @@ /* $Id$ */ +#include "Mw/LowLevel.h" #include #include @@ -485,6 +486,7 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, p4[2].y = rect->y + s * border; } MwLLPolygon(handle->lowlevel, p4, 3, col); + if(color != col) MwLLFreeColor(col); MwLLFreeColor(lighter); From a932fc00ea3645337a984c9ab3b990fbe623ba56 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 3 Dec 2025 22:26:03 -0700 Subject: [PATCH 11/16] opengl complete --- include/Mw/Core.h | 2 +- include/Mw/LowLevel/Wayland.h | 7 +++--- src/backend/wayland.c | 46 +++++++++++++++-------------------- src/backend/x11.c | 1 - 4 files changed, 25 insertions(+), 31 deletions(-) diff --git a/include/Mw/Core.h b/include/Mw/Core.h index 28df4d471..98812a54d 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -128,7 +128,7 @@ MWDECL void MwLoop(MwWidget handle); */ MWDECL int MwStep(MwWidget handle); -/*! +/*!MwStep( * @brief Check if any event is pending * @param handle Widget * @return `1` if any event is pending diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c13e9bf77..2ed3909af 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -71,8 +71,6 @@ struct _MwLLWayland { wayland_protocol_t* value; }* wl_protocol_map; - /*MwLL* subsurfaces;*/ - struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; @@ -80,11 +78,12 @@ struct _MwLLWayland { struct wl_surface* surface; struct wl_shm* shm; struct wl_registry_listener registry_listener; - // cairo_surface_t* cairo_surface; + MwBool configured; MwBool force_redraw; MwBool do_clear; MwU32 x, y, ww, wh; + int z_index; MwLL parent; @@ -97,6 +96,8 @@ struct _MwLLWayland { EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; + GLuint vertex_buffer; + GLuint vertex_array; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index b860f7f49..bfedd173b 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,5 +1,6 @@ /* $Id$ */ +// #include #include #include @@ -22,10 +23,9 @@ #include #include -PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; -PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; -PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; -// PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; +PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; @@ -254,7 +254,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, width, height, -13, -1, 1); + glOrtho(0, width, height, 0, -1, 1); self->wayland.egl_display = display; self->wayland.egl_surface = surface; @@ -283,11 +283,12 @@ static void xdg_toplevel_configure(void* data, if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, width, height); + MwLLForceRender(self); } else { wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); - glOrtho(0, width, height, -13, -1, 1); + glOrtho(0, width, height, 0, -1, 1); self->wayland.do_clear = MwTRUE; // glDeleteTextures(1, &self->wayland.fbo_texture); @@ -303,8 +304,6 @@ static void xdg_toplevel_configure(void* data, // glBindTexture(GL_TEXTURE_2D, 0); } - MwLLForceRender(self); - return; }; @@ -452,6 +451,8 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { // buffer_setup(&r->wayland); wl_surface_commit(r->wayland.surface); + + // glGenBuffers(1, &vertex_buffer); } static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int height) { @@ -518,8 +519,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_subsurface(parent, r, x, y, width, height); } - // buffer_setup(&r->wayland); - return r; } @@ -581,20 +580,21 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); + glLineWidth(1); + + if(points_count == 3) { + glBegin(GL_TRIANGLES); + } else if(points_count == 4) { + glBegin(GL_QUADS); + } else { + glBegin(GL_QUAD_STRIP); + } - glBegin(GL_TRIANGLE_FAN); for(i = 0; i < points_count; i++) { glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); glVertex2f( - (handle->wayland.x + points[i].x), - (handle->wayland.y + points[i].y)); - - if((i % 3) == 0 && i != 0) { - glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - glVertex2f( - (handle->wayland.x + points[i].x), - (handle->wayland.y + points[i].y)); - } + ceil(handle->wayland.x) + ceil(points[i].x), + ceil(handle->wayland.y) + ceil(points[i].y)); } glEnd(); glFinish(); @@ -749,12 +749,6 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); - if(handle->wayland.egl_setup) { - if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { - printf("error swapping buffers! %0X\n", eglGetError()); - } - } - wl_surface_commit(handle->wayland.surface); handle->wayland.force_redraw = MwTRUE; diff --git a/src/backend/x11.c b/src/backend/x11.c index b6d22c0a4..ec50ad21b 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -131,7 +131,6 @@ static XVisualInfo* get_visual_info(Display* display) { } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - printf("%d %d\n", width, height); MwLL r; Window p; XVisualInfo* xvi; From 247e0b361c6f3a731ba29f5e511a83cbe38c051d Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 3 Dec 2025 23:00:40 -0700 Subject: [PATCH 12/16] introduce MwLLEndDraw, which can be stubbed safely on any platforms and exists purely for wayland to be able to swap buffers at a better time --- include/Mw/LowLevel.h | 1 + src/backend/call.c | 1 + src/backend/gdi.c | 2 ++ src/backend/wayland.c | 49 +++++++++++++++++++------------------------ src/backend/x11.c | 2 ++ src/core.c | 2 ++ src/lowlevel.c | 2 ++ 7 files changed, 31 insertions(+), 28 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 49c1cc7fe..2be5b2656 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -164,6 +164,7 @@ MWDECL void (*MwLLDestroy)(MwLL handle); MWDECL void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); MWDECL void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +MWDECL void (*MwLLEndDraw)(MwLL handle); MWDECL MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); MWDECL void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); diff --git a/src/backend/call.c b/src/backend/call.c index de4b7f085..2c8f39956 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -11,6 +11,7 @@ \ MwLLPolygon = MwLLPolygonImpl; \ MwLLLine = MwLLLineImpl; \ + MwLLEndDraw = MwLLEndDrawImpl; \ \ MwLLAllocColor = MwLLAllocColorImpl; \ MwLLColorUpdate = MwLLColorUpdateImpl; \ diff --git a/src/backend/gdi.c b/src/backend/gdi.c index b40c26e80..23c2dd3ea 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -278,6 +278,8 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLEndDrawImpl(MwLL handle) {} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { POINT* p = malloc(sizeof(*p) * points_count); HPEN pen = CreatePen(PS_NULL, 0, RGB(0, 0, 0)); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index bfedd173b..fd8c6bc3a 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -255,6 +255,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, height, 0, -1, 1); + glEnable(GL_TEXTURE_2D); self->wayland.egl_display = display; self->wayland.egl_surface = surface; @@ -556,31 +557,11 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - /* - * TODO: this function sucks shit, ioi needs to make it not suck shit :) - */ - int i; - PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)eglGetProcAddress("glBindFramebuffer"); - PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)eglGetProcAddress("glBindRenderbuffer"); - int w, h; + int i; - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - MwLL parent = handle->wayland.parent; - while(parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - parent = parent->wayland.parent; - } - w = parent->wayland.ww; - h = parent->wayland.wh; - } - - glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); - glLineWidth(1); if(points_count == 3) { glBegin(GL_TRIANGLES); @@ -598,9 +579,26 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } glEnd(); glFinish(); + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + // +} + +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; + } glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); - glBindFramebuffer(GL_FRAMEBUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 1); @@ -618,17 +616,12 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL glEnd(); glFinish(); + wl_surface_damage(handle->wayland.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { printf("error swapping buffers! %0X\n", eglGetError()); } else { wl_surface_commit(handle->wayland.surface); } - glDisable(GL_TEXTURE_2D); - handle->wayland.do_clear = MwFALSE; -} - -static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - // } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { diff --git a/src/backend/x11.c b/src/backend/x11.c index ec50ad21b..6e2426af4 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -256,6 +256,8 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLEndDrawImpl(MwLL handle) {} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; XPoint* p = malloc(sizeof(*p) * points_count); diff --git a/src/core.c b/src/core.c index cb7c6fd08..401600d17 100644 --- a/src/core.c +++ b/src/core.c @@ -334,6 +334,8 @@ void MwLoop(MwWidget handle) { } if(v != 0) break; + MwLLEndDraw(handle->lowlevel); + for(i = 0; i < arrlen(handle->tick_list); i++) { MwDispatch(handle->tick_list[i], tick); MwDispatchUserHandler(handle->tick_list[i], MwNtickHandler, NULL); diff --git a/src/lowlevel.c b/src/lowlevel.c index f8a4ccac1..19445a40b 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -7,6 +7,8 @@ void (*MwLLDestroy)(MwLL handle); void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +void (*MwLLEndDraw)(MwLL handle); + MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); void (*MwLLFreeColor)(MwLLColor color); From 39f44a56e3128ea4f98d6c1d95847a5fd606dc8e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 5 Dec 2025 12:40:44 -0700 Subject: [PATCH 13/16] fixed new kde bug where decorations were null --- src/backend/wayland.c | 157 +++++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 71 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index fd8c6bc3a..77669f1eb 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -339,6 +338,75 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } +static int event_loop(struct _MwLLWayland* wayland) { + enum { + DISPLAY_FD, + KEYREPEAT_FD, + CURSOR_FD + }; + struct pollfd fd; + int timeout = 100; + + if(wayland->force_redraw) { + return 1; + } + + if(wayland->display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(wayland->display); + fd.events = POLLIN; + + while(wl_display_prepare_read(wayland->display) != 0) { + if(wl_display_dispatch_pending(wayland->display) > 0) { + return 0; + } + } + + /* 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); + + wayland->toplevel->running = MwFALSE; + 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 { + wl_display_cancel_read(wayland->display); + } + return 0; +} + #define WL_INTERFACE(interface) \ shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); @@ -361,23 +429,9 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { #undef WL_INTERFACE -static MwBool flush_display(struct wl_display* display) { - while(wl_display_flush(display) == -1) { - if(errno != EAGAIN) { - return MwFALSE; - } - - struct pollfd fd = {wl_display_get_fd(display), POLL_OUT}; - - while(poll(&fd, 1, -1) == -1) { - if(errno != EINTR && errno != EAGAIN) - return MwFALSE; - } - } - return MwTRUE; -} - static void setup_toplevel(MwLL r, int x, int y, int width, int height) { + int i; + r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); @@ -400,6 +454,16 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { return; } + printf("Found globals: \n"); + for(i = 0; i < shlen(r->wayland.wl_protocol_map); i++) { + wayland_protocol_t* proto = shget(r->wayland.wl_protocol_map, r->wayland.wl_protocol_map[i].key); + if(proto != NULL) { + printf("%s (%p)\n", r->wayland.wl_protocol_map[i].key, r->wayland.wl_protocol_map[i].value); + } else { + printf("%s (proto is null)\n", r->wayland.wl_protocol_map[i].key, r->wayland.wl_protocol_map[i].value); + } + } + // Check that all globals we require are available if( r->wayland.compositor == NULL || @@ -433,11 +497,12 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { // Perform the initial commit and wait for the first configure event wl_surface_commit(r->wayland.surface); - while(wl_display_dispatch(r->wayland.display) != -1 && !r->wayland.configured) { - } + event_loop(&r->wayland); + + printf("%p\n", shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name)); // setup decorations if we can - if(WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context != NULL) { + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; dec->decoration = zxdg_decoration_manager_v1_get_toplevel_decoration( @@ -537,7 +602,6 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { handle->wayland.x = x; handle->wayland.y = y; @@ -645,56 +709,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - enum { - DISPLAY_FD, - KEYREPEAT_FD, - CURSOR_FD - }; - struct pollfd fd; - int timeout = 1; - - if(handle->wayland.force_redraw) { - return 1; - } - - if(handle->wayland.display == NULL) { - return 0; - } - fd.fd = wl_display_get_fd(handle->wayland.display); - fd.events = POLLIN; - - while(wl_display_prepare_read(handle->wayland.display) != 0) { - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - return 0; - } - } - - // If an error other than EAGAIN happens, we have likely been disconnected - // from the Wayland session - if(!flush_display(handle->wayland.display)) { - wl_display_cancel_read(handle->wayland.display); - - handle->wayland.toplevel->running = MwFALSE; - return 0; - } - - // Condition where no events are being sent. - if(!poll(&fd, 1, timeout)) { - wl_display_cancel_read(handle->wayland.display); - // In this case, we need to commit the surface for any animations, etc. - wl_surface_commit(handle->wayland.surface); - return 0; - } - - if(fd.revents & POLLIN) { - wl_display_read_events(handle->wayland.display); - if(wl_display_dispatch_pending(handle->wayland.display) > 0) { - } - } else { - wl_display_cancel_read(handle->wayland.display); - } - - return 1; + return event_loop(&handle->wayland); } static void MwLLNextEventImpl(MwLL handle) { From 0fc8b099137e3479fd7336f8004f8e42cc067231 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 5 Dec 2025 14:50:04 -0700 Subject: [PATCH 14/16] wayland resize --- include/Mw/LowLevel/Wayland.h | 8 +- src/backend/wayland.c | 249 ++++++++++++++++++++++++---------- 2 files changed, 178 insertions(+), 79 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 2ed3909af..786ee07fb 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -81,7 +81,8 @@ struct _MwLLWayland { MwBool configured; MwBool force_redraw; - MwBool do_clear; + MwBool egl_setup; + MwBool egl_do_resetup; MwU32 x, y, ww, wh; int z_index; @@ -89,15 +90,12 @@ struct _MwLLWayland { GLuint fbo; unsigned int fbo_texture; - unsigned int rbo; - MwBool egl_setup; EGLNativeWindowType egl_window_native; EGLDisplay egl_display; EGLContext egl_context; EGLSurface egl_surface; - GLuint vertex_buffer; - GLuint vertex_array; + EGLConfig egl_config; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 77669f1eb..056664030 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -64,13 +64,6 @@ void xdg_wm_base_ping(void* data, xdg_wm_base_pong(xdg_wm_base, serial); }; -static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - return NULL; -} -// static void buffer_setup(struct _MwLLWayland* wayland) { -// } - static wayland_protocol_t* wl_seat_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); proto->listener = malloc(sizeof(struct wl_seat_listener)); @@ -143,7 +136,6 @@ static MwBool egl_setup(MwLL self, int width, int height) { EGLint minorVersion; EGLContext context; EGLSurface surface; - EGLConfig config; EGLint fbAttribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, @@ -178,7 +170,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { } // Choose config - if((eglChooseConfig(display, fbAttribs, &config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + if((eglChooseConfig(display, fbAttribs, &self->wayland.egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); return MwFALSE; } @@ -191,7 +183,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { } // Create a surface - surface = eglCreateWindowSurface(display, config, self->wayland.egl_window_native, NULL); + surface = eglCreateWindowSurface(display, self->wayland.egl_config, self->wayland.egl_window_native, NULL); if(surface == EGL_NO_SURFACE) { printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); return MwFALSE; @@ -200,7 +192,7 @@ static MwBool egl_setup(MwLL self, int width, int height) { eglBindAPI(EGL_OPENGL_API); // Create a GL context - context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs); + context = eglCreateContext(display, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs); if(context == EGL_NO_CONTEXT) { printf("ERROR: eglCreateContext, %0X\n", eglGetError()); return MwFALSE; @@ -226,24 +218,15 @@ static MwBool egl_setup(MwLL self, int width, int height) { 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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); glBindTexture(GL_TEXTURE_2D, 0); - glGenRenderbuffers(1, &self->wayland.rbo); - // glBindRenderbuffer(GL_RENDERBUFFER, self->wayland.rbo)); - // glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, 768, 1024); - // glBindRenderbuffer(GL_RENDERBUFFER, 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); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self->wayland.rbo); - if((err = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) { printf("Error binding framebuffer: %0X\n", err); return MwFALSE; @@ -263,6 +246,66 @@ static MwBool egl_setup(MwLL self, int width, int height) { return MwTRUE; } +static void egl_resetup(MwLL handle) { + int err; + + if(!handle->wayland.egl_do_resetup) { + return; + } + + if(!eglMakeCurrent(handle->wayland.egl_display, 0, 0, handle->wayland.egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + return; + } + + if(!eglDestroySurface(handle->wayland.egl_display, handle->wayland.egl_surface)) { + printf("ERROR: eglDestroySurface, %0X\n", eglGetError()); + return; + }; + + handle->wayland.egl_surface = eglCreateWindowSurface(handle->wayland.egl_display, handle->wayland.egl_config, handle->wayland.egl_window_native, NULL); + if(handle->wayland.egl_surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return; + } + + if(!eglMakeCurrent(handle->wayland.egl_display, handle->wayland.egl_surface, handle->wayland.egl_surface, handle->wayland.egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + return; + } + + 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; +} + static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, @@ -284,26 +327,12 @@ static void xdg_toplevel_configure(void* data, if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, width, height); MwLLForceRender(self); - } else { - wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, width, height, 0, -1, 1); - self->wayland.do_clear = MwTRUE; - - // glDeleteTextures(1, &self->wayland.fbo_texture); - // 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); - // 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, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - - // glBindTexture(GL_TEXTURE_2D, 0); } + wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); + self->wayland.egl_do_resetup = MwTRUE; + egl_resetup(self); + return; }; @@ -416,7 +445,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { wayland->wl_protocol_setup_map = NULL; wayland->wl_protocol_map = NULL; - WL_INTERFACE(wl_shm); WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_subcompositor); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { @@ -429,8 +457,9 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { #undef WL_INTERFACE -static void setup_toplevel(MwLL r, int x, int y, int width, int height) { - int i; +static void setup_toplevel(MwLL r, int x, int y) { + int i; + struct wl_region* region; r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); @@ -484,11 +513,9 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); // setup mandatory listeners - r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; - xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, r); @@ -496,8 +523,12 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); // Perform the initial commit and wait for the first configure event + region = wl_compositor_create_region(r->wayland.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); event_loop(&r->wayland); + wl_region_destroy(region); printf("%p\n", shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name)); @@ -516,15 +547,19 @@ static void setup_toplevel(MwLL r, int x, int y, int width, int height) { // buffer_setup(&r->wayland); - wl_surface_commit(r->wayland.surface); - // glGenBuffers(1, &vertex_buffer); } -static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int height) { +static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { struct wl_compositor* compositor = parent->wayland.compositor; struct wl_subcompositor* subcompositor = parent->wayland.subcompositor; struct wl_surface* parent_surface = parent->wayland.surface; + MwLL topmost_parent = parent; + struct wl_region* region; + + while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } r->wayland.type = MWLL_WAYLAND_SUBSURFACE; @@ -532,6 +567,13 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h r->wayland.surface = wl_compositor_create_surface(compositor); + 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); + event_loop(&r->wayland); + wl_region_destroy(region); + r->wayland.subsurface = wl_subcompositor_get_subsurface(subcompositor, r->wayland.surface, parent_surface); wl_subsurface_set_position(r->wayland.subsurface, x, y); @@ -540,8 +582,8 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h setup_callbacks(&r->wayland); - r->wayland.registry = wl_display_get_registry(parent->wayland.display); - r->wayland.display = parent->wayland.display; + r->wayland.registry = wl_display_get_registry(topmost_parent->wayland.display); + r->wayland.display = topmost_parent->wayland.display; wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); if(wl_display_roundtrip(r->wayland.display) == -1) { @@ -554,13 +596,24 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y, int width, int h r->wayland.configured = MwTRUE; - r->wayland.egl_context = parent->wayland.egl_context; - r->wayland.egl_display = parent->wayland.egl_display; - r->wayland.egl_surface = parent->wayland.egl_surface; - r->wayland.fbo = parent->wayland.fbo; - r->wayland.fbo_texture = parent->wayland.fbo_texture; - r->wayland.rbo = parent->wayland.rbo; + 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; } + +static void framebuffer_action_begin(MwLL handle) { + glBindTexture(GL_TEXTURE_2D, 0); + 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); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -576,13 +629,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.parent = parent; r->wayland.force_redraw = MwFALSE; - r->wayland.do_clear = MwFALSE; r->common.success = MwTRUE; if(parent == NULL) { - setup_toplevel(r, x, y, width, height); + setup_toplevel(r, x, y); } else { - setup_subsurface(parent, r, x, y, width, height); + setup_subsurface(parent, r, x, y); } return r; @@ -611,6 +663,10 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { + /* Prevent an integer underflow when the w/h is too low */ + if(w < 10 || h < 10) { + return; + } handle->wayland.ww = w; handle->wayland.wh = h; @@ -621,29 +677,74 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i; + int i, n; + float maxX = 0, maxY = 0; + float centerX, centerY; - glBindTexture(GL_TEXTURE_2D, 0); - glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); + 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 - if(points_count == 3) { - glBegin(GL_TRIANGLES); - } else if(points_count == 4) { - glBegin(GL_QUADS); - } else { - glBegin(GL_QUAD_STRIP); + */ + 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; + } + } } + 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 */ + + framebuffer_action_begin(handle); + glBegin(GL_TRIANGLE_FAN); 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); + glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - glVertex2f( - ceil(handle->wayland.x) + ceil(points[i].x), - ceil(handle->wayland.y) + ceil(points[i].y)); + + /* If we have a polygon that's covering the whole screen, we want to do glClear + */ + if(x == 0 && y == 0) { + /* + We determine this by checking if all of the points are at the edge of the screen (and if there's more then 6 points). + Not a pretty solution, but unless the user does something weird like draw a triangle over itself twice, I'm pretty sure this is effective. + */ + if(points_count >= 6) { + MwBool doClear = MwTRUE; + for(n = 0; n < points_count; n++) { + if((points[n].x >= (handle->wayland.ww) - 1 || points[n].x <= 1) && (points[n].y >= (handle->wayland.wh) - 1 || points[n].y <= 1)) { + } else { + doClear = MwFALSE; + break; + } + } + if(doClear) { + glEnd(); + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1); + glBegin(GL_TRIANGLE_FAN); + } + } + } + + glVertex2f(x, y); + if(points_count > 3) { + glVertex2f(maxX, maxY); + glVertex2f(x, y); + } } glEnd(); - glFinish(); - glBindFramebuffer(GL_FRAMEBUFFER, 0); + + framebuffer_action_end(handle); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -663,8 +764,8 @@ static void MwLLEndDrawImpl(MwLL handle) { } glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0, 0, 0, 1); + // glClear(GL_COLOR_BUFFER_BIT); + // glClearColor(0, 0, 0, 1); glColor3f(1.0, 1.0, 1.0); From 495ea93c7466662b33a02b1420b97d7f596c08fa Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 5 Dec 2025 15:18:21 -0700 Subject: [PATCH 15/16] working pixmap --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 51 ++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 786ee07fb..ed7dcaf07 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -104,6 +104,7 @@ struct _MwLLWaylandColor { struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; + GLuint texture; }; #endif diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 056664030..043530db9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -238,6 +238,8 @@ static MwBool egl_setup(MwLL self, int width, int height) { glLoadIdentity(); glOrtho(0, width, height, 0, -1, 1); glEnable(GL_TEXTURE_2D); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); self->wayland.egl_display = display; self->wayland.egl_surface = surface; @@ -513,9 +515,12 @@ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); // setup mandatory listeners + r->wayland.toplevel->xdg_surface_listener.configure = xdg_surface_configure; + r->wayland.toplevel->xdg_toplevel_listener.configure = xdg_toplevel_configure; r->wayland.toplevel->xdg_toplevel_listener.close = xdg_toplevel_close; + xdg_surface_add_listener(r->wayland.toplevel->xdg_surface, &r->wayland.toplevel->xdg_surface_listener, r); xdg_toplevel_add_listener(r->wayland.toplevel->xdg_top_level, &r->wayland.toplevel->xdg_toplevel_listener, r); @@ -604,7 +609,6 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { } static void framebuffer_action_begin(MwLL handle) { - glBindTexture(GL_TEXTURE_2D, 0); glBindFramebuffer(GL_FRAMEBUFFER, handle->wayland.fbo); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, handle->wayland.fbo_texture, 0); } @@ -836,20 +840,59 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { MwLLPixmap r = malloc(sizeof(*r)); - r->common.width = width; - r->common.height = height; - r->common.raw = data; + 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); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + 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); } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + glDeleteTextures(1, &pixmap->wayland.texture); free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + 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); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { From 82319aa616e71fc9c418882bc3ae10c585671f6a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 5 Dec 2025 17:58:44 -0700 Subject: [PATCH 16/16] h --- src/backend/wayland.c | 92 ++++++++++++++++++------------------------- src/core.c | 9 ++++- 2 files changed, 45 insertions(+), 56 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 043530db9..883b16cbe 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -315,13 +315,17 @@ static void xdg_toplevel_configure(void* data, MwLL self = data; PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)eglGetProcAddress("glFramebufferTexture2D"); - if(width == 0 && height == 0) { + if(width == 0 || height == 0) { width = self->wayland.ww; height = self->wayland.wh; + // if it's still 0 then bail + if(width == 0 || height == 0) { + return; + } } self->wayland.ww = width; self->wayland.wh = height; - xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, self->wayland.x, self->wayland.y, self->wayland.ww, self->wayland.wh); + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); MwLLSetWH(self, width, height); MwLLDispatch(self, resize, NULL); @@ -369,18 +373,15 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } -static int event_loop(struct _MwLLWayland* wayland) { +static int event_loop(MwLL handle) { enum { DISPLAY_FD, KEYREPEAT_FD, CURSOR_FD }; - struct pollfd fd; - int timeout = 100; - - if(wayland->force_redraw) { - return 1; - } + struct pollfd fd; + int timeout = 100; + struct _MwLLWayland* wayland = &handle->wayland; if(wayland->display == NULL) { return 0; @@ -388,12 +389,6 @@ static int event_loop(struct _MwLLWayland* wayland) { fd.fd = wl_display_get_fd(wayland->display); fd.events = POLLIN; - while(wl_display_prepare_read(wayland->display) != 0) { - if(wl_display_dispatch_pending(wayland->display) > 0) { - return 0; - } - } - /* 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) { @@ -433,8 +428,11 @@ static int event_loop(struct _MwLLWayland* wayland) { if(wl_display_dispatch_pending(wayland->display) > 0) { } } else { - wl_display_cancel_read(wayland->display); + if(wl_display_dispatch_pending(wayland->display) == 0) { + MwLLDispatch(handle, draw, NULL); + } } + return 0; } @@ -532,11 +530,9 @@ static void setup_toplevel(MwLL r, int x, int y) { 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); - event_loop(&r->wayland); + event_loop(r); wl_region_destroy(region); - printf("%p\n", shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name)); - // setup decorations if we can if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(r->wayland, zxdg_decoration_manager_v1)->context; @@ -576,7 +572,7 @@ static void setup_subsurface(MwLL parent, MwLL r, int x, int y) { 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); - event_loop(&r->wayland); + event_loop(r); wl_region_destroy(region); r->wayland.subsurface = wl_subcompositor_get_subsurface(subcompositor, r->wayland.surface, parent_surface); @@ -628,13 +624,17 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(width == 0) width = 1; if(height == 0) height = 1; - r->wayland.ww = width; - r->wayland.wh = height; + r->wayland.ww = width; + r->wayland.wh = height; + printf("%d %d\n", x, y); + r->wayland.parent = parent; r->wayland.force_redraw = MwFALSE; r->common.success = MwTRUE; + r->wayland.x = x; + r->wayland.y = y; if(parent == NULL) { setup_toplevel(r, x, y); } else { @@ -668,14 +668,16 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { static void MwLLSetWHImpl(MwLL handle, int w, int h) { /* Prevent an integer underflow when the w/h is too low */ - if(w < 10 || h < 10) { + if((w < 10 || h < 10)) { + handle->wayland.ww = 10; + handle->wayland.wh = 10; return; } handle->wayland.ww = w; handle->wayland.wh = h; if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } else { } } @@ -685,6 +687,8 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL float maxX = 0, maxY = 0; float centerX, centerY; + glLineWidth(5); + 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 @@ -707,46 +711,23 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL /* 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 */ + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); framebuffer_action_begin(handle); - glBegin(GL_TRIANGLE_FAN); + glBegin(GL_TRIANGLES); 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); glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - /* If we have a polygon that's covering the whole screen, we want to do glClear - */ - if(x == 0 && y == 0) { - /* - We determine this by checking if all of the points are at the edge of the screen (and if there's more then 6 points). - Not a pretty solution, but unless the user does something weird like draw a triangle over itself twice, I'm pretty sure this is effective. - */ - if(points_count >= 6) { - MwBool doClear = MwTRUE; - for(n = 0; n < points_count; n++) { - if((points[n].x >= (handle->wayland.ww) - 1 || points[n].x <= 1) && (points[n].y >= (handle->wayland.wh) - 1 || points[n].y <= 1)) { - } else { - doClear = MwFALSE; - break; - } - } - if(doClear) { - glEnd(); - glClear(GL_COLOR_BUFFER_BIT); - glClearColor(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1); - glBegin(GL_TRIANGLE_FAN); - } - } - } - glVertex2f(x, y); - if(points_count > 3) { + if(points_count > 4) { glVertex2f(maxX, maxY); glVertex2f(x, y); } } glEnd(); + // glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); framebuffer_action_end(handle); } @@ -767,11 +748,12 @@ static void MwLLEndDrawImpl(MwLL handle) { h = parent->wayland.wh; } + glClear(GL_COLOR_BUFFER_BIT); + glClearColor(1.0, 0, 0, 1); glBindTexture(GL_TEXTURE_2D, handle->wayland.fbo_texture); - // glClear(GL_COLOR_BUFFER_BIT); - // glClearColor(0, 0, 0, 1); glColor3f(1.0, 1.0, 1.0); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glBegin(GL_QUADS); glTexCoord2f(0.0f, 1); @@ -814,7 +796,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return event_loop(&handle->wayland); + return event_loop(handle) || handle->wayland.force_redraw; } static void MwLLNextEventImpl(MwLL handle) { @@ -881,6 +863,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { glActiveTexture(pixmap->wayland.texture); framebuffer_action_begin(handle); + // glClear(GL_COLOR_BUFFER_BIT); + glColor3f(1, 1, 1); glBegin(GL_QUADS); glTexCoord2f(0.0f, 0); glVertex2f(x, y); diff --git a/src/core.c b/src/core.c index 401600d17..dc9025fe2 100644 --- a/src/core.c +++ b/src/core.c @@ -7,6 +7,7 @@ static void lldrawhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; + int ind; (void)data; @@ -14,6 +15,12 @@ static void lldrawhandler(MwLL handle, void* data) { MwDispatch(h, draw); if(h->draw_inject != NULL) h->draw_inject(h); MwDispatchUserHandler(h, MwNdrawHandler, NULL); + + if(h->parent == NULL) { + MwLLEndDraw(h->lowlevel); + } else if(h->parent->lowlevel == NULL) { + MwLLEndDraw(h->lowlevel); + } } static void lluphandler(MwLL handle, void* data) { @@ -334,8 +341,6 @@ void MwLoop(MwWidget handle) { } if(v != 0) break; - MwLLEndDraw(handle->lowlevel); - for(i = 0; i < arrlen(handle->tick_list); i++) { MwDispatch(handle->tick_list[i], tick); MwDispatchUserHandler(handle->tick_list[i], MwNtickHandler, NULL);