From f68b9a9aaef71d5b9d9a9e01132b678cee0c27b4 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 14 Dec 2025 17:04:35 -0700 Subject: [PATCH 001/409] remove egl stuff from wayland to make way for a software renderer lmao --- Makefile.pl | 6 +- include/Mw/LowLevel/Wayland.h | 47 ++-- pl/ostype/Linux.pl | 6 +- pl/rules.pl | 12 +- src/backend/wayland.c | 453 ++++++++++------------------------ src/widget/opengl.c | 22 +- 6 files changed, 170 insertions(+), 376 deletions(-) diff --git a/Makefile.pl b/Makefile.pl index 6eba069f6..2d42299b3 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -56,14 +56,16 @@ my %features = ( "vulkan" => "build Vulkan widget", "vulkan-string-helper" => "use Vulkan string helper", "shared" => "build shared library", - "static" => "build static library" + "static" => "build static library", + "experimental-wayland" => "enable WIP wayland backend", ); my @features_keys = ( "1classic-theme", "1stb-image", "1stb-truetype", "1freetype2", "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", - "1shared", "1static" + "1shared", "1static", + "1experimental-wayland" ); foreach my $l (@ARGV) { diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index af80f4762..394facf75 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -53,15 +53,27 @@ struct _MwLLWaylandTopLevel { MwBool xdg_surface_created; }; +struct _MwLLWaylandSublevel { + struct wl_subsurface* subsurface; + struct wl_subcompositor* subcompositor; + + MwLL parent; + MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ +}; + struct _MwLLWayland { struct _MwLLCommon common; - /* Pointer for data that's only loaded if the widget is a toplevel */ - struct _MwLLWaylandTopLevel* toplevel; + union { + /* Pointer for data that's only loaded if the widget is a toplevel */ + struct _MwLLWaylandTopLevel* toplevel; + /* Pointer for data that's only loaded if the widget is a sublevel */ + struct _MwLLWaylandSublevel* sublevel; + }; enum { MWLL_WAYLAND_TOPLEVEL = 0, - MWLL_WAYLAND_SUBLEVEL = 1, /* Sublevels are surfaces that have the toplevel as a parent. They could be implemented as subsurfaces if we ever switch away from OpenGL. Some parts of the code also call them subwidgets. */ + MWLL_WAYLAND_SUBLEVEL, /* Sublevels are surfaces that have the toplevel as a parent. Some parts of the code also call them subwidgets. */ } type; /* Map of Wayland interfaces to their relevant setup functions. */ @@ -79,33 +91,22 @@ struct _MwLLWayland { struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; - struct wl_subcompositor* subcompositor; struct wl_surface* surface; struct wl_registry_listener registry_listener; - struct wl_event_queue* event_queue; - - EGLNativeWindowType egl_window_native; - EGLDisplay egl_display; - EGLContext egl_context; - EGLSurface egl_surface; - EGLConfig egl_config; + /*struct wl_event_queue* event_queue;*/ MwLL* sublevels; /* stb_ds managed array of any sublevels */ MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ - MwBool egl_setup; /* Whether or not EGL has been set up */ - MwBool has_set_xy /* Whether or not MwSetXY has been called */; - int resize_counter; /* Counter that's for a hack in event_loop */ - MwU32 x, y, ww, wh; /* Window position */ - MwU32 lw, lh; /* Last known window position */ - MwPoint cur_mouse_pos; /* Currently known mouse position */ + MwU32 x, y, ww, wh; /* Window position */ + MwPoint cur_mouse_pos; /* Currently known mouse position */ - struct timeval timer; - MwU64 cooldown_timer; - MwU64 cooldown_timer_epoch; - - MwLL parent; - MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ + struct wl_shm* shm; + struct wl_shm_pool* shm_pool; + struct wl_buffer* shm_buffer; + void* mapped_shm_buf; + MwU64 mapped_shm_buf_size; + int shm_fd; }; struct _MwLLWaylandColor { diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index f695e4f7f..d87b73879 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,3 +1,7 @@ -use_backend("x11"); +if(param_get("experimental-wayland")) { + use_backend("wayland","x11"); +} else { + use_backend("x11"); +} 1; diff --git a/pl/rules.pl b/pl/rules.pl index ab5521b50..96d7a8e25 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -29,21 +29,15 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - if ($cross) { - add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon"); - } - else { - add_libs("-lGL -lEGL"); - add_cflags(`pkg-config --cflags wayland-egl wayland-client xkbcommon`); - add_libs(`pkg-config --libs wayland-egl wayland-client xkbcommon`); - } + add_cflags(`pkg-config --cflags wayland-client xkbcommon`); + add_libs(`pkg-config --libs wayland-client xkbcommon`); 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"; + $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; } if (param_get("stb-image")) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 307e1ee70..016456bd3 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -6,7 +6,6 @@ #include "../../external/stb_ds.h" #include -#include #include /* TODO: find out what FreeBSD and such wants us to include */ @@ -18,19 +17,6 @@ #include #endif -/* - * TODO: - * make sure MwLLDestroy is finished (+ handle dropdown bug that results from it) - * GNOME doesn't want to support zxdg_decoration_protocol so we're gonna design some Windows 95 ass ui just for that window manager. - * finish the rest of the owl - */ - -/* - * Redraw `handle` if the given cooldown hasn't expired (`time` >= `cooldown_timer` + `cooldown)). - * Used for pointer callbacks, resize callbacks, etc. to ensure we only resize every x milliseconds - */ -static void timed_redraw(MwLL handle, MwU32 time, int cooldown, MwU64* cooldown_timer); - /* Get the registered interface from r, or NULL if it doesn't currently have it. */ #define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) @@ -78,7 +64,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - timed_redraw(self, time, 50, &self->wayland.cooldown_timer); + /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; /* `wl_pointer.button` callback */ @@ -144,17 +130,6 @@ static void recursive_key_released(MwLL handle, void* ud) { } } -/* Recursively dispatch the draw event to `handle` and its children */ -static void recursive_draw(MwLL handle) { - int i; - if(handle->wayland.sublevels != NULL) { - for(i = 0; i < arrlen(handle->wayland.sublevels); i++) { - MwLLDispatch(handle->wayland.sublevels[i], draw, NULL); - recursive_draw(handle->wayland.sublevels[i]); - } - } -} - /* `wl_keyboard.keymap` callback */ static void keyboard_keymap(void* data, struct wl_keyboard* wl_keyboard, @@ -350,7 +325,7 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* /* wl_subcompositor setup function */ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); return NULL; } @@ -398,129 +373,6 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ return proto; } -/* EGL Setup function */ -static MwBool egl_setup(MwLL self, int x, int y, int width, int height) { - int err; - EGLint numConfigs; - EGLint majorVersion; - EGLint minorVersion; - EGLContext context; - EGLSurface surface; - EGLint fbAttribs[] = - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_NONE}; - EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 1, - EGL_CONTEXT_MAJOR_VERSION, 1, - EGL_CONTEXT_MINOR_VERSION, 1, - EGL_NONE}; - - EGLDisplay display; - 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, &self->wayland.egl_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, self->wayland.egl_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, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs); - if(context == EGL_NO_CONTEXT) { - printf("ERROR: eglCreateContext, %0X\n", eglGetError()); - return MwFALSE; - } - - self->wayland.egl_display = display; - self->wayland.egl_surface = surface; - self->wayland.egl_context = context; - - if(self->wayland.parent == NULL) { - if(!eglMakeCurrent(self->wayland.egl_display, self->wayland.egl_surface, self->wayland.egl_surface, self->wayland.egl_context)) { - printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); - } - } - - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glEnable(GL_SCISSOR_TEST); - - return MwTRUE; -} - -/* EGL reconfiguration function for resizes */ -static void egl_resetup(MwLL handle) { - float w, h; - - if(handle->wayland.parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.parent->wayland.ww; - h = handle->wayland.parent->wayland.wh; - } - - glViewport(handle->wayland.x, handle->wayland.y, w, h); - glScissor(handle->wayland.x, handle->wayland.y, w, h); -} - -static void timed_redraw(MwLL handle, MwU32 time, int cooldown, MwU64* cooldown_timer) { - if(handle->wayland.parent == NULL) { - if(time >= (*cooldown_timer + cooldown)) { - egl_resetup(handle); - MwLLDispatch(handle, draw, NULL); - *cooldown_timer = time; - } - } -} - -/* Same as timed_redraw but it uses the unix epoch as the cooldown timer. */ -static void timed_redraw_by_epoch(MwLL handle, int cooldown) { - gettimeofday(&handle->wayland.timer, NULL); - unsigned long long time = - (unsigned long long)(handle->wayland.timer.tv_sec) * 1000 + - (unsigned long long)(handle->wayland.timer.tv_usec) / 1000; - timed_redraw(handle, time, cooldown, &handle->wayland.cooldown_timer_epoch); -} - /* `xdg_toplevel.close` callback */ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, @@ -543,12 +395,12 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); - if(!self->wayland.egl_setup) { + /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); egl_resetup(self); - } + }*/ return; }; @@ -580,6 +432,58 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } +/* wl_shm setup function */ +static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { + int x, y; + int stride = wayland->ww * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + + wayland->mapped_shm_buf_size = wayland->ww * wayland->wh * 4; + + wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + + wayland->shm_fd = mkstemp(temp_name); + + unlink(temp_name); + + if(posix_fallocate(wayland->shm_fd, 0, wayland->mapped_shm_buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(wayland->shm_fd); + return NULL; + } + if(ftruncate(wayland->shm_fd, wayland->mapped_shm_buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(wayland->shm_fd); + return NULL; + } + + wayland->mapped_shm_buf = mmap(NULL, wayland->mapped_shm_buf_size, PROT_WRITE, MAP_SHARED, wayland->shm_fd, 0); + + fsync(wayland->shm_fd); + + if(!(wayland->shm_pool = wl_shm_create_pool(wayland->shm, wayland->shm_fd, wayland->mapped_shm_buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + + wayland->shm_buffer = wl_shm_pool_create_buffer(wayland->shm_pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); + + if(wayland->configured) { + wl_surface_attach(wayland->surface, wayland->shm_buffer, 0, 0); + wl_surface_commit(wayland->surface); + } + + return NULL; +} + +static void update_buffer(MwLL handle) { + fsync(handle->wayland.shm_fd); + + if(handle->wayland.configured) { + wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.surface); + } +} + /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { enum { @@ -588,9 +492,8 @@ static int event_loop(MwLL handle) { CURSOR_FD }; struct pollfd fd; - int timeout = 100; - struct _MwLLWayland* wayland = &handle->wayland; - MwLL topmost_parent = handle->wayland.parent; + int timeout = 1; + struct _MwLLWayland* wayland = &handle->wayland; if(wayland->display == NULL) { return 0; @@ -598,6 +501,12 @@ static int event_loop(MwLL handle) { fd.fd = wl_display_get_fd(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 */ while(wl_display_flush(wayland->display) == -1) { if(errno != EAGAIN) { @@ -614,33 +523,23 @@ static int event_loop(MwLL handle) { } } + /* 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(wayland->display); if(wl_display_dispatch_pending(wayland->display) > 0) { } } else { - /* Condition for no events being sent */ - if(wl_display_dispatch_pending(wayland->display) == 0) { - if(wayland->event_queue != NULL) { - if(wl_display_roundtrip_queue(wayland->display, wayland->event_queue) < 0) { - printf("error\n"); - }; - } - /* HACK: If the last known size is different, force a redraw */ - if(wayland->lw != wayland->ww || wayland->lh != wayland->wh) { - MwLLDispatch(handle, draw, 0); - wayland->resize_counter++; - if(wayland->resize_counter >= 5) { - wayland->lw = wayland->ww; - wayland->lh = wayland->wh; - wayland->lh = wayland->wh; - wayland->resize_counter = 0; - } - } - } + wl_display_cancel_read(handle->wayland.display); } - return 0; + return 1; } /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ @@ -655,13 +554,15 @@ 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); WL_INTERFACE(wl_seat); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(wp_cursor_shape_manager_v1); + } else { + WL_INTERFACE(wl_subcompositor); } #undef WL_INTERFACE } @@ -670,9 +571,8 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { static void setup_toplevel(MwLL r, int x, int y) { int i; - r->wayland.type = MWLL_WAYLAND_TOPLEVEL; - r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); - r->wayland.topmost_parent = NULL; + r->wayland.type = MWLL_WAYLAND_TOPLEVEL; + r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); setup_callbacks(&r->wayland); @@ -731,27 +631,17 @@ static void setup_toplevel(MwLL r, int x, int y) { printf("zxdg null\n"); } - r->wayland.event_queue = wl_display_create_queue(r->wayland.display); - - egl_resetup(r); + /*egl_resetup(r); MwLLDispatch(r, draw, NULL); - recursive_draw(r); + recursive_draw(r);*/ } /* Sublevel setup function */ static void setup_sublevel(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; - struct wl_region* region; - { - MwLL topmost_parent = parent; + struct wl_compositor* compositor = parent->wayland.compositor; + struct wl_surface* parent_surface = parent->wayland.surface; - while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - topmost_parent = topmost_parent->wayland.parent; - } - r->wayland.topmost_parent = topmost_parent; - } + r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); r->wayland.type = MWLL_WAYLAND_SUBLEVEL; @@ -759,17 +649,12 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { 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); - wl_region_destroy(region); - setup_callbacks(&r->wayland); - r->wayland.registry = wl_display_get_registry(r->wayland.topmost_parent->wayland.display); - r->wayland.display = r->wayland.topmost_parent->wayland.display; + // printf("position %d %d\n", x, y); + + 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) { @@ -778,23 +663,11 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { return; } + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.surface, parent_surface); + + wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); + r->wayland.configured = MwTRUE; - if(!r->wayland.egl_setup) { - r->wayland.egl_setup = egl_setup(r, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); - egl_resetup(r); - MwLLDispatch(r, draw, NULL); - recursive_draw(r); - }; - - r->wayland.event_queue = parent->wayland.event_queue; - - arrpush(parent->wayland.sublevels, r); - - wl_surface_damage(parent->wayland.surface, 0, 0, parent->wayland.ww, parent->wayland.wh); - - egl_resetup(r->wayland.topmost_parent); - MwLLDispatch(r->wayland.topmost_parent, draw, NULL); - recursive_draw(r->wayland.topmost_parent); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -819,12 +692,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.x = x; r->wayland.y = y; - r->wayland.parent = parent; - - r->wayland.cooldown_timer = 0; - r->wayland.has_set_xy = MwFALSE; - r->wayland.resize_counter = 0; - r->wayland.sublevels = NULL; if(parent == NULL) { @@ -833,12 +700,21 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_sublevel(parent, r, x, y); } + /* example of writing to the buffer */ + memset(r->wayland.mapped_shm_buf, 127, r->wayland.mapped_shm_buf_size); + update_buffer(r); + return r; } static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); + munmap(handle->wayland.mapped_shm_buf, handle->wayland.mapped_shm_buf_size); + wl_buffer_destroy(handle->wayland.mapped_shm_buf); + wl_shm_pool_destroy(handle->wayland.shm_pool); + close(handle->wayland.shm_fd); + free(handle); } @@ -853,111 +729,64 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { handle->wayland.x = x; handle->wayland.y = y; - if(handle->wayland.has_set_xy) { + /*if(handle->wayland.has_set_xy) { timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - /* recursive_draw(handle->wayland.topmost_parent); */ } else if(x != 0 && y != 0) { handle->wayland.has_set_xy = MwTRUE; - } + }*/ } } 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)) { - handle->wayland.ww = handle->wayland.lw = 10; - handle->wayland.wh = handle->wayland.lh = 10; + handle->wayland.ww = 10; + handle->wayland.wh = 10; return; } - handle->wayland.ww = handle->wayland.lw = w; - handle->wayland.wh = handle->wayland.lh = 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, 0, 0, handle->wayland.ww, handle->wayland.wh); } else { - timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - /* recursive_draw(handle->wayland.topmost_parent); */ + /* timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); + recursive_draw(handle->wayland.topmost_parent); */ } } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i, n; - float maxX = 0, maxY = 0; - float centerX, centerY; - float w, h; - - if(handle->wayland.parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } - - glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - - glBegin(GL_POLYGON); - - for(i = 0; i < points_count; i++) { - float x = ((float)(handle->wayland.x + points[i].x) / (w / 2)) - 1.0; - float y = 1.0 - ((float)(handle->wayland.y + points[i].y) / (h / 2)); - - glVertex2f(x, y); - } - glEnd(); - glColor3f(0, 0, 0); + /* todo */ } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - int i; - float w, h; - - if(handle->wayland.topmost_parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } - - glLineWidth(1); - glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - - glBegin(GL_LINES); - for(i = 0; i < 2; i++) { - float x = ((float)(handle->wayland.x + points[i].x) / (w / 2)) - 1.0; - float y = 1.0 - ((float)(handle->wayland.y + points[i].y) / (h / 2)); - - glVertex2f(x, y); - } - glEnd(); - glColor3f(0, 0, 0); + /* todo */ } static void MwLLBeginDrawImpl(MwLL handle) { - if(handle->wayland.parent == NULL) { - 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; - } - } + /* if(handle->wayland.parent == NULL) { + 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; + } + }*/ } static void MwLLEndDrawImpl(MwLL handle) { int w, h; - recursive_draw(handle); + /*recursive_draw(handle);*/ /* glClear(GL_COLOR_BUFFER_BIT); */ /* glClearColor(1.0, 0, 0, 1); */ - if(handle->wayland.parent == NULL) { + /* if(handle->wayland.parent == NULL) { if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { - printf("error swapping buffers! %0X\n", eglGetError()); - } else { - wl_surface_commit(handle->wayland.surface); - } - } + printf("error swapping buffers! %0X\n", eglGetError()); + } else { + wl_surface_commit(handle->wayland.surface); + } +}*/ } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -981,8 +810,6 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - if(wl_display_dispatch_pending(handle->wayland.display) == 0) { - } return event_loop(handle); } @@ -1029,35 +856,7 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - float x, y, w, h; - - if(handle->wayland.topmost_parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } - - x = ((float)(handle->wayland.x + rect->x) / (w / 2)) - 1.0; - y = 1.0 - ((float)(handle->wayland.y + rect->y) / (h / 2)); - - glColor3f(1.0, 1.0, 1.0); - - glBindTexture(GL_TEXTURE_2D, pixmap->wayland.texture); - glActiveTexture(pixmap->wayland.texture); - - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0); - glVertex2f(x, y); - glTexCoord2f(1, 0); - glVertex2f(x + (rect->width / (w / 2)), y); - glTexCoord2f(1, 1); - glVertex2f(x + (rect->width / (w / 2)), y - (rect->height / (h / 2))); - glTexCoord2f(0.0f, 1); - glVertex2f(x, y - (rect->height / (h / 2))); - glEnd(); - glFinish(); + /* todo */ } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } @@ -1065,9 +864,11 @@ 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) { timed_redraw_by_epoch(handle, 25); } + */ } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index f6cc36933..9552ae4d7 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,12 +1,6 @@ #include #include -#ifdef USE_WAYLAND -#include -#include -#include -#endif - #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); @@ -110,8 +104,8 @@ static int create(MwWidget handle) { } #endif #ifdef USE_WAYLAND - /* Wayland uses OpenGL as its backend so its already initialized */ if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ } #endif @@ -146,7 +140,9 @@ static void destroy(MwWidget handle) { } #endif #ifdef USE_WAYLAND -/* Wayland uses OpenGL as its backend so its destroyed accordingly */ + if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ + } #endif free(handle->internal); @@ -169,6 +165,7 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ } #endif } @@ -189,14 +186,9 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { } #endif #ifdef USE_WAYLAND -#define tp handle->lowlevel->wayland.topmost_parent->wayland if(handle->lowlevel->common.type == MwLLBackendWayland) { - if(!eglSwapBuffers( - tp.egl_display, tp.egl_surface)) { - printf("Userland error: eglSwapBuffers, %0X\n", eglGetError()); - } + /* todo */ } -#undef topmost_parent #endif } @@ -217,7 +209,7 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - return eglGetProcAddress(name); + /* todo */ } #endif return NULL; From 4951e8995e4fd63dd6461544cf2c66a6ad7d5cc5 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 15 Dec 2025 09:31:33 +0900 Subject: [PATCH 002/409] remove egl dependency --- include/Mw/LowLevel/Wayland.h | 6 ------ src/backend/wayland.c | 18 +++--------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 394facf75..cc334e032 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -12,10 +12,6 @@ #include #include -#include -#include -#include -#include #include #include @@ -115,8 +111,6 @@ struct _MwLLWaylandColor { struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; - GLuint texture; - MwBool texture_deleted; }; #endif diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 016456bd3..be24dbcb0 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -827,17 +827,8 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid 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); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); MwLLPixmapUpdate(r); @@ -845,13 +836,10 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid } 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); + /* TODO */ } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - glDeleteTextures(1, &pixmap->wayland.texture); free(pixmap); } From 7a81af99225da838bc7859eb8cc128c75e4d9ef8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 15 Dec 2025 11:05:20 +0900 Subject: [PATCH 003/409] some stuffs work --- Makefile.pl | 7 ++- include/Mw/BaseTypes.h | 4 +- include/Mw/LowLevel/Wayland.h | 4 ++ pl/ostype/Linux.pl | 7 ++- pl/rules.pl | 4 +- src/backend/wayland.c | 108 ++++++++++++++++++++++------------ src/draw.c | 4 +- src/widget/frame.c | 1 - src/widget/listbox.c | 1 - src/widget/opengl.c | 3 +- src/widget/scrollbar.c | 8 +-- 11 files changed, 96 insertions(+), 55 deletions(-) diff --git a/Makefile.pl b/Makefile.pl index 2d42299b3..4f5d5d58d 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -173,8 +173,11 @@ print(OUT "\n"); print(OUT "all: lib examples\n"); print(OUT "\n"); print(OUT "install: lib\n"); -print(OUT " mkdir -p \$(DESTDIR)\$(PREFIX)/lib \$(DESTDIR)\$(PREFIX)/include\n"); -print(OUT " -cp src/${library_prefix}Mw${library_suffix} \$(DESTDIR)\$(PREFIX)/lib/\n"); +print(OUT + " mkdir -p \$(DESTDIR)\$(PREFIX)/lib \$(DESTDIR)\$(PREFIX)/include\n"); +print(OUT +" -cp src/${library_prefix}Mw${library_suffix} \$(DESTDIR)\$(PREFIX)/lib/\n" +); print(OUT " -cp src/libMw.a \$(DESTDIR)\$(PREFIX)/lib/\n"); print(OUT " cp -rf include \$(DESTDIR)\$(PREFIX)/\n"); print(OUT "\n"); diff --git a/include/Mw/BaseTypes.h b/include/Mw/BaseTypes.h index ca718ea4a..101486970 100644 --- a/include/Mw/BaseTypes.h +++ b/include/Mw/BaseTypes.h @@ -58,8 +58,8 @@ typedef unsigned long MwU64; #ifdef MW_OTHER_TYPES_DEFINED #undef MW_OTHER_TYPES_DEFINED #else -typedef int MwI32; -typedef unsigned int MwU32; +typedef int MwI32; +typedef unsigned int MwU32; typedef short MwI16; typedef unsigned short MwU16; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index cc334e032..b37bd45a7 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -15,6 +15,7 @@ #include #include +#include MWDECL int MwLLWaylandCallInit(void); @@ -103,6 +104,9 @@ struct _MwLLWayland { void* mapped_shm_buf; MwU64 mapped_shm_buf_size; int shm_fd; + + cairo_surface_t* cs; + cairo_t* cairo; }; struct _MwLLWaylandColor { diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index d87b73879..155cd4aaf 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,6 +1,7 @@ -if(param_get("experimental-wayland")) { - use_backend("wayland","x11"); -} else { +if (param_get("experimental-wayland")) { + use_backend("wayland", "x11"); +} +else { use_backend("x11"); } diff --git a/pl/rules.pl b/pl/rules.pl index 96d7a8e25..fc88c10b4 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -29,8 +29,8 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - add_cflags(`pkg-config --cflags wayland-client xkbcommon`); - add_libs(`pkg-config --libs wayland-client xkbcommon`); + add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); + add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); 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 be24dbcb0..b034ab4f8 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -38,20 +38,18 @@ static void new_protocol(void* data, struct wl_registry* registry, /* `wl_registry.global_remove` callback */ static void protocol_removed(void* data, struct wl_registry* registry, - MwU32 name) { + MwU32 name){ }; /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y) { -}; + wl_fixed_t surface_y){}; /* `wl_pointer.leave` callback */ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface) { -}; + struct wl_surface* surface){}; /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, @@ -93,12 +91,13 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; } } + MwLLDispatch(self, draw, NULL); }; /* `wl_pointer.axis` callback */ static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, - MwU32 axis, wl_fixed_t value) {}; + MwU32 axis, wl_fixed_t value){}; struct wl_pointer_listener pointer_listener = { .enter = pointer_enter, @@ -267,7 +266,7 @@ static void keyboard_modifiers(void* data, MwU32 mods_depressed, MwU32 mods_latched, MwU32 mods_locked, - MwU32 group) {}; + MwU32 group){}; struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, @@ -279,7 +278,7 @@ struct wl_keyboard_listener keyboard_listener = { /* `wl_seat.name` callback */ static void -wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; +wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name){}; /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, @@ -393,7 +392,13 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); + cairo_destroy(self->wayland.cairo); + cairo_surface_destroy(self->wayland.cs); + self->wayland.cs = cairo_image_surface_create_for_data(self->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); + self->wayland.cairo = cairo_create(self->wayland.cs); + MwLLDispatch(self, resize, NULL); + MwLLDispatch(self, draw, NULL); /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); @@ -544,7 +549,6 @@ static int event_loop(MwLL handle) { /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ static void setup_callbacks(struct _MwLLWayland* wayland) { - /* Convience macro for adding the interface functions to the setup map */ #define WL_INTERFACE(interface) \ shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); @@ -677,8 +681,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.type = MwLLBackendWayland; - if(width == 0) width = 1; - if(height == 0) height = 1; + if(width < 2) width = 2; + if(height < 2) height = 2; if(x == MwDEFAULT) { x = 0; @@ -701,15 +705,23 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } /* example of writing to the buffer */ - memset(r->wayland.mapped_shm_buf, 127, r->wayland.mapped_shm_buf_size); + memset(r->wayland.mapped_shm_buf, 255, r->wayland.mapped_shm_buf_size); update_buffer(r); + r->wayland.cs = cairo_image_surface_create_for_data(r->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); + r->wayland.cairo = cairo_create(r->wayland.cs); + + MwLLForceRender(r); + return r; } static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); + cairo_destroy(handle->wayland.cairo); + cairo_surface_destroy(handle->wayland.cs); + munmap(handle->wayland.mapped_shm_buf, handle->wayland.mapped_shm_buf_size); wl_buffer_destroy(handle->wayland.mapped_shm_buf); wl_shm_pool_destroy(handle->wayland.shm_pool); @@ -734,7 +746,10 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { } else if(x != 0 && y != 0) { handle->wayland.has_set_xy = MwTRUE; }*/ + + wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); } + MwLLDispatch(handle, draw, NULL); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -753,40 +768,47 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { /* timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); recursive_draw(handle->wayland.topmost_parent); */ } + MwLLDispatch(handle, draw, NULL); } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - /* todo */ + int i; + + cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.cairo); + for(i = 0; i < points_count; i++) { + if(i == 0) { + cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle->wayland.cairo); + cairo_fill(handle->wayland.cairo); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - /* todo */ + int i; + + cairo_set_line_cap(handle->wayland.cairo, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.cairo); + for(i = 0; i < 2; i++) { + if(i == 0) { + cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + } + } + cairo_close_path(handle->wayland.cairo); + cairo_stroke(handle->wayland.cairo); } static void MwLLBeginDrawImpl(MwLL handle) { - /* if(handle->wayland.parent == NULL) { - 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; - } - }*/ } static void MwLLEndDrawImpl(MwLL handle) { - int w, h; - - /*recursive_draw(handle);*/ - - /* glClear(GL_COLOR_BUFFER_BIT); */ - /* glClearColor(1.0, 0, 0, 1); */ - - /* if(handle->wayland.parent == NULL) { - if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { - printf("error swapping buffers! %0X\n", eglGetError()); - } else { - wl_surface_commit(handle->wayland.surface); - } -}*/ + update_buffer(handle); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -825,9 +847,9 @@ 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 = malloc(4 * width * height); + r->common.width = width; + r->common.height = height; + r->common.raw = malloc(4 * width * height); memcpy(r->common.raw, data, 4 * width * height); MwLLPixmapUpdate(r); @@ -840,11 +862,21 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap r) { } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - /* todo */ + int y, x; + for(y = rect->y; y < rect->y + rect->height; y++) { + if(y < 0 || y >= handle->wayland.wh) continue; + for(x = rect->x; x < rect->x + rect->width; x++) { + if(x < 0 || x >= handle->wayland.ww) continue; + + /* TODO */ + //((unsigned char*)handle->wayland.mapped_shm_buf)[(x + y * handle->wayland.ww) * 4 + 0] = 0x80; + } + } } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } diff --git a/src/draw.c b/src/draw.c index 636dc7874..f8489dcf7 100644 --- a/src/draw.c +++ b/src/draw.c @@ -109,7 +109,9 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = rect->width * rect->height * 4; - unsigned char* data = malloc(sz); + unsigned char* data; + + data = malloc(sz); memset(data, 0, sz); for(y = 0; y < rect->height; y++) { diff --git a/src/widget/frame.c b/src/widget/frame.c index 38ff990fe..294f1109b 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -29,7 +29,6 @@ static void draw(MwWidget handle) { rr.width = MwGetInteger(handle, MwNwidth) - (MwDefaultBorderWidth(handle) * 2); rr.height = MwGetInteger(handle, MwNheight) - (MwDefaultBorderWidth(handle) * 2); } else { - rr.x = 0; rr.y = 0; rr.width = MwGetInteger(handle, MwNwidth); diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 784594b18..18415949b 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -258,7 +258,6 @@ static void frame_draw(MwWidget handle) { if(j == (arrlen(lb->list[i].name) - 1)) p.x -= MwDefaultBorderWidth(handle); if(arrlen(lb->alignment) <= j || lb->alignment[j] == MwALIGNMENT_BEGINNING) { - p.x += 4; MwDrawText(handle, &p, str, 0, MwALIGNMENT_BEGINNING, selected ? base2 : text2); p.x -= 4; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 9552ae4d7..8c3b1ac88 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -89,7 +89,8 @@ static int create(MwWidget handle) { attribs[3] = 24; attribs[4] = None; - while(glpath[glincr] != NULL && (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL); + while(glpath[glincr] != NULL && (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL) + ; o->glXChooseVisual = (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); o->glXCreateContext = (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index e00d0b550..4058c813e 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -144,7 +144,7 @@ static void draw(MwWidget handle) { } static void mouse_move(MwWidget handle) { - int or = MwGetInteger(handle, MwNorientation); + int or = MwGetInteger(handle, MwNorientation); scrollbar_t* scr = handle->internal; if(!handle->pressed) return; @@ -172,9 +172,9 @@ static void mouse_move(MwWidget handle) { } static void mouse_down(MwWidget handle, void* ptr) { - int ww = MwGetInteger(handle, MwNwidth); - int wh = MwGetInteger(handle, MwNheight); - int or = MwGetInteger(handle, MwNorientation); + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); scrollbar_t* scr = handle->internal; MwLLMouse* m = ptr; From bee6cb81cad42d6dae18810d765a56a8d9a76a36 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 15 Dec 2025 11:07:58 +0900 Subject: [PATCH 004/409] now ACTUALLY format --- include/Mw/BaseTypes.h | 4 ++-- src/backend/wayland.c | 12 ++++++------ src/widget/opengl.c | 3 +-- src/widget/scrollbar.c | 8 ++++---- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/Mw/BaseTypes.h b/include/Mw/BaseTypes.h index 101486970..ca718ea4a 100644 --- a/include/Mw/BaseTypes.h +++ b/include/Mw/BaseTypes.h @@ -58,8 +58,8 @@ typedef unsigned long MwU64; #ifdef MW_OTHER_TYPES_DEFINED #undef MW_OTHER_TYPES_DEFINED #else -typedef int MwI32; -typedef unsigned int MwU32; +typedef int MwI32; +typedef unsigned int MwU32; typedef short MwI16; typedef unsigned short MwU16; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index b034ab4f8..48ce0c439 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -38,18 +38,18 @@ static void new_protocol(void* data, struct wl_registry* registry, /* `wl_registry.global_remove` callback */ static void protocol_removed(void* data, struct wl_registry* registry, - MwU32 name){ + MwU32 name) { }; /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y){}; + wl_fixed_t surface_y) {}; /* `wl_pointer.leave` callback */ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface){}; + struct wl_surface* surface) {}; /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, @@ -97,7 +97,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri /* `wl_pointer.axis` callback */ static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, - MwU32 axis, wl_fixed_t value){}; + MwU32 axis, wl_fixed_t value) {}; struct wl_pointer_listener pointer_listener = { .enter = pointer_enter, @@ -266,7 +266,7 @@ static void keyboard_modifiers(void* data, MwU32 mods_depressed, MwU32 mods_latched, MwU32 mods_locked, - MwU32 group){}; + MwU32 group) {}; struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, @@ -278,7 +278,7 @@ struct wl_keyboard_listener keyboard_listener = { /* `wl_seat.name` callback */ static void -wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name){}; +wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 8c3b1ac88..9552ae4d7 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -89,8 +89,7 @@ static int create(MwWidget handle) { attribs[3] = 24; attribs[4] = None; - while(glpath[glincr] != NULL && (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL) - ; + while(glpath[glincr] != NULL && (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL); o->glXChooseVisual = (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); o->glXCreateContext = (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 4058c813e..e00d0b550 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -144,7 +144,7 @@ static void draw(MwWidget handle) { } static void mouse_move(MwWidget handle) { - int or = MwGetInteger(handle, MwNorientation); + int or = MwGetInteger(handle, MwNorientation); scrollbar_t* scr = handle->internal; if(!handle->pressed) return; @@ -172,9 +172,9 @@ static void mouse_move(MwWidget handle) { } static void mouse_down(MwWidget handle, void* ptr) { - int ww = MwGetInteger(handle, MwNwidth); - int wh = MwGetInteger(handle, MwNheight); - int or = MwGetInteger(handle, MwNorientation); + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); scrollbar_t* scr = handle->internal; MwLLMouse* m = ptr; From 7f43a974cd9cdee870909c95c0afbae41b01e339 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 15 Dec 2025 12:21:14 +0900 Subject: [PATCH 005/409] pixmap works --- include/Mw/LowLevel/Wayland.h | 2 ++ src/backend/wayland.c | 45 +++++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index b37bd45a7..32f6547b2 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -115,6 +115,8 @@ struct _MwLLWaylandColor { struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; + + cairo_surface_t* cs; }; #endif diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 48ce0c439..d0e0e2548 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -852,31 +852,56 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid r->common.raw = malloc(4 * width * height); memcpy(r->common.raw, data, 4 * width * height); + r->wayland.cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); + MwLLPixmapUpdate(r); return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap r) { - /* TODO */ + int i; + unsigned char* d; + + cairo_surface_flush(r->wayland.cs); + d = cairo_image_surface_get_data(r->wayland.cs); + for(i = 0; i < r->common.width * r->common.height * 4; i += 4){ + MwU32* p = (MwU32*)&d[i]; + *p <<= 8; + *p |= r->common.raw[i + 3]; + *p <<= 8; + *p |= r->common.raw[i + 0]; + *p <<= 8; + *p |= r->common.raw[i + 1]; + *p <<= 8; + *p |= r->common.raw[i + 2]; + } + cairo_surface_mark_dirty(r->wayland.cs); } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + cairo_surface_destroy(pixmap->wayland.cs); free(pixmap->common.raw); free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - int y, x; - for(y = rect->y; y < rect->y + rect->height; y++) { - if(y < 0 || y >= handle->wayland.wh) continue; - for(x = rect->x; x < rect->x + rect->width; x++) { - if(x < 0 || x >= handle->wayland.ww) continue; + cairo_t* c; + cairo_surface_t* cs; - /* TODO */ - //((unsigned char*)handle->wayland.mapped_shm_buf)[(x + y * handle->wayland.ww) * 4 + 0] = 0x80; - } - } + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); + c = cairo_create(cs); + + cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); + cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); + cairo_paint(c); + + cairo_set_source_rgb(handle->wayland.cairo, 1, 1, 1); + cairo_set_source_surface(handle->wayland.cairo, cs, rect->x, rect->y); + cairo_paint(handle->wayland.cairo); + + cairo_destroy(c); + cairo_surface_destroy(cs); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } From 7f823e2d34fcdb9b28976ab03066b979a3cc65c0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 15 Dec 2025 12:22:01 +0900 Subject: [PATCH 006/409] format --- src/backend/wayland.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d0e0e2548..83e7439c9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -860,12 +860,12 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid } static void MwLLPixmapUpdateImpl(MwLLPixmap r) { - int i; + int i; unsigned char* d; cairo_surface_flush(r->wayland.cs); d = cairo_image_surface_get_data(r->wayland.cs); - for(i = 0; i < r->common.width * r->common.height * 4; i += 4){ + for(i = 0; i < r->common.width * r->common.height * 4; i += 4) { MwU32* p = (MwU32*)&d[i]; *p <<= 8; *p |= r->common.raw[i + 3]; @@ -886,11 +886,11 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - cairo_t* c; + cairo_t* c; cairo_surface_t* cs; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); - c = cairo_create(cs); + c = cairo_create(cs); cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); From 320de34ce8d280cd01e1327ce3e3e2a6f6d8ea81 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 17 Dec 2025 19:14:54 -0700 Subject: [PATCH 007/409] remove opengl from wayland in favor of cairo --- Makefile.pl | 6 +- include/Mw/LowLevel/Wayland.h | 57 ++-- pl/ostype/Linux.pl | 7 +- pl/rules.pl | 12 +- src/backend/wayland.c | 540 ++++++++++++---------------------- src/widget/frame.c | 1 - src/widget/listbox.c | 1 - src/widget/opengl.c | 22 +- 8 files changed, 242 insertions(+), 404 deletions(-) diff --git a/Makefile.pl b/Makefile.pl index c00ca62b9..ea9f90cb5 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -56,14 +56,16 @@ my %features = ( "vulkan" => "build Vulkan widget", "vulkan-string-helper" => "use Vulkan string helper", "shared" => "build shared library", - "static" => "build static library" + "static" => "build static library", + "experimental-wayland" => "enable WIP wayland backend", ); my @features_keys = ( "1classic-theme", "1stb-image", "1stb-truetype", "1freetype2", "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", - "1shared", "1static" + "1shared", "1static", + "1experimental-wayland" ); foreach my $l (@ARGV) { diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index af80f4762..32f6547b2 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -12,13 +12,10 @@ #include #include -#include -#include -#include -#include #include #include +#include MWDECL int MwLLWaylandCallInit(void); @@ -53,15 +50,27 @@ struct _MwLLWaylandTopLevel { MwBool xdg_surface_created; }; +struct _MwLLWaylandSublevel { + struct wl_subsurface* subsurface; + struct wl_subcompositor* subcompositor; + + MwLL parent; + MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ +}; + struct _MwLLWayland { struct _MwLLCommon common; - /* Pointer for data that's only loaded if the widget is a toplevel */ - struct _MwLLWaylandTopLevel* toplevel; + union { + /* Pointer for data that's only loaded if the widget is a toplevel */ + struct _MwLLWaylandTopLevel* toplevel; + /* Pointer for data that's only loaded if the widget is a sublevel */ + struct _MwLLWaylandSublevel* sublevel; + }; enum { MWLL_WAYLAND_TOPLEVEL = 0, - MWLL_WAYLAND_SUBLEVEL = 1, /* Sublevels are surfaces that have the toplevel as a parent. They could be implemented as subsurfaces if we ever switch away from OpenGL. Some parts of the code also call them subwidgets. */ + MWLL_WAYLAND_SUBLEVEL, /* Sublevels are surfaces that have the toplevel as a parent. Some parts of the code also call them subwidgets. */ } type; /* Map of Wayland interfaces to their relevant setup functions. */ @@ -79,33 +88,25 @@ struct _MwLLWayland { struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; - struct wl_subcompositor* subcompositor; struct wl_surface* surface; struct wl_registry_listener registry_listener; - struct wl_event_queue* event_queue; - - EGLNativeWindowType egl_window_native; - EGLDisplay egl_display; - EGLContext egl_context; - EGLSurface egl_surface; - EGLConfig egl_config; + /*struct wl_event_queue* event_queue;*/ MwLL* sublevels; /* stb_ds managed array of any sublevels */ MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ - MwBool egl_setup; /* Whether or not EGL has been set up */ - MwBool has_set_xy /* Whether or not MwSetXY has been called */; - int resize_counter; /* Counter that's for a hack in event_loop */ - MwU32 x, y, ww, wh; /* Window position */ - MwU32 lw, lh; /* Last known window position */ - MwPoint cur_mouse_pos; /* Currently known mouse position */ + MwU32 x, y, ww, wh; /* Window position */ + MwPoint cur_mouse_pos; /* Currently known mouse position */ - struct timeval timer; - MwU64 cooldown_timer; - MwU64 cooldown_timer_epoch; + struct wl_shm* shm; + struct wl_shm_pool* shm_pool; + struct wl_buffer* shm_buffer; + void* mapped_shm_buf; + MwU64 mapped_shm_buf_size; + int shm_fd; - MwLL parent; - MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ + cairo_surface_t* cs; + cairo_t* cairo; }; struct _MwLLWaylandColor { @@ -114,8 +115,8 @@ struct _MwLLWaylandColor { struct _MwLLWaylandPixmap { struct _MwLLCommonPixmap common; - GLuint texture; - MwBool texture_deleted; + + cairo_surface_t* cs; }; #endif diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index f695e4f7f..155cd4aaf 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,3 +1,8 @@ -use_backend("x11"); +if (param_get("experimental-wayland")) { + use_backend("wayland", "x11"); +} +else { + use_backend("x11"); +} 1; diff --git a/pl/rules.pl b/pl/rules.pl index f8aec46d6..5cb4a90a2 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -29,21 +29,15 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - if ($cross) { - add_libs("-lGL -lEGL -lwayland-egl -lwayland-client -lxkbcommon"); - } - else { - add_libs("-lGL -lEGL"); - add_cflags(`pkg-config --cflags wayland-egl wayland-client xkbcommon`); - add_libs(`pkg-config --libs wayland-egl wayland-client xkbcommon`); - } + add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); + add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); 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"; + $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; } if (param_get("stb-image")) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 307e1ee70..83e7439c9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -6,7 +6,6 @@ #include "../../external/stb_ds.h" #include -#include #include /* TODO: find out what FreeBSD and such wants us to include */ @@ -18,19 +17,6 @@ #include #endif -/* - * TODO: - * make sure MwLLDestroy is finished (+ handle dropdown bug that results from it) - * GNOME doesn't want to support zxdg_decoration_protocol so we're gonna design some Windows 95 ass ui just for that window manager. - * finish the rest of the owl - */ - -/* - * Redraw `handle` if the given cooldown hasn't expired (`time` >= `cooldown_timer` + `cooldown)). - * Used for pointer callbacks, resize callbacks, etc. to ensure we only resize every x milliseconds - */ -static void timed_redraw(MwLL handle, MwU32 time, int cooldown, MwU64* cooldown_timer); - /* Get the registered interface from r, or NULL if it doesn't currently have it. */ #define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) @@ -59,13 +45,11 @@ static void protocol_removed(void* data, /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y) { -}; + wl_fixed_t surface_y) {}; /* `wl_pointer.leave` callback */ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface) { -}; + struct wl_surface* surface) {}; /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, @@ -78,7 +62,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - timed_redraw(self, time, 50, &self->wayland.cooldown_timer); + /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; /* `wl_pointer.button` callback */ @@ -107,6 +91,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; } } + MwLLDispatch(self, draw, NULL); }; @@ -144,17 +129,6 @@ static void recursive_key_released(MwLL handle, void* ud) { } } -/* Recursively dispatch the draw event to `handle` and its children */ -static void recursive_draw(MwLL handle) { - int i; - if(handle->wayland.sublevels != NULL) { - for(i = 0; i < arrlen(handle->wayland.sublevels); i++) { - MwLLDispatch(handle->wayland.sublevels[i], draw, NULL); - recursive_draw(handle->wayland.sublevels[i]); - } - } -} - /* `wl_keyboard.keymap` callback */ static void keyboard_keymap(void* data, struct wl_keyboard* wl_keyboard, @@ -350,7 +324,7 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* /* wl_subcompositor setup function */ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); return NULL; } @@ -398,129 +372,6 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ return proto; } -/* EGL Setup function */ -static MwBool egl_setup(MwLL self, int x, int y, int width, int height) { - int err; - EGLint numConfigs; - EGLint majorVersion; - EGLint minorVersion; - EGLContext context; - EGLSurface surface; - EGLint fbAttribs[] = - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - EGL_NONE}; - EGLint contextAttribs[] = { - EGL_CONTEXT_CLIENT_VERSION, 1, - EGL_CONTEXT_MAJOR_VERSION, 1, - EGL_CONTEXT_MINOR_VERSION, 1, - EGL_NONE}; - - EGLDisplay display; - 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, &self->wayland.egl_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, self->wayland.egl_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, self->wayland.egl_config, EGL_NO_CONTEXT, contextAttribs); - if(context == EGL_NO_CONTEXT) { - printf("ERROR: eglCreateContext, %0X\n", eglGetError()); - return MwFALSE; - } - - self->wayland.egl_display = display; - self->wayland.egl_surface = surface; - self->wayland.egl_context = context; - - if(self->wayland.parent == NULL) { - if(!eglMakeCurrent(self->wayland.egl_display, self->wayland.egl_surface, self->wayland.egl_surface, self->wayland.egl_context)) { - printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); - } - } - - glEnable(GL_TEXTURE_2D); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - glEnable(GL_SCISSOR_TEST); - - return MwTRUE; -} - -/* EGL reconfiguration function for resizes */ -static void egl_resetup(MwLL handle) { - float w, h; - - if(handle->wayland.parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.parent->wayland.ww; - h = handle->wayland.parent->wayland.wh; - } - - glViewport(handle->wayland.x, handle->wayland.y, w, h); - glScissor(handle->wayland.x, handle->wayland.y, w, h); -} - -static void timed_redraw(MwLL handle, MwU32 time, int cooldown, MwU64* cooldown_timer) { - if(handle->wayland.parent == NULL) { - if(time >= (*cooldown_timer + cooldown)) { - egl_resetup(handle); - MwLLDispatch(handle, draw, NULL); - *cooldown_timer = time; - } - } -} - -/* Same as timed_redraw but it uses the unix epoch as the cooldown timer. */ -static void timed_redraw_by_epoch(MwLL handle, int cooldown) { - gettimeofday(&handle->wayland.timer, NULL); - unsigned long long time = - (unsigned long long)(handle->wayland.timer.tv_sec) * 1000 + - (unsigned long long)(handle->wayland.timer.tv_usec) / 1000; - timed_redraw(handle, time, cooldown, &handle->wayland.cooldown_timer_epoch); -} - /* `xdg_toplevel.close` callback */ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, @@ -541,14 +392,20 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); - MwLLDispatch(self, resize, NULL); + cairo_destroy(self->wayland.cairo); + cairo_surface_destroy(self->wayland.cs); + self->wayland.cs = cairo_image_surface_create_for_data(self->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); + self->wayland.cairo = cairo_create(self->wayland.cs); - if(!self->wayland.egl_setup) { + MwLLDispatch(self, resize, NULL); + MwLLDispatch(self, draw, NULL); + + /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); egl_resetup(self); - } + }*/ return; }; @@ -580,6 +437,58 @@ static void xdg_surface_configure( self->wayland.configured = MwTRUE; } +/* wl_shm setup function */ +static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { + int x, y; + int stride = wayland->ww * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + + wayland->mapped_shm_buf_size = wayland->ww * wayland->wh * 4; + + wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + + wayland->shm_fd = mkstemp(temp_name); + + unlink(temp_name); + + if(posix_fallocate(wayland->shm_fd, 0, wayland->mapped_shm_buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(wayland->shm_fd); + return NULL; + } + if(ftruncate(wayland->shm_fd, wayland->mapped_shm_buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(wayland->shm_fd); + return NULL; + } + + wayland->mapped_shm_buf = mmap(NULL, wayland->mapped_shm_buf_size, PROT_WRITE, MAP_SHARED, wayland->shm_fd, 0); + + fsync(wayland->shm_fd); + + if(!(wayland->shm_pool = wl_shm_create_pool(wayland->shm, wayland->shm_fd, wayland->mapped_shm_buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + + wayland->shm_buffer = wl_shm_pool_create_buffer(wayland->shm_pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); + + if(wayland->configured) { + wl_surface_attach(wayland->surface, wayland->shm_buffer, 0, 0); + wl_surface_commit(wayland->surface); + } + + return NULL; +} + +static void update_buffer(MwLL handle) { + fsync(handle->wayland.shm_fd); + + if(handle->wayland.configured) { + wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.surface); + } +} + /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { enum { @@ -588,9 +497,8 @@ static int event_loop(MwLL handle) { CURSOR_FD }; struct pollfd fd; - int timeout = 100; - struct _MwLLWayland* wayland = &handle->wayland; - MwLL topmost_parent = handle->wayland.parent; + int timeout = 1; + struct _MwLLWayland* wayland = &handle->wayland; if(wayland->display == NULL) { return 0; @@ -598,6 +506,12 @@ static int event_loop(MwLL handle) { fd.fd = wl_display_get_fd(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 */ while(wl_display_flush(wayland->display) == -1) { if(errno != EAGAIN) { @@ -614,38 +528,27 @@ static int event_loop(MwLL handle) { } } + /* 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(wayland->display); if(wl_display_dispatch_pending(wayland->display) > 0) { } } else { - /* Condition for no events being sent */ - if(wl_display_dispatch_pending(wayland->display) == 0) { - if(wayland->event_queue != NULL) { - if(wl_display_roundtrip_queue(wayland->display, wayland->event_queue) < 0) { - printf("error\n"); - }; - } - /* HACK: If the last known size is different, force a redraw */ - if(wayland->lw != wayland->ww || wayland->lh != wayland->wh) { - MwLLDispatch(handle, draw, 0); - wayland->resize_counter++; - if(wayland->resize_counter >= 5) { - wayland->lw = wayland->ww; - wayland->lh = wayland->wh; - wayland->lh = wayland->wh; - wayland->resize_counter = 0; - } - } - } + wl_display_cancel_read(handle->wayland.display); } - return 0; + return 1; } /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ static void setup_callbacks(struct _MwLLWayland* wayland) { - /* Convience macro for adding the interface functions to the setup map */ #define WL_INTERFACE(interface) \ shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); @@ -655,13 +558,15 @@ 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); WL_INTERFACE(wl_seat); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(wp_cursor_shape_manager_v1); + } else { + WL_INTERFACE(wl_subcompositor); } #undef WL_INTERFACE } @@ -670,9 +575,8 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { static void setup_toplevel(MwLL r, int x, int y) { int i; - r->wayland.type = MWLL_WAYLAND_TOPLEVEL; - r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); - r->wayland.topmost_parent = NULL; + r->wayland.type = MWLL_WAYLAND_TOPLEVEL; + r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); setup_callbacks(&r->wayland); @@ -731,27 +635,17 @@ static void setup_toplevel(MwLL r, int x, int y) { printf("zxdg null\n"); } - r->wayland.event_queue = wl_display_create_queue(r->wayland.display); - - egl_resetup(r); + /*egl_resetup(r); MwLLDispatch(r, draw, NULL); - recursive_draw(r); + recursive_draw(r);*/ } /* Sublevel setup function */ static void setup_sublevel(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; - struct wl_region* region; - { - MwLL topmost_parent = parent; + struct wl_compositor* compositor = parent->wayland.compositor; + struct wl_surface* parent_surface = parent->wayland.surface; - while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { - topmost_parent = topmost_parent->wayland.parent; - } - r->wayland.topmost_parent = topmost_parent; - } + r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); r->wayland.type = MWLL_WAYLAND_SUBLEVEL; @@ -759,17 +653,12 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { 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); - wl_region_destroy(region); - setup_callbacks(&r->wayland); - r->wayland.registry = wl_display_get_registry(r->wayland.topmost_parent->wayland.display); - r->wayland.display = r->wayland.topmost_parent->wayland.display; + // printf("position %d %d\n", x, y); + + 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) { @@ -778,23 +667,11 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { return; } + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.surface, parent_surface); + + wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); + r->wayland.configured = MwTRUE; - if(!r->wayland.egl_setup) { - r->wayland.egl_setup = egl_setup(r, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); - egl_resetup(r); - MwLLDispatch(r, draw, NULL); - recursive_draw(r); - }; - - r->wayland.event_queue = parent->wayland.event_queue; - - arrpush(parent->wayland.sublevels, r); - - wl_surface_damage(parent->wayland.surface, 0, 0, parent->wayland.ww, parent->wayland.wh); - - egl_resetup(r->wayland.topmost_parent); - MwLLDispatch(r->wayland.topmost_parent, draw, NULL); - recursive_draw(r->wayland.topmost_parent); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -804,8 +681,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.type = MwLLBackendWayland; - if(width == 0) width = 1; - if(height == 0) height = 1; + if(width < 2) width = 2; + if(height < 2) height = 2; if(x == MwDEFAULT) { x = 0; @@ -819,12 +696,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.x = x; r->wayland.y = y; - r->wayland.parent = parent; - - r->wayland.cooldown_timer = 0; - r->wayland.has_set_xy = MwFALSE; - r->wayland.resize_counter = 0; - r->wayland.sublevels = NULL; if(parent == NULL) { @@ -833,12 +704,29 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_sublevel(parent, r, x, y); } + /* example of writing to the buffer */ + memset(r->wayland.mapped_shm_buf, 255, r->wayland.mapped_shm_buf_size); + update_buffer(r); + + r->wayland.cs = cairo_image_surface_create_for_data(r->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); + r->wayland.cairo = cairo_create(r->wayland.cs); + + MwLLForceRender(r); + return r; } static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); + cairo_destroy(handle->wayland.cairo); + cairo_surface_destroy(handle->wayland.cs); + + munmap(handle->wayland.mapped_shm_buf, handle->wayland.mapped_shm_buf_size); + wl_buffer_destroy(handle->wayland.mapped_shm_buf); + wl_shm_pool_destroy(handle->wayland.shm_pool); + close(handle->wayland.shm_fd); + free(handle); } @@ -853,111 +741,74 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { handle->wayland.x = x; handle->wayland.y = y; - if(handle->wayland.has_set_xy) { + /*if(handle->wayland.has_set_xy) { timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - /* recursive_draw(handle->wayland.topmost_parent); */ } else if(x != 0 && y != 0) { handle->wayland.has_set_xy = MwTRUE; - } + }*/ + + wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); } + MwLLDispatch(handle, draw, NULL); } 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)) { - handle->wayland.ww = handle->wayland.lw = 10; - handle->wayland.wh = handle->wayland.lh = 10; + handle->wayland.ww = 10; + handle->wayland.wh = 10; return; } - handle->wayland.ww = handle->wayland.lw = w; - handle->wayland.wh = handle->wayland.lh = 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, 0, 0, handle->wayland.ww, handle->wayland.wh); } else { - timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - /* recursive_draw(handle->wayland.topmost_parent); */ + /* timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); + recursive_draw(handle->wayland.topmost_parent); */ } + MwLLDispatch(handle, draw, NULL); } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i, n; - float maxX = 0, maxY = 0; - float centerX, centerY; - float w, h; - - if(handle->wayland.parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } - - glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - - glBegin(GL_POLYGON); + int i; + cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.cairo); for(i = 0; i < points_count; i++) { - float x = ((float)(handle->wayland.x + points[i].x) / (w / 2)) - 1.0; - float y = 1.0 - ((float)(handle->wayland.y + points[i].y) / (h / 2)); - - glVertex2f(x, y); + if(i == 0) { + cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + } } - glEnd(); - glColor3f(0, 0, 0); + cairo_close_path(handle->wayland.cairo); + cairo_fill(handle->wayland.cairo); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - int i; - float w, h; + int i; - if(handle->wayland.topmost_parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } - - glLineWidth(1); - glColor3f(color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - - glBegin(GL_LINES); + cairo_set_line_cap(handle->wayland.cairo, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.cairo); for(i = 0; i < 2; i++) { - float x = ((float)(handle->wayland.x + points[i].x) / (w / 2)) - 1.0; - float y = 1.0 - ((float)(handle->wayland.y + points[i].y) / (h / 2)); - - glVertex2f(x, y); + if(i == 0) { + cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + } else { + cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + } } - glEnd(); - glColor3f(0, 0, 0); + cairo_close_path(handle->wayland.cairo); + cairo_stroke(handle->wayland.cairo); } static void MwLLBeginDrawImpl(MwLL handle) { - if(handle->wayland.parent == NULL) { - 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; - } - } } static void MwLLEndDrawImpl(MwLL handle) { - int w, h; - - recursive_draw(handle); - - /* glClear(GL_COLOR_BUFFER_BIT); */ - /* glClearColor(1.0, 0, 0, 1); */ - - if(handle->wayland.parent == NULL) { - if(!eglSwapBuffers(handle->wayland.egl_display, handle->wayland.egl_surface)) { - printf("error swapping buffers! %0X\n", eglGetError()); - } else { - wl_surface_commit(handle->wayland.surface); - } - } + update_buffer(handle); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -981,8 +832,6 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - if(wl_display_dispatch_pending(handle->wayland.display) == 0) { - } return event_loop(handle); } @@ -998,19 +847,12 @@ 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->wayland.texture = 0; + r->common.width = width; + r->common.height = height; + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - 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); + r->wayland.cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); MwLLPixmapUpdate(r); @@ -1018,46 +860,48 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int wid } 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); + int i; + unsigned char* d; + + cairo_surface_flush(r->wayland.cs); + d = cairo_image_surface_get_data(r->wayland.cs); + for(i = 0; i < r->common.width * r->common.height * 4; i += 4) { + MwU32* p = (MwU32*)&d[i]; + *p <<= 8; + *p |= r->common.raw[i + 3]; + *p <<= 8; + *p |= r->common.raw[i + 0]; + *p <<= 8; + *p |= r->common.raw[i + 1]; + *p <<= 8; + *p |= r->common.raw[i + 2]; + } + cairo_surface_mark_dirty(r->wayland.cs); } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - glDeleteTextures(1, &pixmap->wayland.texture); + cairo_surface_destroy(pixmap->wayland.cs); + free(pixmap->common.raw); free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - float x, y, w, h; + cairo_t* c; + cairo_surface_t* cs; - if(handle->wayland.topmost_parent == NULL) { - w = handle->wayland.ww; - h = handle->wayland.wh; - } else { - w = handle->wayland.topmost_parent->wayland.ww; - h = handle->wayland.topmost_parent->wayland.wh; - } + cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); + c = cairo_create(cs); - x = ((float)(handle->wayland.x + rect->x) / (w / 2)) - 1.0; - y = 1.0 - ((float)(handle->wayland.y + rect->y) / (h / 2)); + cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); + cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); + cairo_paint(c); - glColor3f(1.0, 1.0, 1.0); + cairo_set_source_rgb(handle->wayland.cairo, 1, 1, 1); + cairo_set_source_surface(handle->wayland.cairo, cs, rect->x, rect->y); + cairo_paint(handle->wayland.cairo); - glBindTexture(GL_TEXTURE_2D, pixmap->wayland.texture); - glActiveTexture(pixmap->wayland.texture); - - glBegin(GL_QUADS); - glTexCoord2f(0.0f, 0); - glVertex2f(x, y); - glTexCoord2f(1, 0); - glVertex2f(x + (rect->width / (w / 2)), y); - glTexCoord2f(1, 1); - glVertex2f(x + (rect->width / (w / 2)), y - (rect->height / (h / 2))); - glTexCoord2f(0.0f, 1); - glVertex2f(x, y - (rect->height / (h / 2))); - glEnd(); - glFinish(); + cairo_destroy(c); + cairo_surface_destroy(cs); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } @@ -1065,9 +909,11 @@ 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) { timed_redraw_by_epoch(handle, 25); } + */ } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { diff --git a/src/widget/frame.c b/src/widget/frame.c index 36085a6d6..d48c2874d 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -29,7 +29,6 @@ static void draw(MwWidget handle) { rr.width = MwGetInteger(handle, MwNwidth) - (MwDefaultBorderWidth(handle) * 2); rr.height = MwGetInteger(handle, MwNheight) - (MwDefaultBorderWidth(handle) * 2); } else { - rr.x = 0; rr.y = 0; rr.width = MwGetInteger(handle, MwNwidth); diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 4141f485d..785468d06 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -258,7 +258,6 @@ static void frame_draw(MwWidget handle) { if(j == (arrlen(lb->list[i].name) - 1)) p.x -= MwDefaultBorderWidth(handle); if(arrlen(lb->alignment) <= j || lb->alignment[j] == MwALIGNMENT_BEGINNING) { - p.x += 4; MwDrawText(handle, &p, str, 0, MwALIGNMENT_BEGINNING, selected ? base2 : text2); p.x -= 4; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 9481c49ce..19a7c4d10 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,12 +1,6 @@ #include #include -#ifdef USE_WAYLAND -#include -#include -#include -#endif - #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); @@ -110,8 +104,8 @@ static int create(MwWidget handle) { } #endif #ifdef USE_WAYLAND - /* Wayland uses OpenGL as its backend so its already initialized */ if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ } #endif @@ -146,7 +140,9 @@ static void destroy(MwWidget handle) { } #endif #ifdef USE_WAYLAND -/* Wayland uses OpenGL as its backend so its destroyed accordingly */ + if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ + } #endif free(handle->internal); @@ -169,6 +165,7 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ } #endif } @@ -189,14 +186,9 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { } #endif #ifdef USE_WAYLAND -#define tp handle->lowlevel->wayland.topmost_parent->wayland if(handle->lowlevel->common.type == MwLLBackendWayland) { - if(!eglSwapBuffers( - tp.egl_display, tp.egl_surface)) { - printf("Userland error: eglSwapBuffers, %0X\n", eglGetError()); - } + /* todo */ } -#undef topmost_parent #endif } @@ -217,7 +209,7 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - return eglGetProcAddress(name); + /* todo */ } #endif return NULL; From 724b0082206e6133c88b70969ab4b9c5817a105c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 17 Dec 2025 19:41:05 -0700 Subject: [PATCH 008/409] impl resizing in wayland --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 71 +++++++++++++++++++++-------------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 32f6547b2..2a9b740a0 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -104,6 +104,7 @@ struct _MwLLWayland { void* mapped_shm_buf; MwU64 mapped_shm_buf_size; int shm_fd; + MwBool shm_setup; cairo_surface_t* cs; cairo_t* cairo; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 83e7439c9..96182874d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,6 +17,11 @@ #include #endif +/* Setup the wl_shm buffer with the saved width/height */ +static void buffer_setup(struct _MwLLWayland* wayland); +/* Destroy the wl_shm buffer */ +static void buffer_destroy(struct _MwLLWayland* handle); + /* Get the registered interface from r, or NULL if it doesn't currently have it. */ #define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) @@ -392,10 +397,8 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); - cairo_destroy(self->wayland.cairo); - cairo_surface_destroy(self->wayland.cs); - self->wayland.cs = cairo_image_surface_create_for_data(self->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); - self->wayland.cairo = cairo_create(self->wayland.cs); + buffer_destroy(&self->wayland); + buffer_setup(&self->wayland); MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); @@ -439,14 +442,28 @@ static void xdg_surface_configure( /* wl_shm setup function */ 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 update_buffer(MwLL handle) { + fsync(handle->wayland.shm_fd); + + if(handle->wayland.configured) { + wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.surface); + } +} + +static void buffer_setup(struct _MwLLWayland* wayland) { int x, y; int stride = wayland->ww * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; wayland->mapped_shm_buf_size = wayland->ww * wayland->wh * 4; - wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); - wayland->shm_fd = mkstemp(temp_name); unlink(temp_name); @@ -454,12 +471,12 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland if(posix_fallocate(wayland->shm_fd, 0, wayland->mapped_shm_buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); close(wayland->shm_fd); - return NULL; + return; } if(ftruncate(wayland->shm_fd, wayland->mapped_shm_buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); close(wayland->shm_fd); - return NULL; + return; } wayland->mapped_shm_buf = mmap(NULL, wayland->mapped_shm_buf_size, PROT_WRITE, MAP_SHARED, wayland->shm_fd, 0); @@ -477,16 +494,25 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland wl_surface_commit(wayland->surface); } - return NULL; + wayland->cs = cairo_image_surface_create_for_data(wayland->mapped_shm_buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->cairo = cairo_create(wayland->cs); + + memset(wayland->mapped_shm_buf, 255, wayland->mapped_shm_buf_size); + update_buffer((MwLL)wayland); + wayland->shm_setup = MwTRUE; } -static void update_buffer(MwLL handle) { - fsync(handle->wayland.shm_fd); - - if(handle->wayland.configured) { - wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); - wl_surface_commit(handle->wayland.surface); +static void buffer_destroy(struct _MwLLWayland* wayland) { + if(!wayland->shm_setup) { + return; } + cairo_destroy(wayland->cairo); + cairo_surface_destroy(wayland->cs); + + wl_buffer_destroy(wayland->shm_buffer); + // munmap(wayland->mapped_shm_buf, wayland->mapped_shm_buf_size); + wl_shm_pool_destroy(wayland->shm_pool); + close(wayland->shm_fd); } /* Standard Wayland event loop. */ @@ -704,12 +730,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_sublevel(parent, r, x, y); } - /* example of writing to the buffer */ - memset(r->wayland.mapped_shm_buf, 255, r->wayland.mapped_shm_buf_size); - update_buffer(r); - - r->wayland.cs = cairo_image_surface_create_for_data(r->wayland.mapped_shm_buf, CAIRO_FORMAT_ARGB32, width, height, 4 * width); - r->wayland.cairo = cairo_create(r->wayland.cs); + buffer_setup(&r->wayland); MwLLForceRender(r); @@ -719,13 +740,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); - cairo_destroy(handle->wayland.cairo); - cairo_surface_destroy(handle->wayland.cs); - - munmap(handle->wayland.mapped_shm_buf, handle->wayland.mapped_shm_buf_size); - wl_buffer_destroy(handle->wayland.mapped_shm_buf); - wl_shm_pool_destroy(handle->wayland.shm_pool); - close(handle->wayland.shm_fd); + buffer_destroy(&handle->wayland); free(handle); } From b8a92f4ae0e7579b10b8de7676c1863baacb08a2 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 17 Dec 2025 19:44:15 -0700 Subject: [PATCH 009/409] wayland: buffer destroy/recreate in SetWHImpl too --- src/backend/wayland.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 96182874d..8c3267a64 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -779,10 +779,9 @@ 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, 0, 0, handle->wayland.ww, handle->wayland.wh); - } else { - /* timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - recursive_draw(handle->wayland.topmost_parent); */ } + buffer_destroy(&handle->wayland); + buffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); } From 72fbba1a7469d2f66cb2cece3cb5108299cedcf2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 18 Dec 2025 12:24:06 +0900 Subject: [PATCH 010/409] force aliasing --- src/backend/wayland.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8c3267a64..a6d003dd9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -908,6 +908,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); + cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); cairo_paint(c); cairo_set_source_rgb(handle->wayland.cairo, 1, 1, 1); From 012650f06f489d1219ba492118d2f35d25e93ce2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 01:36:37 +0900 Subject: [PATCH 011/409] tiny change --- include/Mw/Widget/OpenGL.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index dced6b9a1..5e37c02d4 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -9,12 +9,14 @@ #include #include +#ifndef __gl_h_ #ifdef _WIN32 #include #else #include #endif #include +#endif #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY From c9c3a00ed3c7a05d713ea26b0fb66fd1d780f591 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 02:55:30 +0900 Subject: [PATCH 012/409] unrelated changes --- include/Mw/Widget/OpenGL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index 5e37c02d4..3a063035a 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -16,11 +16,11 @@ #include #endif #include -#endif #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY #endif +#endif #ifdef __cplusplus extern "C" { From 75749697ba25330127fdca110fda9098d65719e3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 03:01:12 +0900 Subject: [PATCH 013/409] netbsd wants pthread. idk why --- pl/ostype/NetBSD.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/pl/ostype/NetBSD.pl b/pl/ostype/NetBSD.pl index 2d816586a..de93b1439 100644 --- a/pl/ostype/NetBSD.pl +++ b/pl/ostype/NetBSD.pl @@ -2,5 +2,6 @@ add_incdir("-I/usr/X11R7/include -I/usr/pkg/include"); add_libdir( "-L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib"); use_backend("x11"); +add_libs("pthread"); 1; From a815998ace9b5e911b1ad484503c9203bcae7b7f Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 11:26:51 -0700 Subject: [PATCH 014/409] wayland: fix pointer --- include/Mw/LowLevel/Wayland.h | 5 ++- src/backend/wayland.c | 58 +++++++++++++++++++++++++++-------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 2a9b740a0..950c258dc 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -90,6 +90,10 @@ struct _MwLLWayland { struct wl_compositor* compositor; struct wl_surface* surface; struct wl_registry_listener registry_listener; + struct wl_region* region; + + MwBool active; /* Whether or not the surface is the one being hovered over. */ + /*struct wl_event_queue* event_queue;*/ MwLL* sublevels; /* stb_ds managed array of any sublevels */ @@ -104,7 +108,6 @@ struct _MwLLWayland { void* mapped_shm_buf; MwU64 mapped_shm_buf_size; int shm_fd; - MwBool shm_setup; cairo_surface_t* cs; cairo_t* cairo; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index a6d003dd9..835f91d44 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -22,6 +22,9 @@ static void buffer_setup(struct _MwLLWayland* wayland); /* Destroy the wl_shm buffer */ static void buffer_destroy(struct _MwLLWayland* handle); +static void region_setup(MwLL handle); +static void region_invalidate(MwLL handle); + /* Get the registered interface from r, or NULL if it doesn't currently have it. */ #define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) @@ -50,11 +53,13 @@ static void protocol_removed(void* data, /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, - wl_fixed_t surface_y) {}; + wl_fixed_t surface_y) { +}; /* `wl_pointer.leave` callback */ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, - struct wl_surface* surface) {}; + struct wl_surface* surface) { +}; /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, @@ -64,7 +69,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); - p.point = self->wayland.cur_mouse_pos; + + p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ @@ -383,6 +389,7 @@ static void xdg_toplevel_configure(void* data, MwI32 width, MwI32 height, struct wl_array* states) { MwLL self = data; + int i; if(width == 0 || height == 0) { width = self->wayland.ww; @@ -393,16 +400,23 @@ static void xdg_toplevel_configure(void* data, } } + region_invalidate(self); self->wayland.ww = width; self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); buffer_destroy(&self->wayland); buffer_setup(&self->wayland); + region_setup(self); MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); + for(i = 0; i < arrlen(self->wayland.sublevels); i++) { + MwLL handle = self->wayland.sublevels[i]; + region_setup(handle); + } + /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { @@ -499,11 +513,10 @@ static void buffer_setup(struct _MwLLWayland* wayland) { memset(wayland->mapped_shm_buf, 255, wayland->mapped_shm_buf_size); update_buffer((MwLL)wayland); - wayland->shm_setup = MwTRUE; } static void buffer_destroy(struct _MwLLWayland* wayland) { - if(!wayland->shm_setup) { + if(!wayland->configured) { return; } cairo_destroy(wayland->cairo); @@ -515,6 +528,21 @@ static void buffer_destroy(struct _MwLLWayland* wayland) { close(wayland->shm_fd); } +static void region_invalidate(MwLL handle) { + if(!handle->wayland.configured) { + return; + } + wl_region_subtract(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); +} +static void region_setup(MwLL handle) { + if(!handle->wayland.configured) { + return; + } + wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + wl_surface_set_input_region(handle->wayland.surface, handle->wayland.region); + wl_surface_set_opaque_region(handle->wayland.surface, handle->wayland.region); +} + /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { enum { @@ -732,6 +760,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { buffer_setup(&r->wayland); + r->wayland.region = wl_compositor_create_region(r->wayland.compositor); + region_setup(r); + MwLLForceRender(r); return r; @@ -741,6 +772,7 @@ static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); buffer_destroy(&handle->wayland); + wl_region_destroy(handle->wayland.region); free(handle); } @@ -754,25 +786,23 @@ 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) { + region_invalidate(handle); handle->wayland.x = x; handle->wayland.y = y; - /*if(handle->wayland.has_set_xy) { - timed_redraw_by_epoch(handle->wayland.topmost_parent, 25); - } else if(x != 0 && y != 0) { - handle->wayland.has_set_xy = MwTRUE; - }*/ - wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); + region_setup(handle); } + MwLLDispatch(handle, draw, NULL); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { + region_invalidate(handle); /* Prevent an integer underflow when the w/h is too low */ if((w < 10 || h < 10)) { handle->wayland.ww = 10; handle->wayland.wh = 10; - return; + goto refresh; } handle->wayland.ww = w; handle->wayland.wh = h; @@ -780,6 +810,10 @@ 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, 0, 0, handle->wayland.ww, handle->wayland.wh); } + +refresh: + region_setup(handle); + buffer_destroy(&handle->wayland); buffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); From c6e7421b31bb19fb068627cad5b6f2d68d9d4066 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 11:36:04 -0700 Subject: [PATCH 015/409] wayland: key modifiers --- include/Mw/LowLevel/Wayland.h | 2 +- src/backend/wayland.c | 38 ++++++++++++----------------------- 2 files changed, 14 insertions(+), 26 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 950c258dc..fc54ac838 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -94,7 +94,7 @@ struct _MwLLWayland { MwBool active; /* Whether or not the surface is the one being hovered over. */ - /*struct wl_event_queue* event_queue;*/ + MwU32 mod_state; MwLL* sublevels; /* stb_ds managed array of any sublevels */ MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 835f91d44..4a7fe67fa 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -118,28 +118,6 @@ struct wl_pointer_listener pointer_listener = { .axis = pointer_axis, }; -/* Recursively dispatch the key event to `handle` and its children */ -static void recursive_key(MwLL handle, void* ud) { - int i; - if(handle->wayland.sublevels != NULL) { - for(i = 0; i < arrlen(handle->wayland.sublevels); i++) { - MwLLDispatch(handle->wayland.sublevels[i], key, ud); - recursive_key(handle->wayland.sublevels[i], ud); - } - } -} - -/* Recursively dispatch the key_released event to `handle` and its children */ -static void recursive_key_released(MwLL handle, void* ud) { - int i; - if(handle->wayland.sublevels != NULL) { - for(i = 0; i < arrlen(handle->wayland.sublevels); i++) { - MwLLDispatch(handle->wayland.sublevels[i], key_released, ud); - recursive_key(handle->wayland.sublevels[i], ud); - } - } -} - /* `wl_keyboard.keymap` callback */ static void keyboard_keymap(void* data, struct wl_keyboard* wl_keyboard, @@ -259,12 +237,16 @@ static void keyboard_key(void* data, default: key = sym; } + if((self->wayland.mod_state & 4) == 4) { + key |= MwLLControlMask; + } + if((self->wayland.mod_state & 8) == 8) { + key |= MwLLAltMask; + } if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { MwLLDispatch(self, key, &key); - recursive_key(self, &key); } else { MwLLDispatch(self, key_released, &key); - recursive_key_released(self, &key); } } } @@ -277,7 +259,13 @@ static void keyboard_modifiers(void* data, MwU32 mods_depressed, MwU32 mods_latched, MwU32 mods_locked, - MwU32 group) {}; + MwU32 group) { + MwLL self = data; + + self->wayland.mod_state = 0; + self->wayland.mod_state |= mods_depressed; + self->wayland.mod_state |= mods_locked; +}; struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_keymap, From 19f52488b882e883aff3d82e3315a22de4f493fe Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 03:57:40 +0900 Subject: [PATCH 016/409] fancy things --- milsko.xml | 1 + src/core.c | 2 +- src/widget/image.c | 8 ++++++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/milsko.xml b/milsko.xml index f7f5baefa..758eb1f88 100644 --- a/milsko.xml +++ b/milsko.xml @@ -526,6 +526,7 @@ + diff --git a/src/core.c b/src/core.c index 4afafb77f..0ae8d4aab 100644 --- a/src/core.c +++ b/src/core.c @@ -693,7 +693,7 @@ static void force_render_all(MwWidget handle) { for(i = 0; i < arrlen(handle->children); i++) { force_render_all(handle->children[i]); } - MwForceRender(handle); + if(handle->lowlevel != NULL) MwForceRender(handle); } void MwToggleDarkTheme(MwWidget handle, int toggle) { diff --git a/src/widget/image.c b/src/widget/image.c index 487521dd5..4995568d1 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -5,6 +5,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNhasBorder, 0); MwSetInteger(handle, MwNinverted, 1); + MwSetInteger(handle, MwNfillArea, 1); return 0; } @@ -23,6 +24,13 @@ static void draw(MwWidget handle) { MwDrawRect(handle, &r, base); if(px != NULL) { + if(!MwGetInteger(handle, MwNfillArea)) { + r.x = (r.width - px->common.width) / 2; + r.y = (r.height - px->common.height) / 2; + r.width = px->common.width; + r.height = px->common.height; + } + MwLLDrawPixmap(handle->lowlevel, &r, px); } From bfa0a5811ec066be64f756e88f8ba1ee4553e5a7 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 04:38:29 +0900 Subject: [PATCH 017/409] fix --- src/widget/box.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widget/box.c b/src/widget/box.c index e2808c4ea..c363e0ec8 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -58,7 +58,6 @@ static void layout(MwWidget handle) { } else { wsz = sz * n / sum; } - wsz -= Margin; MwVaApply(handle->children[i], horiz ? MwNx : MwNy, sk, /* this is what gets changed */ From d8c08f80d64954f88716b395177b190df9e91a1c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 13:15:03 -0700 Subject: [PATCH 018/409] wayland: cursor support --- include/Mw/LowLevel/Wayland.h | 24 +++-- src/backend/wayland.c | 181 ++++++++++++++++++++++------------ 2 files changed, 137 insertions(+), 68 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index fc54ac838..05a4d5065 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -58,6 +58,18 @@ struct _MwLLWaylandSublevel { MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ }; +/* Shared set of anything needed for a shm buffer. Used both for surface framebuffers, and cursors. */ +struct _MwLLWaylandShmBuffer { + struct wl_shm* shm; + struct wl_shm_pool* shm_pool; + struct wl_buffer* shm_buffer; + MwU8* buf; + MwU64 buf_size; + int fd; + MwBool setup; + struct wl_surface* surface; +}; + struct _MwLLWayland { struct _MwLLCommon common; @@ -88,10 +100,12 @@ struct _MwLLWayland { struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; - struct wl_surface* surface; struct wl_registry_listener registry_listener; struct wl_region* region; + struct wl_pointer* pointer; + MwU32 pointer_serial; + MwBool active; /* Whether or not the surface is the one being hovered over. */ MwU32 mod_state; @@ -102,12 +116,8 @@ struct _MwLLWayland { MwU32 x, y, ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ - struct wl_shm* shm; - struct wl_shm_pool* shm_pool; - struct wl_buffer* shm_buffer; - void* mapped_shm_buf; - MwU64 mapped_shm_buf_size; - int shm_fd; + struct _MwLLWaylandShmBuffer framebuffer; + struct _MwLLWaylandShmBuffer cursor; cairo_surface_t* cs; cairo_t* cairo; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 4a7fe67fa..5695a8360 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,10 +17,10 @@ #include #endif -/* Setup the wl_shm buffer with the saved width/height */ -static void buffer_setup(struct _MwLLWayland* wayland); -/* Destroy the wl_shm buffer */ -static void buffer_destroy(struct _MwLLWayland* handle); +/* Setup the framebuffer with the saved width/height */ +static void framebuffer_setup(struct _MwLLWayland* wayland); +/* Destroy the framebuffer */ +static void framebuffer_destroy(struct _MwLLWayland* handle); static void region_setup(MwLL handle); static void region_invalidate(MwLL handle); @@ -54,6 +54,10 @@ static void protocol_removed(void* data, static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { + MwLL self = data; + self->wayland.pointer_serial = serial; + + wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); }; /* `wl_pointer.leave` callback */ @@ -288,8 +292,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, wl_keyboard_add_listener(keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - struct wl_pointer* pointer = wl_seat_get_pointer(wl_seat); - wl_pointer_add_listener(pointer, &pointer_listener, data); + self->wayland.pointer = wl_seat_get_pointer(wl_seat); + wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } }; @@ -393,8 +397,8 @@ static void xdg_toplevel_configure(void* data, self->wayland.wh = height; xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); - buffer_destroy(&self->wayland); - buffer_setup(&self->wayland); + framebuffer_destroy(&self->wayland); + framebuffer_setup(&self->wayland); region_setup(self); MwLLDispatch(self, resize, NULL); @@ -436,7 +440,7 @@ static void xdg_surface_configure( xdg_surface_ack_configure(xdg_surface, serial); if(self->wayland.configured) { - wl_surface_commit(self->wayland.surface); + wl_surface_commit(self->wayland.framebuffer.surface); } self->wayland.configured = MwTRUE; @@ -445,76 +449,80 @@ static void xdg_surface_configure( /* wl_shm setup function */ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); return NULL; } -static void update_buffer(MwLL handle) { - fsync(handle->wayland.shm_fd); +static void update_framebuffer(struct _MwLLWayland* wayland) { + struct _MwLLWaylandShmBuffer* buffer = &wayland->framebuffer; + fsync(buffer->fd); - if(handle->wayland.configured) { - wl_surface_attach(handle->wayland.surface, handle->wayland.shm_buffer, 0, 0); - wl_surface_commit(handle->wayland.surface); + if(wayland->configured && buffer->setup) { + wl_surface_attach(wayland->framebuffer.surface, buffer->shm_buffer, wayland->x, wayland->y); + wl_surface_commit(wayland->framebuffer.surface); } } -static void buffer_setup(struct _MwLLWayland* wayland) { +static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { int x, y; - int stride = wayland->ww * 4; + int stride = width * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - wayland->mapped_shm_buf_size = wayland->ww * wayland->wh * 4; + buffer->buf_size = width * height * 4; - wayland->shm_fd = mkstemp(temp_name); + buffer->fd = mkstemp(temp_name); unlink(temp_name); - if(posix_fallocate(wayland->shm_fd, 0, wayland->mapped_shm_buf_size) != 0) { + if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(wayland->shm_fd); + close(buffer->fd); return; } - if(ftruncate(wayland->shm_fd, wayland->mapped_shm_buf_size) != 0) { + if(ftruncate(buffer->fd, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(wayland->shm_fd); + close(buffer->fd); return; } - wayland->mapped_shm_buf = mmap(NULL, wayland->mapped_shm_buf_size, PROT_WRITE, MAP_SHARED, wayland->shm_fd, 0); + buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); - fsync(wayland->shm_fd); + fsync(buffer->fd); - if(!(wayland->shm_pool = wl_shm_create_pool(wayland->shm, wayland->shm_fd, wayland->mapped_shm_buf_size))) { + if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { printf("failure setting up wl_shm: could not create pool.\n"); } - wayland->shm_buffer = wl_shm_pool_create_buffer(wayland->shm_pool, 0, wayland->ww, wayland->wh, stride, WL_SHM_FORMAT_ARGB8888); - - if(wayland->configured) { - wl_surface_attach(wayland->surface, wayland->shm_buffer, 0, 0); - wl_surface_commit(wayland->surface); - } - - wayland->cs = cairo_image_surface_create_for_data(wayland->mapped_shm_buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); - wayland->cairo = cairo_create(wayland->cs); - - memset(wayland->mapped_shm_buf, 255, wayland->mapped_shm_buf_size); - update_buffer((MwLL)wayland); + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; } -static void buffer_destroy(struct _MwLLWayland* wayland) { - if(!wayland->configured) { +static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { + if(!buffer->setup) { return; } + wl_buffer_destroy(buffer->shm_buffer); + wl_shm_pool_destroy(buffer->shm_pool); + close(buffer->fd); + buffer->setup = MwFALSE; +} + +static void framebuffer_setup(struct _MwLLWayland* wayland) { + buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh); + + wayland->cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->cairo = cairo_create(wayland->cs); + + memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); + update_framebuffer(wayland); +}; +static void framebuffer_destroy(struct _MwLLWayland* wayland) { + buffer_destroy(&wayland->framebuffer); cairo_destroy(wayland->cairo); cairo_surface_destroy(wayland->cs); - - wl_buffer_destroy(wayland->shm_buffer); - // munmap(wayland->mapped_shm_buf, wayland->mapped_shm_buf_size); - wl_shm_pool_destroy(wayland->shm_pool); - close(wayland->shm_fd); -} +}; static void region_invalidate(MwLL handle) { if(!handle->wayland.configured) { @@ -527,8 +535,8 @@ static void region_setup(MwLL handle) { return; } wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); - wl_surface_set_input_region(handle->wayland.surface, handle->wayland.region); - wl_surface_set_opaque_region(handle->wayland.surface, handle->wayland.region); + wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } /* Standard Wayland event loop. */ @@ -574,7 +582,7 @@ static int event_loop(MwLL handle) { 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); + wl_surface_commit(handle->wayland.framebuffer.surface); return 0; } @@ -630,6 +638,8 @@ static void setup_toplevel(MwLL r, int x, int y) { return; } + r->wayland.framebuffer.surface = NULL; + /* Do a roundtrip to ensure all interfaces are setup. */ r->wayland.registry = wl_display_get_registry(r->wayland.display); wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); @@ -642,9 +652,9 @@ static void setup_toplevel(MwLL r, int x, int y) { 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.framebuffer.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); + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); /* setup mandatory listeners */ @@ -661,7 +671,7 @@ static void setup_toplevel(MwLL r, int x, int y) { xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); /* Perform the initial commit and wait for the first configure event */ - wl_surface_commit(r->wayland.surface); + wl_surface_commit(r->wayland.framebuffer.surface); event_loop(r); /* setup decorations if we can */ @@ -685,7 +695,7 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Sublevel setup function */ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { struct wl_compositor* compositor = parent->wayland.compositor; - struct wl_surface* parent_surface = parent->wayland.surface; + struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); @@ -693,7 +703,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.display = parent->wayland.display; - r->wayland.surface = wl_compositor_create_surface(compositor); + r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); setup_callbacks(&r->wayland); @@ -709,7 +719,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { return; } - r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.surface, parent_surface); + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); @@ -719,6 +729,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); r->common.type = MwLLBackendWayland; @@ -746,7 +757,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_sublevel(parent, r, x, y); } - buffer_setup(&r->wayland); + framebuffer_setup(&r->wayland); r->wayland.region = wl_compositor_create_region(r->wayland.compositor); region_setup(r); @@ -759,7 +770,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); - buffer_destroy(&handle->wayland); + buffer_destroy(&handle->wayland.framebuffer); + buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); free(handle); @@ -802,8 +814,8 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { refresh: region_setup(handle); - buffer_destroy(&handle->wayland); - buffer_setup(&handle->wayland); + framebuffer_destroy(&handle->wayland); + framebuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); } @@ -844,7 +856,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } static void MwLLEndDrawImpl(MwLL handle) { - update_buffer(handle); + update_framebuffer(&handle->wayland); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -944,7 +956,7 @@ 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); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); /* if(handle->wayland.egl_setup) { @@ -954,6 +966,53 @@ static void MwLLForceRenderImpl(MwLL handle) { } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + int x, y; + + if(handle->wayland.cursor.setup) { + buffer_destroy(&handle->wayland.cursor); + wl_surface_destroy(handle->wayland.cursor.surface); + } + buffer_setup(&handle->wayland.cursor, image->width, image->height); + memset(handle->wayland.cursor.buf, 0, handle->wayland.cursor.buf_size); + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + handle->wayland.cursor.buf[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; + + if(d & 1) { + px = 255; + }; + + handle->wayland.cursor.buf[idx] = px; + handle->wayland.cursor.buf[idx + 1] = px; + handle->wayland.cursor.buf[idx + 2] = px; + d = d >> 1; + } + } + + handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); + + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); + wl_surface_commit(handle->wayland.cursor.surface); + + /* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */ + if(handle->wayland.pointer != NULL) { + wl_pointer_set_cursor(handle->wayland.pointer, handle->wayland.pointer_serial, handle->wayland.cursor.surface, 0, 0); + } } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { From aeaf0a4547b8b34db7f5cc3c4279cadd44b6ccae Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 13:16:16 -0700 Subject: [PATCH 019/409] wayland: MwLLGetCursorCoordImpl --- src/backend/wayland.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5695a8360..e15dd1e48 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1066,6 +1066,7 @@ static void MwLLMakeToolWindowImpl(MwLL handle) { } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + *point = handle->wayland.cur_mouse_pos; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { From 8d4e845e7c812b779944c8d675a48de5bbcfaa8a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 13:43:45 -0700 Subject: [PATCH 020/409] wayland: MwLLGetScreenSize --- include/Mw/LowLevel/Wayland.h | 13 ++++++++---- src/backend/wayland.c | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 05a4d5065..0c6036c42 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -63,11 +63,13 @@ struct _MwLLWaylandShmBuffer { struct wl_shm* shm; struct wl_shm_pool* shm_pool; struct wl_buffer* shm_buffer; - MwU8* buf; - MwU64 buf_size; - int fd; - MwBool setup; struct wl_surface* surface; + struct wl_output* output; + + MwU8* buf; + MwU64 buf_size; + int fd; + MwBool setup; }; struct _MwLLWayland { @@ -102,6 +104,7 @@ struct _MwLLWayland { struct wl_compositor* compositor; struct wl_registry_listener registry_listener; struct wl_region* region; + struct wl_output* output; struct wl_pointer* pointer; MwU32 pointer_serial; @@ -116,6 +119,8 @@ struct _MwLLWayland { MwU32 x, y, ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ + MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ + struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index e15dd1e48..919575a35 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -297,6 +297,32 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, } }; +static void output_geometry(void* data, + struct wl_output* wl_output, + int32_t x, + int32_t y, + int32_t physical_width, + int32_t physical_height, + int32_t subpixel, + const char* make, + const char* model, + int32_t transform) {}; +static void output_mode(void* data, + struct wl_output* wl_output, + uint32_t flags, + int32_t width, + int32_t height, + int32_t refresh) { + MwLL self = data; + self->wayland.mw = width; + self->wayland.mh = height; +}; + +struct wl_output_listener output_listener = { + .geometry = output_geometry, + .mode = output_mode, +}; + /* `xdg_wm_base.ping` callback */ void xdg_wm_base_ping(void* data, struct xdg_wm_base* xdg_wm_base, @@ -318,6 +344,14 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { return proto; } +/* wl_output setup function */ +static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { + ll->wayland.output = wl_registry_bind(ll->wayland.registry, name, &wl_output_interface, 1); + wl_output_add_listener(ll->wayland.output, &output_listener, ll); + + return NULL; +} + /* wl_compositor setup function */ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); @@ -611,6 +645,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_shm); WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_seat); + WL_INTERFACE(wl_output); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); @@ -653,6 +688,7 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.toplevel->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); @@ -1070,6 +1106,10 @@ static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + rect->x = 0; + rect->y = 0; + rect->width = handle->wayland.mw; + rect->height = handle->wayland.mh; } static void MwLLBeginStateChangeImpl(MwLL handle) { From b0f4713ff11b4268027c7827ec9b2521969c6fbb Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 13:46:22 -0700 Subject: [PATCH 021/409] wayland: remove unused cursor_shape --- src/backend/wayland.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 919575a35..cb50ddc34 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -379,16 +379,6 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa return proto; } -/* wp_cursor_shape_manager setup function */ -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; -} - /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { struct zxdg_decoration_manager_v1* manager; @@ -649,7 +639,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); - WL_INTERFACE(wp_cursor_shape_manager_v1); } else { WL_INTERFACE(wl_subcompositor); } From a27a01ce414e2cc0f45b19cfb21bb68911ebba34 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 17:46:23 -0700 Subject: [PATCH 022/409] wayland: MwLLGetClipboardImpl. --- examples/basic/clipboard.c | 65 ++++++++++++++ include/Mw/LowLevel/Wayland.h | 3 + pl/rules.pl | 2 + src/backend/wayland.c | 161 +++++++++++++++++++++++++++++++++- 4 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 examples/basic/clipboard.c diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c new file mode 100644 index 000000000..9efae7af7 --- /dev/null +++ b/examples/basic/clipboard.c @@ -0,0 +1,65 @@ +#define _MILSKO +#include + +MwWidget window, button, text; + +void resize(MwWidget handle, void* user_data, void* call_data) { + unsigned int w, h, mh; + + (void)user_data; + (void)call_data; + + w = MwGetInteger(handle, MwNwidth); + h = MwGetInteger(handle, MwNheight); + + MwVaApply(button, + MwNy, 50 + mh, + MwNwidth, w - 50 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + + MwVaApply(text, + MwNy, 200 + mh, + MwNwidth, w - 50 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); +} + +void handler(MwWidget handle, void* user_data, void* call_data) { + (void)handle; + (void)user_data; + (void)call_data; + char* clipboard; + + clipboard = MwLLGetClipboard(handle->lowlevel); + + if(clipboard != NULL) { + MwVaApply(text, MwNtext, clipboard); + MwForceRender(text); + } + + resize(window, NULL, NULL); +} + +int main() { + MwMenu m, m2; + + MwLibraryInit(); + + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "clipboard", + NULL); + button = MwVaCreateWidget(MwButtonClass, "button", window, 50, 50, 300, 125, + MwNtext, "get clipboard contents", + NULL); + text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125, + MwNtext, "", + NULL); + + MwAddUserHandler(window, MwNresizeHandler, resize, NULL); + MwAddUserHandler(button, MwNactivateHandler, handler, NULL); + + resize(window, NULL, NULL); + + MwLoop(window); +} diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0c6036c42..e47caed1e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -24,6 +24,7 @@ MWDECL int MwLLWaylandCallInit(void); #include "Wayland/xdg-shell-client-protocol.h" #include "Wayland/xdg-decoration-client-protocol.h" #include "Wayland/cursor-shape-client-protocol.h" +#include "Wayland/primary-selection-client-protocol.h" #endif struct _MwLLWayland; @@ -121,6 +122,8 @@ struct _MwLLWayland { MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ + char* cur_selection; + struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/pl/rules.pl b/pl/rules.pl index 5cb4a90a2..094d8effd 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -36,6 +36,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("stable", "tablet", "-v2"); scan_wayland_protocol("staging", "cursor-shape", "-v1"); scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); + scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; } @@ -112,6 +113,7 @@ new_example("examples/basic/colorpicker"); new_example("examples/basic/combobox"); new_example("examples/basic/treeview"); new_example("examples/basic/box"); +new_example("examples/basic/clipboard"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index cb50ddc34..ed730ad9e 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -7,6 +7,7 @@ #include #include +#include /* TODO: find out what FreeBSD and such wants us to include */ #ifdef __FreeBSD__ @@ -36,8 +37,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)); + char* inter = malloc(strlen(interface)); + strcpy(inter, interface); + + shput(wayland->wl_protocol_map, inter, func(name, data)); } else { /* printf("unknown interface %s\n", interface); */ } @@ -50,6 +53,63 @@ static void protocol_removed(void* data, }; +static void offer_offer(void* data, + struct zwp_primary_selection_offer_v1* zwp_primary_selection_offer_v1, + const char* mime_type) { +}; + +struct zwp_primary_selection_offer_v1_listener offer_listener = { + .offer = offer_offer, +}; + +typedef struct primary_selection_device_context { + struct zwp_primary_selection_device_v1* device; + struct zwp_primary_selection_offer_v1* offer; +} primary_selection_device_context_t; + +typedef struct primary_selection_context { + struct zwp_primary_selection_device_manager_v1* manager; + /* stored seperately of the listeners because it's not a pointer and it gets assigned to data devices dynamically. */ + struct zwp_primary_selection_device_v1_listener listener; + + struct zwp_primary_selection_source_v1* source; + primary_selection_device_context_t** devices; +} primary_selection_context_t; + +static void primary_selection_data_offer(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* offer) { + struct primary_selection_device_context* self = data; + zwp_primary_selection_offer_v1_add_listener(offer, &offer_listener, data); + + self->offer = offer; +}; +static void primary_selection_selection(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* id) { +}; + +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + primary_selection_context_t* context = malloc(sizeof(primary_selection_context_t)); + + context->manager = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); + + struct zwp_primary_selection_device_manager_v1* device; + context->listener.data_offer = primary_selection_data_offer; + context->listener.selection = primary_selection_selection; + + context->source = zwp_primary_selection_device_manager_v1_create_source(context->manager); + + context->devices = NULL; + + proto->context = context; + proto->listener = NULL; + + return proto; +} + /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, @@ -295,6 +355,19 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, self->wayland.pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } + + /* primary selection support */ + if(WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1) != NULL) { + primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1)->context; + primary_selection_device_context_t* device_ctx = malloc(sizeof(primary_selection_device_context_t)); + + device_ctx->device = + zwp_primary_selection_device_manager_v1_get_device(primary_selection->manager, wl_seat); + + zwp_primary_selection_device_v1_add_listener(device_ctx->device, &primary_selection->listener, device_ctx); + + arrpush(primary_selection->devices, device_ctx); + } }; static void output_geometry(void* data, @@ -636,6 +709,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_seat); WL_INTERFACE(wl_output); + WL_INTERFACE(zwp_primary_selection_device_manager_v1); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); @@ -799,6 +873,19 @@ static void MwLLDestroyImpl(MwLL handle) { buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); + if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { + primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; + int i; + + for(i = 0; i < arrlen(primary_selection->devices); i++) { + zwp_primary_selection_offer_v1_destroy(primary_selection->devices[i]->offer); + } + + // zwp_primary_selection_source_v1_send(); + + // arrpush(primary_selection->devices, device); + } + free(handle); } @@ -1083,8 +1170,74 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { } static char* MwLLGetClipboardImpl(MwLL handle) { - char* r = NULL; - return r; + if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { + enum { + DISPLAY_FD, + KEYREPEAT_FD, + CURSOR_FD + }; + struct pollfd pfd; + primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; + int i, n = 0; + int fds[2]; + struct timeval timeout; + fd_set set; + char* clip_buffer = NULL; + + pfd.fd = wl_display_get_fd(handle->wayland.display); + pfd.events = POLLIN; + + if(pipe(fds) != 0) { + return NULL; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + + timeout.tv_sec = 0; + timeout.tv_usec = 100; + + for(i = 0; i < arrlen(primary_selection->devices); i++) { + primary_selection_device_context_t* device = primary_selection->devices[i]; + size_t size = 0; + char ch; + int rc = 0; + + zwp_primary_selection_offer_v1_receive(device->offer, "text/plain", fds[1]); + + while(MwTRUE) { + rc = wl_display_flush(handle->wayland.display); + if(errno != EAGAIN || rc != -1) { + break; + } + + if(poll(&pfd, 1, -1) == -1) { + break; + } + } + + fcntl(fds[0], F_SETFL, O_NONBLOCK); + + while(MwTRUE) { + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + read(fds[0], &ch, 1); + arrpush(clip_buffer, ch); + if(n++ >= 10240) { + break; + } + } + } + return clip_buffer; + } + + // zwp_primary_selection_source_v1_send(); + + // arrpush(primary_selection->devices, device); + } + return NULL; } static void MwLLMakeToolWindowImpl(MwLL handle) { From 59ff6f10087c32050b0692ff295c2cc53bd9ea2a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 18:21:57 -0700 Subject: [PATCH 023/409] wayland: add icon support --- include/Mw/LowLevel/Wayland.h | 6 ++-- pl/rules.pl | 1 + src/backend/wayland.c | 64 ++++++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 10 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index e47caed1e..9c6069311 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -25,6 +25,7 @@ MWDECL int MwLLWaylandCallInit(void); #include "Wayland/xdg-decoration-client-protocol.h" #include "Wayland/cursor-shape-client-protocol.h" #include "Wayland/primary-selection-client-protocol.h" +#include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif struct _MwLLWayland; @@ -124,8 +125,9 @@ struct _MwLLWayland { char* cur_selection; - struct _MwLLWaylandShmBuffer framebuffer; - struct _MwLLWaylandShmBuffer cursor; + struct _MwLLWaylandShmBuffer framebuffer; + struct _MwLLWaylandShmBuffer cursor; + struct _MwLLWaylandShmBuffer* icon; cairo_surface_t* cs; cairo_t* cairo; diff --git a/pl/rules.pl b/pl/rules.pl index 094d8effd..f34ee2baf 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -34,6 +34,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("stable", "xdg-shell", ""); scan_wayland_protocol("stable", "tablet", "-v2"); + scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); scan_wayland_protocol("staging", "cursor-shape", "-v1"); scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index ed730ad9e..0c262b990 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -552,14 +552,11 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland return NULL; } -static void update_framebuffer(struct _MwLLWayland* wayland) { - struct _MwLLWaylandShmBuffer* buffer = &wayland->framebuffer; +static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { fsync(buffer->fd); - if(wayland->configured && buffer->setup) { - wl_surface_attach(wayland->framebuffer.surface, buffer->shm_buffer, wayland->x, wayland->y); - wl_surface_commit(wayland->framebuffer.surface); - } + wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); + wl_surface_commit(buffer->surface); } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { @@ -613,7 +610,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { wayland->cairo = cairo_create(wayland->cs); memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); - update_framebuffer(wayland); + update_buffer(&wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -636,6 +633,16 @@ static void region_setup(MwLL handle) { wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } +/* wl_shm setup function */ +static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + + proto->context = wl_registry_bind(wayland->registry, name, &xdg_toplevel_icon_manager_v1_interface, 1); + proto->listener = NULL; + + return proto; +} + /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { enum { @@ -713,6 +720,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); + WL_INTERFACE(xdg_toplevel_icon_manager_v1); } else { WL_INTERFACE(wl_subcompositor); } @@ -886,6 +894,11 @@ static void MwLLDestroyImpl(MwLL handle) { // arrpush(primary_selection->devices, device); } + if(handle->wayland.icon != NULL) { + buffer_destroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + free(handle); } @@ -968,7 +981,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } static void MwLLEndDrawImpl(MwLL handle) { - update_framebuffer(&handle->wayland); + update_buffer(&handle->wayland.framebuffer); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -1065,6 +1078,41 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_surface_destroy(cs); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { + void* map; + struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; + struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(icon_manager); + MwU64 size = pixmap->common.width * pixmap->common.height * 4; + int i = 0; + + if(handle->wayland.icon == NULL) { + handle->wayland.icon = calloc(sizeof(struct _MwLLWaylandShmBuffer), 0); + handle->wayland.icon->shm = handle->wayland.framebuffer.shm; + } + + if(handle->wayland.icon->setup) { + buffer_destroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + handle->wayland.icon->surface = wl_compositor_create_surface(handle->wayland.compositor); + + buffer_setup(handle->wayland.icon, pixmap->common.width, pixmap->common.height); + + for(; i < size; i += 2) { + handle->wayland.icon->buf[i] = pixmap->common.raw[i + 2]; + handle->wayland.icon->buf[i + 1] = pixmap->common.raw[i + 1]; + handle->wayland.icon->buf[i + 2] = pixmap->common.raw[i + 0]; + handle->wayland.icon->buf[i + 3] = 255; + } + + update_buffer(handle->wayland.icon); + + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); + + xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); + } + } } static void MwLLForceRenderImpl(MwLL handle) { From 18511dec2f6d80b984104b88c43f4721a6cf4dc9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 18:27:44 -0700 Subject: [PATCH 024/409] wayland: remove a few unused fields --- include/Mw/LowLevel/Wayland.h | 7 +------ src/backend/wayland.c | 17 ++++++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 9c6069311..efb0279ff 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -60,7 +60,7 @@ struct _MwLLWaylandSublevel { MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ }; -/* Shared set of anything needed for a shm buffer. Used both for surface framebuffers, and cursors. */ +/* Shared set of anything needed for a shm buffer. */ struct _MwLLWaylandShmBuffer { struct wl_shm* shm; struct wl_shm_pool* shm_pool; @@ -111,11 +111,8 @@ struct _MwLLWayland { struct wl_pointer* pointer; MwU32 pointer_serial; - MwBool active; /* Whether or not the surface is the one being hovered over. */ - MwU32 mod_state; - MwLL* sublevels; /* stb_ds managed array of any sublevels */ MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ MwU32 x, y, ww, wh; /* Window position */ @@ -123,8 +120,6 @@ struct _MwLLWayland { MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ - char* cur_selection; - struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 0c262b990..5d6144d55 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -9,6 +9,16 @@ #include #include +/* TODO: + * - MwLLMakeToolWindowImpl + * - MwLLSetClipboardImpl + * - MwLLGrabPointerImpl + * - MwLLFocusImpl + * - MwLLMakePopupImpl + * - MwLLShowImpl + * - MwLLDetachImpl + */ + /* TODO: find out what FreeBSD and such wants us to include */ #ifdef __FreeBSD__ /* XXX: Untested (nishi) */ @@ -501,11 +511,6 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); - for(i = 0; i < arrlen(self->wayland.sublevels); i++) { - MwLL handle = self->wayland.sublevels[i]; - region_setup(handle); - } - /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { @@ -856,8 +861,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.x = x; r->wayland.y = y; - r->wayland.sublevels = NULL; - if(parent == NULL) { setup_toplevel(r, x, y); } else { From b7488b944068e86a99b77904c850b9ed39f53c75 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 19:59:40 -0700 Subject: [PATCH 025/409] wayland: seperate MwLLPending and MwLLNextEvent --- include/Mw/LowLevel/Wayland.h | 3 +++ src/backend/wayland.c | 23 +++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index efb0279ff..432055eb7 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -42,6 +42,7 @@ struct _MwLLWaylandTopLevel { struct xdg_toplevel* xdg_top_level; struct xdg_toplevel_listener xdg_toplevel_listener; struct xdg_surface_listener xdg_surface_listener; + struct xdg_positioner* xdg_positioner; struct xkb_context* xkb_context; struct xkb_keymap* xkb_keymap; @@ -111,6 +112,8 @@ struct _MwLLWayland { struct wl_pointer* pointer; MwU32 pointer_serial; + MwBool events_pending; + MwU32 mod_state; MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5d6144d55..47c1a10f0 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -13,7 +13,6 @@ * - MwLLMakeToolWindowImpl * - MwLLSetClipboardImpl * - MwLLGrabPointerImpl - * - MwLLFocusImpl * - MwLLMakePopupImpl * - MwLLShowImpl * - MwLLDetachImpl @@ -146,6 +145,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); + self->wayland.events_pending = MwTRUE; /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; @@ -178,6 +178,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } MwLLDispatch(self, draw, NULL); + self->wayland.events_pending = MwTRUE; }; /* `wl_pointer.axis` callback */ @@ -229,6 +230,7 @@ static void keyboard_enter(void* data, struct wl_array* keys) { MwLL self = data; MwLLDispatch(self, focus_in, NULL); + self->wayland.events_pending = MwTRUE; }; /* `wl_keyboard.leave` callback */ @@ -238,6 +240,7 @@ static void keyboard_leave(void* data, struct wl_surface* surface) { MwLL self = data; MwLLDispatch(self, focus_out, NULL); + self->wayland.events_pending = MwTRUE; }; /* `wl_keyboard.key` callback */ @@ -324,6 +327,7 @@ static void keyboard_key(void* data, } } } + self->wayland.events_pending = MwTRUE; }; /* `wl_keyboard.modifiers` callback */ @@ -616,6 +620,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); update_buffer(&wayland->framebuffer); + wayland->events_pending = MwTRUE; }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -940,6 +945,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } refresh: + MwLLDispatch(handle, draw, NULL); region_setup(handle); framebuffer_destroy(&handle->wayland); @@ -961,6 +967,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } cairo_close_path(handle->wayland.cairo); cairo_fill(handle->wayland.cairo); + handle->wayland.events_pending = MwTRUE; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -978,6 +985,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { } cairo_close_path(handle->wayland.cairo); cairo_stroke(handle->wayland.cairo); + handle->wayland.events_pending = MwTRUE; } static void MwLLBeginDrawImpl(MwLL handle) { @@ -985,6 +993,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { update_buffer(&handle->wayland.framebuffer); + handle->wayland.events_pending = MwTRUE; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -1008,10 +1017,11 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return event_loop(handle); + return handle->wayland.events_pending; } static void MwLLNextEventImpl(MwLL handle) { + event_loop(handle); } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -1185,6 +1195,13 @@ static void MwLLShowImpl(MwLL handle, int show) { } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + struct xdg_wm_base* wm_base = WAYLAND_GET_INTERFACE(handle->wayland, xdg_wm_base)->context; + + handle->wayland.toplevel->xdg_positioner = xdg_wm_base_create_positioner(wm_base); + xdg_surface_get_popup(handle->wayland.toplevel->xdg_surface, handle->wayland.toplevel->xdg_surface, handle->wayland.toplevel->xdg_positioner); + } else { + } } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { @@ -1212,6 +1229,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { } static void MwLLFocusImpl(MwLL handle) { + printf("[WARNING] MwLLFocus not supported on Wayland\n"); } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { @@ -1292,6 +1310,7 @@ static char* MwLLGetClipboardImpl(MwLL handle) { } static void MwLLMakeToolWindowImpl(MwLL handle) { + printf("sub menu\n"); } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { From 6123fd1304de77eaa67546c9ed6fa826e8e104f3 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 23:32:51 -0700 Subject: [PATCH 026/409] wayland: implement tool windows. add destructors for protocols --- include/Mw/LowLevel/Wayland.h | 46 ++++- src/backend/wayland.c | 342 ++++++++++++++++++++++++++++------ 2 files changed, 321 insertions(+), 67 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 432055eb7..2720d4976 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -36,13 +36,18 @@ typedef struct wayland_protocol { } wayland_protocol_t; typedef wayland_protocol_t*(wl_setup_func)(MwU32, struct _MwLLWayland*); +typedef void(wl_destroy_func)(struct _MwLLWayland* wayland, wayland_protocol_t* data); + +typedef struct wayland_protocol_callback_table { + wl_setup_func* setup; + wl_destroy_func* destroy; +} wayland_protocol_callback_table_t; 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 xdg_positioner* xdg_positioner; struct xkb_context* xkb_context; struct xkb_keymap* xkb_keymap; @@ -58,7 +63,17 @@ struct _MwLLWaylandSublevel { struct wl_subcompositor* subcompositor; MwLL parent; - MwLL topmost_parent; /* The parent at the top of all the other parents. Usually a toplevel. */ + + struct xdg_surface* parent_xdg_surface; +}; + +struct _MwLLWaylandPopup { + struct xdg_surface* xdg_surface; + struct xdg_popup* xdg_popup; + struct xdg_positioner* xdg_positioner; + struct xdg_surface_listener xdg_surface_listener; + struct xdg_wm_base* xdg_wm_base; + MwLL parent; }; /* Shared set of anything needed for a shm buffer. */ @@ -75,6 +90,13 @@ struct _MwLLWaylandShmBuffer { MwBool setup; }; +enum _MwLLWaylandType { + MWLL_WAYLAND_UNKNOWN = 0, + MWLL_WAYLAND_TOPLEVEL, + MWLL_WAYLAND_SUBLEVEL, + MWLL_WAYLAND_POPUP, +}; + struct _MwLLWayland { struct _MwLLCommon common; @@ -83,17 +105,17 @@ struct _MwLLWayland { struct _MwLLWaylandTopLevel* toplevel; /* Pointer for data that's only loaded if the widget is a sublevel */ struct _MwLLWaylandSublevel* sublevel; + /* Pointer for data that's only loaded if the widget is a popup */ + struct _MwLLWaylandPopup* popup; }; - enum { - MWLL_WAYLAND_TOPLEVEL = 0, - MWLL_WAYLAND_SUBLEVEL, /* Sublevels are surfaces that have the toplevel as a parent. Some parts of the code also call them subwidgets. */ - } type; + enum _MwLLWaylandType type; + enum _MwLLWaylandType type_to_be; /* Map of Wayland interfaces to their relevant setup functions. */ struct { - const char* key; - wl_setup_func* value; + const char* key; + wayland_protocol_callback_table_t* value; }* wl_protocol_setup_map; /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ @@ -109,10 +131,12 @@ struct _MwLLWayland { struct wl_region* region; struct wl_output* output; - struct wl_pointer* pointer; - MwU32 pointer_serial; + struct wl_pointer* pointer; + struct wl_keyboard* keyboard; + MwU32 pointer_serial; MwBool events_pending; + MwBool test; MwU32 mod_state; @@ -123,6 +147,8 @@ struct _MwLLWayland { MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ + MwLL parent; + struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 47c1a10f0..5c65906e6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -10,7 +10,6 @@ #include /* TODO: - * - MwLLMakeToolWindowImpl * - MwLLSetClipboardImpl * - MwLLGrabPointerImpl * - MwLLMakePopupImpl @@ -32,6 +31,8 @@ static void framebuffer_setup(struct _MwLLWayland* wayland); /* Destroy the framebuffer */ static void framebuffer_destroy(struct _MwLLWayland* handle); +static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer); + static void region_setup(MwLL handle); static void region_invalidate(MwLL handle); @@ -44,12 +45,11 @@ static void new_protocol(void* data, struct wl_registry* registry, MwU32 version) { struct _MwLLWayland* wayland = data; - wl_setup_func* func = shget(wayland->wl_protocol_setup_map, interface); - if(func != NULL) { + wayland_protocol_callback_table_t* cb = shget(wayland->wl_protocol_setup_map, interface); + if(cb != NULL) { char* inter = malloc(strlen(interface)); strcpy(inter, interface); - - shput(wayland->wl_protocol_map, inter, func(name, data)); + shput(wayland->wl_protocol_map, inter, cb->setup(name, data)); } else { /* printf("unknown interface %s\n", interface); */ } @@ -59,7 +59,7 @@ static void new_protocol(void* data, struct wl_registry* registry, static void protocol_removed(void* data, struct wl_registry* registry, MwU32 name) { - + printf("%d destroyed\n", name); }; static void offer_offer(void* data, @@ -119,6 +119,25 @@ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 n return proto; } +static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + primary_selection_context_t* context = data->context; + int i; + + zwp_primary_selection_device_manager_v1_destroy(context->manager); + + for(i = 0; i < arrlen(context->devices); i++) { + primary_selection_device_context_t* device = context->devices[i]; + // zwp_primary_selection_device_v1_destroy(device->device); + // zwp_primary_selection_offer_v1_destroy(device->offer); + free(device); + } + arrfree(context->devices); + + zwp_primary_selection_source_v1_destroy(context->source); + + free(data->listener); +} + /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, @@ -362,8 +381,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) { MwLL self = data; if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { - struct wl_keyboard* keyboard = wl_seat_get_keyboard(wl_seat); - wl_keyboard_add_listener(keyboard, &keyboard_listener, data); + self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); + wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER) { self->wayland.pointer = wl_seat_get_pointer(wl_seat); @@ -380,6 +399,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, zwp_primary_selection_device_v1_add_listener(device_ctx->device, &primary_selection->listener, device_ctx); + device_ctx->offer = NULL; + arrpush(primary_selection->devices, device_ctx); } }; @@ -431,6 +452,11 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { return proto; } +static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + free(data->listener); + wl_seat_destroy(data->context); +} + /* wl_output setup function */ static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { ll->wayland.output = wl_registry_bind(ll->wayland.registry, name, &wl_output_interface, 1); @@ -439,6 +465,10 @@ static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { return NULL; } +static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + // wl_output_destroy(wayland->output); +} + /* wl_compositor setup function */ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland->compositor = wl_registry_bind(wayland->registry, name, &wl_compositor_interface, 1); @@ -446,6 +476,10 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* return NULL; } +static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + // wl_compositor_destroy(wayland->compositor); +} + /* wl_subcompositor setup function */ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); @@ -453,6 +487,10 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan return NULL; } +static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + wl_subcompositor_destroy(wayland->sublevel->subcompositor); +} + /* xdg_wm_base setup function */ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -466,6 +504,11 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa return proto; } +static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + xdg_wm_base_destroy(data->context); + free(data->listener); +} + /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { struct zxdg_decoration_manager_v1* manager; @@ -486,6 +529,13 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ return proto; } +static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + zxdg_decoration_manager_v1_context_t* context = data->context; + + zxdg_decoration_manager_v1_destroy(context->manager); + zxdg_toplevel_decoration_v1_destroy(context->decoration); +} + /* `xdg_toplevel.close` callback */ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, @@ -561,6 +611,10 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland return NULL; } +static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + // buffer_destroy(&wayland->framebuffer); +} + static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { fsync(buffer->fd); @@ -643,7 +697,6 @@ static void region_setup(MwLL handle) { wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } -/* wl_shm setup function */ static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -653,13 +706,32 @@ static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct return proto; } +static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + free(data->listener); + xdg_toplevel_icon_manager_v1_destroy(data->context); +} + +/* Flush Wayland events */ +static void wl_flush(MwLL handle) { + struct pollfd pfd; + int rc; + + pfd.fd = wl_display_get_fd(handle->wayland.display); + pfd.events = POLLIN; + while(MwTRUE) { + rc = wl_display_flush(handle->wayland.display); + if(errno != EAGAIN || rc != -1) { + break; + } + + if(poll(&pfd, 1, -1) == -1) { + break; + } + } +} + /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { - enum { - DISPLAY_FD, - KEYREPEAT_FD, - CURSOR_FD - }; struct pollfd fd; int timeout = 1; struct _MwLLWayland* wayland = &handle->wayland; @@ -715,7 +787,12 @@ static int event_loop(MwLL handle) { static void setup_callbacks(struct _MwLLWayland* wayland) { /* Convience macro for adding the interface functions to the setup map */ #define WL_INTERFACE(interface) \ - shput(wayland->wl_protocol_setup_map, interface##_interface.name, (wl_setup_func*)interface##_setup); + do { \ + wayland_protocol_callback_table_t* cb = malloc(sizeof(wayland_protocol_callback_table_t)); \ + cb->setup = (wl_setup_func*)interface##_setup; \ + cb->destroy = (wl_destroy_func*)interface##_interface_destroy; \ + shput(wayland->wl_protocol_setup_map, interface##_interface.name, cb); \ + } while(0); wayland->registry_listener.global = new_protocol; wayland->registry_listener.global_remove = protocol_removed; @@ -731,6 +808,8 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(xdg_toplevel_icon_manager_v1); + } else if(wayland->type == MWLL_WAYLAND_POPUP) { + WL_INTERFACE(xdg_wm_base); } else { WL_INTERFACE(wl_subcompositor); } @@ -803,10 +882,28 @@ static void setup_toplevel(MwLL r, int x, int y) { } else { printf("zxdg null\n"); } +} - /*egl_resetup(r); - MwLLDispatch(r, draw, NULL); - recursive_draw(r);*/ +/* Toplevel destroy function */ +static void destroy_toplevel(MwLL r) { + int i; + + 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; + zxdg_decoration_manager_v1_destroy(dec->manager); + } + + wl_compositor_destroy(r->wayland.compositor); + + xdg_surface_destroy(r->wayland.toplevel->xdg_surface); + + xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + + xkb_context_unref(r->wayland.toplevel->xkb_context); + + wl_registry_destroy(r->wayland.registry); + + wl_display_disconnect(r->wayland.display); } /* Sublevel setup function */ @@ -814,7 +911,14 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { struct wl_compositor* compositor = parent->wayland.compositor; struct wl_surface* parent_surface = parent->wayland.framebuffer.surface; - r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); + r->wayland.sublevel = malloc(sizeof(struct _MwLLWaylandSublevel)); + r->wayland.sublevel->parent = parent; + + if(parent->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + r->wayland.sublevel->parent_xdg_surface = parent->wayland.toplevel->xdg_surface; + } else { + r->wayland.sublevel->parent_xdg_surface = parent->wayland.sublevel->parent_xdg_surface; + } r->wayland.type = MWLL_WAYLAND_SUBLEVEL; @@ -843,6 +947,113 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.configured = MwTRUE; } +/* Sublevel setup function */ +static void destroy_sublevel(MwLL r) { + wl_subsurface_destroy(r->wayland.sublevel->subsurface); + + wl_surface_destroy(r->wayland.framebuffer.surface); + + free(r->wayland.sublevel); +} + +static void popup_configure(void* data, + struct xdg_popup* xdg_popup, + int32_t x, + int32_t y, + int32_t width, + int32_t height) { + MwLL self = data; + + self->wayland.x = x; + self->wayland.y = y; + self->wayland.ww = width; + self->wayland.wh = height; +}; + +static void popup_done(void* data, + struct xdg_popup* xdg_popup) { + printf("Sdfgs\n"); +}; + +struct xdg_popup_listener popup_listener = { + .configure = popup_configure, + .popup_done = popup_done, +}; + +/* Popup setup function */ +static void setup_popup(MwLL r) { + int i; + struct xdg_surface* xdg_surface; + MwLL topmost_parent = r->wayland.parent; + + while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } + + r->wayland.type = MWLL_WAYLAND_POPUP; + + setup_callbacks(&r->wayland); + + /* 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"); + raise(SIGTRAP); + return; + } + + r->wayland.popup = calloc(sizeof(struct _MwLLWaylandPopup), 0); + // r->wayland.popup->parent = parent; + + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + + r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; + + r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); + + xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_anchor_rect( + r->wayland.popup->xdg_positioner, + topmost_parent->wayland.cur_mouse_pos.x, + topmost_parent->wayland.cur_mouse_pos.y, + 1, 1); + + xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; + + r->wayland.popup->xdg_surface = + xdg_wm_base_get_xdg_surface(r->wayland.popup->xdg_wm_base, r->wayland.framebuffer.surface); + + r->wayland.popup->xdg_popup = xdg_surface_get_popup( + r->wayland.popup->xdg_surface, + xdg_surface, + r->wayland.popup->xdg_positioner); + + xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); + + r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; + + xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r); + + /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.framebuffer.surface); + event_loop(r); +} +/* Popup destroy function */ +static void destroy_popup(MwLL r) { + xdg_popup_destroy(r->wayland.popup->xdg_popup); + + xdg_surface_destroy(r->wayland.popup->xdg_surface); + + xdg_positioner_destroy(r->wayland.popup->xdg_positioner); + + wl_surface_destroy(r->wayland.framebuffer.surface); + + // free(r->wayland.popup); + + wl_registry_destroy(r->wayland.registry); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -861,10 +1072,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { y = 0; } - r->wayland.ww = width; - r->wayland.wh = height; - r->wayland.x = x; - r->wayland.y = y; + r->wayland.ww = width; + r->wayland.wh = height; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.parent = parent; if(parent == NULL) { setup_toplevel(r, x, y); @@ -883,6 +1095,10 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } static void MwLLDestroyImpl(MwLL handle) { + int i; + + event_loop(handle); + MwLLDestroyCommon(handle); buffer_destroy(&handle->wayland.framebuffer); @@ -891,15 +1107,10 @@ static void MwLLDestroyImpl(MwLL handle) { if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; - int i; for(i = 0; i < arrlen(primary_selection->devices); i++) { zwp_primary_selection_offer_v1_destroy(primary_selection->devices[i]->offer); } - - // zwp_primary_selection_source_v1_send(); - - // arrpush(primary_selection->devices, device); } if(handle->wayland.icon != NULL) { @@ -907,6 +1118,29 @@ static void MwLLDestroyImpl(MwLL handle) { wl_surface_destroy(handle->wayland.icon->surface); } + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + destroy_toplevel(handle); + } else if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + destroy_sublevel(handle); + } else if(handle->wayland.type == MWLL_WAYLAND_POPUP) { + destroy_popup(handle); + } + + for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { + void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); + + handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + } + shfree(handle->wayland.wl_protocol_map); + shfree(handle->wayland.wl_protocol_setup_map); + + if(handle->wayland.pointer != NULL) { + wl_pointer_destroy(handle->wayland.pointer); + } + if(handle->wayland.keyboard != NULL) { + wl_keyboard_destroy(handle->wayland.keyboard); + } + free(handle); } @@ -1017,11 +1251,10 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return handle->wayland.events_pending; + return event_loop(handle); } static void MwLLNextEventImpl(MwLL handle) { - event_loop(handle); } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -1189,19 +1422,32 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + switch(handle->wayland.type) { + case MWLL_WAYLAND_UNKNOWN: + case MWLL_WAYLAND_TOPLEVEL: + destroy_toplevel(handle); + break; + case MWLL_WAYLAND_SUBLEVEL: + destroy_sublevel(handle); + break; + case MWLL_WAYLAND_POPUP: + return; + } + + switch(handle->wayland.type_to_be) { + case MWLL_WAYLAND_POPUP: + setup_popup(handle); + return; + default: + setup_toplevel(handle, point->x, point->y); + break; + } } static void MwLLShowImpl(MwLL handle, int show) { } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - struct xdg_wm_base* wm_base = WAYLAND_GET_INTERFACE(handle->wayland, xdg_wm_base)->context; - - handle->wayland.toplevel->xdg_positioner = xdg_wm_base_create_positioner(wm_base); - xdg_surface_get_popup(handle->wayland.toplevel->xdg_surface, handle->wayland.toplevel->xdg_surface, handle->wayland.toplevel->xdg_positioner); - } else { - } } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { @@ -1240,12 +1486,6 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { static char* MwLLGetClipboardImpl(MwLL handle) { if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { - enum { - DISPLAY_FD, - KEYREPEAT_FD, - CURSOR_FD - }; - struct pollfd pfd; primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; int i, n = 0; int fds[2]; @@ -1253,9 +1493,6 @@ static char* MwLLGetClipboardImpl(MwLL handle) { fd_set set; char* clip_buffer = NULL; - pfd.fd = wl_display_get_fd(handle->wayland.display); - pfd.events = POLLIN; - if(pipe(fds) != 0) { return NULL; } @@ -1274,16 +1511,7 @@ static char* MwLLGetClipboardImpl(MwLL handle) { zwp_primary_selection_offer_v1_receive(device->offer, "text/plain", fds[1]); - while(MwTRUE) { - rc = wl_display_flush(handle->wayland.display); - if(errno != EAGAIN || rc != -1) { - break; - } - - if(poll(&pfd, 1, -1) == -1) { - break; - } - } + wl_flush(handle); fcntl(fds[0], F_SETFL, O_NONBLOCK); @@ -1310,7 +1538,7 @@ static char* MwLLGetClipboardImpl(MwLL handle) { } static void MwLLMakeToolWindowImpl(MwLL handle) { - printf("sub menu\n"); + handle->wayland.type_to_be = MWLL_WAYLAND_POPUP; } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { From a384add9e973d13b050411c14a3286c90916a81b Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 18 Dec 2025 23:50:03 -0700 Subject: [PATCH 027/409] wayland: properly do MwLLPending and MwLLNextEvent --- src/backend/wayland.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5c65906e6..f05511724 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -972,7 +972,6 @@ static void popup_configure(void* data, static void popup_done(void* data, struct xdg_popup* xdg_popup) { - printf("Sdfgs\n"); }; struct xdg_popup_listener popup_listener = { @@ -1251,10 +1250,14 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return event_loop(handle); + return handle->wayland.events_pending || wl_display_dispatch(handle->wayland.display); } static void MwLLNextEventImpl(MwLL handle) { + event_loop(handle); + if(handle->wayland.events_pending) { + handle->wayland.events_pending = MwFALSE; + } } static void MwLLSetTitleImpl(MwLL handle, const char* title) { From 604ff72d6ec7edc4faea4629a6398da9544a03db Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 22:35:26 +0900 Subject: [PATCH 028/409] add MwNbitmapFont --- include/Mw/StringDefs.h | 1 + milsko.xml | 2 ++ src/core.c | 4 ++++ src/text.c | 6 +++--- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 071137332..deac295e0 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -35,6 +35,7 @@ #define MwNratio "Iratio" #define MwNfixedSize "IfixedSize" #define MwNmargin "Imargin" +#define MwNbitmapFont "IbitmapFont" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/milsko.xml b/milsko.xml index 758eb1f88..d46e0d3f7 100644 --- a/milsko.xml +++ b/milsko.xml @@ -51,6 +51,7 @@ - MwNbackgroundPixmap - MwNratio - MwNfixedSize + - MwNbitmapFont Integer properties must be prefixed with I. String properties must be prefixed with S. @@ -87,6 +88,7 @@ + diff --git a/src/core.c b/src/core.c index 0ae8d4aab..c68e39a91 100644 --- a/src/core.c +++ b/src/core.c @@ -593,8 +593,12 @@ void MwSetDefault(MwWidget handle) { inherit_integer(handle, MwNmodernLook, 1); #endif #if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) + inherit_integer(handle, MwNbitmapFont, 0); + set_font(handle); set_boldfont(handle); +#else + inherit_integer(handle, MwNbitmapFont, 1); #endif } diff --git a/src/text.c b/src/text.c index 7d94e5cf4..a9ff6a0a5 100644 --- a/src/text.c +++ b/src/text.c @@ -294,7 +294,7 @@ static int ttf_MwTextHeight(MwWidget handle, int count) { void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { if(strlen(text) == 0) return; #ifdef TTF - if(ttf_MwDrawText(handle, point, text, bold, align, color)) + if(!MwGetInteger(handle, MwNbitmapFont) && ttf_MwDrawText(handle, point, text, bold, align, color)) #endif bitmap_MwDrawText(handle, point, text, bold, align, color); } @@ -304,7 +304,7 @@ int MwTextWidth(MwWidget handle, const char* text) { #ifdef TTF int st; - if((st = ttf_MwTextWidth(handle, text)) != -1) return st; + if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextWidth(handle, text)) != -1) return st; #else (void)handle; @@ -331,7 +331,7 @@ int MwTextHeight(MwWidget handle, const char* text) { if(out == '\n') c++; } #ifdef TTF - if((st = ttf_MwTextHeight(handle, c)) != -1) return st; + if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextHeight(handle, c)) != -1) return st; #endif return FontHeight * c; } From dc8168df129041dcc25e2d7b3123d07a0aa7cf9d Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 22:36:49 +0900 Subject: [PATCH 029/409] fix --- src/text.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text.c b/src/text.c index a9ff6a0a5..c0e00c6db 100644 --- a/src/text.c +++ b/src/text.c @@ -294,7 +294,7 @@ static int ttf_MwTextHeight(MwWidget handle, int count) { void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { if(strlen(text) == 0) return; #ifdef TTF - if(!MwGetInteger(handle, MwNbitmapFont) && ttf_MwDrawText(handle, point, text, bold, align, color)) + if(MwGetInteger(handle, MwNbitmapFont) || ttf_MwDrawText(handle, point, text, bold, align, color)) #endif bitmap_MwDrawText(handle, point, text, bold, align, color); } From a67a0c11f8e42033d246ae284e51ebd97c8e9672 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 19 Dec 2025 23:31:05 +0900 Subject: [PATCH 030/409] fix --- pl/rules.pl | 10 +++++----- src/core.c | 43 +++++++++++++++++++++---------------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/pl/rules.pl b/pl/rules.pl index f34ee2baf..71f38c016 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -32,11 +32,11 @@ if (grep(/^wayland$/, @backends)) { add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); - scan_wayland_protocol("stable", "xdg-shell", ""); - scan_wayland_protocol("stable", "tablet", "-v2"); - scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); - scan_wayland_protocol("staging", "cursor-shape", "-v1"); - scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); + scan_wayland_protocol("stable", "xdg-shell", ""); + scan_wayland_protocol("stable", "tablet", "-v2"); + scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); + scan_wayland_protocol("staging", "cursor-shape", "-v1"); + scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; diff --git a/src/core.c b/src/core.c index c68e39a91..cde8b0d72 100644 --- a/src/core.c +++ b/src/core.c @@ -428,6 +428,15 @@ void MwSetVoid(MwWidget handle, const char* key, void* value) { } } +static int inherit_integer(MwWidget handle, const char* key, int default_v) { + int v; + + if(handle->parent != NULL && (v = MwGetInteger(handle->parent, key)) != MwDEFAULT) { + return v; + } + return default_v; +} + int MwGetInteger(MwWidget handle, const char* key) { if(strcmp(key, MwNx) == 0 || strcmp(key, MwNy) == 0 || strcmp(key, MwNwidth) == 0 || strcmp(key, MwNheight) == 0) { int x, y; @@ -441,6 +450,18 @@ int MwGetInteger(MwWidget handle, const char* key) { if(strcmp(key, MwNheight) == 0) return h; return MwDEFAULT; } else { + if(shgeti(handle->integer, key) == -1) { +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) + if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 0); +#else + if(strcmp(key, MwNbitmapFont) == 0) return inherit_integer(handle, key, 1); +#endif +#ifdef USE_CLASSIC_THEME + if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 0); +#else + if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 1); +#endif + } return shget(handle->integer, key); } } @@ -541,19 +562,6 @@ void MwVaListApply(MwWidget handle, va_list va) { } } -static void inherit_integer(MwWidget handle, const char* key, int default_value) { - int n; - MwWidget h = handle; - while(h != NULL) { - if((n = MwGetInteger(h, key)) != MwDEFAULT) { - MwSetInteger(handle, key, n); - return; - } - h = h->parent; - } - MwSetInteger(handle, key, default_value); -} - #if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) static void set_font(MwWidget handle) { void* f; @@ -587,18 +595,9 @@ static void set_boldfont(MwWidget handle) { void MwSetDefault(MwWidget handle) { if(handle->lowlevel != NULL) MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); -#ifdef USE_CLASSIC_THEME - inherit_integer(handle, MwNmodernLook, 0); -#else - inherit_integer(handle, MwNmodernLook, 1); -#endif #if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) - inherit_integer(handle, MwNbitmapFont, 0); - set_font(handle); set_boldfont(handle); -#else - inherit_integer(handle, MwNbitmapFont, 1); #endif } From ab9d0ffc5f5c7a98ec6dff36e4e60db82399808e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 11:53:47 +0900 Subject: [PATCH 031/409] improve submenu --- src/widget/submenu.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 09a02744e..3172084c3 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -160,14 +160,14 @@ static void click(MwWidget handle) { } static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point) { - int i, w = 0, h = 0; + int i, w = 0, h = 0; + MwRect rc; + MwPoint p = *point; + + MwGetScreenSize(handle, &rc); handle->internal = menu; - MwLLMakeToolWindow(handle->lowlevel); - MwLLDetach(handle->lowlevel, point); - MwLLEndStateChange(handle->lowlevel); - for(i = 0; i < arrlen(menu->sub); i++) { if(strcmp(menu->sub[i]->name, "----") == 0) { h += MwDefaultBorderWidth(handle) * 2 + 2; @@ -183,6 +183,16 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point) { w += 10 + 15; h += 3; + MwLLMakeToolWindow(handle->lowlevel); + MwLLDetach(handle->lowlevel, &p); + + if(MwGetInteger(handle, MwNy) + h > rc.height) { + MwVaApply(handle, + MwNy, rc.height - h, + NULL); + } + MwLLEndStateChange(handle->lowlevel); + MwVaApply(handle, MwNwidth, w, MwNheight, h, From f09960195f5a33dd0d878898edd33a5bf13b0fd9 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 12:08:08 +0900 Subject: [PATCH 032/409] submenu --- include/Mw/Widget/SubMenu.h | 11 +++++++++-- src/widget/menu.c | 2 +- src/widget/submenu.c | 15 ++++++++++----- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/Mw/Widget/SubMenu.h b/include/Mw/Widget/SubMenu.h index bf26fa862..126a73bbb 100644 --- a/include/Mw/Widget/SubMenu.h +++ b/include/Mw/Widget/SubMenu.h @@ -18,8 +18,15 @@ extern "C" { */ MWDECL MwClass MwSubMenuClass; -MwInline void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point) { - MwVaWidgetExecute(handle, "mwSubMenuAppear", NULL, menu, point); +/*! + * @brief Makes submenu appear + * @param handle Handle + * @param menu Menu + * @param point Point + * @param diff_calc Toggles different way to calculate positiion + */ +MwInline void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) { + MwVaWidgetExecute(handle, "mwSubMenuAppear", NULL, menu, point, diff_calc); } #ifdef __cplusplus diff --git a/src/widget/menu.c b/src/widget/menu.c index ffb8bb60e..327d6f5e7 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -129,7 +129,7 @@ static void mouse_down(MwWidget handle, void* ptr) { p2.y = p.y + th / 2 + 5; m->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0); - MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2); + MwSubMenuAppear(m->sub[i]->wsub, m->sub[i], &p2, 0); } else if(m->sub[i]->wsub != NULL && m->sub[i]->keep) { MwDestroyWidget(m->sub[i]->wsub); m->sub[i]->wsub = NULL; diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 3172084c3..ea51f029b 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -130,7 +130,7 @@ static void click(MwWidget handle) { p.y = rc.y - 3; menu->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0); - MwSubMenuAppear(menu->sub[i]->wsub, menu->sub[i], &p); + MwSubMenuAppear(menu->sub[i]->wsub, menu->sub[i], &p, 0); i = -1; } else if(menu->sub[i]->wsub != NULL && arrlen(menu->sub[i]->sub) > 0) { while(w->parent->widget_class != MwMenuClass) w = w->parent; @@ -159,7 +159,7 @@ static void click(MwWidget handle) { } } -static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point) { +static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) { int i, w = 0, h = 0; MwRect rc; MwPoint p = *point; @@ -183,6 +183,10 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point) { w += 10 + 15; h += 3; + if(diff_calc) { + p.y = rc.height - p.y - h; + } + MwLLMakeToolWindow(handle->lowlevel); MwLLDetach(handle->lowlevel, &p); @@ -203,9 +207,10 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v (void)out; if(strcmp(name, "mwSubMenuAppear") == 0) { - MwMenu menu = va_arg(va, MwMenu); - MwPoint* point = va_arg(va, MwPoint*); - mwSubMenuAppearImpl(handle, menu, point); + MwMenu menu = va_arg(va, MwMenu); + MwPoint* point = va_arg(va, MwPoint*); + int diff_calc = va_arg(va, int); + mwSubMenuAppearImpl(handle, menu, point, diff_calc); } } From 91d9677bf71fc06fe78acd4b86e75ea9477f7d08 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 14:38:07 +0900 Subject: [PATCH 033/409] add seven segment --- .gitignore | 1 + examples/basic/sevensegment.c | 22 +++ include/Mw/StringDefs.h | 1 + include/Mw/TypeDefs.h | 18 ++ include/Mw/Widget/Label.h | 11 ++ milsko.xml | 10 ++ pl/ostype/NetBSD.pl | 2 +- pl/rules.pl | 1 + src/widget/button.c | 2 + src/widget/label.c | 321 +++++++++++++++++++++++++++++++--- src/widget/scrollbar.c | 30 ++-- 11 files changed, 376 insertions(+), 43 deletions(-) create mode 100644 examples/basic/sevensegment.c diff --git a/.gitignore b/.gitignore index 005ebea58..1dcc6d174 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ examples/*/*.exe *.lib *.a /Makefile +/build compile_flags.txt diff --git a/examples/basic/sevensegment.c b/examples/basic/sevensegment.c new file mode 100644 index 000000000..7479da9fc --- /dev/null +++ b/examples/basic/sevensegment.c @@ -0,0 +1,22 @@ +#include + +int main() { + MwWidget wnd, label; + int W = 480, H = 40; + + MwLibraryInit(); + + wnd = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, W, H, + MwNtitle, "seven segment", + NULL); + + label = MwVaCreateWidget(MwLabelClass, "label", wnd, 0, 0, W, H, + MwNtext, " 123456:78.90 abcdef", + MwNsevenSegment, 1, + MwNalignment, MwALIGNMENT_BEGINNING, + NULL); + + MwLabelSetSevenSegment(label, 0, (1 << 0) | (1 << 3) | (1 << 6)); + + MwLoop(wnd); +} diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index deac295e0..f5b723afd 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -36,6 +36,7 @@ #define MwNfixedSize "IfixedSize" #define MwNmargin "Imargin" #define MwNbitmapFont "IbitmapFont" +#define MwNsevenSegment "IsevenSegment" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 0d2eeca4e..2a6efc715 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -20,6 +20,9 @@ typedef struct _MwViewport* MwViewport; typedef struct _MwListBox* MwListBox; typedef struct _MwComboBox* MwComboBox; typedef struct _MwTreeView* MwTreeView; +typedef struct _MwScrollBar* MwScrollBar; +typedef struct _MwLabel* MwLabel; +typedef struct _MwLabelSegment MwLabelSegment; typedef struct _MwListBoxEntry MwListBoxEntry; typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; @@ -164,6 +167,21 @@ struct _MwTreeView { MwPoint pressed; }; +struct _MwScrollBar { + MwPoint point; + int drag; + int pos; +}; + +struct _MwLabel { + MwLabelSegment* segment; +}; + +struct _MwLabelSegment { + int key; + unsigned char value; +}; + struct _MwDirectoryEntry { char* name; int type; diff --git a/include/Mw/Widget/Label.h b/include/Mw/Widget/Label.h index f11c06b6c..4c7513310 100644 --- a/include/Mw/Widget/Label.h +++ b/include/Mw/Widget/Label.h @@ -17,6 +17,17 @@ extern "C" { */ MWDECL MwClass MwLabelClass; +/*! + * @brief Sets the custom data for seven segment + * @param handle Widget + * @param index Index + * @param data Data, `GFEDCBA` as 7-bit value + * @note See https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg for what alphabets mean here + * */ +MwInline void MwLabelSetSevenSegment(MwWidget handle, int index, int data) { + MwVaWidgetExecute(handle, "mwLabelSetSevenSegment", NULL, index, data); +} + #ifdef __cplusplus } #endif diff --git a/milsko.xml b/milsko.xml index d46e0d3f7..9448e30a9 100644 --- a/milsko.xml +++ b/milsko.xml @@ -89,6 +89,7 @@ + @@ -536,7 +537,16 @@ + + + + + + + + + diff --git a/pl/ostype/NetBSD.pl b/pl/ostype/NetBSD.pl index de93b1439..0eec1061f 100644 --- a/pl/ostype/NetBSD.pl +++ b/pl/ostype/NetBSD.pl @@ -2,6 +2,6 @@ add_incdir("-I/usr/X11R7/include -I/usr/pkg/include"); add_libdir( "-L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib"); use_backend("x11"); -add_libs("pthread"); +add_libs("-lpthread"); 1; diff --git a/pl/rules.pl b/pl/rules.pl index 71f38c016..1ad3ff3de 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -115,6 +115,7 @@ new_example("examples/basic/combobox"); new_example("examples/basic/treeview"); new_example("examples/basic/box"); new_example("examples/basic/clipboard"); +new_example("examples/basic/sevensegment"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); diff --git a/src/widget/button.c b/src/widget/button.c index dfff6d5bf..7e5b36cdb 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -1,5 +1,7 @@ #include +#include "../../external/stb_ds.h" + static int create(MwWidget handle) { MwSetDefault(handle); diff --git a/src/widget/label.c b/src/widget/label.c index 2cf6a8da3..a2ae407fd 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -1,13 +1,119 @@ #include +#include "../../external/stb_ds.h" + +#define ShortOne 5 +#define LongOne 10 +#define Spacing 2 + static int create(MwWidget handle) { + MwLabel lab = malloc(sizeof(*lab)); + + lab->segment = NULL; + handle->internal = lab; + MwSetDefault(handle); MwSetInteger(handle, MwNalignment, MwALIGNMENT_CENTER); MwSetInteger(handle, MwNbold, 0); + MwSetInteger(handle, MwNsevenSegment, 0); return 0; } +static void destroy(MwWidget handle) { + MwLabel lab = handle->internal; + + hmfree(lab->segment); + + free(handle->internal); +} + +static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + for(cy = y; cy < y + LongOne; cy++) { + for(cx = x; cx < x + ShortOne; cx++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y - (ShortOne - 1) / 2; + for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { + int w = (cy - b) * 2 + 1; + int b2 = x + (ShortOne - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = y + LongOne; + for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { + int w = ((ShortOne - 1) / 2 - 1 - (cy - b)) * 2 + 1; + int b2 = x + (ShortOne - w) / 2; + for(cx = b2; cx < b2 + w; cx++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + +static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) { + int cy, cx, b; + for(cx = x; cx < x + LongOne; cx++) { + for(cy = y; cy < y + ShortOne; cy++) { + unsigned char* px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x - (ShortOne - 1) / 2; + for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { + int w = (cx - b) * 2 + 1; + int b2 = y + (ShortOne - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + + b = x + LongOne; + for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { + int w = ((ShortOne - 1) / 2 - 1 - (cx - b)) * 2 + 1; + int b2 = y + (ShortOne - w) / 2; + for(cy = b2; cy < b2 + w; cy++) { + unsigned char* px; + + px = &raw[(cy * stride + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } +} + static void draw(MwWidget handle) { MwRect r; MwPoint p; @@ -16,6 +122,7 @@ static void draw(MwWidget handle) { int align; const char* str = MwGetText(handle, MwNtext); MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLabel lab = handle->internal; if(str == NULL) str = ""; @@ -28,40 +135,206 @@ static void draw(MwWidget handle) { if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); align = MwGetInteger(handle, MwNalignment); - if(align == MwALIGNMENT_CENTER) { - p.x = r.width / 2; - } else if(align == MwALIGNMENT_BEGINNING) { - p.x = MwTextWidth(handle, str) / 2; - } else if(align == MwALIGNMENT_END) { - p.x = r.width - MwTextWidth(handle, str) / 2; + if(MwGetInteger(handle, MwNsevenSegment)) { + MwLLPixmap px; + unsigned char* raw; + int w = 0, h = ShortOne * 3 + LongOne * 2, i; + int x = 0; + + /* so - this mode cannot do unicode. + * but you wouldn't show unicode on 7 segment anyways + */ + + /* L + * S <---> + * + * S + * ^ + * | + * L | + * | + * v + */ + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; + if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + w += LongOne + ShortOne * 2; + } else if(str[i] == ':' || str[i] == ' ') { + w += ShortOne; + } + } + + raw = malloc(w * h * 4); + memset(raw, 0, w * h * 4); + + for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { + if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { + int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; + + /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ + + if(hmgeti(lab->segment, i) != -1) { + unsigned char c = hmget(lab->segment, i); + + if(c & (1 << 0)) la = 1; + if(c & (1 << 1)) lb = 1; + if(c & (1 << 2)) lc = 1; + if(c & (1 << 3)) ld = 1; + if(c & (1 << 4)) le = 1; + if(c & (1 << 5)) lf = 1; + if(c & (1 << 6)) lg = 1; + } else { + if(str[i] == '0') { + la = lb = lc = ld = le = lf = 1; + } else if(str[i] == '1') { + lb = lc = 1; + } else if(str[i] == '2') { + la = lb = ld = le = lg = 1; + } else if(str[i] == '3') { + la = lb = lc = ld = lg = 1; + } else if(str[i] == '4') { + lb = lc = lf = lg = 1; + } else if(str[i] == '5') { + la = lc = ld = lf = lg = 1; + } else if(str[i] == '6') { + la = lc = ld = le = lf = lg = 1; + } else if(str[i] == '7') { + la = lb = lc = 1; + } else if(str[i] == '8') { + la = lb = lc = ld = le = lf = lg = 1; + } else if(str[i] == '9') { + la = lb = lc = ld = lf = lg = 1; + } else if(str[i] == 'A' || str[i] == 'a') { + la = lb = lc = le = lf = lg = 1; + } else if(str[i] == 'B' || str[i] == 'b') { + lc = ld = le = lf = lg = 1; + } else if(str[i] == 'C' || str[i] == 'c') { + ld = le = lg = 1; + } else if(str[i] == 'D' || str[i] == 'd') { + lb = lc = ld = le = lg = 1; + } else if(str[i] == 'E' || str[i] == 'e') { + la = ld = le = lf = lg = 1; + } else if(str[i] == 'F' || str[i] == 'f') { + la = le = lf = lg = 1; + } + } + + if(la) draw_h(raw, x + ShortOne, 0, w, text); + if(lb) draw_v(raw, x + ShortOne + LongOne, ShortOne, w, text); + if(lc) draw_v(raw, x + ShortOne + LongOne, ShortOne * 2 + LongOne, w, text); + if(ld) draw_h(raw, x + ShortOne, ShortOne * 2 + LongOne * 2, w, text); + if(le) draw_v(raw, x, ShortOne * 2 + LongOne, w, text); + if(lf) draw_v(raw, x, ShortOne, w, text); + if(lg) draw_h(raw, x + ShortOne, ShortOne + LongOne, w, text); + + x += LongOne + ShortOne * 2; + } else if(str[i] == ':') { + int cy, cx; + for(cy = 1; cy < h - 1; cy++) { + int c = (LongOne - ShortOne) / 2 + ShortOne; + + int c1 = (c <= cy && cy <= (c + ShortOne)) ? 1 : 0; + int c2 = ((ShortOne + LongOne + c) <= cy && cy <= (ShortOne + LongOne + c + ShortOne)) ? 1 : 0; + + if(c1 || c2) { + for(cx = x; cx < x + ShortOne; cx++) { + unsigned char* px = &raw[(cy * w + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + } + x += ShortOne; + } else if(str[i] == ' ') { + x += ShortOne; + } else if(str[i] == '.') { + int cy, cx; + for(cy = h - (ShortOne - 1) / 2 - 1; cy < h; cy++) { + for(cx = x - Spacing - (ShortOne - 1) / 2 - 1; cx < (x - Spacing); cx++) { + unsigned char* px = &raw[(cy * w + cx) * 4]; + px[0] = text->common.red; + px[1] = text->common.green; + px[2] = text->common.blue; + px[3] = 255; + } + } + continue; + } + + x += Spacing; + } + + px = MwLoadRaw(handle, raw, w, h); + + r.y = 0; + r.height = h; + if(align == MwALIGNMENT_CENTER) { + r.x = (r.width - w) / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + r.x = 0; + } else if(align == MwALIGNMENT_END) { + r.x = r.width - w; + } + r.width = w; + MwLLDrawPixmap(handle->lowlevel, &r, px); + + MwLLDestroyPixmap(px); + } else { + if(align == MwALIGNMENT_CENTER) { + p.x = r.width / 2; + } else if(align == MwALIGNMENT_BEGINNING) { + p.x = MwTextWidth(handle, str) / 2; + } else if(align == MwALIGNMENT_END) { + p.x = r.width - MwTextWidth(handle, str) / 2; + } + p.y = r.height / 2; + MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); } - p.y = r.height / 2; - MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); MwLLFreeColor(text); MwLLFreeColor(base); } static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0) MwForceRender(handle); + if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0) MwForceRender(handle); +} + +static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) { + MwLabel lab = handle->internal; + + hmput(lab->segment, index, data); +} + +static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { + (void)out; + + if(strcmp(name, "mwLabelSetSevenSegment") == 0) { + int index = va_arg(va, int); + int data = va_arg(va, int); + + mwLabelSetSevenSegmentImpl(handle, index, data); + } } MwClassRec MwLabelClassRec = { - create, /* create */ - NULL, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ + create, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ NULL, NULL, NULL, diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 254e05beb..ff42d3aad 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -1,13 +1,7 @@ #include -typedef struct scrollbar { - MwPoint point; - int drag; - int pos; -} scrollbar_t; - static int create(MwWidget handle) { - scrollbar_t* scr = malloc(sizeof(*scr)); + MwScrollBar scr = malloc(sizeof(*scr)); handle->internal = scr; @@ -60,10 +54,10 @@ static void add_value(MwWidget handle, int mul) { } static void draw(MwWidget handle) { - MwRect r, rt, rbar; - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); - scrollbar_t* scr = handle->internal; + MwRect r, rt, rbar; + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); + MwScrollBar scr = handle->internal; int or ; int uy, dy, ux, dx; MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); @@ -144,8 +138,8 @@ static void draw(MwWidget handle) { } static void mouse_move(MwWidget handle) { - int or = MwGetInteger(handle, MwNorientation); - scrollbar_t* scr = handle->internal; + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; if(!handle->pressed) return; @@ -172,11 +166,11 @@ static void mouse_move(MwWidget handle) { } static void mouse_down(MwWidget handle, void* ptr) { - int ww = MwGetInteger(handle, MwNwidth); - int wh = MwGetInteger(handle, MwNheight); - int or = MwGetInteger(handle, MwNorientation); - scrollbar_t* scr = handle->internal; - MwLLMouse* m = ptr; + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight); + int or = MwGetInteger(handle, MwNorientation); + MwScrollBar scr = handle->internal; + MwLLMouse* m = ptr; if(m->button == MwLLMouseWheelUp) { int min = MwGetInteger(handle, MwNminValue); From 2304b493d1d8774ce79102d6909d5df4cc8acb84 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 15:17:00 +0900 Subject: [PATCH 034/409] add MwNlength --- examples/basic/sevensegment.c | 1 + include/Mw/StringDefs.h | 1 + milsko.xml | 2 + src/widget/label.c | 145 ++++++++++++++++++++-------------- 4 files changed, 90 insertions(+), 59 deletions(-) diff --git a/examples/basic/sevensegment.c b/examples/basic/sevensegment.c index 7479da9fc..08149a9fd 100644 --- a/examples/basic/sevensegment.c +++ b/examples/basic/sevensegment.c @@ -14,6 +14,7 @@ int main() { MwNtext, " 123456:78.90 abcdef", MwNsevenSegment, 1, MwNalignment, MwALIGNMENT_BEGINNING, + MwNlength, 8, NULL); MwLabelSetSevenSegment(label, 0, (1 << 0) | (1 << 3) | (1 << 6)); diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index f5b723afd..afcbedcbe 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -37,6 +37,7 @@ #define MwNmargin "Imargin" #define MwNbitmapFont "IbitmapFont" #define MwNsevenSegment "IsevenSegment" +#define MwNlength "Ilength" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/milsko.xml b/milsko.xml index 9448e30a9..5838ce400 100644 --- a/milsko.xml +++ b/milsko.xml @@ -90,6 +90,7 @@ + @@ -538,6 +539,7 @@ + diff --git a/src/widget/label.c b/src/widget/label.c index a2ae407fd..dac2060c2 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -2,9 +2,7 @@ #include "../../external/stb_ds.h" -#define ShortOne 5 -#define LongOne 10 -#define Spacing 2 +#define Spacing 1 static int create(MwWidget handle) { MwLabel lab = malloc(sizeof(*lab)); @@ -16,6 +14,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNalignment, MwALIGNMENT_CENTER); MwSetInteger(handle, MwNbold, 0); MwSetInteger(handle, MwNsevenSegment, 0); + MwSetInteger(handle, MwNlength, 4); return 0; } @@ -28,10 +27,14 @@ static void destroy(MwWidget handle) { free(handle->internal); } -static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) { +static void draw_v(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { int cy, cx, b; - for(cy = y; cy < y + LongOne; cy++) { - for(cx = x; cx < x + ShortOne; cx++) { + + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + + for(cy = y; cy < y + l_one; cy++) { + for(cx = x; cx < x + s_one; cx++) { unsigned char* px = &raw[(cy * stride + cx) * 4]; px[0] = text->common.red; px[1] = text->common.green; @@ -40,10 +43,10 @@ static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) } } - b = y - (ShortOne - 1) / 2; - for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { + b = y - (s_one - 1) / 2; + for(cy = b; cy < b + (s_one - 1) / 2; cy++) { int w = (cy - b) * 2 + 1; - int b2 = x + (ShortOne - w) / 2; + int b2 = x + (s_one - w) / 2; for(cx = b2; cx < b2 + w; cx++) { unsigned char* px; @@ -55,10 +58,10 @@ static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) } } - b = y + LongOne; - for(cy = b; cy < b + (ShortOne - 1) / 2; cy++) { - int w = ((ShortOne - 1) / 2 - 1 - (cy - b)) * 2 + 1; - int b2 = x + (ShortOne - w) / 2; + b = y + l_one; + for(cy = b; cy < b + (s_one - 1) / 2; cy++) { + int w = ((s_one - 1) / 2 - 1 - (cy - b)) * 2 + 1; + int b2 = x + (s_one - w) / 2; for(cx = b2; cx < b2 + w; cx++) { unsigned char* px; @@ -71,10 +74,14 @@ static void draw_v(unsigned char* raw, int x, int y, int stride, MwLLColor text) } } -static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) { +static void draw_h(MwWidget handle, unsigned char* raw, int x, int y, int stride, MwLLColor text) { int cy, cx, b; - for(cx = x; cx < x + LongOne; cx++) { - for(cy = y; cy < y + ShortOne; cy++) { + + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; + + for(cx = x; cx < x + l_one; cx++) { + for(cy = y; cy < y + s_one; cy++) { unsigned char* px = &raw[(cy * stride + cx) * 4]; px[0] = text->common.red; px[1] = text->common.green; @@ -83,10 +90,10 @@ static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) } } - b = x - (ShortOne - 1) / 2; - for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { + b = x - (s_one - 1) / 2; + for(cx = b; cx < b + (s_one - 1) / 2; cx++) { int w = (cx - b) * 2 + 1; - int b2 = y + (ShortOne - w) / 2; + int b2 = y + (s_one - w) / 2; for(cy = b2; cy < b2 + w; cy++) { unsigned char* px; @@ -98,10 +105,10 @@ static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) } } - b = x + LongOne; - for(cx = b; cx < b + (ShortOne - 1) / 2; cx++) { - int w = ((ShortOne - 1) / 2 - 1 - (cx - b)) * 2 + 1; - int b2 = y + (ShortOne - w) / 2; + b = x + l_one; + for(cx = b; cx < b + (s_one - 1) / 2; cx++) { + int w = ((s_one - 1) / 2 - 1 - (cx - b)) * 2 + 1; + int b2 = y + (s_one - w) / 2; for(cy = b2; cy < b2 + w; cy++) { unsigned char* px; @@ -117,12 +124,15 @@ static void draw_h(unsigned char* raw, int x, int y, int stride, MwLLColor text) static void draw(MwWidget handle) { MwRect r; MwPoint p; - MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); - MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); + MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); + MwLLColor shadow = MwLightenColor(handle, base, -32, -32, -32); int align; - const char* str = MwGetText(handle, MwNtext); - MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); - MwLabel lab = handle->internal; + const char* str = MwGetText(handle, MwNtext); + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + MwLabel lab = handle->internal; + int l_one = MwGetInteger(handle, MwNlength) - (MwGetInteger(handle, MwNlength) % 2); + int s_one = (l_one * 3 / 4) - ((l_one * 3 / 4) % 2) + 1; if(str == NULL) str = ""; @@ -138,7 +148,7 @@ static void draw(MwWidget handle) { if(MwGetInteger(handle, MwNsevenSegment)) { MwLLPixmap px; unsigned char* raw; - int w = 0, h = ShortOne * 3 + LongOne * 2, i; + int w = 0, h = s_one * 3 + l_one * 2, i; int x = 0; /* so - this mode cannot do unicode. @@ -159,18 +169,22 @@ static void draw(MwWidget handle) { for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { if(i > 0 && ((hmgeti(lab->segment, i) != -1) || str[i] != '.')) w += Spacing; if(hmgeti(lab->segment, i) != -1 || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { - w += LongOne + ShortOne * 2; + w += l_one + s_one * 2; } else if(str[i] == ':' || str[i] == ' ') { - w += ShortOne; + w += s_one; } } + w++; + h++; + raw = malloc(w * h * 4); memset(raw, 0, w * h * 4); for(i = 0; (hmgeti(lab->segment, i) != -1) || str[i] != 0; i++) { if((hmgeti(lab->segment, i) != -1) || ('0' <= str[i] && str[i] <= '9') || ('A' <= str[i] && str[i] <= 'F') || ('a' <= str[i] && str[i] <= 'f')) { int la = 0, lb = 0, lc = 0, ld = 0, le = 0, lf = 0, lg = 0; + int j; /* https://en.wikipedia.org/wiki/File:7_Segment_Display_with_Labeled_Segments.svg */ @@ -220,45 +234,57 @@ static void draw(MwWidget handle) { } } - if(la) draw_h(raw, x + ShortOne, 0, w, text); - if(lb) draw_v(raw, x + ShortOne + LongOne, ShortOne, w, text); - if(lc) draw_v(raw, x + ShortOne + LongOne, ShortOne * 2 + LongOne, w, text); - if(ld) draw_h(raw, x + ShortOne, ShortOne * 2 + LongOne * 2, w, text); - if(le) draw_v(raw, x, ShortOne * 2 + LongOne, w, text); - if(lf) draw_v(raw, x, ShortOne, w, text); - if(lg) draw_h(raw, x + ShortOne, ShortOne + LongOne, w, text); + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; - x += LongOne + ShortOne * 2; + if(la) draw_h(handle, raw, x + s_one + j, j, w, cl); + if(lb) draw_v(handle, raw, x + s_one + l_one + j, s_one + j, w, cl); + if(lc) draw_v(handle, raw, x + s_one + l_one + j, s_one * 2 + l_one + j, w, cl); + if(ld) draw_h(handle, raw, x + s_one + j, s_one * 2 + l_one * 2 + j, w, cl); + if(le) draw_v(handle, raw, x + j, s_one * 2 + l_one + j, w, cl); + if(lf) draw_v(handle, raw, x + j, s_one + j, w, cl); + if(lg) draw_h(handle, raw, x + s_one + j, s_one + l_one + j, w, cl); + } + + x += l_one + s_one * 2; } else if(str[i] == ':') { int cy, cx; - for(cy = 1; cy < h - 1; cy++) { - int c = (LongOne - ShortOne) / 2 + ShortOne; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = 1; cy < h - 1; cy++) { + int c = (l_one - s_one) / 2 + s_one; - int c1 = (c <= cy && cy <= (c + ShortOne)) ? 1 : 0; - int c2 = ((ShortOne + LongOne + c) <= cy && cy <= (ShortOne + LongOne + c + ShortOne)) ? 1 : 0; + int c1 = (c <= cy && cy <= (c + s_one)) ? 1 : 0; + int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + s_one)) ? 1 : 0; - if(c1 || c2) { - for(cx = x; cx < x + ShortOne; cx++) { - unsigned char* px = &raw[(cy * w + cx) * 4]; - px[0] = text->common.red; - px[1] = text->common.green; - px[2] = text->common.blue; - px[3] = 255; + if(c1 || c2) { + for(cx = x; cx < x + s_one; cx++) { + unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; + px[0] = cl->common.red; + px[1] = cl->common.green; + px[2] = cl->common.blue; + px[3] = 255; + } } } } - x += ShortOne; + x += s_one; } else if(str[i] == ' ') { - x += ShortOne; + x += s_one; } else if(str[i] == '.') { int cy, cx; - for(cy = h - (ShortOne - 1) / 2 - 1; cy < h; cy++) { - for(cx = x - Spacing - (ShortOne - 1) / 2 - 1; cx < (x - Spacing); cx++) { - unsigned char* px = &raw[(cy * w + cx) * 4]; - px[0] = text->common.red; - px[1] = text->common.green; - px[2] = text->common.blue; - px[3] = 255; + int j; + for(j = 1; j >= 0; j--) { + MwLLColor cl = j == 1 ? shadow : text; + for(cy = h - (s_one - 1) / 2 - 1; cy < h; cy++) { + for(cx = x - Spacing - (s_one - 1) / 2 - 1; cx < (x - Spacing); cx++) { + unsigned char* px = &raw[((cy + j) * w + (cx + j)) * 4]; + px[0] = cl->common.red; + px[1] = cl->common.green; + px[2] = cl->common.blue; + px[3] = 255; + } } } continue; @@ -294,6 +320,7 @@ static void draw(MwWidget handle) { MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); } + MwLLFreeColor(shadow); MwLLFreeColor(text); MwLLFreeColor(base); } From 188da6803e5ba8099653459c858f1aff18ea01d3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 15:33:48 +0900 Subject: [PATCH 035/409] adjust some stuff --- milsko.xml | 2 ++ src/widget/box.c | 21 ++++++++++++++------- src/widget/label.c | 2 +- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/milsko.xml b/milsko.xml index 5838ce400..f60f7c799 100644 --- a/milsko.xml +++ b/milsko.xml @@ -497,6 +497,8 @@ + + diff --git a/src/widget/box.c b/src/widget/box.c index c363e0ec8..e6966654d 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -8,6 +8,8 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNorientation, MwHORIZONTAL); MwSetInteger(handle, MwNmargin, 0); MwSetInteger(handle, MwNpadding, 0); + MwSetInteger(handle, MwNhasBorder, 0); + MwSetInteger(handle, MwNinverted, 1); return 0; } @@ -20,6 +22,11 @@ static void draw(MwWidget handle) { r.y = 0; r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); + + if(MwGetInteger(handle, MwNhasBorder)) { + MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); + } + MwDrawRect(handle, &r, base); MwLLFreeColor(base); @@ -31,9 +38,9 @@ static void layout(MwWidget handle) { int i; int sum = 0; int horiz = MwGetInteger(handle, MwNorientation) == MwHORIZONTAL ? 1 : 0; - int sz = MwGetInteger(handle, horiz ? MwNwidth : MwNheight) - MwGetInteger(handle, MwNpadding) * 2; - int fsz = MwGetInteger(handle, horiz ? MwNheight : MwNwidth) - MwGetInteger(handle, MwNpadding) * 2; - int sk = MwGetInteger(handle, MwNpadding); + int sz = MwGetInteger(handle, horiz ? MwNwidth : MwNheight) - (MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0)) * 2; + int fsz = MwGetInteger(handle, horiz ? MwNheight : MwNwidth) - (MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0)) * 2; + int sk = MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0); for(i = 0; i < arrlen(handle->children); i++) { int n = MwGetInteger(handle->children[i], MwNratio); @@ -60,10 +67,10 @@ static void layout(MwWidget handle) { } MwVaApply(handle->children[i], - horiz ? MwNx : MwNy, sk, /* this is what gets changed */ - horiz ? MwNy : MwNx, MwGetInteger(handle, MwNpadding), /* fixed between widgets */ - horiz ? MwNwidth : MwNheight, wsz, /* this is what gets changed */ - horiz ? MwNheight : MwNwidth, fsz, /* fixed between widgets */ + horiz ? MwNx : MwNy, sk, /* this is what gets changed */ + horiz ? MwNy : MwNx, MwGetInteger(handle, MwNpadding) + (MwGetInteger(handle, MwNhasBorder) ? MwDefaultBorderWidth(handle) : 0), /* fixed between widgets */ + horiz ? MwNwidth : MwNheight, wsz, /* this is what gets changed */ + horiz ? MwNheight : MwNwidth, fsz, /* fixed between widgets */ NULL); sk += wsz + Margin; } diff --git a/src/widget/label.c b/src/widget/label.c index dac2060c2..a137ca021 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -295,7 +295,7 @@ static void draw(MwWidget handle) { px = MwLoadRaw(handle, raw, w, h); - r.y = 0; + r.y = (r.height - h) / 2; r.height = h; if(align == MwALIGNMENT_CENTER) { r.x = (r.width - w) / 2; From 2b30a06ecf014a81f9a2a02994bc3613c141fba4 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 19:29:05 +0900 Subject: [PATCH 036/409] wip VMS port --- src/draw.c | 10 +- tools/gendcl.pl | 106 ++++++++++++++ vms/build.com | 382 ++++++++++++++++++++++++++++++++++++++++++++++++ vms/clean.com | 63 ++++++++ 4 files changed, 558 insertions(+), 3 deletions(-) create mode 100755 tools/gendcl.pl create mode 100644 vms/build.com create mode 100644 vms/clean.com diff --git a/src/draw.c b/src/draw.c index 24e5785aa..d1f3c7894 100644 --- a/src/draw.c +++ b/src/draw.c @@ -1,6 +1,7 @@ #include -#ifdef USE_STB_IMAGE +#ifdef NO_IMAGE +#elif defined(USE_STB_IMAGE) #include "../external/stb_image.h" #else #include @@ -502,7 +503,8 @@ void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int invert, MwLLFreeColor(darker); } -#ifndef USE_STB_IMAGE +#if defined(NO_IMAGE) +#elif !defined(USE_STB_IMAGE) static void PNGCAPI user_error(png_structp png, const char* str) { (void)str; @@ -617,7 +619,9 @@ static unsigned char* load_jpeg(FILE* f, int* w, int* h) { #endif static unsigned char* load_image(const char* path, int* w, int* h) { -#ifdef USE_STB_IMAGE +#if defined(NO_IMAGE) + return NULL; +#elif defined(USE_STB_IMAGE) int ch; return stbi_load(path, w, h, &ch, 4); diff --git a/tools/gendcl.pl b/tools/gendcl.pl new file mode 100755 index 000000000..94e4ad196 --- /dev/null +++ b/tools/gendcl.pl @@ -0,0 +1,106 @@ +#!/usr/bin/env perl + +our $clean = 0; +my @objs = (); + +sub compile { + my ($source) = @_; + my $object = ""; + my $dir = ""; + + $dir = $source; + $dir =~ s/\/([^\/]+)$//; + + $source =~ s/^(.+)\/([^\/]+)$/[\/\1]\2/; + $source =~ s/\//\./g; + + $object = $source; + $object =~ s/\.c$/.obj/; + + print(OUT "\$ if f\$search(\"$object;*\") .eqs. \"\"\n"); + print(OUT "\$ then\n"); + print(OUT "\$ write sys\$output \"CC $object\"\n"); + print(OUT +"\$ cc /include_directory=(\"./include\",\"./$dir\") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=$object $source\n" + ); + print(OUT "\$ endif\n"); + + push(@objs, $object); +} + +sub clean { + my ($source) = @_; + my $object = ""; + my $dir = ""; + + $source =~ s/^(.+)\/([^\/]+)$/[\/\1]\2/; + $source =~ s/\//\./g; + + $object = $source; + $object =~ s/\.c$/.obj/; + + print(OUT + "\$ if f\$search(\"$object\") .nes. \"\" then delete $object;*\n"); +} + +sub thing { + if ($clean) { + clean($_[0]); + } + else { + compile($_[0]); + } +} + +sub scan { + my ($dir) = @_; + + opendir(my $dh, $dir); + while (my $file = readdir($dh)) { + if ( !(($dir . "/" . $file) eq "src/widget/opengl.c") + && !(($dir . "/" . $file) eq "src/widget/vulkan.c") + && !(($dir . "/" . $file) eq "external/stb_truetype.c") + && !(($dir . "/" . $file) eq "external/stb_image.c") + && ($file =~ /\.c$/)) + { + thing($dir . "/" . $file); + } + } + closedir($dh); +} + +for (my $i = 0 ; $i < 2 ; $i++) { + $clean = $i; + + open(OUT, ">", $i == 0 ? "vms/build.com" : "vms/clean.com"); + scan("src"); + scan("src/cursor"); + scan("src/widget"); + scan("src/dialog"); + scan("src/font"); + scan("src/icon"); + scan("src/abstract"); + scan("external"); + thing("src/backend/x11.c"); + + if ($i == 0) { + print(OUT "\$ if f\$search(\"[.src]MwSHR.exe;*\") .eqs. \"\"\n"); + print(OUT "\$ then\n"); + print(OUT "\$ write sys\$output \"LINK [.src]MwSHR.exe\"\n"); + print(OUT "\$ OPEN /WRITE LINK_OPT LINK.OPT\n"); + foreach my $obj (@objs) { + print(OUT "\$ WRITE LINK_OPT \"$obj\"\n"); + } + print(OUT + "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE/SHARE\"\n"); + print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECC\$SHR/SHARE/SHARE\"\n"); + print(OUT "\$ CLOSE LINK_OPT\n"); + print(OUT "\$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options\n"); + print(OUT "\$ DELETE LINK.OPT;*\n"); + print(OUT "\$ endif\n"); + } + else { + clean("src/MwSHR.exe"); + } + close(OUT); +} diff --git a/vms/build.com b/vms/build.com new file mode 100644 index 000000000..17d48299c --- /dev/null +++ b/vms/build.com @@ -0,0 +1,382 @@ +$ if f$search("[.src]color.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]color.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]color.obj [.src]color.c +$ endif +$ if f$search("[.src]core.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]core.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]core.obj [.src]core.c +$ endif +$ if f$search("[.src]default.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]default.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]default.obj [.src]default.c +$ endif +$ if f$search("[.src]draw.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]draw.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]draw.obj [.src]draw.c +$ endif +$ if f$search("[.src]error.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]error.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]error.obj [.src]error.c +$ endif +$ if f$search("[.src]lowlevel.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]lowlevel.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]lowlevel.obj [.src]lowlevel.c +$ endif +$ if f$search("[.src]string.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]string.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]string.obj [.src]string.c +$ endif +$ if f$search("[.src]text.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]text.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]text.obj [.src]text.c +$ endif +$ if f$search("[.src]unicode.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src]unicode.obj" +$ cc /include_directory=("./include","./src") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src]unicode.obj [.src]unicode.c +$ endif +$ if f$search("[.src.cursor]arrow.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.cursor]arrow.obj" +$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]arrow.obj [.src.cursor]arrow.c +$ endif +$ if f$search("[.src.cursor]cross.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.cursor]cross.obj" +$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]cross.obj [.src.cursor]cross.c +$ endif +$ if f$search("[.src.cursor]default.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.cursor]default.obj" +$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]default.obj [.src.cursor]default.c +$ endif +$ if f$search("[.src.cursor]hidden.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.cursor]hidden.obj" +$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]hidden.obj [.src.cursor]hidden.c +$ endif +$ if f$search("[.src.cursor]text.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.cursor]text.obj" +$ cc /include_directory=("./include","./src/cursor") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.cursor]text.obj [.src.cursor]text.c +$ endif +$ if f$search("[.src.widget]button.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]button.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]button.obj [.src.widget]button.c +$ endif +$ if f$search("[.src.widget]checkbox.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]checkbox.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]checkbox.obj [.src.widget]checkbox.c +$ endif +$ if f$search("[.src.widget]combobox.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]combobox.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]combobox.obj [.src.widget]combobox.c +$ endif +$ if f$search("[.src.widget]entry.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]entry.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]entry.obj [.src.widget]entry.c +$ endif +$ if f$search("[.src.widget]frame.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]frame.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]frame.obj [.src.widget]frame.c +$ endif +$ if f$search("[.src.widget]image.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]image.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]image.obj [.src.widget]image.c +$ endif +$ if f$search("[.src.widget]label.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]label.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]label.obj [.src.widget]label.c +$ endif +$ if f$search("[.src.widget]listbox.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]listbox.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]listbox.obj [.src.widget]listbox.c +$ endif +$ if f$search("[.src.widget]menu.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]menu.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]menu.obj [.src.widget]menu.c +$ endif +$ if f$search("[.src.widget]numberentry.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]numberentry.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]numberentry.obj [.src.widget]numberentry.c +$ endif +$ if f$search("[.src.widget]progressbar.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]progressbar.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]progressbar.obj [.src.widget]progressbar.c +$ endif +$ if f$search("[.src.widget]radiobox.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]radiobox.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]radiobox.obj [.src.widget]radiobox.c +$ endif +$ if f$search("[.src.widget]scrollbar.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]scrollbar.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]scrollbar.obj [.src.widget]scrollbar.c +$ endif +$ if f$search("[.src.widget]separator.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]separator.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]separator.obj [.src.widget]separator.c +$ endif +$ if f$search("[.src.widget]submenu.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]submenu.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]submenu.obj [.src.widget]submenu.c +$ endif +$ if f$search("[.src.widget]treeview.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]treeview.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]treeview.obj [.src.widget]treeview.c +$ endif +$ if f$search("[.src.widget]viewport.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]viewport.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]viewport.obj [.src.widget]viewport.c +$ endif +$ if f$search("[.src.widget]window.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]window.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]window.obj [.src.widget]window.c +$ endif +$ if f$search("[.src.widget]box.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.widget]box.obj" +$ cc /include_directory=("./include","./src/widget") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.widget]box.obj [.src.widget]box.c +$ endif +$ if f$search("[.src.dialog]colorpicker.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.dialog]colorpicker.obj" +$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]colorpicker.obj [.src.dialog]colorpicker.c +$ endif +$ if f$search("[.src.dialog]directorychooser.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.dialog]directorychooser.obj" +$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]directorychooser.obj [.src.dialog]directorychooser.c +$ endif +$ if f$search("[.src.dialog]filechooser.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.dialog]filechooser.obj" +$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]filechooser.obj [.src.dialog]filechooser.c +$ endif +$ if f$search("[.src.dialog]messagebox.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.dialog]messagebox.obj" +$ cc /include_directory=("./include","./src/dialog") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.dialog]messagebox.obj [.src.dialog]messagebox.c +$ endif +$ if f$search("[.src.font]boldfont.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.font]boldfont.obj" +$ cc /include_directory=("./include","./src/font") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.font]boldfont.obj [.src.font]boldfont.c +$ endif +$ if f$search("[.src.font]boldttf.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.font]boldttf.obj" +$ cc /include_directory=("./include","./src/font") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.font]boldttf.obj [.src.font]boldttf.c +$ endif +$ if f$search("[.src.font]font.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.font]font.obj" +$ cc /include_directory=("./include","./src/font") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.font]font.obj [.src.font]font.c +$ endif +$ if f$search("[.src.font]ttf.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.font]ttf.obj" +$ cc /include_directory=("./include","./src/font") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.font]ttf.obj [.src.font]ttf.c +$ endif +$ if f$search("[.src.icon]back.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]back.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]back.obj [.src.icon]back.c +$ endif +$ if f$search("[.src.icon]clock.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]clock.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]clock.obj [.src.icon]clock.c +$ endif +$ if f$search("[.src.icon]computer.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]computer.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]computer.obj [.src.icon]computer.c +$ endif +$ if f$search("[.src.icon]directory.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]directory.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]directory.obj [.src.icon]directory.c +$ endif +$ if f$search("[.src.icon]down.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]down.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]down.obj [.src.icon]down.c +$ endif +$ if f$search("[.src.icon]error.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]error.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]error.obj [.src.icon]error.c +$ endif +$ if f$search("[.src.icon]file.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]file.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]file.obj [.src.icon]file.c +$ endif +$ if f$search("[.src.icon]forward.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]forward.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]forward.obj [.src.icon]forward.c +$ endif +$ if f$search("[.src.icon]info.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]info.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]info.obj [.src.icon]info.c +$ endif +$ if f$search("[.src.icon]left.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]left.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]left.obj [.src.icon]left.c +$ endif +$ if f$search("[.src.icon]news.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]news.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]news.obj [.src.icon]news.c +$ endif +$ if f$search("[.src.icon]note.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]note.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]note.obj [.src.icon]note.c +$ endif +$ if f$search("[.src.icon]right.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]right.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]right.obj [.src.icon]right.c +$ endif +$ if f$search("[.src.icon]search.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]search.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]search.obj [.src.icon]search.c +$ endif +$ if f$search("[.src.icon]up.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]up.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]up.obj [.src.icon]up.c +$ endif +$ if f$search("[.src.icon]warning.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.icon]warning.obj" +$ cc /include_directory=("./include","./src/icon") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.icon]warning.obj [.src.icon]warning.c +$ endif +$ if f$search("[.src.abstract]directory.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.abstract]directory.obj" +$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]directory.obj [.src.abstract]directory.c +$ endif +$ if f$search("[.src.abstract]dynamic.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.abstract]dynamic.obj" +$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]dynamic.obj [.src.abstract]dynamic.c +$ endif +$ if f$search("[.src.abstract]time.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.abstract]time.obj" +$ cc /include_directory=("./include","./src/abstract") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.abstract]time.obj [.src.abstract]time.c +$ endif +$ if f$search("[.external]stb_ds.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.external]stb_ds.obj" +$ cc /include_directory=("./include","./external") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.external]stb_ds.obj [.external]stb_ds.c +$ endif +$ if f$search("[.src.backend]x11.obj;*") .eqs. "" +$ then +$ write sys$output "CC [.src.backend]x11.obj" +$ cc /include_directory=("./include","./src/backend") /define=(_MILSKO,USE_X11,NO_IMAGE) /object=[.src.backend]x11.obj [.src.backend]x11.c +$ endif +$ if f$search("[.src]MwSHR.exe;*") .eqs. "" +$ then +$ write sys$output "LINK [.src]MwSHR.exe" +$ OPEN /WRITE LINK_OPT LINK.OPT +$ WRITE LINK_OPT "[.src]color.obj" +$ WRITE LINK_OPT "[.src]core.obj" +$ WRITE LINK_OPT "[.src]default.obj" +$ WRITE LINK_OPT "[.src]draw.obj" +$ WRITE LINK_OPT "[.src]error.obj" +$ WRITE LINK_OPT "[.src]lowlevel.obj" +$ WRITE LINK_OPT "[.src]string.obj" +$ WRITE LINK_OPT "[.src]text.obj" +$ WRITE LINK_OPT "[.src]unicode.obj" +$ WRITE LINK_OPT "[.src.cursor]arrow.obj" +$ WRITE LINK_OPT "[.src.cursor]cross.obj" +$ WRITE LINK_OPT "[.src.cursor]default.obj" +$ WRITE LINK_OPT "[.src.cursor]hidden.obj" +$ WRITE LINK_OPT "[.src.cursor]text.obj" +$ WRITE LINK_OPT "[.src.widget]button.obj" +$ WRITE LINK_OPT "[.src.widget]checkbox.obj" +$ WRITE LINK_OPT "[.src.widget]combobox.obj" +$ WRITE LINK_OPT "[.src.widget]entry.obj" +$ WRITE LINK_OPT "[.src.widget]frame.obj" +$ WRITE LINK_OPT "[.src.widget]image.obj" +$ WRITE LINK_OPT "[.src.widget]label.obj" +$ WRITE LINK_OPT "[.src.widget]listbox.obj" +$ WRITE LINK_OPT "[.src.widget]menu.obj" +$ WRITE LINK_OPT "[.src.widget]numberentry.obj" +$ WRITE LINK_OPT "[.src.widget]progressbar.obj" +$ WRITE LINK_OPT "[.src.widget]radiobox.obj" +$ WRITE LINK_OPT "[.src.widget]scrollbar.obj" +$ WRITE LINK_OPT "[.src.widget]separator.obj" +$ WRITE LINK_OPT "[.src.widget]submenu.obj" +$ WRITE LINK_OPT "[.src.widget]treeview.obj" +$ WRITE LINK_OPT "[.src.widget]viewport.obj" +$ WRITE LINK_OPT "[.src.widget]window.obj" +$ WRITE LINK_OPT "[.src.widget]box.obj" +$ WRITE LINK_OPT "[.src.dialog]colorpicker.obj" +$ WRITE LINK_OPT "[.src.dialog]directorychooser.obj" +$ WRITE LINK_OPT "[.src.dialog]filechooser.obj" +$ WRITE LINK_OPT "[.src.dialog]messagebox.obj" +$ WRITE LINK_OPT "[.src.font]boldfont.obj" +$ WRITE LINK_OPT "[.src.font]boldttf.obj" +$ WRITE LINK_OPT "[.src.font]font.obj" +$ WRITE LINK_OPT "[.src.font]ttf.obj" +$ WRITE LINK_OPT "[.src.icon]back.obj" +$ WRITE LINK_OPT "[.src.icon]clock.obj" +$ WRITE LINK_OPT "[.src.icon]computer.obj" +$ WRITE LINK_OPT "[.src.icon]directory.obj" +$ WRITE LINK_OPT "[.src.icon]down.obj" +$ WRITE LINK_OPT "[.src.icon]error.obj" +$ WRITE LINK_OPT "[.src.icon]file.obj" +$ WRITE LINK_OPT "[.src.icon]forward.obj" +$ WRITE LINK_OPT "[.src.icon]info.obj" +$ WRITE LINK_OPT "[.src.icon]left.obj" +$ WRITE LINK_OPT "[.src.icon]news.obj" +$ WRITE LINK_OPT "[.src.icon]note.obj" +$ WRITE LINK_OPT "[.src.icon]right.obj" +$ WRITE LINK_OPT "[.src.icon]search.obj" +$ WRITE LINK_OPT "[.src.icon]up.obj" +$ WRITE LINK_OPT "[.src.icon]warning.obj" +$ WRITE LINK_OPT "[.src.abstract]directory.obj" +$ WRITE LINK_OPT "[.src.abstract]dynamic.obj" +$ WRITE LINK_OPT "[.src.abstract]time.obj" +$ WRITE LINK_OPT "[.external]stb_ds.obj" +$ WRITE LINK_OPT "[.src.backend]x11.obj" +$ WRITE LINK_OPT "SYS$LIBRARY:DECW$XLIBSHR/SHARE/SHARE" +$ WRITE LINK_OPT "SYS$LIBRARY:DECC$SHR/SHARE/SHARE" +$ CLOSE LINK_OPT +$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options +$ DELETE LINK.OPT;* +$ endif diff --git a/vms/clean.com b/vms/clean.com new file mode 100644 index 000000000..e0900f2e0 --- /dev/null +++ b/vms/clean.com @@ -0,0 +1,63 @@ +$ if f$search("[.src]color.obj") .nes. "" then delete [.src]color.obj;* +$ if f$search("[.src]core.obj") .nes. "" then delete [.src]core.obj;* +$ if f$search("[.src]default.obj") .nes. "" then delete [.src]default.obj;* +$ if f$search("[.src]draw.obj") .nes. "" then delete [.src]draw.obj;* +$ if f$search("[.src]error.obj") .nes. "" then delete [.src]error.obj;* +$ if f$search("[.src]lowlevel.obj") .nes. "" then delete [.src]lowlevel.obj;* +$ if f$search("[.src]string.obj") .nes. "" then delete [.src]string.obj;* +$ if f$search("[.src]text.obj") .nes. "" then delete [.src]text.obj;* +$ if f$search("[.src]unicode.obj") .nes. "" then delete [.src]unicode.obj;* +$ if f$search("[.src.cursor]arrow.obj") .nes. "" then delete [.src.cursor]arrow.obj;* +$ if f$search("[.src.cursor]cross.obj") .nes. "" then delete [.src.cursor]cross.obj;* +$ if f$search("[.src.cursor]default.obj") .nes. "" then delete [.src.cursor]default.obj;* +$ if f$search("[.src.cursor]hidden.obj") .nes. "" then delete [.src.cursor]hidden.obj;* +$ if f$search("[.src.cursor]text.obj") .nes. "" then delete [.src.cursor]text.obj;* +$ if f$search("[.src.widget]button.obj") .nes. "" then delete [.src.widget]button.obj;* +$ if f$search("[.src.widget]checkbox.obj") .nes. "" then delete [.src.widget]checkbox.obj;* +$ if f$search("[.src.widget]combobox.obj") .nes. "" then delete [.src.widget]combobox.obj;* +$ if f$search("[.src.widget]entry.obj") .nes. "" then delete [.src.widget]entry.obj;* +$ if f$search("[.src.widget]frame.obj") .nes. "" then delete [.src.widget]frame.obj;* +$ if f$search("[.src.widget]image.obj") .nes. "" then delete [.src.widget]image.obj;* +$ if f$search("[.src.widget]label.obj") .nes. "" then delete [.src.widget]label.obj;* +$ if f$search("[.src.widget]listbox.obj") .nes. "" then delete [.src.widget]listbox.obj;* +$ if f$search("[.src.widget]menu.obj") .nes. "" then delete [.src.widget]menu.obj;* +$ if f$search("[.src.widget]numberentry.obj") .nes. "" then delete [.src.widget]numberentry.obj;* +$ if f$search("[.src.widget]progressbar.obj") .nes. "" then delete [.src.widget]progressbar.obj;* +$ if f$search("[.src.widget]radiobox.obj") .nes. "" then delete [.src.widget]radiobox.obj;* +$ if f$search("[.src.widget]scrollbar.obj") .nes. "" then delete [.src.widget]scrollbar.obj;* +$ if f$search("[.src.widget]separator.obj") .nes. "" then delete [.src.widget]separator.obj;* +$ if f$search("[.src.widget]submenu.obj") .nes. "" then delete [.src.widget]submenu.obj;* +$ if f$search("[.src.widget]treeview.obj") .nes. "" then delete [.src.widget]treeview.obj;* +$ if f$search("[.src.widget]viewport.obj") .nes. "" then delete [.src.widget]viewport.obj;* +$ if f$search("[.src.widget]window.obj") .nes. "" then delete [.src.widget]window.obj;* +$ if f$search("[.src.widget]box.obj") .nes. "" then delete [.src.widget]box.obj;* +$ if f$search("[.src.dialog]colorpicker.obj") .nes. "" then delete [.src.dialog]colorpicker.obj;* +$ if f$search("[.src.dialog]directorychooser.obj") .nes. "" then delete [.src.dialog]directorychooser.obj;* +$ if f$search("[.src.dialog]filechooser.obj") .nes. "" then delete [.src.dialog]filechooser.obj;* +$ if f$search("[.src.dialog]messagebox.obj") .nes. "" then delete [.src.dialog]messagebox.obj;* +$ if f$search("[.src.font]boldfont.obj") .nes. "" then delete [.src.font]boldfont.obj;* +$ if f$search("[.src.font]boldttf.obj") .nes. "" then delete [.src.font]boldttf.obj;* +$ if f$search("[.src.font]font.obj") .nes. "" then delete [.src.font]font.obj;* +$ if f$search("[.src.font]ttf.obj") .nes. "" then delete [.src.font]ttf.obj;* +$ if f$search("[.src.icon]back.obj") .nes. "" then delete [.src.icon]back.obj;* +$ if f$search("[.src.icon]clock.obj") .nes. "" then delete [.src.icon]clock.obj;* +$ if f$search("[.src.icon]computer.obj") .nes. "" then delete [.src.icon]computer.obj;* +$ if f$search("[.src.icon]directory.obj") .nes. "" then delete [.src.icon]directory.obj;* +$ if f$search("[.src.icon]down.obj") .nes. "" then delete [.src.icon]down.obj;* +$ if f$search("[.src.icon]error.obj") .nes. "" then delete [.src.icon]error.obj;* +$ if f$search("[.src.icon]file.obj") .nes. "" then delete [.src.icon]file.obj;* +$ if f$search("[.src.icon]forward.obj") .nes. "" then delete [.src.icon]forward.obj;* +$ if f$search("[.src.icon]info.obj") .nes. "" then delete [.src.icon]info.obj;* +$ if f$search("[.src.icon]left.obj") .nes. "" then delete [.src.icon]left.obj;* +$ if f$search("[.src.icon]news.obj") .nes. "" then delete [.src.icon]news.obj;* +$ if f$search("[.src.icon]note.obj") .nes. "" then delete [.src.icon]note.obj;* +$ if f$search("[.src.icon]right.obj") .nes. "" then delete [.src.icon]right.obj;* +$ if f$search("[.src.icon]search.obj") .nes. "" then delete [.src.icon]search.obj;* +$ if f$search("[.src.icon]up.obj") .nes. "" then delete [.src.icon]up.obj;* +$ if f$search("[.src.icon]warning.obj") .nes. "" then delete [.src.icon]warning.obj;* +$ if f$search("[.src.abstract]directory.obj") .nes. "" then delete [.src.abstract]directory.obj;* +$ if f$search("[.src.abstract]dynamic.obj") .nes. "" then delete [.src.abstract]dynamic.obj;* +$ if f$search("[.src.abstract]time.obj") .nes. "" then delete [.src.abstract]time.obj;* +$ if f$search("[.external]stb_ds.obj") .nes. "" then delete [.external]stb_ds.obj;* +$ if f$search("[.src.backend]x11.obj") .nes. "" then delete [.src.backend]x11.obj;* +$ if f$search("[.src]MwSHR.exe") .nes. "" then delete [.src]MwSHR.exe;* From 0d281c09ced81a4510d181e29314081ae83237e2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 20:25:57 +0900 Subject: [PATCH 037/409] i will work on vms port at some point --- tools/gendcl.pl | 4 ++-- vms/build.com | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/gendcl.pl b/tools/gendcl.pl index 94e4ad196..be81d9cc1 100755 --- a/tools/gendcl.pl +++ b/tools/gendcl.pl @@ -92,8 +92,8 @@ for (my $i = 0 ; $i < 2 ; $i++) { print(OUT "\$ WRITE LINK_OPT \"$obj\"\n"); } print(OUT - "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE/SHARE\"\n"); - print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECC\$SHR/SHARE/SHARE\"\n"); + "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE\"\n"); + print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DPML\$SHR/SHARE\"\n"); print(OUT "\$ CLOSE LINK_OPT\n"); print(OUT "\$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options\n"); print(OUT "\$ DELETE LINK.OPT;*\n"); diff --git a/vms/build.com b/vms/build.com index 17d48299c..dc8f9e257 100644 --- a/vms/build.com +++ b/vms/build.com @@ -375,7 +375,7 @@ $ WRITE LINK_OPT "[.src.abstract]time.obj" $ WRITE LINK_OPT "[.external]stb_ds.obj" $ WRITE LINK_OPT "[.src.backend]x11.obj" $ WRITE LINK_OPT "SYS$LIBRARY:DECW$XLIBSHR/SHARE/SHARE" -$ WRITE LINK_OPT "SYS$LIBRARY:DECC$SHR/SHARE/SHARE" +$ WRITE LINK_OPT "SYS$LIBRARY:DPML$SHR/SHARE/SHARE" $ CLOSE LINK_OPT $ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options $ DELETE LINK.OPT;* From e44eaa2c16eb08622539f27f2a8a78e077894adc Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 22:02:33 +0900 Subject: [PATCH 038/409] fix --- src/widget/submenu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index ea51f029b..587b335c6 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -133,7 +133,7 @@ static void click(MwWidget handle) { MwSubMenuAppear(menu->sub[i]->wsub, menu->sub[i], &p, 0); i = -1; } else if(menu->sub[i]->wsub != NULL && arrlen(menu->sub[i]->sub) > 0) { - while(w->parent->widget_class != MwMenuClass) w = w->parent; + while(w->parent->widget_class == MwSubMenuClass) w = w->parent; MwDestroyWidget(menu->sub[i]->wsub); menu->sub[i]->wsub = NULL; @@ -142,7 +142,7 @@ static void click(MwWidget handle) { MwForceRender(handle); } else if(strcmp(menu->sub[i]->name, "----") != 0 && arrlen(menu->sub[i]->sub) == 0) { - while(w->parent->widget_class != MwMenuClass) w = w->parent; + while(w->parent->widget_class == MwSubMenuClass) w = w->parent; MwGetBeforeStep(w, &jmp); MwDestroyWidget(w); From 873c75b882155b94441e0fe710e207c0b1729237 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 22:21:10 +0900 Subject: [PATCH 039/409] fix --- src/widget/submenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 587b335c6..d22c3c233 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -184,7 +184,7 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in h += 3; if(diff_calc) { - p.y = rc.height - p.y - h; + p.y = p.y - h; } MwLLMakeToolWindow(handle->lowlevel); From bdc67d6369700547ec8cd43996dd5c619f0e445c Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 23:02:02 +0900 Subject: [PATCH 040/409] text shadow --- include/Mw/Default.h | 5 +++++ src/default.c | 2 ++ src/widget/label.c | 9 ++++++++- tools/gendcl.pl | 3 +-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/include/Mw/Default.h b/include/Mw/Default.h index 93f919a5d..3d197d011 100644 --- a/include/Mw/Default.h +++ b/include/Mw/Default.h @@ -52,6 +52,11 @@ MWDECL const char* MwDefaultDarkSubBackground; */ MWDECL const char* MwDefaultDarkSubForeground; +/*! + * @brief Default shadow difference + */ +MWDECL const int MwDefaultShadow; + /*! * @brief Gets default border width * @param handle Widget diff --git a/src/default.c b/src/default.c index 4a7d52c73..36537a183 100644 --- a/src/default.c +++ b/src/default.c @@ -10,6 +10,8 @@ const char* MwDefaultDarkForeground = "#ddd"; const char* MwDefaultDarkSubBackground = "#333"; const char* MwDefaultDarkSubForeground = "#ddd"; +const int MwDefaultShadow = -32; + int MwDefaultBorderWidth(MwWidget handle) { int bw = MwGetInteger(handle, MwNborderWidth); diff --git a/src/widget/label.c b/src/widget/label.c index a137ca021..86aefe865 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -126,7 +126,7 @@ static void draw(MwWidget handle) { MwPoint p; MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor text = MwParseColor(handle, MwGetText(handle, MwNforeground)); - MwLLColor shadow = MwLightenColor(handle, base, -32, -32, -32); + MwLLColor shadow = MwLightenColor(handle, base, MwDefaultShadow, MwDefaultShadow, MwDefaultShadow); int align; const char* str = MwGetText(handle, MwNtext); MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); @@ -317,6 +317,13 @@ static void draw(MwWidget handle) { p.x = r.width - MwTextWidth(handle, str) / 2; } p.y = r.height / 2; + + p.x += 1; + p.y += 1; + MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, shadow); + + p.x -= 1; + p.y -= 1; MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, text); } diff --git a/tools/gendcl.pl b/tools/gendcl.pl index be81d9cc1..f2e3399c3 100755 --- a/tools/gendcl.pl +++ b/tools/gendcl.pl @@ -91,8 +91,7 @@ for (my $i = 0 ; $i < 2 ; $i++) { foreach my $obj (@objs) { print(OUT "\$ WRITE LINK_OPT \"$obj\"\n"); } - print(OUT - "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE\"\n"); + print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DECW\$XLIBSHR/SHARE\"\n"); print(OUT "\$ WRITE LINK_OPT \"SYS\$LIBRARY:DPML\$SHR/SHARE\"\n"); print(OUT "\$ CLOSE LINK_OPT\n"); print(OUT "\$ link /SHAREABLE=[.src]MwSHR.exe LINK.OPT/options\n"); From c7c8f236b048deb30987356805c9a0f560cb2383 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 23:03:33 +0900 Subject: [PATCH 041/409] yes --- include/Mw/StringDefs.h | 1 + milsko.xml | 2 ++ src/draw.c | 3 +++ 3 files changed, 6 insertions(+) diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index afcbedcbe..6588be2da 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -38,6 +38,7 @@ #define MwNbitmapFont "IbitmapFont" #define MwNsevenSegment "IsevenSegment" #define MwNlength "Ilength" +#define MwNforceInverted "IforceInverted" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/milsko.xml b/milsko.xml index f60f7c799..756e4f144 100644 --- a/milsko.xml +++ b/milsko.xml @@ -52,6 +52,7 @@ - MwNratio - MwNfixedSize - MwNbitmapFont + - MwNforceInverted Integer properties must be prefixed with I. String properties must be prefixed with S. @@ -91,6 +92,7 @@ + diff --git a/src/draw.c b/src/draw.c index d1f3c7894..4286d6696 100644 --- a/src/draw.c +++ b/src/draw.c @@ -131,6 +131,9 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { } void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { + int inv; + + if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1; if(MwGetInteger(handle, MwNmodernLook)) { MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0); } else { From a824b4fc441f645124a10a2a3a7f277e5ea54d47 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 23:04:53 +0900 Subject: [PATCH 042/409] oops --- src/widget/button.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widget/button.c b/src/widget/button.c index 7e5b36cdb..8db12c3a8 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -29,7 +29,9 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); if(MwGetInteger(handle, MwNflat)) { - if(handle->pressed) { + int inv; + + if(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv)) { MwDrawWidgetBack(handle, &r, base, handle->pressed, 1); } else { MwDrawRect(handle, &r, base); From e9fd2705d4c34a3c42b0307d718b915a881633b6 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 21 Dec 2025 23:05:42 +0900 Subject: [PATCH 043/409] fix --- src/widget/button.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/widget/button.c b/src/widget/button.c index 8db12c3a8..885ff9d49 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -20,6 +20,7 @@ static void draw(MwWidget handle) { const char* str = MwGetText(handle, MwNtext); MwLLPixmap px = MwGetVoid(handle, MwNpixmap); MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + int inv; if(str == NULL) str = ""; @@ -29,8 +30,6 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); if(MwGetInteger(handle, MwNflat)) { - int inv; - if(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv)) { MwDrawWidgetBack(handle, &r, base, handle->pressed, 1); } else { @@ -40,7 +39,7 @@ static void draw(MwWidget handle) { MwDrawWidgetBack(handle, &r, base, handle->pressed, 1); } if(bgpx != NULL) MwLLDrawPixmap(handle->lowlevel, &r, bgpx); - if(MwGetInteger(handle, MwNflat) && !handle->pressed) { + if(MwGetInteger(handle, MwNflat) && !(handle->pressed || ((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv))) { r.x += MwDefaultBorderWidth(handle); r.y += MwDefaultBorderWidth(handle); r.width -= MwDefaultBorderWidth(handle) * 2; From df99e66d878c5e763fdda5e609b87eaf8e98c44f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 23 Dec 2025 18:10:50 +0900 Subject: [PATCH 044/409] tiny fix --- src/widget/submenu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index d22c3c233..7c23c819e 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -66,7 +66,7 @@ static void draw(MwWidget handle) { if(menu->sub[i]->wsub != NULL) { r.x = 0; r.y = p.y - 3; - r.width = tw + 15 + 5 * 2; + r.width = MwGetInteger(handle, MwNwidth); r.height = th + 3 * 2; MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); } @@ -79,7 +79,7 @@ static void draw(MwWidget handle) { if(arrlen(menu->sub[i]->sub) > 0) { MwRect tr; - tr.x = p.x + tw / 2 + 5; + tr.x = MwGetInteger(handle, MwNwidth) - MwDefaultBorderWidth(handle) - 11 - 2; tr.y = p.y - th / 2 + 2; tr.width = tr.height = 11; From a23016bc051ea056589add8a6efb96172fcff21a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 23 Dec 2025 18:14:00 +0900 Subject: [PATCH 045/409] yes --- src/widget/submenu.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 7c23c819e..463d207d1 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -126,7 +126,7 @@ static void click(MwWidget handle) { menu->sub[j]->wsub = NULL; } - p.x = rc.x + rc.width + 3; + p.x = MwGetInteger(handle, MwNwidth); p.y = rc.y - 3; menu->sub[i]->wsub = MwCreateWidget(MwSubMenuClass, "submenu", handle, 0, 0, 0, 0); @@ -183,6 +183,8 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in w += 10 + 15; h += 3; + if(w < 150) w = 150; + if(diff_calc) { p.y = p.y - h; } From 55f82e4fbc5ade9ce7d35d3e6a4a7636172a0a3c Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 23 Dec 2025 22:08:49 +0900 Subject: [PATCH 046/409] update --- include/Mw/TypeDefs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 2a6efc715..79f459e4a 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -108,6 +108,7 @@ struct _MwMenu { int keep; MwWidget wsub; MwMenu* sub; + void* user; }; struct _MwEntry { From 9ea54b4f8832c8bf7171b5b70dfefbf2989e76b7 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 23 Dec 2025 22:08:55 +0900 Subject: [PATCH 047/409] format --- include/Mw/TypeDefs.h | 2 +- src/widget/submenu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 79f459e4a..d1469b884 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -108,7 +108,7 @@ struct _MwMenu { int keep; MwWidget wsub; MwMenu* sub; - void* user; + void* user; }; struct _MwEntry { diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 463d207d1..649281132 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -66,7 +66,7 @@ static void draw(MwWidget handle) { if(menu->sub[i]->wsub != NULL) { r.x = 0; r.y = p.y - 3; - r.width = MwGetInteger(handle, MwNwidth); + r.width = MwGetInteger(handle, MwNwidth); r.height = th + 3 * 2; MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); } From c8e7f582302eff67224804e0d3b312dcf9fd5122 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 23 Dec 2025 22:11:22 +0900 Subject: [PATCH 048/409] wrong --- include/Mw/TypeDefs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index d1469b884..3275096f1 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -108,7 +108,7 @@ struct _MwMenu { int keep; MwWidget wsub; MwMenu* sub; - void* user; + void* opaque; }; struct _MwEntry { From 7b4752428623f7317411a6ff18eccc8508a16b90 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 24 Dec 2025 13:56:08 +0900 Subject: [PATCH 049/409] improve submenu --- src/widget/submenu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 649281132..9eb6f7808 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -116,7 +116,7 @@ static void click(MwWidget handle) { int th = MwTextHeight(handle, menu->sub[i]->name); rc.height = th; - if(rc.x <= handle->mouse_point.x && rc.y <= handle->mouse_point.y && handle->mouse_point.x <= (int)(rc.x + rc.width) && handle->mouse_point.y <= (int)(rc.y + rc.height)) { + if(rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) { MwPoint p; int j; @@ -183,7 +183,7 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in w += 10 + 15; h += 3; - if(w < 150) w = 150; + w += 32; if(diff_calc) { p.y = p.y - h; From 86effbdfd71911b142cb12d272496b54aba62cb7 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 24 Dec 2025 22:52:26 +0900 Subject: [PATCH 050/409] fix --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d9aeed73..ca3c76509 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,7 +195,6 @@ target_compile_definitions( _MILSKO ) -include(GNUInstallDirs) install( TARGETS Mw RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} From 509351a0a0339cd61bef14c303b55e68dd974fa8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 00:19:27 +0900 Subject: [PATCH 051/409] fix submenu --- src/widget/submenu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 9eb6f7808..a83f7b6df 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -116,6 +116,10 @@ static void click(MwWidget handle) { int th = MwTextHeight(handle, menu->sub[i]->name); rc.height = th; + if(strcmp(menu->sub[i]->name, "----") == 0) { + rc.height = MwDefaultBorderWidth(handle) * 2 - 1; + } + if(rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) { MwPoint p; From 22b4737c3367810632a19281fd56e3182fe4e41f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 02:27:41 +0900 Subject: [PATCH 052/409] better separator --- src/widget/submenu.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index a83f7b6df..a265dee18 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -54,11 +54,11 @@ static void draw(MwWidget handle) { rc.x = MwDefaultBorderWidth(handle) * 2; rc.y = p.y; rc.width = r.width - (rc.x * 2); - rc.height = MwDefaultBorderWidth(handle) * 2; + rc.height = 2; - MwDrawFrame(handle, &rc, base, 1); + MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0); - p.y += MwDefaultBorderWidth(handle) * 2 + 1; + p.y += 2 + 1; } else { int tw = MwTextWidth(handle, menu->sub[i]->name); int th = MwTextHeight(handle, menu->sub[i]->name); @@ -117,7 +117,7 @@ static void click(MwWidget handle) { rc.height = th; if(strcmp(menu->sub[i]->name, "----") == 0) { - rc.height = MwDefaultBorderWidth(handle) * 2 - 1; + rc.height = 2 - 1; } if(rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { From e77c4f3c38c53d247d42c98192cd411eca60f6f0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 03:56:04 +0900 Subject: [PATCH 053/409] add MwNleftPadding to SubMenu --- milsko.xml | 3 +++ src/widget/submenu.c | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/milsko.xml b/milsko.xml index 756e4f144..82b5b6b95 100644 --- a/milsko.xml +++ b/milsko.xml @@ -640,6 +640,9 @@ + + + diff --git a/src/widget/submenu.c b/src/widget/submenu.c index a265dee18..7a23ba5f2 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -6,6 +6,7 @@ static int create(MwWidget handle) { MwLLBeginStateChange(handle->lowlevel); MwSetDefault(handle); + MwSetInteger(handle, MwNleftPadding, 16); return 0; } @@ -53,9 +54,11 @@ static void draw(MwWidget handle) { rc.x = MwDefaultBorderWidth(handle) * 2; rc.y = p.y; - rc.width = r.width - (rc.x * 2); + rc.width = r.width - (rc.x * 2) - MwGetInteger(handle, MwNleftPadding); rc.height = 2; + rc.x += MwGetInteger(handle, MwNleftPadding); + MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0); p.y += 2 + 1; @@ -71,7 +74,7 @@ static void draw(MwWidget handle) { MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); } - p.x = 5 + tw / 2; + p.x = 5 + tw / 2 + MwGetInteger(handle, MwNleftPadding); p.y += th / 2; MwDrawText(handle, &p, menu->sub[i]->name, menu->sub[i]->wsub != NULL ? 1 : 0, MwALIGNMENT_CENTER, text); @@ -120,7 +123,7 @@ static void click(MwWidget handle) { rc.height = 2 - 1; } - if(rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { + if(MwGetInteger(handle, MwNleftPadding) <= handle->mouse_point.x && rc.y <= handle->mouse_point.y && handle->mouse_point.y <= (int)(rc.y + rc.height)) { if(menu->sub[i]->wsub == NULL && arrlen(menu->sub[i]->sub) > 0) { MwPoint p; int j; @@ -184,6 +187,8 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in } } + w += MwGetInteger(handle, MwNleftPadding); + w += 10 + 15; h += 3; From d3a7b0a01d3e40c5627fed61cc7ab24d2e74906e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 04:03:05 +0900 Subject: [PATCH 054/409] oops --- src/widget/submenu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 7a23ba5f2..1f499b172 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -6,7 +6,7 @@ static int create(MwWidget handle) { MwLLBeginStateChange(handle->lowlevel); MwSetDefault(handle); - MwSetInteger(handle, MwNleftPadding, 16); + MwSetInteger(handle, MwNleftPadding, 0); return 0; } From c80987ffe41251d206df66b50411f27f7a36027e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 04:18:12 +0900 Subject: [PATCH 055/409] better --- include/Mw/Widget/SubMenu.h | 10 ++++++ src/widget/submenu.c | 64 ++++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 26 deletions(-) diff --git a/include/Mw/Widget/SubMenu.h b/include/Mw/Widget/SubMenu.h index 126a73bbb..636f29bc4 100644 --- a/include/Mw/Widget/SubMenu.h +++ b/include/Mw/Widget/SubMenu.h @@ -29,6 +29,16 @@ MwInline void MwSubMenuAppear(MwWidget handle, MwMenu menu, MwPoint* point, int MwVaWidgetExecute(handle, "mwSubMenuAppear", NULL, menu, point, diff_calc); } +/*! + * @brief Calculates the size of submenu + * @param handle Handle + * @param menu Menu + * @param rect Size + */ +MwInline void MwSubMenuGetSize(MwWidget handle, MwMenu menu, MwRect* rect) { + MwVaWidgetExecute(handle, "mwSubMenuGetSize", NULL, menu, rect); +} + #ifdef __cplusplus } #endif diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 1f499b172..c9e2e37ba 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -167,53 +167,61 @@ static void click(MwWidget handle) { } static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, int diff_calc) { - int i, w = 0, h = 0; - MwRect rc; + MwRect rc, sz; MwPoint p = *point; + MwSubMenuGetSize(handle, menu, &sz); + MwGetScreenSize(handle, &rc); handle->internal = menu; - for(i = 0; i < arrlen(menu->sub); i++) { - if(strcmp(menu->sub[i]->name, "----") == 0) { - h += MwDefaultBorderWidth(handle) * 2 + 2; - } else { - int tw = MwTextWidth(handle, menu->sub[i]->name); - h += MwTextHeight(handle, menu->sub[i]->name) + 3; - if(tw > w) { - w = tw; - } - } - } - - w += MwGetInteger(handle, MwNleftPadding); - - w += 10 + 15; - h += 3; - - w += 32; - if(diff_calc) { - p.y = p.y - h; + p.y = p.y - sz.height; } MwLLMakeToolWindow(handle->lowlevel); MwLLDetach(handle->lowlevel, &p); - if(MwGetInteger(handle, MwNy) + h > rc.height) { + if(MwGetInteger(handle, MwNy) + sz.height > rc.height) { MwVaApply(handle, - MwNy, rc.height - h, + MwNy, rc.height - sz.height, NULL); } MwLLEndStateChange(handle->lowlevel); MwVaApply(handle, - MwNwidth, w, - MwNheight, h, + MwNwidth, sz.width, + MwNheight, sz.height, NULL); } +static void mwSubMenuGetSizeImpl(MwWidget handle, MwMenu menu, MwRect* rect) { + int i; + + rect->width = 0; + rect->height = 0; + + for(i = 0; i < arrlen(menu->sub); i++) { + if(strcmp(menu->sub[i]->name, "----") == 0) { + rect->height += 2 + 2; + } else { + int tw = MwTextWidth(handle, menu->sub[i]->name); + rect->height += MwTextHeight(handle, menu->sub[i]->name) + 3; + if(tw > rect->width) { + rect->width = tw; + } + } + } + + rect->width += MwGetInteger(handle, MwNleftPadding); + + rect->width += 10 + 15; + rect->height += 3; + + rect->width += 16; +} + static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { (void)out; @@ -222,6 +230,10 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v MwPoint* point = va_arg(va, MwPoint*); int diff_calc = va_arg(va, int); mwSubMenuAppearImpl(handle, menu, point, diff_calc); + } else if(strcmp(name, "mwSubMenuGetSize") == 0) { + MwMenu menu = va_arg(va, MwMenu); + MwRect* rect = va_arg(va, MwRect*); + mwSubMenuGetSizeImpl(handle, menu, rect); } } From 0d79141a49009b69904f16f33317385905f14729 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 04:21:33 +0900 Subject: [PATCH 056/409] tiny fix --- src/widget/submenu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widget/submenu.c b/src/widget/submenu.c index c9e2e37ba..6b97934cb 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -67,9 +67,9 @@ static void draw(MwWidget handle) { int th = MwTextHeight(handle, menu->sub[i]->name); if(menu->sub[i]->wsub != NULL) { - r.x = 0; + r.x = MwGetInteger(handle, MwNleftPadding); r.y = p.y - 3; - r.width = MwGetInteger(handle, MwNwidth); + r.width = MwGetInteger(handle, MwNwidth) - MwGetInteger(handle, MwNleftPadding); r.height = th + 3 * 2; MwDrawWidgetBack(handle, &r, base, 0, MwTRUE); } From e895e9694187c11fd907e4b1786404a2032c9705 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 25 Dec 2025 15:39:54 +0900 Subject: [PATCH 057/409] introduce MwNleftPadding to label --- milsko.xml | 1 + src/widget/label.c | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/milsko.xml b/milsko.xml index 82b5b6b95..f7dcf2c78 100644 --- a/milsko.xml +++ b/milsko.xml @@ -544,6 +544,7 @@ + diff --git a/src/widget/label.c b/src/widget/label.c index 86aefe865..f85fb5d87 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -15,6 +15,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNbold, 0); MwSetInteger(handle, MwNsevenSegment, 0); MwSetInteger(handle, MwNlength, 4); + MwSetInteger(handle, MwNleftPadding, 0); return 0; } @@ -309,6 +310,8 @@ static void draw(MwWidget handle) { MwLLDestroyPixmap(px); } else { + r.width -= MwGetInteger(handle, MwNleftPadding); + if(align == MwALIGNMENT_CENTER) { p.x = r.width / 2; } else if(align == MwALIGNMENT_BEGINNING) { @@ -318,6 +321,8 @@ static void draw(MwWidget handle) { } p.y = r.height / 2; + p.x += MwGetInteger(handle, MwNleftPadding); + p.x += 1; p.y += 1; MwDrawText(handle, &p, str, MwGetInteger(handle, MwNbold), MwALIGNMENT_CENTER, shadow); @@ -333,7 +338,7 @@ static void draw(MwWidget handle) { } static void prop_change(MwWidget handle, const char* key) { - if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0) MwForceRender(handle); + if(strcmp(key, MwNtext) == 0 || strcmp(key, MwNalignment) == 0 || strcmp(key, MwNsevenSegment) == 0 || strcmp(key, MwNlength) == 0 || strcmp(key, MwNleftPadding) == 0) MwForceRender(handle); } static void mwLabelSetSevenSegmentImpl(MwWidget handle, int index, unsigned char data) { From 0ca7f6ed8ad626ca0d73340ff49488b8d0ac7ff7 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 28 Dec 2025 17:41:11 +0900 Subject: [PATCH 058/409] dispatch children_update --- src/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core.c b/src/core.c index cde8b0d72..bd46f9fae 100644 --- a/src/core.c +++ b/src/core.c @@ -261,6 +261,8 @@ void MwDestroyWidget(MwWidget handle) { if(i == arrlen(handle->parent->destroy_queue)) { arrput(handle->parent->destroy_queue, handle); } + + MwDispatch(handle->parent, children_update); } destroy_children(handle); handle->destroyed = 1; From 0daa527b1da73526e54bd2f106f5485ddbac40a9 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 28 Dec 2025 18:03:37 +0900 Subject: [PATCH 059/409] fix --- src/widget/box.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/widget/box.c b/src/widget/box.c index e6966654d..3bf7528ef 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -47,6 +47,8 @@ static void layout(MwWidget handle) { int s = MwGetInteger(handle->children[i], MwNfixedSize); if(n == MwDEFAULT) n = 1; + if(handle->children[i]->destroyed) continue; + if(s != MwDEFAULT) { sz -= s + Margin; } else { @@ -60,6 +62,8 @@ static void layout(MwWidget handle) { int wsz; if(n == MwDEFAULT) n = 1; + if(handle->children[i]->destroyed) continue; + if(s != MwDEFAULT) { wsz = s; } else { From 549d23589398b65ec40f802b051ea3476a953747 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 28 Dec 2025 21:56:45 +0900 Subject: [PATCH 060/409] better --- src/widget/label.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/widget/label.c b/src/widget/label.c index f85fb5d87..792d00918 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -254,10 +254,11 @@ static void draw(MwWidget handle) { for(j = 1; j >= 0; j--) { MwLLColor cl = j == 1 ? shadow : text; for(cy = 1; cy < h - 1; cy++) { - int c = (l_one - s_one) / 2 + s_one; + int h = s_one / 2; + int c = (l_one - h) / 2 + s_one; - int c1 = (c <= cy && cy <= (c + s_one)) ? 1 : 0; - int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + s_one)) ? 1 : 0; + int c1 = (c <= cy && cy <= (c + h)) ? 1 : 0; + int c2 = ((s_one + l_one + c) <= cy && cy <= (s_one + l_one + c + h)) ? 1 : 0; if(c1 || c2) { for(cx = x; cx < x + s_one; cx++) { From 3f9125d1aebae177d6ec7340e036c4f7ade63569 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 30 Dec 2025 23:54:30 +0900 Subject: [PATCH 061/409] fix --- src/core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core.c b/src/core.c index bd46f9fae..656699024 100644 --- a/src/core.c +++ b/src/core.c @@ -387,6 +387,9 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { MwDispatch3(handle, prop_change, key); if(handle->parent != NULL) MwDispatch4(handle->parent, children_prop_change, handle, key); } + if(strcmp(key, MwNforceInverted) == 0) { + MwForceRender(handle); + } } void MwSetText(MwWidget handle, const char* key, const char* value) { From 823c8657911fc62cf1cc7a468afdfbfe76f8bc59 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 31 Dec 2025 00:48:44 +0900 Subject: [PATCH 062/409] handle WM_DELETE_WINDOW better --- include/Mw/LowLevel/X11.h | 1 + src/backend/x11.c | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/Mw/LowLevel/X11.h b/include/Mw/LowLevel/X11.h index ab9c43df2..ec36c0484 100644 --- a/include/Mw/LowLevel/X11.h +++ b/include/Mw/LowLevel/X11.h @@ -29,6 +29,7 @@ struct _MwLLX11 { GC gc; Colormap colormap; Atom wm_delete; + Atom wm_protocols; XIM xim; XIC xic; diff --git a/src/backend/x11.c b/src/backend/x11.c index c44daafd1..0353a248a 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -209,8 +209,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.grabbed = 0; r->x11.force_render = 0; - r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); - r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); + r->x11.colormap = DefaultColormap(r->x11.display, XDefaultScreen(r->x11.display)); + r->x11.wm_delete = XInternAtom(r->x11.display, "WM_DELETE_WINDOW", False); + r->x11.wm_protocols = XInternAtom(r->x11.display, "WM_PROTOCOLS", False); XSetWMProtocols(r->x11.display, r->x11.window, &r->x11.wm_delete, 1); r->x11.gc = XCreateGC(r->x11.display, r->x11.window, 0, NULL); @@ -471,7 +472,7 @@ static void MwLLNextEventImpl(MwLL handle) { handle->x11.width = ev.xconfigure.width; handle->x11.height = ev.xconfigure.height; } else if(ev.type == ClientMessage) { - if(ev.xclient.data.l[0] == (long)handle->x11.wm_delete) { + if(ev.xclient.message_type == handle->x11.wm_protocols && ev.xclient.data.l[0] == (long)handle->x11.wm_delete) { MwLLDispatch(handle, close, NULL); } } else if(ev.type == FocusIn) { From 4bdda59693977f31092a38a052b7a94897d345c3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 31 Dec 2025 04:29:04 +0900 Subject: [PATCH 063/409] better api for clipboard --- examples/basic/clipboard.c | 4 ++++ include/Mw/LowLevel.h | 3 ++- include/Mw/LowLevel/GDI.h | 1 + include/Mw/TypeDefs.h | 3 ++- src/backend/gdi.c | 37 ++++++++++++++++++++-------------- src/backend/x11.c | 41 +++----------------------------------- src/core.c | 7 +++++++ src/lowlevel.c | 2 +- src/widget/box.c | 2 +- src/widget/button.c | 2 +- src/widget/checkbox.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 34 +++++++++++++++++-------------- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/label.c | 2 +- src/widget/listbox.c | 2 +- src/widget/menu.c | 2 +- src/widget/numberentry.c | 2 +- src/widget/opengl.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/radiobox.c | 2 +- src/widget/scrollbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 2 +- src/widget/viewport.c | 2 +- src/widget/vulkan.c | 2 +- src/widget/window.c | 2 +- 29 files changed, 81 insertions(+), 91 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 9efae7af7..2fe3265a9 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -29,6 +29,9 @@ void handler(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; (void)call_data; + + /* nishi: please rewrite this part */ + /* char* clipboard; clipboard = MwLLGetClipboard(handle->lowlevel); @@ -37,6 +40,7 @@ void handler(MwWidget handle, void* user_data, void* call_data) { MwVaApply(text, MwNtext, clipboard); MwForceRender(text); } + */ resize(window, NULL, NULL); } diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 0b0357d89..24418ec08 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -147,6 +147,7 @@ struct _MwLLHandler { void (*key_released)(MwLL handle, void* data); void (*focus_in)(MwLL handle, void* data); void (*focus_out)(MwLL handle, void* data); + void (*clipboard_received)(MwLL handle, void* data); }; #ifdef __cplusplus @@ -203,7 +204,7 @@ MWDECL void (*MwLLFocus)(MwLL handle); MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text); -MWDECL char* (*MwLLGetClipboard)(MwLL handle); +MWDECL void (*MwLLGetClipboard)(MwLL handle); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); diff --git a/include/Mw/LowLevel/GDI.h b/include/Mw/LowLevel/GDI.h index 9fee9ac02..1bf997c23 100644 --- a/include/Mw/LowLevel/GDI.h +++ b/include/Mw/LowLevel/GDI.h @@ -21,6 +21,7 @@ struct _MwLLGDI { int grabbed; int force_render; + int get_clipboard; }; struct _MwLLGDIColor { diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 3275096f1..de97cd9a5 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -39,6 +39,7 @@ typedef void (*MwHandlerChildrenProp)(MwWidget handle, MwWidget child, const cha typedef void (*MwHandlerKey)(MwWidget handle, int key); typedef void (*MwHandlerMouse)(MwWidget handle, void* ptr); typedef void (*MwHandlerExecute)(MwWidget handle, const char* name, void* out, va_list args); +typedef void (*MwHandlerClipboardReceived)(MwWidget handle, const char* data); typedef void (*MwUserHandler)(MwWidget handle, void* user_data, void* call_data); typedef void (*MwErrorHandler)(int code, const char* message, void* user_data); @@ -211,11 +212,11 @@ struct _MwClass { MwHandler resize; MwHandler children_update; MwHandlerChildrenProp children_prop_change; + MwHandlerClipboardReceived clipboard_received; void* reserved1; void* reserved2; void* reserved3; void* reserved4; - void* reserved5; }; #endif diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 85f8fcbb0..f027fe07b 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -237,6 +237,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.copy_buffer = 1; r->common.type = MwLLBackendGDI; + r->gdi.get_clipboard = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); @@ -383,6 +384,7 @@ static int MwLLPendingImpl(MwLL handle) { (void)handle; + if(handle->gdi.get_clipboard) return 1; return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0; } @@ -391,6 +393,24 @@ static void MwLLNextEventImpl(MwLL handle) { (void)handle; + if(handle->gdi.get_clipboard){ + HGLOBAL hg; + if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL){ + char* txt = malloc(GlobalSize(hg)); + char* clp = GlobalLock(hg); + + strcpy(txt, clp); + + GlobalUnlock(hg); + CloseClipboard(); + + MwLLDispatch(handle, clipboard_received, txt); + + free(txt); + } + + handle->gdi.get_clipboard = 0; + } while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { GetMessage(&msg, handle->gdi.hWnd, 0, 0); TranslateMessage(&msg); @@ -697,21 +717,8 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { } } -static char* MwLLGetClipboardImpl(MwLL handle) { - HGLOBAL hg; - char* r = NULL; - if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) { - char* lock; - - r = malloc(GlobalSize(hg)); - - lock = GlobalLock(hg); - strcpy(r, lock); - GlobalUnlock(hg); - - CloseClipboard(); - } - return r; +static void MwLLGetClipboardImpl(MwLL handle) { + handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */ } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/backend/x11.c b/src/backend/x11.c index 0353a248a..8ece5d8e8 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -957,45 +957,10 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { (void)text; } -static char* MwLLGetClipboardImpl(MwLL handle) { - Atom clip, target, prop; - XEvent ev; - XEvent* queue = NULL; - char* r = NULL; +static void MwLLGetClipboardImpl(MwLL handle) { + /* TODO */ - clip = XInternAtom(handle->x11.display, "CLIPBOARD", 0); - target = XA_STRING; - prop = XInternAtom(handle->x11.display, "XSEL_DATA", 0); - - XConvertSelection(handle->x11.display, clip, target, prop, handle->x11.window, CurrentTime); - - while(1) { - XNextEvent(handle->x11.display, &ev); - if(ev.type == SelectionNotify) { - if(ev.xselection.selection == clip && ev.xselection.property != 0) { - Atom t; - unsigned long size, N; - char* data; - int format; - - XGetWindowProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property, 0, (~0L), 0, AnyPropertyType, &t, &format, &size, &N, (unsigned char**)&data); - if(t == target) { - r = MwStringDuplicate(data); - XFree(data); - } - XDeleteProperty(ev.xselection.display, ev.xselection.requestor, ev.xselection.property); - } - break; - } - } - - while(arrlen(queue) > 0) { - XPutBackEvent(handle->x11.display, &queue[0]); - arrdel(queue, 0); - } - arrfree(queue); - - return r; + (void)handle; } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/core.c b/src/core.c index 656699024..f44a9f820 100644 --- a/src/core.c +++ b/src/core.c @@ -107,6 +107,12 @@ static void llfocusouthandler(MwLL handle, void* data) { MwDispatchUserHandler(h, MwNfocusOutHandler, data); } +static void llclipboardreceivedhandler(MwLL handle, void* data){ + MwWidget h = (MwWidget)handle->common.user; + + MwDispatch3(h, clipboard_received, data); +} + MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { MwWidget h = malloc(sizeof(*h)); @@ -148,6 +154,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->lowlevel->common.handler->key_released = llkeyrelhandler; h->lowlevel->common.handler->focus_in = llfocusinhandler; h->lowlevel->common.handler->focus_out = llfocusouthandler; + h->lowlevel->common.handler->clipboard_received = llclipboardreceivedhandler; } if(parent != NULL) arrput(parent->children, h); diff --git a/src/lowlevel.c b/src/lowlevel.c index 96f619613..30037c876 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -46,7 +46,7 @@ void (*MwLLFocus)(MwLL handle); void (*MwLLGrabPointer)(MwLL handle, int toggle); void (*MwLLSetClipboard)(MwLL handle, const char* text); -char* (*MwLLGetClipboard)(MwLL handle); +void (*MwLLGetClipboard)(MwLL handle); void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); diff --git a/src/widget/box.c b/src/widget/box.c index 3bf7528ef..c38a37720 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -114,7 +114,7 @@ MwClassRec MwBoxClassRec = { resize, /* resize */ children_update, /* children_update */ children_prop_change, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/button.c b/src/widget/button.c index 885ff9d49..296a14de0 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -107,7 +107,7 @@ MwClassRec MwButtonClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 8a42b8904..390b65685 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -53,7 +53,7 @@ MwClassRec MwCheckBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 156242e81..0cdd629c7 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -204,7 +204,7 @@ MwClassRec MwComboBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/entry.c b/src/widget/entry.c index 85f9a86c1..790586aec 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -109,20 +109,7 @@ static void key(MwWidget handle, int code) { } else if(code == MwLLKeyEnter) { MwDispatchUserHandler(handle, MwNactivateHandler, NULL); } else if(code == (MwLLControlMask | 'v')) { - char* c = MwLLGetClipboard(handle->lowlevel); - if(c != NULL) { - char* out = malloc(strlen(str) + strlen(c) + 1); - - MwUTF8Copy(str, 0, out, 0, t->cursor); - MwUTF8Copy(c, 0, out, t->cursor, MwUTF8Length(c)); - MwUTF8Copy(str, t->cursor, out, t->cursor + MwUTF8Length(c), MwUTF8Length(str) - t->cursor); - - t->cursor += MwUTF8Length(c); - - MwSetText(handle, MwNtext, out); - free(out); - free(c); - } + MwLLGetClipboard(handle->lowlevel); } else if(!(code & MwLLKeyMask)) { int incr = 0; out = malloc(strlen(str) + 5 + 1); @@ -157,6 +144,23 @@ static void prop_change(MwWidget handle, const char* prop) { } } +static void clipboard_received(MwWidget handle, const char* data){ + MwEntry t = handle->internal; + const char* str = MwGetText(handle, MwNtext); + char* out = malloc(strlen(str) + strlen(data) + 1); + + if(str == NULL) str = ""; + + MwUTF8Copy(str, 0, out, 0, t->cursor); + MwUTF8Copy(data, 0, out, t->cursor, MwUTF8Length(data)); + MwUTF8Copy(str, t->cursor, out, t->cursor + MwUTF8Length(data), MwUTF8Length(str) - t->cursor); + + t->cursor += MwUTF8Length(data); + + MwSetText(handle, MwNtext, out); + free(out); +} + MwClassRec MwEntryClassRec = { create, /* create */ destroy, /* destroy */ @@ -173,7 +177,7 @@ MwClassRec MwEntryClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + clipboard_received, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/frame.c b/src/widget/frame.c index d48c2874d..869f604fe 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -61,7 +61,7 @@ MwClassRec MwFrameClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/image.c b/src/widget/image.c index 4995568d1..a9c0c264c 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -57,7 +57,7 @@ MwClassRec MwImageClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/label.c b/src/widget/label.c index 792d00918..570dc10cd 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -375,7 +375,7 @@ MwClassRec MwLabelClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 785468d06..5c741ff4e 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -608,7 +608,7 @@ MwClassRec MwListBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/menu.c b/src/widget/menu.c index 327d6f5e7..6dba8a124 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -204,7 +204,7 @@ MwClassRec MwMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index ccbdf1433..cb8d6a28c 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -143,7 +143,7 @@ MwClassRec MwNumberEntryClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 19a7c4d10..20b51f2bb 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -244,7 +244,7 @@ MwClassRec MwOpenGLClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index bd036dd3d..7ab3274b4 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -61,7 +61,7 @@ MwClassRec MwProgressBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index a6f78f9d5..063c09d8e 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -62,7 +62,7 @@ MwClassRec MwRadioBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index ff42d3aad..eaa87ae1c 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -272,7 +272,7 @@ MwClassRec MwScrollBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/separator.c b/src/widget/separator.c index 5800ba302..424305e9a 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -50,7 +50,7 @@ MwClassRec MwSeparatorClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 6b97934cb..3b5553eb4 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -253,7 +253,7 @@ MwClassRec MwSubMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 27607ceeb..7dad52bbb 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -496,7 +496,7 @@ MwClassRec MwTreeViewClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/viewport.c b/src/widget/viewport.c index 9bdf86017..5b66b6ed6 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -191,7 +191,7 @@ MwClassRec MwViewportClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index bda24bfff..15039f7db 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -524,7 +524,7 @@ MwClassRec MwVulkanClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/window.c b/src/widget/window.c index 98a128f8f..84c7140bb 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -59,7 +59,7 @@ MwClassRec MwWindowClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, + NULL, /* clipboard_received */ NULL, NULL, NULL, From d3147ac0874a52528e92a788239608bcdac236ae Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 31 Dec 2025 04:29:27 +0900 Subject: [PATCH 064/409] format --- include/Mw/TypeDefs.h | 38 +++++++++++++++++++------------------- src/backend/gdi.c | 16 ++++++++-------- src/core.c | 28 ++++++++++++++-------------- src/widget/box.c | 2 +- src/widget/button.c | 2 +- src/widget/checkbox.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 38 +++++++++++++++++++------------------- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/label.c | 2 +- src/widget/listbox.c | 2 +- src/widget/menu.c | 2 +- src/widget/numberentry.c | 2 +- src/widget/opengl.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/radiobox.c | 2 +- src/widget/scrollbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 2 +- src/widget/viewport.c | 2 +- src/widget/vulkan.c | 2 +- src/widget/window.c | 2 +- 24 files changed, 80 insertions(+), 80 deletions(-) diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index de97cd9a5..043215e23 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -197,26 +197,26 @@ struct _MwListBoxPacket { }; struct _MwClass { - MwHandlerWithStatus create; - MwHandler destroy; - MwHandler draw; - MwHandler click; - MwHandler parent_resize; - MwHandlerProp prop_change; - MwHandler mouse_move; - MwHandlerMouse mouse_up; - MwHandlerMouse mouse_down; - MwHandlerKey key; - MwHandlerExecute execute; - MwHandler tick; - MwHandler resize; - MwHandler children_update; - MwHandlerChildrenProp children_prop_change; + MwHandlerWithStatus create; + MwHandler destroy; + MwHandler draw; + MwHandler click; + MwHandler parent_resize; + MwHandlerProp prop_change; + MwHandler mouse_move; + MwHandlerMouse mouse_up; + MwHandlerMouse mouse_down; + MwHandlerKey key; + MwHandlerExecute execute; + MwHandler tick; + MwHandler resize; + MwHandler children_update; + MwHandlerChildrenProp children_prop_change; MwHandlerClipboardReceived clipboard_received; - void* reserved1; - void* reserved2; - void* reserved3; - void* reserved4; + void* reserved1; + void* reserved2; + void* reserved3; + void* reserved4; }; #endif diff --git a/src/backend/gdi.c b/src/backend/gdi.c index f027fe07b..3308fdcac 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -238,12 +238,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.type = MwLLBackendGDI; r->gdi.get_clipboard = 1; - r->gdi.force_render = 0; - r->gdi.grabbed = 0; - r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); - r->gdi.hInstance = wc.hInstance; - r->gdi.cursor = NULL; - r->gdi.icon = NULL; + r->gdi.force_render = 0; + r->gdi.grabbed = 0; + r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); + r->gdi.hInstance = wc.hInstance; + r->gdi.cursor = NULL; + r->gdi.icon = NULL; u->ll = r; u->min_set = 0; @@ -393,9 +393,9 @@ static void MwLLNextEventImpl(MwLL handle) { (void)handle; - if(handle->gdi.get_clipboard){ + if(handle->gdi.get_clipboard) { HGLOBAL hg; - if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL){ + if(OpenClipboard(handle->gdi.hWnd) != 0 && (hg = GetClipboardData(CF_TEXT)) != NULL) { char* txt = malloc(GlobalSize(hg)); char* clp = GlobalLock(hg); diff --git a/src/core.c b/src/core.c index f44a9f820..94ee54ead 100644 --- a/src/core.c +++ b/src/core.c @@ -107,8 +107,8 @@ static void llfocusouthandler(MwLL handle, void* data) { MwDispatchUserHandler(h, MwNfocusOutHandler, data); } -static void llclipboardreceivedhandler(MwLL handle, void* data){ - MwWidget h = (MwWidget)handle->common.user; +static void llclipboardreceivedhandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; MwDispatch3(h, clipboard_received, data); } @@ -143,18 +143,18 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, if(parent == NULL) arrput(h->tick_list, h); if(h->lowlevel != NULL) { - h->lowlevel->common.user = h; - h->lowlevel->common.handler->draw = lldrawhandler; - h->lowlevel->common.handler->up = lluphandler; - h->lowlevel->common.handler->down = lldownhandler; - h->lowlevel->common.handler->resize = llresizehandler; - h->lowlevel->common.handler->close = llclosehandler; - h->lowlevel->common.handler->move = llmovehandler; - h->lowlevel->common.handler->key = llkeyhandler; - h->lowlevel->common.handler->key_released = llkeyrelhandler; - h->lowlevel->common.handler->focus_in = llfocusinhandler; - h->lowlevel->common.handler->focus_out = llfocusouthandler; - h->lowlevel->common.handler->clipboard_received = llclipboardreceivedhandler; + h->lowlevel->common.user = h; + h->lowlevel->common.handler->draw = lldrawhandler; + h->lowlevel->common.handler->up = lluphandler; + h->lowlevel->common.handler->down = lldownhandler; + h->lowlevel->common.handler->resize = llresizehandler; + h->lowlevel->common.handler->close = llclosehandler; + h->lowlevel->common.handler->move = llmovehandler; + h->lowlevel->common.handler->key = llkeyhandler; + h->lowlevel->common.handler->key_released = llkeyrelhandler; + h->lowlevel->common.handler->focus_in = llfocusinhandler; + h->lowlevel->common.handler->focus_out = llfocusouthandler; + h->lowlevel->common.handler->clipboard_received = llclipboardreceivedhandler; } if(parent != NULL) arrput(parent->children, h); diff --git a/src/widget/box.c b/src/widget/box.c index c38a37720..68f266e9d 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -114,7 +114,7 @@ MwClassRec MwBoxClassRec = { resize, /* resize */ children_update, /* children_update */ children_prop_change, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/button.c b/src/widget/button.c index 296a14de0..677e30938 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -107,7 +107,7 @@ MwClassRec MwButtonClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 390b65685..49264338c 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -53,7 +53,7 @@ MwClassRec MwCheckBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 0cdd629c7..20def29ef 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -204,7 +204,7 @@ MwClassRec MwComboBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/entry.c b/src/widget/entry.c index 790586aec..f85a1914f 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -144,10 +144,10 @@ static void prop_change(MwWidget handle, const char* prop) { } } -static void clipboard_received(MwWidget handle, const char* data){ +static void clipboard_received(MwWidget handle, const char* data) { MwEntry t = handle->internal; - const char* str = MwGetText(handle, MwNtext); - char* out = malloc(strlen(str) + strlen(data) + 1); + const char* str = MwGetText(handle, MwNtext); + char* out = malloc(strlen(str) + strlen(data) + 1); if(str == NULL) str = ""; @@ -162,22 +162,22 @@ static void clipboard_received(MwWidget handle, const char* data){ } MwClassRec MwEntryClassRec = { - create, /* create */ - destroy, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - MwForceRender2, /* mouse_up */ - MwForceRender2, /* mouse_down */ - key, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - clipboard_received, /* clipboard_received */ + create, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + key, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + clipboard_received, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/frame.c b/src/widget/frame.c index 869f604fe..eb324f0fc 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -61,7 +61,7 @@ MwClassRec MwFrameClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/image.c b/src/widget/image.c index a9c0c264c..07afbab46 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -57,7 +57,7 @@ MwClassRec MwImageClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/label.c b/src/widget/label.c index 570dc10cd..f53b72ee3 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -375,7 +375,7 @@ MwClassRec MwLabelClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 5c741ff4e..2fadc5fc3 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -608,7 +608,7 @@ MwClassRec MwListBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/menu.c b/src/widget/menu.c index 6dba8a124..4572d3fc3 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -204,7 +204,7 @@ MwClassRec MwMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index cb8d6a28c..83577aa01 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -143,7 +143,7 @@ MwClassRec MwNumberEntryClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 20b51f2bb..7413acda3 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -244,7 +244,7 @@ MwClassRec MwOpenGLClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index 7ab3274b4..c0b44bee9 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -61,7 +61,7 @@ MwClassRec MwProgressBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index 063c09d8e..d932ba6f4 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -62,7 +62,7 @@ MwClassRec MwRadioBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index eaa87ae1c..055ea5a3c 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -272,7 +272,7 @@ MwClassRec MwScrollBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/separator.c b/src/widget/separator.c index 424305e9a..c608dd1d4 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -50,7 +50,7 @@ MwClassRec MwSeparatorClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 3b5553eb4..13b694198 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -253,7 +253,7 @@ MwClassRec MwSubMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 7dad52bbb..903a12973 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -496,7 +496,7 @@ MwClassRec MwTreeViewClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/viewport.c b/src/widget/viewport.c index 5b66b6ed6..3a9e3fd82 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -191,7 +191,7 @@ MwClassRec MwViewportClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 15039f7db..c85ea4311 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -524,7 +524,7 @@ MwClassRec MwVulkanClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, diff --git a/src/widget/window.c b/src/widget/window.c index 84c7140bb..4a821dee5 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -59,7 +59,7 @@ MwClassRec MwWindowClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard_received */ NULL, NULL, NULL, From 72820e87f14faff0692b665b1513cee946f89ddf Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 31 Dec 2025 04:35:10 +0900 Subject: [PATCH 065/409] rename clipboard_received to clipboard --- .gitignore | 1 + include/Mw/LowLevel.h | 2 +- include/Mw/StringDefs.h | 1 + include/Mw/TypeDefs.h | 2 +- milsko.xml | 1 + src/backend/gdi.c | 2 +- src/core.c | 29 +++++++++++++++-------------- src/widget/box.c | 2 +- src/widget/button.c | 2 +- src/widget/checkbox.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 34 +++++++++++++++++----------------- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/label.c | 2 +- src/widget/listbox.c | 2 +- src/widget/menu.c | 2 +- src/widget/numberentry.c | 2 +- src/widget/opengl.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/radiobox.c | 2 +- src/widget/scrollbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 2 +- src/widget/viewport.c | 2 +- src/widget/vulkan.c | 2 +- src/widget/window.c | 2 +- 28 files changed, 58 insertions(+), 54 deletions(-) diff --git a/.gitignore b/.gitignore index 1dcc6d174..2ebdbc2a8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ examples/*/*.exe !examples/*/ !examples/*.* !examples/*/*.* +*.exe *.o *.so *.dll diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 24418ec08..3c8bdf7b1 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -147,7 +147,7 @@ struct _MwLLHandler { void (*key_released)(MwLL handle, void* data); void (*focus_in)(MwLL handle, void* data); void (*focus_out)(MwLL handle, void* data); - void (*clipboard_received)(MwLL handle, void* data); + void (*clipboard)(MwLL handle, void* data); }; #ifdef __cplusplus diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 6588be2da..5d6896598 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -71,5 +71,6 @@ #define MwNdirectoryChosenHandler "CdirectoryChosen" /* char* */ #define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */ #define MwNdrawHandler "Cdraw" /* NULL */ +#define MwNclipboardHandler "Cclipboard" /* char* */ #endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 043215e23..caf388797 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -212,7 +212,7 @@ struct _MwClass { MwHandler resize; MwHandler children_update; MwHandlerChildrenProp children_prop_change; - MwHandlerClipboardReceived clipboard_received; + MwHandlerClipboardReceived clipboard; void* reserved1; void* reserved2; void* reserved3; diff --git a/milsko.xml b/milsko.xml index f7dcf2c78..dc980cd8d 100644 --- a/milsko.xml +++ b/milsko.xml @@ -122,6 +122,7 @@ + diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 3308fdcac..764e9838d 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -404,7 +404,7 @@ static void MwLLNextEventImpl(MwLL handle) { GlobalUnlock(hg); CloseClipboard(); - MwLLDispatch(handle, clipboard_received, txt); + MwLLDispatch(handle, clipboard, txt); free(txt); } diff --git a/src/core.c b/src/core.c index 94ee54ead..3d41a3603 100644 --- a/src/core.c +++ b/src/core.c @@ -107,10 +107,11 @@ static void llfocusouthandler(MwLL handle, void* data) { MwDispatchUserHandler(h, MwNfocusOutHandler, data); } -static void llclipboardreceivedhandler(MwLL handle, void* data) { +static void llclipboardhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; - MwDispatch3(h, clipboard_received, data); + MwDispatch3(h, clipboard, data); + MwDispatchUserHandler(h, MwNclipboardHandler, data); } MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { @@ -143,18 +144,18 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, if(parent == NULL) arrput(h->tick_list, h); if(h->lowlevel != NULL) { - h->lowlevel->common.user = h; - h->lowlevel->common.handler->draw = lldrawhandler; - h->lowlevel->common.handler->up = lluphandler; - h->lowlevel->common.handler->down = lldownhandler; - h->lowlevel->common.handler->resize = llresizehandler; - h->lowlevel->common.handler->close = llclosehandler; - h->lowlevel->common.handler->move = llmovehandler; - h->lowlevel->common.handler->key = llkeyhandler; - h->lowlevel->common.handler->key_released = llkeyrelhandler; - h->lowlevel->common.handler->focus_in = llfocusinhandler; - h->lowlevel->common.handler->focus_out = llfocusouthandler; - h->lowlevel->common.handler->clipboard_received = llclipboardreceivedhandler; + h->lowlevel->common.user = h; + h->lowlevel->common.handler->draw = lldrawhandler; + h->lowlevel->common.handler->up = lluphandler; + h->lowlevel->common.handler->down = lldownhandler; + h->lowlevel->common.handler->resize = llresizehandler; + h->lowlevel->common.handler->close = llclosehandler; + h->lowlevel->common.handler->move = llmovehandler; + h->lowlevel->common.handler->key = llkeyhandler; + h->lowlevel->common.handler->key_released = llkeyrelhandler; + h->lowlevel->common.handler->focus_in = llfocusinhandler; + h->lowlevel->common.handler->focus_out = llfocusouthandler; + h->lowlevel->common.handler->clipboard = llclipboardhandler; } if(parent != NULL) arrput(parent->children, h); diff --git a/src/widget/box.c b/src/widget/box.c index 68f266e9d..99f3e0772 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -114,7 +114,7 @@ MwClassRec MwBoxClassRec = { resize, /* resize */ children_update, /* children_update */ children_prop_change, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/button.c b/src/widget/button.c index 677e30938..dac7739c6 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -107,7 +107,7 @@ MwClassRec MwButtonClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 49264338c..1ccccd416 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -53,7 +53,7 @@ MwClassRec MwCheckBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 20def29ef..6b5437335 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -204,7 +204,7 @@ MwClassRec MwComboBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/entry.c b/src/widget/entry.c index f85a1914f..34a90a36b 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -144,7 +144,7 @@ static void prop_change(MwWidget handle, const char* prop) { } } -static void clipboard_received(MwWidget handle, const char* data) { +static void clipboard(MwWidget handle, const char* data) { MwEntry t = handle->internal; const char* str = MwGetText(handle, MwNtext); char* out = malloc(strlen(str) + strlen(data) + 1); @@ -162,22 +162,22 @@ static void clipboard_received(MwWidget handle, const char* data) { } MwClassRec MwEntryClassRec = { - create, /* create */ - destroy, /* destroy */ - draw, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - prop_change, /* prop_change */ - NULL, /* mouse_move */ - MwForceRender2, /* mouse_up */ - MwForceRender2, /* mouse_down */ - key, /* key */ - NULL, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - clipboard_received, /* clipboard_received */ + create, /* create */ + destroy, /* destroy */ + draw, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + prop_change, /* prop_change */ + NULL, /* mouse_move */ + MwForceRender2, /* mouse_up */ + MwForceRender2, /* mouse_down */ + key, /* key */ + NULL, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + clipboard, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/frame.c b/src/widget/frame.c index eb324f0fc..117b0f8b9 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -61,7 +61,7 @@ MwClassRec MwFrameClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/image.c b/src/widget/image.c index 07afbab46..74ee0bfd6 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -57,7 +57,7 @@ MwClassRec MwImageClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/label.c b/src/widget/label.c index f53b72ee3..7c70d2571 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -375,7 +375,7 @@ MwClassRec MwLabelClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 2fadc5fc3..cb84e44c4 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -608,7 +608,7 @@ MwClassRec MwListBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/menu.c b/src/widget/menu.c index 4572d3fc3..44fc2fe57 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -204,7 +204,7 @@ MwClassRec MwMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 83577aa01..5f14fc317 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -143,7 +143,7 @@ MwClassRec MwNumberEntryClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 7413acda3..a1c36d96f 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -244,7 +244,7 @@ MwClassRec MwOpenGLClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index c0b44bee9..d85a8ddaf 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -61,7 +61,7 @@ MwClassRec MwProgressBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index d932ba6f4..3229faad3 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -62,7 +62,7 @@ MwClassRec MwRadioBoxClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index 055ea5a3c..5c0d8ddbf 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -272,7 +272,7 @@ MwClassRec MwScrollBarClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/separator.c b/src/widget/separator.c index c608dd1d4..8fcfc5b71 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -50,7 +50,7 @@ MwClassRec MwSeparatorClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 13b694198..59673e3e7 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -253,7 +253,7 @@ MwClassRec MwSubMenuClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 903a12973..76e1e0139 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -496,7 +496,7 @@ MwClassRec MwTreeViewClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/viewport.c b/src/widget/viewport.c index 3a9e3fd82..de71af790 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -191,7 +191,7 @@ MwClassRec MwViewportClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index c85ea4311..441bc2731 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -524,7 +524,7 @@ MwClassRec MwVulkanClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, diff --git a/src/widget/window.c b/src/widget/window.c index 4a821dee5..979e073c8 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -59,7 +59,7 @@ MwClassRec MwWindowClassRec = { NULL, /* resize */ NULL, /* children_update */ NULL, /* children_prop_change */ - NULL, /* clipboard_received */ + NULL, /* clipboard */ NULL, NULL, NULL, From 67bd6029af37a4d6ae687faeb4f49136429239d1 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 17:12:12 -0700 Subject: [PATCH 066/409] wayland: finish clipboard --- examples/basic/clipboard.c | 39 +-- include/Mw/LowLevel/Wayland.h | 49 ++- src/backend/wayland.c | 552 ++++++++++++++++++++++++---------- 3 files changed, 448 insertions(+), 192 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 2fe3265a9..57f14984b 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -1,7 +1,7 @@ #define _MILSKO #include -MwWidget window, button, text; +MwWidget window, instructions, text; void resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h, mh; @@ -12,7 +12,7 @@ void resize(MwWidget handle, void* user_data, void* call_data) { w = MwGetInteger(handle, MwNwidth); h = MwGetInteger(handle, MwNheight); - MwVaApply(button, + MwVaApply(instructions, MwNy, 50 + mh, MwNwidth, w - 50 * 2, MwNheight, h - 125 - 50 * 3, @@ -24,25 +24,18 @@ void resize(MwWidget handle, void* user_data, void* call_data) { MwNheight, h - 125 - 50 * 3, NULL); } - -void handler(MwWidget handle, void* user_data, void* call_data) { +void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; - (void)call_data; - - /* nishi: please rewrite this part */ - /* - char* clipboard; - - clipboard = MwLLGetClipboard(handle->lowlevel); + char* clipboard = call_data; if(clipboard != NULL) { MwVaApply(text, MwNtext, clipboard); MwForceRender(text); } - */ + MwForceRender(window); - resize(window, NULL, NULL); + MwLLSetClipboard(window->lowlevel, "Milsko clipboard test"); } int main() { @@ -50,18 +43,18 @@ int main() { MwLibraryInit(); - window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, - MwNtitle, "clipboard", - NULL); - button = MwVaCreateWidget(MwButtonClass, "button", window, 50, 50, 300, 125, - MwNtext, "get clipboard contents", - NULL); - text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125, - MwNtext, "", - NULL); + window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, + MwNtitle, "clipboard", + NULL); + instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, + MwNtext, "clipboard contents will show up below.", + NULL); + text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125, + MwNtext, "", + NULL); MwAddUserHandler(window, MwNresizeHandler, resize, NULL); - MwAddUserHandler(button, MwNactivateHandler, handler, NULL); + MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL); resize(window, NULL, NULL); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 2720d4976..dcdcd5f55 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -97,6 +97,21 @@ enum _MwLLWaylandType { MWLL_WAYLAND_POPUP, }; +typedef struct wl_clipboard_device_context { + union { + struct wl_data_device* wl; + struct zwp_primary_selection_device_v1* zwp; + } device; + union { + struct wl_data_offer* wl; + struct zwp_primary_selection_offer_v1* zwp; + } offer; + + MwLL ll; + struct wl_seat* seat; + MwU32 capabilities; +} wl_clipboard_device_context_t; + struct _MwLLWayland { struct _MwLLCommon common; @@ -131,11 +146,29 @@ struct _MwLLWayland { struct wl_region* region; struct wl_output* output; - struct wl_pointer* pointer; - struct wl_keyboard* keyboard; - MwU32 pointer_serial; + /* clipboard related stuff. + * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ - MwBool events_pending; + union { + struct wl_data_device_manager* wl; + struct zwp_primary_selection_device_manager_v1* zwp; + } clipboard_manager; + union { + struct wl_data_source* wl; + struct zwp_primary_selection_source_v1* zwp; + } clipboard_source; + char* clipboard_buffer; + MwBool supports_zwp; + + uint32_t clipboard_serial; + wl_clipboard_device_context_t** clipboard_devices; + + struct wl_pointer* pointer; + MwU32 pointer_serial; + struct wl_keyboard* keyboard; + MwU32 keyboard_serial; + + MwU64 events_pending; MwBool test; MwU32 mod_state; @@ -149,6 +182,14 @@ struct _MwLLWayland { MwLL parent; + MwBool force_render; + + pthread_mutex_t dispatch_mutex; + pthread_mutex_t pending_mutex; + + MwBool break_dispatch; + MwBool break_pending; + struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f05511724..8131e7044 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -8,9 +8,9 @@ #include #include #include +#include /* TODO: - * - MwLLSetClipboardImpl * - MwLLGrabPointerImpl * - MwLLMakePopupImpl * - MwLLShowImpl @@ -62,78 +62,275 @@ static void protocol_removed(void* data, printf("%d destroyed\n", name); }; -static void offer_offer(void* data, - struct zwp_primary_selection_offer_v1* zwp_primary_selection_offer_v1, - const char* mime_type) { +/* Flush Wayland events */ +static void wl_flush(MwLL handle) { + struct pollfd pfd; + int rc; + + pfd.fd = wl_display_get_fd(handle->wayland.display); + pfd.events = POLLIN; + while(MwTRUE) { + rc = wl_display_flush(handle->wayland.display); + if(errno != EAGAIN || rc != -1) { + break; + } + + if(poll(&pfd, 1, -1) == -1) { + break; + } + } +} + +static void wl_offer(void* data, + struct wl_data_offer* wl_data_offer, + const char* mime_type) { + wl_clipboard_device_context_t* self = data; + wl_data_offer_accept(wl_data_offer, self->ll->wayland.clipboard_serial, mime_type); }; -struct zwp_primary_selection_offer_v1_listener offer_listener = { - .offer = offer_offer, +struct wl_data_offer_listener offer_listener = { + .offer = wl_offer, }; -typedef struct primary_selection_device_context { - struct zwp_primary_selection_device_v1* device; - struct zwp_primary_selection_offer_v1* offer; -} primary_selection_device_context_t; +static void wl_data_device_data_offer(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* offer) { + wl_clipboard_device_context_t* self = data; -typedef struct primary_selection_context { - struct zwp_primary_selection_device_manager_v1* manager; - /* stored seperately of the listeners because it's not a pointer and it gets assigned to data devices dynamically. */ - struct zwp_primary_selection_device_v1_listener listener; + wl_data_offer_add_listener(offer, &offer_listener, data); - struct zwp_primary_selection_source_v1* source; - primary_selection_device_context_t** devices; -} primary_selection_context_t; - -static void primary_selection_data_offer(void* data, - struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, - struct zwp_primary_selection_offer_v1* offer) { - struct primary_selection_device_context* self = data; - zwp_primary_selection_offer_v1_add_listener(offer, &offer_listener, data); - - self->offer = offer; + self->offer.wl = offer; }; -static void primary_selection_selection(void* data, - struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, - struct zwp_primary_selection_offer_v1* id) { + +static void wl_data_device_enter(void* data, + struct wl_data_device* wl_data_device, + uint32_t serial, + struct wl_surface* surface, + wl_fixed_t x, + wl_fixed_t y, + struct wl_data_offer* id) { + MwLL self = data; + self->wayland.clipboard_serial = serial; }; +static void wl_data_device_leave(void* data, + struct wl_data_device* wl_data_device) { + wl_data_device_destroy(wl_data_device); +}; +static void wl_data_device_motion(void* data, + struct wl_data_device* wl_data_device, + uint32_t time, + wl_fixed_t x, + wl_fixed_t y) { +}; +static void wl_data_device_drop(void* data, + struct wl_data_device* wl_data_device) { +}; + +static void wl_data_device_selection(void* data, + struct wl_data_device* wl_data_device, + struct wl_data_offer* id) { +}; + +struct wl_data_device_listener wl_data_device_listener = { + .data_offer = wl_data_device_data_offer, + .enter = wl_data_device_enter, + .leave = wl_data_device_leave, + .motion = wl_data_device_motion, + .drop = wl_data_device_drop, + .selection = wl_data_device_selection, +}; + +static void zwp_primary_selection_device_v1_data_offer(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* offer) { + wl_clipboard_device_context_t* self = data; + + self->offer.zwp = offer; +}; + +static void zwp_primary_selection_device_v1_selection(void* data, + struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, + struct zwp_primary_selection_offer_v1* id) { +}; + +struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = { + .data_offer = zwp_primary_selection_device_v1_data_offer, + .selection = zwp_primary_selection_device_v1_selection, +}; + +static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { + int fds[2]; + fd_set set; + char* buf = NULL; + struct timeval timeout; + int rc = 0; + int n; + + if(pipe(fds) != 0) { + return; + } + + FD_ZERO(&set); + FD_SET(fds[0], &set); + timeout.tv_sec = 0; + timeout.tv_usec = 100; + + if(ctx->ll->wayland.supports_zwp) { + zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); + } else { + wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); + } + close(fds[1]); + + wl_flush(ctx->ll); + wl_display_roundtrip(ctx->ll->wayland.display); + + while(MwTRUE) { + char ch; + rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); + if(rc <= 0) { + break; + } else { + char b; + ssize_t n = read(fds[0], &b, sizeof(b)); + if(n <= 0) { + break; + } + arrpush(buf, b); + } + } + arrpush(buf, 0); + close(fds[0]); + + MwLLDispatch(ctx->ll, clipboard, buf); + arrfree(buf); +} + +static void wl_data_source_listener_target(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type) { +}; +static void wl_data_source_listener_send(void* data, + struct wl_data_source* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + + self->wayland.events_pending = 1; + } +}; +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source); + +struct wl_data_source_listener wl_data_source_listener = { + .target = wl_data_source_listener_target, + .send = wl_data_source_listener_send, + .cancelled = wl_data_source_listener_cancelled, +}; + +static void wl_data_source_listener_cancelled(void* data, + struct wl_data_source* wl_data_source) { + MwLL self = data; + + wl_data_source_destroy(wl_data_source); + + self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl); + + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "TEXT"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "STRING"); + wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); +}; + +static void zwp_primary_selection_source_v1_send(void* data, + struct zwp_primary_selection_source_v1* wl_data_source, + const char* mime_type, + int32_t fd) { + MwLL self = data; + if(self->wayland.clipboard_buffer != NULL) { + write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); + close(fd); + + self->wayland.events_pending = 1; + } +}; +static void zwp_primary_selection_source_v1_cancelled(void* data, + struct zwp_primary_selection_source_v1* wl_data_source) { + MwLL self = data; + + zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp); + + self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp); + + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING"); +}; + +struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = { + .send = zwp_primary_selection_source_v1_send, + .cancelled = zwp_primary_selection_source_v1_cancelled, +}; + +/* wl_data_device_manager setup function */ +static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland->clipboard_manager.wl = wl_registry_bind(wayland->registry, name, &wl_data_device_manager_interface, 2); + + wayland->clipboard_source.wl = wl_data_device_manager_create_data_source(wayland->clipboard_manager.wl); + + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain"); + wl_data_source_offer(wayland->clipboard_source.wl, "text/plain;charset=utf-8"); + wl_data_source_offer(wayland->clipboard_source.wl, "TEXT"); + wl_data_source_offer(wayland->clipboard_source.wl, "STRING"); + wl_data_source_offer(wayland->clipboard_source.wl, "UTF8_STRING"); + + wl_data_source_add_listener(wayland->clipboard_source.wl, &wl_data_source_listener, wayland); + + return NULL; +} + +static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + wl_data_device_manager_destroy(wayland->clipboard_manager.wl); + wl_data_source_destroy(wayland->clipboard_source.wl); +} /* zwp_primary_selection_device_manager_v1 setup function */ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - primary_selection_context_t* context = malloc(sizeof(primary_selection_context_t)); + if(wayland->clipboard_manager.wl != NULL) { + wl_data_device_manager_interface_destroy(wayland, NULL); + } - context->manager = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); + wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); - struct zwp_primary_selection_device_manager_v1* device; - context->listener.data_offer = primary_selection_data_offer; - context->listener.selection = primary_selection_selection; + wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); - context->source = zwp_primary_selection_device_manager_v1_create_source(context->manager); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "text/plain;charset=utf-8"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "TEXT"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "STRING"); + zwp_primary_selection_source_v1_offer(wayland->clipboard_source.zwp, "UTF8_STRING"); - context->devices = NULL; + zwp_primary_selection_source_v1_add_listener(wayland->clipboard_source.zwp, &zwp_primary_selection_source_v1_listener, wayland); - proto->context = context; - proto->listener = NULL; + wayland->supports_zwp = MwTRUE; - return proto; + return NULL; } static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - primary_selection_context_t* context = data->context; - int i; + return; - zwp_primary_selection_device_manager_v1_destroy(context->manager); + zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp); - for(i = 0; i < arrlen(context->devices); i++) { - primary_selection_device_context_t* device = context->devices[i]; - // zwp_primary_selection_device_v1_destroy(device->device); - // zwp_primary_selection_offer_v1_destroy(device->offer); - free(device); - } - arrfree(context->devices); - - zwp_primary_selection_source_v1_destroy(context->source); + zwp_primary_selection_source_v1_destroy(wayland->clipboard_source.zwp); free(data->listener); } @@ -164,7 +361,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - self->wayland.events_pending = MwTRUE; + self->wayland.events_pending += 1; /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; @@ -181,6 +378,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; case BTN_MIDDLE: p.button = MwLLMouseMiddle; + for(int i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { + wl_clipboard_read( + self->wayland.clipboard_devices[i]); + } break; case BTN_RIGHT: p.button = MwLLMouseRight; @@ -197,7 +398,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } MwLLDispatch(self, draw, NULL); - self->wayland.events_pending = MwTRUE; + self->wayland.events_pending += 1; }; /* `wl_pointer.axis` callback */ @@ -247,9 +448,11 @@ static void keyboard_enter(void* data, MwU32 serial, struct wl_surface* surface, struct wl_array* keys) { - MwLL self = data; + MwLL self = data; + self->wayland.keyboard_serial = serial; + MwLLDispatch(self, focus_in, NULL); - self->wayland.events_pending = MwTRUE; + self->wayland.events_pending += 1; }; /* `wl_keyboard.leave` callback */ @@ -259,7 +462,7 @@ static void keyboard_leave(void* data, struct wl_surface* surface) { MwLL self = data; MwLLDispatch(self, focus_out, NULL); - self->wayland.events_pending = MwTRUE; + self->wayland.events_pending += 1; }; /* `wl_keyboard.key` callback */ @@ -334,11 +537,19 @@ static void keyboard_key(void* data, key = sym; } if((self->wayland.mod_state & 4) == 4) { + /* clipboard paste */ + if(key == 'V') { + for(int i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { + wl_clipboard_read( + self->wayland.clipboard_devices[i]); + } + } key |= MwLLControlMask; } if((self->wayland.mod_state & 8) == 8) { key |= MwLLAltMask; } + if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { MwLLDispatch(self, key, &key); } else { @@ -346,7 +557,8 @@ static void keyboard_key(void* data, } } } - self->wayland.events_pending = MwTRUE; + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; }; /* `wl_keyboard.modifiers` callback */ @@ -379,7 +591,9 @@ wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) { - MwLL self = data; + MwLL self = data; + wl_clipboard_device_context_t* device_ctx = malloc(sizeof(wl_clipboard_device_context_t)); + if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); @@ -389,20 +603,22 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } - /* primary selection support */ - if(WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1) != NULL) { - primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(self->wayland, zwp_primary_selection_device_manager_v1)->context; - primary_selection_device_context_t* device_ctx = malloc(sizeof(primary_selection_device_context_t)); - - device_ctx->device = - zwp_primary_selection_device_manager_v1_get_device(primary_selection->manager, wl_seat); - - zwp_primary_selection_device_v1_add_listener(device_ctx->device, &primary_selection->listener, device_ctx); - - device_ctx->offer = NULL; - - arrpush(primary_selection->devices, device_ctx); + if(self->wayland.supports_zwp) { + device_ctx->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + } else { + device_ctx->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); } + device_ctx->ll = self; + device_ctx->seat = wl_seat; + device_ctx->capabilities = capabilities; + + if(self->wayland.supports_zwp) { + zwp_primary_selection_device_v1_add_listener(device_ctx->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx); + } else { + wl_data_device_add_listener(device_ctx->device.wl, &wl_data_device_listener, device_ctx); + } + + arrpush(self->wayland.clipboard_devices, device_ctx); }; static void output_geometry(void* data, @@ -466,7 +682,6 @@ static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { } static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // wl_output_destroy(wayland->output); } /* wl_compositor setup function */ @@ -477,7 +692,6 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* } static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // wl_compositor_destroy(wayland->compositor); } /* wl_subcompositor setup function */ @@ -544,6 +758,11 @@ static void xdg_toplevel_configure(void* data, MwLL self = data; int i; + /* Yes, somehow this can get called before */ + if(!self->wayland.configured) { + return; + } + if(width == 0 || height == 0) { width = self->wayland.ww; height = self->wayland.wh; @@ -612,7 +831,6 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland } static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // buffer_destroy(&wayland->framebuffer); } static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { @@ -674,7 +892,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); update_buffer(&wayland->framebuffer); - wayland->events_pending = MwTRUE; + wayland->events_pending += 1; }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -711,25 +929,6 @@ static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* xdg_toplevel_icon_manager_v1_destroy(data->context); } -/* Flush Wayland events */ -static void wl_flush(MwLL handle) { - struct pollfd pfd; - int rc; - - pfd.fd = wl_display_get_fd(handle->wayland.display); - pfd.events = POLLIN; - while(MwTRUE) { - rc = wl_display_flush(handle->wayland.display); - if(errno != EAGAIN || rc != -1) { - break; - } - - if(poll(&pfd, 1, -1) == -1) { - break; - } - } -} - /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { struct pollfd fd; @@ -803,6 +1002,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_compositor); WL_INTERFACE(wl_seat); WL_INTERFACE(wl_output); + WL_INTERFACE(wl_data_device_manager); WL_INTERFACE(zwp_primary_selection_device_manager_v1); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); @@ -869,6 +1069,8 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Perform the initial commit and wait for the first configure event */ wl_surface_commit(r->wayland.framebuffer.surface); event_loop(r); + while(!r->wayland.configured) { + } /* setup decorations if we can */ if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { @@ -924,12 +1126,8 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.display = parent->wayland.display; - r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); - setup_callbacks(&r->wayland); - // printf("position %d %d\n", x, y); - r->wayland.registry = wl_display_get_registry(parent->wayland.display); r->wayland.display = parent->wayland.display; @@ -940,6 +1138,8 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { return; } + r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); + r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); @@ -1003,7 +1203,6 @@ static void setup_popup(MwLL r) { } r->wayland.popup = calloc(sizeof(struct _MwLLWaylandPopup), 0); - // r->wayland.popup->parent = parent; r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); @@ -1038,6 +1237,7 @@ static void setup_popup(MwLL r) { wl_surface_commit(r->wayland.framebuffer.surface); event_loop(r); } + /* Popup destroy function */ static void destroy_popup(MwLL r) { xdg_popup_destroy(r->wayland.popup->xdg_popup); @@ -1048,8 +1248,6 @@ static void destroy_popup(MwLL r) { wl_surface_destroy(r->wayland.framebuffer.surface); - // free(r->wayland.popup); - wl_registry_destroy(r->wayland.registry); } @@ -1090,6 +1288,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLForceRender(r); + pthread_mutex_init(&r->wayland.dispatch_mutex, NULL); + pthread_mutex_init(&r->wayland.pending_mutex, NULL); + return r; } @@ -1104,14 +1305,11 @@ static void MwLLDestroyImpl(MwLL handle) { buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); - if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { - primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; - - for(i = 0; i < arrlen(primary_selection->devices); i++) { - zwp_primary_selection_offer_v1_destroy(primary_selection->devices[i]->offer); - } + if(handle->wayland.supports_zwp) { + zwp_primary_selection_source_v1_destroy(handle->wayland.clipboard_source.zwp); + } else { + wl_data_source_destroy(handle->wayland.clipboard_source.wl); } - if(handle->wayland.icon != NULL) { buffer_destroy(handle->wayland.icon); wl_surface_destroy(handle->wayland.icon->surface); @@ -1164,6 +1362,7 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { static void MwLLSetWHImpl(MwLL handle, int w, int h) { region_invalidate(handle); + /* Prevent an integer underflow when the w/h is too low */ if((w < 10 || h < 10)) { handle->wayland.ww = 10; @@ -1173,7 +1372,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.ww = w; handle->wayland.wh = h; - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } @@ -1200,7 +1399,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } cairo_close_path(handle->wayland.cairo); cairo_fill(handle->wayland.cairo); - handle->wayland.events_pending = MwTRUE; + handle->wayland.events_pending += 1; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -1218,7 +1417,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { } cairo_close_path(handle->wayland.cairo); cairo_stroke(handle->wayland.cairo); - handle->wayland.events_pending = MwTRUE; + handle->wayland.events_pending += 1; } static void MwLLBeginDrawImpl(MwLL handle) { @@ -1226,7 +1425,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { update_buffer(&handle->wayland.framebuffer); - handle->wayland.events_pending = MwTRUE; + handle->wayland.events_pending += 1; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -1249,14 +1448,68 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } +static void* display_dispatch_thread(void* data) { + MwLL handle = data; + MwU64 pending = 0; + struct timespec timeout; + + timeout.tv_nsec = 100; + timeout.tv_sec = 0; + + while(pending == 0 && !handle->wayland.break_dispatch) { + pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); + } + + handle->wayland.break_dispatch = MwTRUE; + return (void*)pending; +}; +static void* force_render_thread(void* data) { + MwLL handle = data; + + while(!handle->wayland.force_render && !handle->wayland.events_pending) { + } + + handle->wayland.break_pending = MwTRUE; + return NULL; +}; + static int MwLLPendingImpl(MwLL handle) { - return handle->wayland.events_pending || wl_display_dispatch(handle->wayland.display); + pthread_t t1, t2; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_create(&t1, &attr, display_dispatch_thread, handle); + pthread_create(&t2, &attr, force_render_thread, handle); + + while(MwTRUE) { + if(handle->wayland.break_dispatch) { + pthread_join(t1, (void**)&handle->wayland.events_pending); + handle->wayland.break_dispatch = MwFALSE; + + handle->wayland.force_render = MwTRUE; + + pthread_cancel(t2); + break; + } + + if(handle->wayland.break_pending) { + + handle->wayland.break_dispatch = MwTRUE; + pthread_join(t2, NULL); + pthread_join(t1, (void**)&handle->wayland.events_pending); + handle->wayland.break_pending = MwFALSE; + + break; + } + } + + return handle->wayland.events_pending; } static void MwLLNextEventImpl(MwLL handle) { event_loop(handle); if(handle->wayland.events_pending) { - handle->wayland.events_pending = MwFALSE; + handle->wayland.events_pending = 0; } } @@ -1485,59 +1738,28 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { + if(handle->wayland.clipboard_buffer != NULL) { + free(handle->wayland.clipboard_buffer); + } + handle->wayland.clipboard_buffer = malloc(strlen(text)); + strcpy(handle->wayland.clipboard_buffer, text); + + if(handle->wayland.supports_zwp) { + for(int i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; + zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + } + } else { + for(int i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; + wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); + } + } } -static char* MwLLGetClipboardImpl(MwLL handle) { - if(WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1) != NULL) { - primary_selection_context_t* primary_selection = WAYLAND_GET_INTERFACE(handle->wayland, zwp_primary_selection_device_manager_v1)->context; - int i, n = 0; - int fds[2]; - struct timeval timeout; - fd_set set; - char* clip_buffer = NULL; - - if(pipe(fds) != 0) { - return NULL; - } - - FD_ZERO(&set); - FD_SET(fds[0], &set); - - timeout.tv_sec = 0; - timeout.tv_usec = 100; - - for(i = 0; i < arrlen(primary_selection->devices); i++) { - primary_selection_device_context_t* device = primary_selection->devices[i]; - size_t size = 0; - char ch; - int rc = 0; - - zwp_primary_selection_offer_v1_receive(device->offer, "text/plain", fds[1]); - - wl_flush(handle); - - fcntl(fds[0], F_SETFL, O_NONBLOCK); - - while(MwTRUE) { - rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); - if(rc <= 0) { - break; - } else { - read(fds[0], &ch, 1); - arrpush(clip_buffer, ch); - if(n++ >= 10240) { - break; - } - } - } - return clip_buffer; - } - - // zwp_primary_selection_source_v1_send(); - - // arrpush(primary_selection->devices, device); - } - return NULL; +static void MwLLGetClipboardImpl(MwLL handle) { + /* no-op */ + return; } static void MwLLMakeToolWindowImpl(MwLL handle) { From bed63dd245c1aeb75098915a2c91001ffdac8057 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 17:14:39 -0700 Subject: [PATCH 067/409] clipboard: fix syntax --- examples/basic/clipboard.c | 5 ++--- src/backend/wayland.c | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 57f14984b..6cfeb833b 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -25,9 +25,10 @@ void resize(MwWidget handle, void* user_data, void* call_data) { NULL); } void clipboard(MwWidget handle, void* user_data, void* call_data) { + char* clipboard = call_data; + (void)handle; (void)user_data; - char* clipboard = call_data; if(clipboard != NULL) { MwVaApply(text, MwNtext, clipboard); @@ -39,8 +40,6 @@ void clipboard(MwWidget handle, void* user_data, void* call_data) { } int main() { - MwMenu m, m2; - MwLibraryInit(); window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 400, 400, diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8131e7044..a5653ed06 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -14,7 +14,6 @@ * - MwLLGrabPointerImpl * - MwLLMakePopupImpl * - MwLLShowImpl - * - MwLLDetachImpl */ /* TODO: find out what FreeBSD and such wants us to include */ From afecb048489fe686aa4b352692d76e4ff5951e2e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 17:14:57 -0700 Subject: [PATCH 068/409] clipboard: don't set clipboard after pasting --- examples/basic/clipboard.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 6cfeb833b..c8882d352 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -1,4 +1,3 @@ -#define _MILSKO #include MwWidget window, instructions, text; @@ -35,8 +34,6 @@ void clipboard(MwWidget handle, void* user_data, void* call_data) { MwForceRender(text); } MwForceRender(window); - - MwLLSetClipboard(window->lowlevel, "Milsko clipboard test"); } int main() { From 324257c43fb40c832f00588dfb6cd37edfa0d2e9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 19:15:33 -0700 Subject: [PATCH 069/409] wayland: no pthreads needed --- src/backend/wayland.c | 50 +++---------------------------------------- 1 file changed, 3 insertions(+), 47 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index a5653ed06..515e88b8d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1447,9 +1447,8 @@ static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static void* display_dispatch_thread(void* data) { - MwLL handle = data; - MwU64 pending = 0; +static int MwLLPendingImpl(MwLL handle) { + MwBool pending = MwFALSE; struct timespec timeout; timeout.tv_nsec = 100; @@ -1459,50 +1458,7 @@ static void* display_dispatch_thread(void* data) { pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); } - handle->wayland.break_dispatch = MwTRUE; - return (void*)pending; -}; -static void* force_render_thread(void* data) { - MwLL handle = data; - - while(!handle->wayland.force_render && !handle->wayland.events_pending) { - } - - handle->wayland.break_pending = MwTRUE; - return NULL; -}; - -static int MwLLPendingImpl(MwLL handle) { - pthread_t t1, t2; - pthread_attr_t attr; - - pthread_attr_init(&attr); - pthread_create(&t1, &attr, display_dispatch_thread, handle); - pthread_create(&t2, &attr, force_render_thread, handle); - - while(MwTRUE) { - if(handle->wayland.break_dispatch) { - pthread_join(t1, (void**)&handle->wayland.events_pending); - handle->wayland.break_dispatch = MwFALSE; - - handle->wayland.force_render = MwTRUE; - - pthread_cancel(t2); - break; - } - - if(handle->wayland.break_pending) { - - handle->wayland.break_dispatch = MwTRUE; - pthread_join(t2, NULL); - pthread_join(t1, (void**)&handle->wayland.events_pending); - handle->wayland.break_pending = MwFALSE; - - break; - } - } - - return handle->wayland.events_pending; + return handle->wayland.force_render || handle->wayland.events_pending || pending; } static void MwLLNextEventImpl(MwLL handle) { From a03065ae528f6c2b448647b8247a1e15106839a7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 19:16:01 -0700 Subject: [PATCH 070/409] wayland: forgot to commit .h --- include/Mw/LowLevel/Wayland.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index dcdcd5f55..99ac280d5 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -139,6 +139,8 @@ struct _MwLLWayland { wayland_protocol_t* value; }* wl_protocol_map; + MwBool always_render; + struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; @@ -184,9 +186,6 @@ struct _MwLLWayland { MwBool force_render; - pthread_mutex_t dispatch_mutex; - pthread_mutex_t pending_mutex; - MwBool break_dispatch; MwBool break_pending; From 029e62d765b18c5d9332331fe2a0eed83058bdce Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 20:30:22 -0700 Subject: [PATCH 071/409] wayland: opengl --- include/Mw/LowLevel/Wayland.h | 6 +- pl/rules.pl | 11 +- src/backend/wayland.c | 53 ++++++---- src/widget/opengl.c | 183 +++++++++++++++++++++++++++++++++- 4 files changed, 227 insertions(+), 26 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 99ac280d5..0d3227f6e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -170,8 +170,7 @@ struct _MwLLWayland { struct wl_keyboard* keyboard; MwU32 keyboard_serial; - MwU64 events_pending; - MwBool test; + MwU64 events_pending; MwU32 mod_state; @@ -186,8 +185,7 @@ struct _MwLLWayland { MwBool force_render; - MwBool break_dispatch; - MwBool break_pending; + MwBool hmmmm; struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/pl/rules.pl b/pl/rules.pl index 1ad3ff3de..123c128f0 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -32,6 +32,10 @@ if (grep(/^wayland$/, @backends)) { add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); + if (param_get("opengl")) { + add_libs(`pkg-config --libs egl wayland-egl`); + } + scan_wayland_protocol("stable", "xdg-shell", ""); scan_wayland_protocol("stable", "tablet", "-v2"); scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); @@ -39,7 +43,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); - $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; + $gl_libs = "-lGL -lGLU"; } if (param_get("stb-image")) { @@ -48,6 +52,11 @@ if (param_get("stb-image")) { if (param_get("stb-truetype")) { add_cflags("-DUSE_STB_TRUETYPE"); } + +if (param_get("opengl")) { + add_cflags("-DHAS_OPENGL"); +} + if (param_get("freetype2")) { add_cflags("-DUSE_FREETYPE2"); if ($cross) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 515e88b8d..6108aa742 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -8,7 +8,6 @@ #include #include #include -#include /* TODO: * - MwLLGrabPointerImpl @@ -360,6 +359,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); + self->wayland.events_pending += 1; /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ @@ -396,8 +396,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } } - MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; + if(!self->wayland.always_render) { + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; + } }; /* `wl_pointer.axis` callback */ @@ -556,8 +558,11 @@ static void keyboard_key(void* data, } } } - MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; + + if(!self->wayland.always_render) { + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; + } }; /* `wl_keyboard.modifiers` callback */ @@ -783,6 +788,8 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); + MwLLForceRender(self); + /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { @@ -891,6 +898,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); update_buffer(&wayland->framebuffer); + wayland->events_pending += 1; }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { @@ -1287,9 +1295,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLForceRender(r); - pthread_mutex_init(&r->wayland.dispatch_mutex, NULL); - pthread_mutex_init(&r->wayland.pending_mutex, NULL); - return r; } @@ -1398,6 +1403,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } cairo_close_path(handle->wayland.cairo); cairo_fill(handle->wayland.cairo); + handle->wayland.events_pending += 1; } @@ -1416,6 +1422,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { } cairo_close_path(handle->wayland.cairo); cairo_stroke(handle->wayland.cairo); + handle->wayland.events_pending += 1; } @@ -1424,6 +1431,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { update_buffer(&handle->wayland.framebuffer); + handle->wayland.events_pending += 1; } @@ -1451,20 +1459,29 @@ static int MwLLPendingImpl(MwLL handle) { MwBool pending = MwFALSE; struct timespec timeout; - timeout.tv_nsec = 100; - timeout.tv_sec = 0; - - while(pending == 0 && !handle->wayland.break_dispatch) { - pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); + if(handle->wayland.always_render) { + /* call event loop twice to make it to flush out events like mouse events and ensure we don't lag the render when doing that + */ + event_loop(handle); + return event_loop(handle); } - return handle->wayland.force_render || handle->wayland.events_pending || pending; + timeout.tv_nsec = 10; + timeout.tv_sec = 0; + + printf("%d\n", handle->wayland.force_render); + return handle->wayland.force_render || handle->wayland.events_pending || wl_display_dispatch_timeout(handle->wayland.display, &timeout); } static void MwLLNextEventImpl(MwLL handle) { - event_loop(handle); - if(handle->wayland.events_pending) { - handle->wayland.events_pending = 0; + if(!handle->wayland.always_render) { + event_loop(handle); + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } + if(handle->wayland.force_render) { + handle->wayland.force_render = 0; + } } } @@ -1575,6 +1592,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + handle->wayland.force_render = MwTRUE; + /* if(handle->wayland.egl_setup) { timed_redraw_by_epoch(handle, 25); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index a1c36d96f..1391fa41b 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,6 +1,7 @@ #include #include +#ifdef HAS_OPENGL #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); @@ -42,6 +43,19 @@ typedef struct x11opengl { } x11opengl_t; #endif +#ifdef USE_WAYLAND +#include +#include + +typedef struct waylandopengl { + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; +} waylandopengl_t; +#endif + static int create(MwWidget handle) { void* r = NULL; #ifdef USE_GDI @@ -105,7 +119,85 @@ static int create(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE}; + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_CONTEXT_MAJOR_VERSION, 1, + EGL_CONTEXT_MINOR_VERSION, 1, + EGL_NONE}; + EGLDisplay display; + waylandopengl_t* o = r = malloc(sizeof(*o)); + + handle->lowlevel->wayland.parent->wayland.always_render = MwTRUE; + handle->lowlevel->wayland.always_render = MwTRUE; + + display = eglGetDisplay(handle->lowlevel->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, &o->egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return MwFALSE; + } + + o->egl_window_native = + (EGLNativeWindowType)wl_egl_window_create(handle->lowlevel->wayland.framebuffer.surface, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + if(o->egl_window_native == EGL_NO_SURFACE) { + printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); + return MwFALSE; + } + + /* Create a surface */ + surface = eglCreateWindowSurface(display, o->egl_config, o->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, o->egl_config, EGL_NO_CONTEXT, contextAttribs); + if(context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return MwFALSE; + } + + if(!eglMakeCurrent(display, surface, surface, context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } + + o->egl_display = display; + o->egl_surface = surface; + o->egl_context = context; } #endif @@ -165,7 +257,11 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + waylandopengl_t* o = handle->internal; + + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + } } #endif } @@ -187,7 +283,12 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + waylandopengl_t* o = handle->internal; + if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { + printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); + }; + wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, 0, 0); + MwLLForceRender(handle->lowlevel); } #endif } @@ -209,11 +310,85 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + return eglGetProcAddress(name); } #endif return NULL; } +#else +#ifdef USE_GDI +typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); +typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); +typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); +typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); + +typedef struct gdiopengl { + HDC dc; + HGLRC gl; + + void* lib; + + MWwglCreateContext wglCreateContext; + MWwglMakeCurrent wglMakeCurrent; + MWwglDeleteContext wglDeleteContext; + MWwglGetProcAddress wglGetProcAddress; +} gdiopengl_t; +#endif +#ifdef USE_X11 +typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, int* attribList); +typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, GLXContext shareList, Bool direct); +typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); +typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); +typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); + +typedef struct x11opengl { + XVisualInfo* visual; + GLXContext gl; + + void* lib; + + MWglXChooseVisual glXChooseVisual; + MWglXCreateContext glXCreateContext; + MWglXDestroyContext glXDestroyContext; + MWglXMakeCurrent glXMakeCurrent; + MWglXSwapBuffers glXSwapBuffers; + MWglXGetProcAddress glXGetProcAddress; +} x11opengl_t; +#endif + +#ifdef USE_WAYLAND +#include +#include + +typedef struct waylandopengl { + struct wl_egl_window* egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; +} waylandopengl_t; + +#endif + +static int create(MwWidget handle) { + printf("Milsko compiled without OpenGL support! OpenGL widgets will not work properly.\n"); + return 1; +} + +static void destroy(MwWidget handle) { +} + +static void mwOpenGLMakeCurrentImpl(MwWidget handle) { +} + +static void mwOpenGLSwapBufferImpl(MwWidget handle) { +} + +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { + return NULL; +} +#endif static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { From 6946c1eaf349efc7660844d3bb5cbf844cfbaed9 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 22:26:19 -0700 Subject: [PATCH 072/409] wayland: opengl support --- include/Mw/LowLevel/Wayland.h | 6 +- pl/rules.pl | 11 +- src/backend/wayland.c | 53 ++++++---- src/widget/opengl.c | 188 +++++++++++++++++++++++++++++++++- 4 files changed, 229 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 99ac280d5..0d3227f6e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -170,8 +170,7 @@ struct _MwLLWayland { struct wl_keyboard* keyboard; MwU32 keyboard_serial; - MwU64 events_pending; - MwBool test; + MwU64 events_pending; MwU32 mod_state; @@ -186,8 +185,7 @@ struct _MwLLWayland { MwBool force_render; - MwBool break_dispatch; - MwBool break_pending; + MwBool hmmmm; struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/pl/rules.pl b/pl/rules.pl index 1ad3ff3de..123c128f0 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -32,6 +32,10 @@ if (grep(/^wayland$/, @backends)) { add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); + if (param_get("opengl")) { + add_libs(`pkg-config --libs egl wayland-egl`); + } + scan_wayland_protocol("stable", "xdg-shell", ""); scan_wayland_protocol("stable", "tablet", "-v2"); scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); @@ -39,7 +43,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); - $gl_libs = "-lEGL -lwayland-egl lGL -lGLU"; + $gl_libs = "-lGL -lGLU"; } if (param_get("stb-image")) { @@ -48,6 +52,11 @@ if (param_get("stb-image")) { if (param_get("stb-truetype")) { add_cflags("-DUSE_STB_TRUETYPE"); } + +if (param_get("opengl")) { + add_cflags("-DHAS_OPENGL"); +} + if (param_get("freetype2")) { add_cflags("-DUSE_FREETYPE2"); if ($cross) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 515e88b8d..62a8b41b0 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -8,7 +8,6 @@ #include #include #include -#include /* TODO: * - MwLLGrabPointerImpl @@ -46,7 +45,7 @@ static void new_protocol(void* data, struct wl_registry* registry, wayland_protocol_callback_table_t* cb = shget(wayland->wl_protocol_setup_map, interface); if(cb != NULL) { - char* inter = malloc(strlen(interface)); + char* inter = malloc(strlen(interface) + 1); strcpy(inter, interface); shput(wayland->wl_protocol_map, inter, cb->setup(name, data)); } else { @@ -360,6 +359,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); + self->wayland.events_pending += 1; /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ @@ -396,8 +396,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } } - MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; + if(!self->wayland.always_render) { + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; + } }; /* `wl_pointer.axis` callback */ @@ -433,8 +435,6 @@ static void keyboard_keymap(void* data, close(fd); struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); - xkb_keymap_unref(wayland->xkb_keymap); - xkb_state_unref(wayland->xkb_state); wayland->xkb_keymap = xkb_keymap; wayland->xkb_state = xkb_state; @@ -556,8 +556,11 @@ static void keyboard_key(void* data, } } } - MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; + + if(!self->wayland.always_render) { + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; + } }; /* `wl_keyboard.modifiers` callback */ @@ -783,6 +786,8 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); + MwLLForceRender(self); + /*if(!self->wayland.egl_setup) { self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); } else { @@ -891,6 +896,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); update_buffer(&wayland->framebuffer); + wayland->events_pending += 1; }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { @@ -1287,9 +1293,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLForceRender(r); - pthread_mutex_init(&r->wayland.dispatch_mutex, NULL); - pthread_mutex_init(&r->wayland.pending_mutex, NULL); - return r; } @@ -1398,6 +1401,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } cairo_close_path(handle->wayland.cairo); cairo_fill(handle->wayland.cairo); + handle->wayland.events_pending += 1; } @@ -1416,6 +1420,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { } cairo_close_path(handle->wayland.cairo); cairo_stroke(handle->wayland.cairo); + handle->wayland.events_pending += 1; } @@ -1424,6 +1429,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { update_buffer(&handle->wayland.framebuffer); + handle->wayland.events_pending += 1; } @@ -1451,20 +1457,25 @@ static int MwLLPendingImpl(MwLL handle) { MwBool pending = MwFALSE; struct timespec timeout; - timeout.tv_nsec = 100; - timeout.tv_sec = 0; - - while(pending == 0 && !handle->wayland.break_dispatch) { - pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); + if(handle->wayland.always_render) { + return event_loop(handle); } - return handle->wayland.force_render || handle->wayland.events_pending || pending; + timeout.tv_nsec = 10; + timeout.tv_sec = 0; + + return handle->wayland.force_render || handle->wayland.events_pending || wl_display_dispatch_timeout(handle->wayland.display, &timeout); } static void MwLLNextEventImpl(MwLL handle) { - event_loop(handle); - if(handle->wayland.events_pending) { - handle->wayland.events_pending = 0; + if(!handle->wayland.always_render) { + event_loop(handle); + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } + if(handle->wayland.force_render) { + handle->wayland.force_render = 0; + } } } @@ -1575,6 +1586,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + handle->wayland.force_render = MwTRUE; + /* if(handle->wayland.egl_setup) { timed_redraw_by_epoch(handle, 25); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index a1c36d96f..e0ee8acc5 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,6 +1,7 @@ #include #include +#ifdef HAS_OPENGL #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); @@ -42,6 +43,19 @@ typedef struct x11opengl { } x11opengl_t; #endif +#ifdef USE_WAYLAND +#include +#include + +typedef struct waylandopengl { + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; +} waylandopengl_t; +#endif + static int create(MwWidget handle) { void* r = NULL; #ifdef USE_GDI @@ -105,7 +119,89 @@ static int create(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = + { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_NONE}; + EGLint contextAttribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 1, + EGL_CONTEXT_MAJOR_VERSION, 1, + EGL_CONTEXT_MINOR_VERSION, 1, + EGL_NONE}; + EGLDisplay display; + waylandopengl_t* o = r = malloc(sizeof(*o)); + MwLL topmost_parent = handle->lowlevel->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; + + while(topmost_parent->wayland.parent != NULL) { + topmost_parent = topmost_parent->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; + } + + display = eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->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, &o->egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return MwFALSE; + } + + o->egl_window_native = + (EGLNativeWindowType)wl_egl_window_create(handle->lowlevel->wayland.framebuffer.surface, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + if(o->egl_window_native == EGL_NO_SURFACE) { + printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); + return MwFALSE; + } + + /* Create a surface */ + surface = eglCreateWindowSurface(display, o->egl_config, o->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, o->egl_config, EGL_NO_CONTEXT, contextAttribs); + if(context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return MwFALSE; + } + + if(!eglMakeCurrent(display, surface, surface, context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } + + o->egl_display = display; + o->egl_surface = surface; + o->egl_context = context; } #endif @@ -165,7 +261,11 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + waylandopengl_t* o = handle->internal; + + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + } } #endif } @@ -187,7 +287,13 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + waylandopengl_t* o = handle->internal; + eglSwapInterval(o->egl_display, 0); + if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { + printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); + }; + wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, 0, 0); + MwLLForceRender(handle->lowlevel); } #endif } @@ -209,11 +315,85 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ + return eglGetProcAddress(name); } #endif return NULL; } +#else +#ifdef USE_GDI +typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); +typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); +typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); +typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); + +typedef struct gdiopengl { + HDC dc; + HGLRC gl; + + void* lib; + + MWwglCreateContext wglCreateContext; + MWwglMakeCurrent wglMakeCurrent; + MWwglDeleteContext wglDeleteContext; + MWwglGetProcAddress wglGetProcAddress; +} gdiopengl_t; +#endif +#ifdef USE_X11 +typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, int* attribList); +typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, GLXContext shareList, Bool direct); +typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); +typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, GLXContext ctx); +typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); +typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); + +typedef struct x11opengl { + XVisualInfo* visual; + GLXContext gl; + + void* lib; + + MWglXChooseVisual glXChooseVisual; + MWglXCreateContext glXCreateContext; + MWglXDestroyContext glXDestroyContext; + MWglXMakeCurrent glXMakeCurrent; + MWglXSwapBuffers glXSwapBuffers; + MWglXGetProcAddress glXGetProcAddress; +} x11opengl_t; +#endif + +#ifdef USE_WAYLAND +#include +#include + +typedef struct waylandopengl { + struct wl_egl_window* egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; +} waylandopengl_t; + +#endif + +static int create(MwWidget handle) { + printf("Milsko compiled without OpenGL support! OpenGL widgets will not work properly.\n"); + return 1; +} + +static void destroy(MwWidget handle) { +} + +static void mwOpenGLMakeCurrentImpl(MwWidget handle) { +} + +static void mwOpenGLSwapBufferImpl(MwWidget handle) { +} + +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { + return NULL; +} +#endif static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { From f3683dece30e4c1552e590ec60e40bf727bfa7ac Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 22:38:01 -0700 Subject: [PATCH 073/409] undo HAS_OPENGL stuff --- pl/rules.pl | 4 --- src/backend/wayland.c | 13 +++----- src/widget/opengl.c | 75 ------------------------------------------- 3 files changed, 5 insertions(+), 87 deletions(-) diff --git a/pl/rules.pl b/pl/rules.pl index 123c128f0..f55fce33f 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -53,10 +53,6 @@ if (param_get("stb-truetype")) { add_cflags("-DUSE_STB_TRUETYPE"); } -if (param_get("opengl")) { - add_cflags("-DHAS_OPENGL"); -} - if (param_get("freetype2")) { add_cflags("-DUSE_FREETYPE2"); if ($cross) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 62a8b41b0..3e4b9ee09 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1468,14 +1468,11 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - if(!handle->wayland.always_render) { - event_loop(handle); - if(handle->wayland.events_pending) { - handle->wayland.events_pending = 0; - } - if(handle->wayland.force_render) { - handle->wayland.force_render = 0; - } + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } + if(handle->wayland.force_render) { + handle->wayland.force_render = 0; } } diff --git a/src/widget/opengl.c b/src/widget/opengl.c index e0ee8acc5..8e90d39c4 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,7 +1,6 @@ #include #include -#ifdef HAS_OPENGL #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); @@ -320,80 +319,6 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif return NULL; } -#else -#ifdef USE_GDI -typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); -typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); -typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); -typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); - -typedef struct gdiopengl { - HDC dc; - HGLRC gl; - - void* lib; - - MWwglCreateContext wglCreateContext; - MWwglMakeCurrent wglMakeCurrent; - MWwglDeleteContext wglDeleteContext; - MWwglGetProcAddress wglGetProcAddress; -} gdiopengl_t; -#endif -#ifdef USE_X11 -typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, int* attribList); -typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, GLXContext shareList, Bool direct); -typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); -typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, GLXContext ctx); -typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); -typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); - -typedef struct x11opengl { - XVisualInfo* visual; - GLXContext gl; - - void* lib; - - MWglXChooseVisual glXChooseVisual; - MWglXCreateContext glXCreateContext; - MWglXDestroyContext glXDestroyContext; - MWglXMakeCurrent glXMakeCurrent; - MWglXSwapBuffers glXSwapBuffers; - MWglXGetProcAddress glXGetProcAddress; -} x11opengl_t; -#endif - -#ifdef USE_WAYLAND -#include -#include - -typedef struct waylandopengl { - struct wl_egl_window* egl_window_native; - EGLDisplay egl_display; - EGLContext egl_context; - EGLSurface egl_surface; - EGLConfig egl_config; -} waylandopengl_t; - -#endif - -static int create(MwWidget handle) { - printf("Milsko compiled without OpenGL support! OpenGL widgets will not work properly.\n"); - return 1; -} - -static void destroy(MwWidget handle) { -} - -static void mwOpenGLMakeCurrentImpl(MwWidget handle) { -} - -static void mwOpenGLSwapBufferImpl(MwWidget handle) { -} - -static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { - return NULL; -} -#endif static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { From f32f6cefc09f0a4e9015c30e60c279a8572c45c0 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 30 Dec 2025 22:44:04 -0700 Subject: [PATCH 074/409] wayland: accidentally removed event_loop call from MwLLNextEventImpl --- src/backend/wayland.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 3e4b9ee09..556a9c0bf 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1468,6 +1468,9 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { + if(!handle->wayland.always_render) { + event_loop(handle); + } if(handle->wayland.events_pending) { handle->wayland.events_pending = 0; } From 6183a1ccda326c44ee9e9c43eaa3abd0dc40a9da Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 2 Jan 2026 00:24:48 +0900 Subject: [PATCH 075/409] update license --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 4e2b25f16..a7729adbf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2025, Pyrite development team +Copyright (c) 2025-2026, Pyrite development team All rights reserved. Redistribution and use in source and binary forms, with or without From bed668b84a830175a2982c2871a13424afb10e3f Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 2 Jan 2026 14:19:30 -0700 Subject: [PATCH 076/409] wayland: fix misc. crashes on the destruction of widgets --- include/Mw/LowLevel/Wayland.h | 2 +- src/backend/wayland.c | 62 ++++++++++++++++++++--------------- 2 files changed, 37 insertions(+), 27 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0d3227f6e..a0282c3c5 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -185,7 +185,7 @@ struct _MwLLWayland { MwBool force_render; - MwBool hmmmm; + MwBool disabled; struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 556a9c0bf..a686db4bc 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -296,8 +296,11 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL } static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - wl_data_device_manager_destroy(wayland->clipboard_manager.wl); - wl_data_source_destroy(wayland->clipboard_source.wl); + if(wayland->clipboard_manager.wl != NULL && !wayland->supports_zwp) { + wl_data_device_manager_destroy(wayland->clipboard_manager.wl); + wl_data_source_destroy(wayland->clipboard_source.wl); + wayland->clipboard_manager.wl = NULL; + } } /* zwp_primary_selection_device_manager_v1 setup function */ @@ -605,22 +608,24 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } - if(self->wayland.supports_zwp) { - device_ctx->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); - } else { - device_ctx->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); - } - device_ctx->ll = self; - device_ctx->seat = wl_seat; - device_ctx->capabilities = capabilities; + if(self->wayland.clipboard_manager.wl != NULL) { + if(self->wayland.supports_zwp) { + device_ctx->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + } else { + device_ctx->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + } + device_ctx->ll = self; + device_ctx->seat = wl_seat; + device_ctx->capabilities = capabilities; - if(self->wayland.supports_zwp) { - zwp_primary_selection_device_v1_add_listener(device_ctx->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx); - } else { - wl_data_device_add_listener(device_ctx->device.wl, &wl_data_device_listener, device_ctx); - } + if(self->wayland.supports_zwp) { + zwp_primary_selection_device_v1_add_listener(device_ctx->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx); + } else { + wl_data_device_add_listener(device_ctx->device.wl, &wl_data_device_listener, device_ctx); + } - arrpush(self->wayland.clipboard_devices, device_ctx); + arrpush(self->wayland.clipboard_devices, device_ctx); + } }; static void output_geometry(void* data, @@ -1100,6 +1105,8 @@ static void destroy_toplevel(MwLL r) { zxdg_decoration_manager_v1_destroy(dec->manager); } + wl_surface_destroy(r->wayland.framebuffer.surface); + wl_compositor_destroy(r->wayland.compositor); xdg_surface_destroy(r->wayland.toplevel->xdg_surface); @@ -1190,11 +1197,14 @@ static void setup_popup(MwLL r) { struct xdg_surface* xdg_surface; MwLL topmost_parent = r->wayland.parent; + r->wayland.type = MWLL_WAYLAND_POPUP; + while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { topmost_parent = topmost_parent->wayland.parent; } - r->wayland.type = MWLL_WAYLAND_POPUP; + r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); + memset(r->wayland.popup, 0, sizeof(struct _MwLLWaylandPopup)); setup_callbacks(&r->wayland); @@ -1207,10 +1217,6 @@ static void setup_popup(MwLL r) { return; } - r->wayland.popup = calloc(sizeof(struct _MwLLWaylandPopup), 0); - - r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); @@ -1224,6 +1230,8 @@ static void setup_popup(MwLL r) { xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; + r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.popup->xdg_surface = xdg_wm_base_get_xdg_surface(r->wayland.popup->xdg_wm_base, r->wayland.framebuffer.surface); @@ -1299,11 +1307,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static void MwLLDestroyImpl(MwLL handle) { int i; - event_loop(handle); - MwLLDestroyCommon(handle); - buffer_destroy(&handle->wayland.framebuffer); + event_loop(handle); + + framebuffer_destroy(&handle->wayland); buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); @@ -1329,6 +1337,7 @@ static void MwLLDestroyImpl(MwLL handle) { void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); } shfree(handle->wayland.wl_protocol_map); shfree(handle->wayland.wl_protocol_setup_map); @@ -1351,7 +1360,7 @@ 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) { + if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { region_invalidate(handle); handle->wayland.x = x; handle->wayland.y = y; @@ -1555,7 +1564,8 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { int i = 0; if(handle->wayland.icon == NULL) { - handle->wayland.icon = calloc(sizeof(struct _MwLLWaylandShmBuffer), 0); + handle->wayland.icon = malloc(sizeof(struct _MwLLWaylandShmBuffer)); + memset(handle->wayland.icon, 0, sizeof(struct _MwLLWaylandShmBuffer)); handle->wayland.icon->shm = handle->wayland.framebuffer.shm; } From a148b3bedfe2ff6baf56bb433404d4bf613420cd Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sat, 3 Jan 2026 18:27:34 -0700 Subject: [PATCH 077/409] wayland: use mutexes to ensure that MwLLDestroyImpl never conflicts with wayland events. --- include/Mw/LowLevel/Wayland.h | 7 +++ src/backend/wayland.c | 87 +++++++++++++++++++++++++++++++---- 2 files changed, 86 insertions(+), 8 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index a0282c3c5..1e8e1e130 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -16,6 +16,7 @@ #include #include #include +#include MWDECL int MwLLWaylandCallInit(void); @@ -191,6 +192,12 @@ struct _MwLLWayland { struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; + /* + Events mutex. Any time a keyboard/mouse event happens, we try to lock this for 100 milliseconds, then give up if we can't do it. This is used in conjunction with some code in the MwLLDestroyImpl to make sure that destroy is NEVER interferes with an ongoing event. + + IOI_XD: This sounds like a hilariously rare edge case, so it's almost funnier that this happened with 100% certainty for me and I spent day(s) trying to figure out what was happening. */ + pthread_mutex_t eventsMutex; + cairo_surface_t* cs; cairo_t* cairo; }; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index a686db4bc..86cd489bd 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -340,10 +340,18 @@ static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _Mw static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - MwLL self = data; + MwLL self = data; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; self->wayland.pointer_serial = serial; wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); + + pthread_mutex_unlock(&self->wayland.eventsMutex); }; /* `wl_pointer.leave` callback */ @@ -357,6 +365,12 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL self = data; MwLLMouse p; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); @@ -364,14 +378,22 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLLDispatch(self, move, &p); self->wayland.events_pending += 1; + pthread_mutex_unlock(&self->wayland.eventsMutex); /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; /* `wl_pointer.button` callback */ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { - MwLL self = data; - MwLLMouse p; + MwLL self = data; + MwLLMouse p; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; + p.point = self->wayland.cur_mouse_pos; if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { switch(button) { @@ -403,6 +425,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self, draw, NULL); self->wayland.events_pending += 1; } + pthread_mutex_unlock(&self->wayland.eventsMutex); }; /* `wl_pointer.axis` callback */ @@ -450,11 +473,19 @@ static void keyboard_enter(void* data, MwU32 serial, struct wl_surface* surface, struct wl_array* keys) { - MwLL self = data; + MwLL self = data; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; + self->wayland.keyboard_serial = serial; MwLLDispatch(self, focus_in, NULL); self->wayland.events_pending += 1; + pthread_mutex_unlock(&self->wayland.eventsMutex); }; /* `wl_keyboard.leave` callback */ @@ -462,9 +493,18 @@ static void keyboard_leave(void* data, struct wl_keyboard* wl_keyboard, MwU32 serial, struct wl_surface* surface) { - MwLL self = data; + MwLL self = data; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; + MwLLDispatch(self, focus_out, NULL); self->wayland.events_pending += 1; + + pthread_mutex_unlock(&self->wayland.eventsMutex); }; /* `wl_keyboard.key` callback */ @@ -474,7 +514,13 @@ static void keyboard_key(void* data, MwU32 time, MwU32 key, MwU32 state) { - MwLL self = data; + MwLL self = data; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; xkb_layout_index_t layout; @@ -564,6 +610,8 @@ static void keyboard_key(void* data, MwLLDispatch(self, draw, NULL); self->wayland.events_pending += 1; } + + pthread_mutex_unlock(&self->wayland.eventsMutex); }; /* `wl_keyboard.modifiers` callback */ @@ -574,11 +622,19 @@ static void keyboard_modifiers(void* data, MwU32 mods_latched, MwU32 mods_locked, MwU32 group) { - MwLL self = data; + MwLL self = data; + struct timespec t; + t.tv_nsec = 100; + + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { + return; + }; self->wayland.mod_state = 0; self->wayland.mod_state |= mods_depressed; self->wayland.mod_state |= mods_locked; + + pthread_mutex_unlock(&self->wayland.eventsMutex); }; struct wl_keyboard_listener keyboard_listener = { @@ -1305,7 +1361,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } static void MwLLDestroyImpl(MwLL handle) { - int i; + int i; + struct timeval tv; + int select_ret; + + pthread_mutex_lock(&handle->wayland.eventsMutex); MwLLDestroyCommon(handle); @@ -1349,6 +1409,16 @@ static void MwLLDestroyImpl(MwLL handle) { wl_keyboard_destroy(handle->wayland.keyboard); } + /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ + tv.tv_sec = 0; + tv.tv_usec = 250; + do { + select_ret = select(1, NULL, NULL, NULL, &tv); + } while((select_ret == -1) && (errno == EINTR)); + + pthread_mutex_unlock(&handle->wayland.eventsMutex); + pthread_mutex_destroy(&handle->wayland.eventsMutex); + free(handle); } @@ -1465,6 +1535,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { static int MwLLPendingImpl(MwLL handle) { MwBool pending = MwFALSE; struct timespec timeout; + int i; if(handle->wayland.always_render) { return event_loop(handle); From 30a100fd286917663088e94f5a22b839813996ad Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sat, 3 Jan 2026 19:21:03 -0700 Subject: [PATCH 078/409] wayland/opengl: set EGL_DEPTH_SIZE to 24 --- src/widget/opengl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 8e90d39c4..578b8817b 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -131,6 +131,7 @@ static int create(MwWidget handle) { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 24, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE}; EGLint contextAttribs[] = { From 933b5198c73fff6b0813a84bee33258fad64fe1f Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 11:12:57 -0700 Subject: [PATCH 079/409] wayland/vulkan: quickly get that going --- src/widget/vulkan.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 441bc2731..b78e7429b 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -13,6 +13,9 @@ #ifdef USE_X11 #define VK_USE_PLATFORM_XLIB_KHR 1 #endif +#ifdef USE_WAYLAND +#define VK_USE_PLATFORM_WAYLAND_KHR 1 +#endif #include #include @@ -22,6 +25,9 @@ #ifdef USE_X11 #include #endif +#ifdef USE_WAYLAND +#include +#endif #ifdef HAS_VK_ENUM_STRING_HELPER #include @@ -219,6 +225,20 @@ static MwErrorEnum vulkan_instance_setup(MwWidget handle, vulkan_t* o) { arrput(enabledExtensions, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); } #endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + MwLL topmost_parent = handle->lowlevel->wayland.parent; + + arrput(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); + /* take this opprutunity to set the widget to always render */ + topmost_parent->wayland.always_render = MwTRUE; + + while(topmost_parent->wayland.parent != NULL) { + topmost_parent = topmost_parent->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; + } + } +#endif /* passing null gives us all the extensions provided by the current vulkan implementation */ VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL)); @@ -313,6 +333,20 @@ static MwErrorEnum vulkan_surface_setup(MwWidget handle, vulkan_t* o) { }; VK_CMD(_vkCreateXlibSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface)); } +#endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendWayland) { + LOAD_VK_FUNCTION(vkCreateWaylandSurfaceKHR); + + VkWaylandSurfaceCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR, + .pNext = NULL, + .flags = 0, + .display = handle->lowlevel->wayland.display, + .surface = handle->lowlevel->wayland.framebuffer.surface, + }; + VK_CMD(_vkCreateWaylandSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface)); + } #endif return MwEsuccess; } From 8cdffa12ae8e070fec70560ceed974be0c4f137c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 11:13:59 -0700 Subject: [PATCH 080/409] wayland/opengl: fix o->egl_window_native warning --- src/widget/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 578b8817b..0dedd7fed 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -174,7 +174,7 @@ static int create(MwWidget handle) { o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create(handle->lowlevel->wayland.framebuffer.surface, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); - if(o->egl_window_native == EGL_NO_SURFACE) { + if(!o->egl_window_native) { printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); return MwFALSE; } From 12f279e83ac1639e81b12075eff34962f4d9ab45 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 11:40:34 -0700 Subject: [PATCH 081/409] wayland: ensure every event callback uses the mutex --- src/backend/wayland.c | 168 +++++++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 74 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 86cd489bd..5d5dcda6d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -24,6 +24,21 @@ #include #endif +/* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ +#define WAYLAND_EVENT_OP_START(self) \ + do { \ + struct timespec t; \ + t.tv_sec = 0; \ + t.tv_nsec = 250; \ + if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { \ + /*printf("deadlock at line %d\n", __LINE__);*/ \ + return; \ + }; \ + } while(0); + +/* Footer for WAYLAND_EVENT_OP_START */ +#define WAYLAND_EVENT_OP_END(self) pthread_mutex_unlock(&self->wayland.eventsMutex); + /* Setup the framebuffer with the saved width/height */ static void framebuffer_setup(struct _MwLLWayland* wayland); /* Destroy the framebuffer */ @@ -41,16 +56,20 @@ static void region_invalidate(MwLL handle); static void new_protocol(void* data, struct wl_registry* registry, MwU32 name, const char* interface, MwU32 version) { - struct _MwLLWayland* wayland = data; + MwLL self = data; - wayland_protocol_callback_table_t* cb = shget(wayland->wl_protocol_setup_map, interface); + WAYLAND_EVENT_OP_START(self); + + wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { char* inter = malloc(strlen(interface) + 1); strcpy(inter, interface); - shput(wayland->wl_protocol_map, inter, cb->setup(name, data)); + shput(self->wayland.wl_protocol_map, inter, cb->setup(name, data)); } else { /* printf("unknown interface %s\n", interface); */ } + + WAYLAND_EVENT_OP_END(self); }; /* `wl_registry.global_remove` callback */ @@ -107,12 +126,21 @@ static void wl_data_device_enter(void* data, wl_fixed_t x, wl_fixed_t y, struct wl_data_offer* id) { - MwLL self = data; + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + self->wayland.clipboard_serial = serial; + + WAYLAND_EVENT_OP_END(self); }; static void wl_data_device_leave(void* data, struct wl_data_device* wl_data_device) { + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); wl_data_device_destroy(wl_data_device); + WAYLAND_EVENT_OP_END(self); }; static void wl_data_device_motion(void* data, struct wl_data_device* wl_data_device, @@ -213,12 +241,15 @@ static void wl_data_source_listener_send(void* data, const char* mime_type, int32_t fd) { MwLL self = data; + + WAYLAND_EVENT_OP_START(self); if(self->wayland.clipboard_buffer != NULL) { write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); close(fd); self->wayland.events_pending = 1; } + WAYLAND_EVENT_OP_END(self); }; static void wl_data_source_listener_cancelled(void* data, struct wl_data_source* wl_data_source); @@ -233,6 +264,8 @@ static void wl_data_source_listener_cancelled(void* data, struct wl_data_source* wl_data_source) { MwLL self = data; + WAYLAND_EVENT_OP_START(self); + wl_data_source_destroy(wl_data_source); self->wayland.clipboard_source.wl = wl_data_device_manager_create_data_source(self->wayland.clipboard_manager.wl); @@ -244,6 +277,8 @@ static void wl_data_source_listener_cancelled(void* data, wl_data_source_offer(self->wayland.clipboard_source.wl, "UTF8_STRING"); wl_data_source_add_listener(self->wayland.clipboard_source.wl, &wl_data_source_listener, self); + + WAYLAND_EVENT_OP_END(self); }; static void zwp_primary_selection_source_v1_send(void* data, @@ -251,17 +286,24 @@ static void zwp_primary_selection_source_v1_send(void* data, const char* mime_type, int32_t fd) { MwLL self = data; + + WAYLAND_EVENT_OP_START(self); + if(self->wayland.clipboard_buffer != NULL) { write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); close(fd); self->wayland.events_pending = 1; } + + WAYLAND_EVENT_OP_END(self); }; static void zwp_primary_selection_source_v1_cancelled(void* data, struct zwp_primary_selection_source_v1* wl_data_source) { MwLL self = data; + WAYLAND_EVENT_OP_START(self); + zwp_primary_selection_source_v1_destroy(self->wayland.clipboard_source.zwp); self->wayland.clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(self->wayland.clipboard_manager.zwp); @@ -271,6 +313,8 @@ static void zwp_primary_selection_source_v1_cancelled(void* data, zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "TEXT"); zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "STRING"); zwp_primary_selection_source_v1_offer(self->wayland.clipboard_source.zwp, "UTF8_STRING"); + + WAYLAND_EVENT_OP_END(self); }; struct zwp_primary_selection_source_v1_listener zwp_primary_selection_source_v1_listener = { @@ -327,31 +371,22 @@ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 n } static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - return; - zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp); - - zwp_primary_selection_source_v1_destroy(wayland->clipboard_source.zwp); - - free(data->listener); } /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { - MwLL self = data; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; self->wayland.pointer_serial = serial; wl_pointer_set_cursor(wl_pointer, serial, self->wayland.cursor.surface, 0, 0); - pthread_mutex_unlock(&self->wayland.eventsMutex); + WAYLAND_EVENT_OP_END(self); }; /* `wl_pointer.leave` callback */ @@ -365,12 +400,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL self = data; MwLLMouse p; - struct timespec t; - t.tv_nsec = 100; + WAYLAND_EVENT_OP_START(self); - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); @@ -378,21 +409,18 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLLDispatch(self, move, &p); self->wayland.events_pending += 1; - pthread_mutex_unlock(&self->wayland.eventsMutex); + + WAYLAND_EVENT_OP_END(self); /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; /* `wl_pointer.button` callback */ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { - MwLL self = data; - MwLLMouse p; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; + MwLLMouse p; - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; + WAYLAND_EVENT_OP_START(self); p.point = self->wayland.cur_mouse_pos; if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { @@ -425,7 +453,8 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self, draw, NULL); self->wayland.events_pending += 1; } - pthread_mutex_unlock(&self->wayland.eventsMutex); + + WAYLAND_EVENT_OP_END(self); }; /* `wl_pointer.axis` callback */ @@ -447,6 +476,7 @@ static void keyboard_keymap(void* data, int32_t fd, MwU32 size) { MwLL self = data; + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); @@ -473,19 +503,16 @@ static void keyboard_enter(void* data, MwU32 serial, struct wl_surface* surface, struct wl_array* keys) { - MwLL self = data; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; + WAYLAND_EVENT_OP_START(self); self->wayland.keyboard_serial = serial; MwLLDispatch(self, focus_in, NULL); self->wayland.events_pending += 1; - pthread_mutex_unlock(&self->wayland.eventsMutex); + + WAYLAND_EVENT_OP_END(self); }; /* `wl_keyboard.leave` callback */ @@ -493,18 +520,14 @@ static void keyboard_leave(void* data, struct wl_keyboard* wl_keyboard, MwU32 serial, struct wl_surface* surface) { - MwLL self = data; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; + WAYLAND_EVENT_OP_START(self); MwLLDispatch(self, focus_out, NULL); self->wayland.events_pending += 1; - pthread_mutex_unlock(&self->wayland.eventsMutex); + WAYLAND_EVENT_OP_END(self); }; /* `wl_keyboard.key` callback */ @@ -514,13 +537,10 @@ static void keyboard_key(void* data, MwU32 time, MwU32 key, MwU32 state) { - MwLL self = data; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; + + WAYLAND_EVENT_OP_START(self); - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; xkb_layout_index_t layout; @@ -611,7 +631,7 @@ static void keyboard_key(void* data, self->wayland.events_pending += 1; } - pthread_mutex_unlock(&self->wayland.eventsMutex); + WAYLAND_EVENT_OP_END(self); }; /* `wl_keyboard.modifiers` callback */ @@ -622,19 +642,15 @@ static void keyboard_modifiers(void* data, MwU32 mods_latched, MwU32 mods_locked, MwU32 group) { - MwLL self = data; - struct timespec t; - t.tv_nsec = 100; + MwLL self = data; - if(pthread_mutex_timedlock(&self->wayland.eventsMutex, &t) != 0) { - return; - }; + WAYLAND_EVENT_OP_START(self); self->wayland.mod_state = 0; self->wayland.mod_state |= mods_depressed; self->wayland.mod_state |= mods_locked; - pthread_mutex_unlock(&self->wayland.eventsMutex); + WAYLAND_EVENT_OP_END(self); }; struct wl_keyboard_listener keyboard_listener = { @@ -655,6 +671,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwLL self = data; wl_clipboard_device_context_t* device_ctx = malloc(sizeof(wl_clipboard_device_context_t)); + WAYLAND_EVENT_OP_START(self); + if(capabilities & WL_SEAT_CAPABILITY_KEYBOARD) { self->wayland.keyboard = wl_seat_get_keyboard(wl_seat); wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); @@ -682,6 +700,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, arrpush(self->wayland.clipboard_devices, device_ctx); } + + WAYLAND_EVENT_OP_END(self); }; static void output_geometry(void* data, @@ -849,13 +869,6 @@ static void xdg_toplevel_configure(void* data, MwLLForceRender(self); - /*if(!self->wayland.egl_setup) { - self->wayland.egl_setup = egl_setup(self, self->wayland.x, self->wayland.y, width, height); - } else { - wl_egl_window_resize(self->wayland.egl_window_native, width, height, 0, 0); - egl_resetup(self); - }*/ - return; }; @@ -869,7 +882,9 @@ static void decoration_configure( static void xdg_toplevel_close( void* data, struct xdg_toplevel* xdg_toplevel) { MwLL self = data; + WAYLAND_EVENT_OP_START(self); MwLLDispatch(self, close, NULL); + WAYLAND_EVENT_OP_END(self); }; /* `xdg_surface.configure` callback */ @@ -1279,9 +1294,7 @@ static void setup_popup(MwLL r) { xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); xdg_positioner_set_anchor_rect( - r->wayland.popup->xdg_positioner, - topmost_parent->wayland.cur_mouse_pos.x, - topmost_parent->wayland.cur_mouse_pos.y, + r->wayland.popup->xdg_positioner, 0, 0, 1, 1); xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; @@ -1361,11 +1374,18 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } static void MwLLDestroyImpl(MwLL handle) { - int i; - struct timeval tv; - int select_ret; + int i; + struct timeval tv; + struct timespec t = { + .tv_sec = 0, + .tv_nsec = 100, + }; + int select_ret; - pthread_mutex_lock(&handle->wayland.eventsMutex); + if(pthread_mutex_timedlock(&handle->wayland.eventsMutex, &t) != 0) { + printf("WARNING: Couldn't call MwLLDestroyImpl due to deadlock.\n"); + return; + }; MwLLDestroyCommon(handle); @@ -1411,7 +1431,7 @@ static void MwLLDestroyImpl(MwLL handle) { /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ tv.tv_sec = 0; - tv.tv_usec = 250; + tv.tv_usec = 500; do { select_ret = select(1, NULL, NULL, NULL, &tv); } while((select_ret == -1) && (errno == EINTR)); From d784770ca9340c39aa2e1a27dc7b9a47fd3c462b Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 13:01:44 -0700 Subject: [PATCH 082/409] wayland: popup positioning --- include/Mw/LowLevel/Wayland.h | 2 +- src/backend/wayland.c | 27 ++++++++++++++++++--------- src/widget/submenu.c | 1 + 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 1e8e1e130..cd9642484 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -74,7 +74,7 @@ struct _MwLLWaylandPopup { struct xdg_positioner* xdg_positioner; struct xdg_surface_listener xdg_surface_listener; struct xdg_wm_base* xdg_wm_base; - MwLL parent; + MwLL topmost_parent; }; /* Shared set of anything needed for a shm buffer. */ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5d5dcda6d..f6532fa41 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1263,12 +1263,14 @@ struct xdg_popup_listener popup_listener = { }; /* Popup setup function */ -static void setup_popup(MwLL r) { +static void setup_popup(MwLL r, int x, int y) { int i; struct xdg_surface* xdg_surface; MwLL topmost_parent = r->wayland.parent; r->wayland.type = MWLL_WAYLAND_POPUP; + r->wayland.x = x; + r->wayland.y = y; while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { topmost_parent = topmost_parent->wayland.parent; @@ -1276,6 +1278,7 @@ static void setup_popup(MwLL r) { r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); memset(r->wayland.popup, 0, sizeof(struct _MwLLWaylandPopup)); + r->wayland.popup->topmost_parent = topmost_parent; setup_callbacks(&r->wayland); @@ -1288,14 +1291,16 @@ static void setup_popup(MwLL r) { return; } - r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; + r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(topmost_parent->wayland, xdg_wm_base)->context; r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_anchor_rect( - r->wayland.popup->xdg_positioner, 0, 0, - 1, 1); + r->wayland.popup->xdg_positioner, 0, 0, 1, 1); + printf("%d, %d\n", x, y); + xdg_positioner_set_offset(r->wayland.popup->xdg_positioner, x, y); xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; @@ -1450,13 +1455,17 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { + region_invalidate(handle); + handle->wayland.x = x; + handle->wayland.y = y; if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - region_invalidate(handle); - handle->wayland.x = x; - handle->wayland.y = y; wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); - region_setup(handle); } + if(handle->wayland.type == MWLL_WAYLAND_POPUP) { + destroy_popup(handle); + setup_popup(handle, x, y); + } + region_setup(handle); MwLLDispatch(handle, draw, NULL); } @@ -1761,7 +1770,7 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { switch(handle->wayland.type_to_be) { case MWLL_WAYLAND_POPUP: - setup_popup(handle); + setup_popup(handle, point->x, point->y); return; default: setup_toplevel(handle, point->x, point->y); diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 59673e3e7..54ee8ea8e 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -188,6 +188,7 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in MwNy, rc.height - sz.height, NULL); } + MwLLEndStateChange(handle->lowlevel); MwVaApply(handle, From 54cdd8501574eb8ec5e1b39a15fabde53e728a17 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 13:06:36 -0700 Subject: [PATCH 083/409] coords --- include/Mw/Core.h | 5 +++++ include/Mw/LowLevel.h | 1 + include/Mw/TypeDefs.h | 6 ++++++ src/backend/wayland.c | 4 ++++ src/core.c | 8 ++++++++ src/widget/submenu.c | 16 ++++++++++++---- 6 files changed, 36 insertions(+), 4 deletions(-) diff --git a/include/Mw/Core.h b/include/Mw/Core.h index e714a32ed..cd7cabd19 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -354,6 +354,11 @@ MWDECL void MwGetCursorCoord(MwWidget handle, MwPoint* point); */ MWDECL void MwGetScreenSize(MwWidget handle, MwRect* rect); +/*! + * @brief Reports whether a widget reports global or local coordinates upon GetXY/SetXY. Anything with a parent reports local, and most backends report global coordinates being supported for top level windows, but some (Wayland) do not. + */ +MWDECL int MwGetCoordinateType(MwWidget handle); + #ifdef __cplusplus } #endif diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 3c8bdf7b1..c748bf939 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -33,6 +33,7 @@ struct _MwLLCommon { void* user; int copy_buffer; int type; + int coordinate_type; MwLLHandler handler; }; diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index caf388797..6434f5236 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -219,4 +219,10 @@ struct _MwClass { void* reserved4; }; +/* Whether or not GetXY/SetXY works with global or local coordinates */ +enum MwCoordinateType { + MwCoordinatesGlobal = 0, + MwCoordinatesLocal, +}; + #endif diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f6532fa41..68aab8e31 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1344,6 +1344,10 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. + */ + r->common.coordinate_type = MwCoordinatesLocal; + r->common.type = MwLLBackendWayland; if(width < 2) width = 2; diff --git a/src/core.c b/src/core.c index 3d41a3603..d47e3b8af 100644 --- a/src/core.c +++ b/src/core.c @@ -797,3 +797,11 @@ void MwGetCursorCoord(MwWidget handle, MwPoint* point) { void MwGetScreenSize(MwWidget handle, MwRect* rect) { MwLLGetScreenSize(handle->lowlevel, rect); } + +int MwGetCoordinateType(MwWidget handle) { + if(handle->parent == NULL) { + return handle->lowlevel->common.coordinate_type; + } else { + return MwCoordinatesLocal; + } +}; diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 54ee8ea8e..f05c573f4 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -183,10 +183,18 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in MwLLMakeToolWindow(handle->lowlevel); MwLLDetach(handle->lowlevel, &p); - if(MwGetInteger(handle, MwNy) + sz.height > rc.height) { - MwVaApply(handle, - MwNy, rc.height - sz.height, - NULL); + if(handle->lowlevel->common.coordinate_type == MwCoordinatesGlobal) { + if(MwGetInteger(handle, MwNy) + sz.height > rc.height) { + MwVaApply(handle, + MwNy, rc.height - sz.height, + NULL); + } + } else { + if(MwGetInteger(handle, MwNy) > sz.height) { + MwVaApply(handle, + MwNy, sz.height, + NULL); + } } MwLLEndStateChange(handle->lowlevel); From d3751c0bf9f3b3f776fed09e737b8721375a8916 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 4 Jan 2026 18:25:33 -0700 Subject: [PATCH 084/409] submenu: just don't adjust if there's no global coordinates, there's not much of another way --- src/backend/wayland.c | 1 - src/widget/submenu.c | 6 ------ 2 files changed, 7 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 68aab8e31..9169a10bd 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1299,7 +1299,6 @@ static void setup_popup(MwLL r, int x, int y) { xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_anchor_rect( r->wayland.popup->xdg_positioner, 0, 0, 1, 1); - printf("%d, %d\n", x, y); xdg_positioner_set_offset(r->wayland.popup->xdg_positioner, x, y); xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; diff --git a/src/widget/submenu.c b/src/widget/submenu.c index f05c573f4..828155014 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -189,12 +189,6 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in MwNy, rc.height - sz.height, NULL); } - } else { - if(MwGetInteger(handle, MwNy) > sz.height) { - MwVaApply(handle, - MwNy, sz.height, - NULL); - } } MwLLEndStateChange(handle->lowlevel); From e2aecbf9d4a60f12a48b80d688a6d4ec8e1a2291 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 5 Jan 2026 23:27:18 +0900 Subject: [PATCH 085/409] this should be more correct --- src/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core.c b/src/core.c index d47e3b8af..d9a5d6586 100644 --- a/src/core.c +++ b/src/core.c @@ -799,7 +799,7 @@ void MwGetScreenSize(MwWidget handle, MwRect* rect) { } int MwGetCoordinateType(MwWidget handle) { - if(handle->parent == NULL) { + if(handle->parent == NULL || handle->parent->lowlevel == NULL) { return handle->lowlevel->common.coordinate_type; } else { return MwCoordinatesLocal; From 85df90ceafd2ee91b75a8fe88b146d63fb3fb4f5 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 6 Jan 2026 00:54:00 +0900 Subject: [PATCH 086/409] what did i even change? --- Makefile.pl | 2 +- src/backend/x11.c | 3 +++ src/core.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.pl b/Makefile.pl index ea9f90cb5..b244aa11a 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -226,7 +226,7 @@ foreach my $l (@library_targets) { } print(OUT "${l}: ${s}\n"); - print(OUT " \$(CC) $warn \$(CFLAGS\) \$\(INCDIR) -c -o ${l} ${s}\n"); + print(OUT " \$(CC) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); } print(OUT "\n"); print(OUT "\n"); diff --git a/src/backend/x11.c b/src/backend/x11.c index 8ece5d8e8..ce6dae0e1 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -159,6 +159,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.toplevel = 0; } r->x11.window = XCreateSimpleWindow(r->x11.display, p, px, py, width, height, 0, 0, WhitePixel(r->x11.display, DefaultScreen(r->x11.display))); + sh.flags = PWinGravity; sh.win_gravity = StaticGravity; XSetWMNormalHints(r->x11.display, r->x11.window, &sh); @@ -412,6 +413,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { 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)) { XPutBackEvent(handle->x11.display, &ev); return 1; @@ -421,6 +423,7 @@ static int MwLLPendingImpl(MwLL handle) { static void MwLLNextEventImpl(MwLL handle) { XEvent ev; + while(XCheckTypedWindowEvent(handle->x11.display, handle->x11.window, ClientMessage, &ev) || XCheckWindowEvent(handle->x11.display, handle->x11.window, mask, &ev)) { int render = 0; if(ev.type == Expose) { diff --git a/src/core.c b/src/core.c index d9a5d6586..52a8f23e6 100644 --- a/src/core.c +++ b/src/core.c @@ -121,6 +121,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->parent = parent; h->children = NULL; + if(widget_class != NULL) { if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) { free(h->name); From 1f1318d0e1afa560e889ba695f6fc0f56bc30664 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 7 Jan 2026 12:30:18 -0700 Subject: [PATCH 087/409] cmake: allow shared or static building --- CMakeLists.txt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca3c76509..37e23d98f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,8 @@ option(BUILD_EXAMPLES "Build examples" OFF) option(USE_STB_IMAGE "Use stb_image" ON) option(USE_STB_TRUETYPE "Use stb_truetype" OFF) option(USE_FREETYPE2 "Use FreeType 2" ON) +option(BUILD_SHARED "Build a shared library" ON) +option(BUILD_STATIC "Build a static library" OFF) file( GLOB @@ -61,11 +63,22 @@ if(TRY_OPENGL) endif() endif() +if(BUILD_STATIC) +message(STATUS "Building Milsko as a static library") +add_library( + Mw + ${SOURCES} +) +elseif(BUILD_SHARED) +message(STATUS "Building Milsko as a shared library") add_library( Mw SHARED ${SOURCES} ) +else() +message(ERROR "Must either build a shared library or a static library") +endif() if(USE_STB_IMAGE) target_compile_definitions( From debdaf998e0b5edfe42214934d8fcf4dfea3e7bd Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 9 Jan 2026 03:06:14 +0900 Subject: [PATCH 088/409] add MW_OPENGL_NO_INCLUDE --- include/Mw/Widget/OpenGL.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index 3a063035a..26f44abf5 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -9,7 +9,7 @@ #include #include -#ifndef __gl_h_ +#if !defined(MW_OPENGL_NO_INCLUDE) && !defined(__gl_h_) #ifdef _WIN32 #include #else From 079cfa18b9d8dae98cb472c3a72768dfbb36933f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 9 Jan 2026 07:25:05 +0900 Subject: [PATCH 089/409] fix english --- Makefile.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.pl b/Makefile.pl index b244aa11a..454fd791e 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -48,7 +48,7 @@ param_set("static", 1); my %features = ( "classic-theme" => "use classic theme", - "stb-image" => "use stb_image instead of libjpeg/libpng", + "stb-image" => "use stb_image, instead use libjpeg/libpng", "stb-truetype" => "use stb_truetype", "freetype2" => "use FreeType2", "xrender" => "use XRender", From 2d3bd9213ed5e4f57b1da8396eb453546e1c3bf1 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 9 Jan 2026 14:43:44 -0700 Subject: [PATCH 090/409] appkit --- .gitignore | 1 + Makefile.pl | 65 +++++++---- include/Mw/LowLevel.h | 13 +++ include/Mw/LowLevel/AppKit.h | 27 +++++ include/Mw/MachDep.h | 7 +- pl/ostype/Darwin.pl | 8 ++ pl/ostype/Linux.pl | 2 +- pl/rules.pl | 7 ++ pl/utils.pl | 6 +- src/abstract/dynamic.c | 2 +- src/abstract/time.c | 32 +++++- src/backend/appkit.m | 214 +++++++++++++++++++++++++++++++++++ src/lowlevel.c | 87 ++++++++------ 13 files changed, 402 insertions(+), 69 deletions(-) create mode 100644 include/Mw/LowLevel/AppKit.h create mode 100644 pl/ostype/Darwin.pl create mode 100644 src/backend/appkit.m diff --git a/.gitignore b/.gitignore index 2ebdbc2a8..9b18b9c39 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ examples/*/*.exe *.so *.dll *.lib +*.dylib *.a /Makefile /build diff --git a/Makefile.pl b/Makefile.pl index 454fd791e..cf5c55438 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -18,7 +18,7 @@ our $cflags = "-fPIC -D_MILSKO"; our $libdir = ""; our $ldflags = ""; our $math = "-lm"; -our $shared = "-shared"; +our @shared = "-shared"; our @backends = (); our $library_prefix = "lib"; @@ -45,6 +45,7 @@ param_set("vulkan", 0); param_set("vulkan-string-helper", 1); param_set("shared", 1); param_set("static", 1); +param_set("examples", 1); my %features = ( "classic-theme" => "use classic theme", @@ -166,7 +167,7 @@ print(OUT "LIBDIR = ${libdir}\n"); print(OUT "LDFLAGS = ${ldflags}\n"); print(OUT "LIBS = ${math} ${libs}\n"); print(OUT "MATH = ${math}\n"); -print(OUT "SHARED = ${shared}\n"); +print(OUT "SHARED = @{shared}\n"); print(OUT "\n"); print(OUT ".PHONY: all format clean distclean lib examples install\n"); print(OUT "\n"); @@ -219,7 +220,13 @@ foreach my $l (@library_targets) { my $s = $l; my $o = $object_suffix; $o =~ s/\./\\\./g; - $s =~ s/$o$/.c/; + + if ($l =~ /appkit/) { + $s =~ s/$o$/.m/; + + } else { + $s =~ s/$o$/.c/; + } if ($l =~ /^external\//) { $warn = ""; @@ -230,34 +237,42 @@ foreach my $l (@library_targets) { } print(OUT "\n"); print(OUT "\n"); -print(OUT "examples: " . join(" ", @examples_targets) . "\n"); -print(OUT "\n"); -foreach my $l (@examples_targets) { - my $libs = ""; - my $s = $l; - my $o = $executable_suffix; - $o =~ s/\./\\\./g; - $s =~ s/$o$//; +if(param_get("examples")) { + print(OUT "examples: " . join(" ", @examples_targets) . "\n"); + print(OUT "\n"); + foreach my $l (@examples_targets) { + my $libs = ""; + my $s = $l; + my $o = $executable_suffix; + $o =~ s/\./\\\./g; + $s =~ s/$o$//; - if (defined($examples_libs{$l})) { - $libs = $examples_libs{$l}; - } + if (defined($examples_libs{$l})) { + $libs = $examples_libs{$l}; + } - print(OUT -"${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" - ); - print(OUT -" \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" - ); - print(OUT "${s}${object_suffix}: ${s}.c\n"); - print(OUT - " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" - ); + print(OUT + "${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" + ); + if (grep(/^appkit$/, @backends)) { + print(OUT + " \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } else { + print(OUT + " \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } + print(OUT "${s}${object_suffix}: ${s}.c\n"); + print(OUT + " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" + ); + } } print(OUT "\n"); print(OUT "clean:\n"); print(OUT -" rm -f */*.o */*/*.o */*/*/*.o */*.exe */*/*.exe */*/*/*.exe src/*.so src/*.dll src/*.a " +" rm -f */*.o */*/*.o */*/*/*.o */*.exe */*/*.exe */*/*/*.exe src/*.so src/*.dll src/*.dylib src/*.a " . join(" ", @examples_targets) . "\n"); print(OUT "\n"); diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index c748bf939..e3cf6438e 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -27,6 +27,7 @@ enum MwLLBackends { MwLLBackendX11 = 0, MwLLBackendGDI, MwLLBackendWayland, + MwLLBackendAppKit, }; struct _MwLLCommon { @@ -61,6 +62,9 @@ struct _MwLLCommonPixmap { #ifdef USE_WAYLAND #include #endif +#ifdef USE_APPKIT +#include +#endif union _MwLL { struct _MwLLCommon common; @@ -73,6 +77,9 @@ union _MwLL { #ifdef USE_WAYLAND struct _MwLLWayland wayland; #endif +#ifdef USE_APPKIT + struct _MwLLAppKit appkit; +#endif }; union _MwLLColor { @@ -86,6 +93,9 @@ union _MwLLColor { #ifdef USE_WAYLAND struct _MwLLWaylandColor wayland; #endif +#ifdef USE_APPKIT + struct _MwLLAppKitColor appkit; +#endif }; union _MwLLPixmap { @@ -99,6 +109,9 @@ union _MwLLPixmap { #ifdef USE_WAYLAND struct _MwLLWaylandPixmap wayland; #endif +#ifdef USE_APPKIT + struct _MwLLAppKitPixmap appkit; +#endif }; #endif #include diff --git a/include/Mw/LowLevel/AppKit.h b/include/Mw/LowLevel/AppKit.h new file mode 100644 index 000000000..985cf5f38 --- /dev/null +++ b/include/Mw/LowLevel/AppKit.h @@ -0,0 +1,27 @@ +/*! + * @file Mw/LowLevel/AppKit.h + * @brief Work in progress AppKit Backend + * @warning This is used internally. + */ +#ifndef __MW_LOWLEVEL_APPKIT_H__ +#define __MW_LOWLEVEL_APPKIT_H__ + +#include +#include +#include  + +MWDECL int MwLLAppKitCallInit(void); + +struct _MwLLAppKit { + struct _MwLLCommon common; +}; + +struct _MwLLAppKitColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLAppKitPixmap { + struct _MwLLCommonPixmap common; +}; + +#endif diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 6eb37be7f..1fe154948 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -43,10 +43,15 @@ #include #include #include -#include +#include  #include #endif +#ifdef __APPLE__ +#include +#include +#endif + #ifndef M_PI #define M_PI 3.14159265 #endif diff --git a/pl/ostype/Darwin.pl b/pl/ostype/Darwin.pl new file mode 100644 index 000000000..675bd75c2 --- /dev/null +++ b/pl/ostype/Darwin.pl @@ -0,0 +1,8 @@ +$library_suffix = ".dylib"; +set_shared_flag("-dynamiclib"); + +use_backend("appkit"); + +add_cflags("-DSTBI_NO_THREAD_LOCALS"); + +1; \ No newline at end of file diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 155cd4aaf..b7e074d77 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,4 +1,4 @@ -if (param_get("experimental-wayland")) { +IF (param_get("experimental-wayland")) { use_backend("wayland", "x11"); } else { diff --git a/pl/rules.pl b/pl/rules.pl index f55fce33f..2299e0d97 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -46,6 +46,13 @@ if (grep(/^wayland$/, @backends)) { $gl_libs = "-lGL -lGLU"; } +if (grep(/^appkit$/, @backends)) { + add_cflags("-DUSE_APPKIT"); + new_object("src/backend/appkit.m"); + + $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 971c19626..264e6797f 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -40,10 +40,14 @@ sub new_example { push(@examples_targets, "${_[0]}${executable_suffix}"); } +sub set_shared_flag { + @shared = $_[0]; +} + sub new_object { my @l = glob($_[0]); foreach my $e (@l) { - $e =~ s/\.c$/$object_suffix/; + $e =~ s/\.(c|m)$/$object_suffix/; push(@library_targets, $e); } } diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index 7f56e0f57..79cad83fc 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -12,7 +12,7 @@ void* MwDynamicSymbol(void* handle, const char* symbol) { void MwDynamicClose(void* handle) { FreeLibrary(handle); } -#elif defined(__unix__) +#elif defined(__unix__) || defined(__APPLE__) void* MwDynamicOpen(const char* path) { return dlopen(path, RTLD_LOCAL | RTLD_LAZY); } diff --git a/src/abstract/time.c b/src/abstract/time.c index 8c85d580a..97e6fb3bf 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -1,23 +1,47 @@ -#include +#include  #if defined(_WIN32) long MwTimeGetTick(void) { - return GetTickCount(); + return GetTickCount(); } void MwTimeSleep(int ms) { Sleep(ms); } +#elif defined(__APPLE__) +long MwTimeGetTick(void) { + struct timespec ts; + long n = 0; + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + n += ts.tv_nsec / 1000 / 1000; + n += ts.tv_sec * 1000; + + return n; +} +void MwTimeSleep(int ms) { + struct timespec ts; + + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000 * 1000; + + nanosleep(&ts, NULL); +} #elif defined(__unix__) long MwTimeGetTick(void) { struct timespec ts; long n = 0; - + clock_gettime(CLOCK_MONOTONIC, &ts); n += ts.tv_nsec / 1000 / 1000; n += ts.tv_sec * 1000; - + return n; } diff --git a/src/backend/appkit.m b/src/backend/appkit.m new file mode 100644 index 000000000..772f33a52 --- /dev/null +++ b/src/backend/appkit.m @@ -0,0 +1,214 @@ +#include  + +#include "../../external/stb_ds.h" + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; + + r = malloc(sizeof(*r)); + + + MwLLCreateCommon(r); + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + (void)points; + (void)points_count; + (void)color; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + (void)handle; + (void)points; + (void)color; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +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) { + (void)handle; + (void)x; + (void)y; +} + +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + (void)handle; + (void)w; + (void)h; +} + +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} + +static int MwLLPendingImpl(MwLL handle) { + (void)handle; + return 0; +} + +static void MwLLNextEventImpl(MwLL handle) { + (void)handle; +} + +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + (void)title; + (void)handle; +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { + (void)handle; + + MwLLPixmap r = malloc(sizeof(*r)); + + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { + (void)r; +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap); +} + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + (void)handle; + (void)rect; + (void)pixmap; +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + (void)handle; + (void)pixmap; +} + +static void MwLLForceRenderImpl(MwLL handle) { + (void)handle; +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + (void)handle; + (void)image; + (void)mask; +} + +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + (void)handle; + (void)point; +} + +static void MwLLShowImpl(MwLL handle, int show) { + (void)handle; + (void)show; +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { + (void)handle; + (void)minx; + (void)miny; + (void)maxx; + (void)maxy; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static void MwLLFocusImpl(MwLL handle) { + (void)handle; +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static void MwLLSetClipboardImpl(MwLL handle, const char* text) { + (void)handle; + (void)text; +} + +static void MwLLGetClipboardImpl(MwLL handle) { + (void)handle; +} + +static void MwLLMakeToolWindowImpl(MwLL handle) { + (void)handle; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + (void)handle; + (void)point; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + (void)handle; + (void)rect; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} + +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} + +static int AppKit(void) { + return 0; +} + +#include "call.c" +CALL(AppKit); diff --git a/src/lowlevel.c b/src/lowlevel.c index 30037c876..c3a20c4c0 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -1,55 +1,70 @@ #include -MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height); -void (*MwLLDestroy)(MwLL handle); +/* Older GCC doesn't like this part of the code because of common sections. + What are common sections? This question is so obscure and unknown + that newer GCC actually compiles with -fno-common by default because + not enough people ever figured this out. But when compiling under + older Mac OS X. specifically the gcc that comes with tigerbrew (this + has not yet been tried under XCode 10.5), this comes up. Furthermore, + adding -fno-common to either the cflags or ldflags doesn't seem to fix this. + But what does fix it is using GNU attributes. So...yeah, sure, we'll just do + this.*/ +#ifdef __APPLE__ +#define NOCOMMON __attribute__((nocommon)) +#else +#define NOCOMMON +#endif -void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); -void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +NOCOMMON MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height); +NOCOMMON void (*MwLLDestroy)(MwLL handle); -void (*MwLLBeginDraw)(MwLL handle); -void (*MwLLEndDraw)(MwLL handle); +NOCOMMON void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); +NOCOMMON void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); -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); +NOCOMMON void (*MwLLBeginDraw)(MwLL handle); +NOCOMMON void (*MwLLEndDraw)(MwLL handle); -void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h); -void (*MwLLSetXY)(MwLL handle, int x, int y); -void (*MwLLSetWH)(MwLL handle, int w, int h); +NOCOMMON MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); +NOCOMMON void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); +NOCOMMON void (*MwLLFreeColor)(MwLLColor color); -void (*MwLLSetTitle)(MwLL handle, const char* title); +NOCOMMON void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h); +NOCOMMON void (*MwLLSetXY)(MwLL handle, int x, int y); +NOCOMMON void (*MwLLSetWH)(MwLL handle, int w, int h); -int (*MwLLPending)(MwLL handle); -void (*MwLLNextEvent)(MwLL handle); +NOCOMMON void (*MwLLSetTitle)(MwLL handle, const char* title); -MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height); -void (*MwLLPixmapUpdate)(MwLLPixmap pixmap); -void (*MwLLDestroyPixmap)(MwLLPixmap pixmap); -void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap); -void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap); +NOCOMMON int (*MwLLPending)(MwLL handle); +NOCOMMON void (*MwLLNextEvent)(MwLL handle); -void (*MwLLForceRender)(MwLL handle); +NOCOMMON MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height); +NOCOMMON void (*MwLLPixmapUpdate)(MwLLPixmap pixmap); +NOCOMMON void (*MwLLDestroyPixmap)(MwLLPixmap pixmap); +NOCOMMON void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap); +NOCOMMON void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap); -void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask); -void (*MwLLDetach)(MwLL handle, MwPoint* point); -void (*MwLLShow)(MwLL handle, int show); +NOCOMMON void (*MwLLForceRender)(MwLL handle); -void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy); -void (*MwLLMakeBorderless)(MwLL handle, int toggle); -void (*MwLLMakeToolWindow)(MwLL handle); -void (*MwLLMakePopup)(MwLL handle, MwLL parent); +NOCOMMON void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask); +NOCOMMON void (*MwLLDetach)(MwLL handle, MwPoint* point); +NOCOMMON void (*MwLLShow)(MwLL handle, int show); -void (*MwLLBeginStateChange)(MwLL handle); -void (*MwLLEndStateChange)(MwLL handle); +NOCOMMON void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy); +NOCOMMON void (*MwLLMakeBorderless)(MwLL handle, int toggle); +NOCOMMON void (*MwLLMakeToolWindow)(MwLL handle); +NOCOMMON void (*MwLLMakePopup)(MwLL handle, MwLL parent); -void (*MwLLFocus)(MwLL handle); -void (*MwLLGrabPointer)(MwLL handle, int toggle); +NOCOMMON void (*MwLLBeginStateChange)(MwLL handle); +NOCOMMON void (*MwLLEndStateChange)(MwLL handle); -void (*MwLLSetClipboard)(MwLL handle, const char* text); -void (*MwLLGetClipboard)(MwLL handle); +NOCOMMON void (*MwLLFocus)(MwLL handle); +NOCOMMON void (*MwLLGrabPointer)(MwLL handle, int toggle); -void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); -void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +NOCOMMON void (*MwLLSetClipboard)(MwLL handle, const char* text); +NOCOMMON void (*MwLLGetClipboard)(MwLL handle); + +NOCOMMON void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); +NOCOMMON void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); void MwLLCreateCommon(MwLL handle) { handle->common.handler = malloc(sizeof(*handle->common.handler)); From da33a1a3c6fad279d65135633e183e484bb41bd7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 9 Jan 2026 14:45:12 -0700 Subject: [PATCH 091/409] darwin: remove invalid characters --- include/Mw/LowLevel/AppKit.h | 2 +- include/Mw/MachDep.h | 2 +- pl/ostype/Linux.pl | 2 +- src/abstract/time.c | 14 +++++++------- src/backend/appkit.m | 14 +++++++------- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/Mw/LowLevel/AppKit.h b/include/Mw/LowLevel/AppKit.h index 985cf5f38..4a6c8e53c 100644 --- a/include/Mw/LowLevel/AppKit.h +++ b/include/Mw/LowLevel/AppKit.h @@ -8,7 +8,7 @@ #include #include -#include  +#include MWDECL int MwLLAppKitCallInit(void); diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 1fe154948..c8cb06052 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -43,7 +43,7 @@ #include #include #include -#include  +#include #include #endif diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index b7e074d77..155cd4aaf 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,4 +1,4 @@ -IF (param_get("experimental-wayland")) { +if (param_get("experimental-wayland")) { use_backend("wayland", "x11"); } else { diff --git a/src/abstract/time.c b/src/abstract/time.c index 97e6fb3bf..2fbc58428 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -1,8 +1,8 @@ -#include  +#include #if defined(_WIN32) long MwTimeGetTick(void) { - return GetTickCount(); + return GetTickCount(); } void MwTimeSleep(int ms) { @@ -12,13 +12,13 @@ void MwTimeSleep(int ms) { long MwTimeGetTick(void) { struct timespec ts; long n = 0; - clock_serv_t cclock; + clock_serv_t cclock; mach_timespec_t mts; - + host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); clock_get_time(cclock, &mts); mach_port_deallocate(mach_task_self(), cclock); - + n += ts.tv_nsec / 1000 / 1000; n += ts.tv_sec * 1000; @@ -36,12 +36,12 @@ void MwTimeSleep(int ms) { long MwTimeGetTick(void) { struct timespec ts; long n = 0; - + clock_gettime(CLOCK_MONOTONIC, &ts); n += ts.tv_nsec / 1000 / 1000; n += ts.tv_sec * 1000; - + return n; } diff --git a/src/backend/appkit.m b/src/backend/appkit.m index 772f33a52..6deea7c75 100644 --- a/src/backend/appkit.m +++ b/src/backend/appkit.m @@ -1,4 +1,4 @@ -#include  +#include #include "../../external/stb_ds.h" @@ -8,9 +8,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { (void)y; (void)width; (void)height; - + r = malloc(sizeof(*r)); - + MwLLCreateCommon(r); @@ -19,7 +19,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); - + free(handle); } @@ -51,7 +51,7 @@ static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { (void)handle; - + c->common.red = r; c->common.green = g; c->common.blue = b; @@ -96,7 +96,7 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { (void)handle; - + MwLLPixmap r = malloc(sizeof(*r)); r->common.raw = malloc(4 * width * height); @@ -206,7 +206,7 @@ static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } -static int AppKit(void) { +static int MwLLAppKitCallInitImpl(void) { return 0; } From e73964882eea4ade018b4cff81e6a40c6026a96d Mon Sep 17 00:00:00 2001 From: IoIxD Date: Fri, 9 Jan 2026 21:35:23 -0700 Subject: [PATCH 092/409] renamed appkit backend to cocoa and got something that compiles --- Makefile.pl | 9 +- include/Mw/LowLevel.h | 18 +- include/Mw/LowLevel/Cocoa.h | 28 +++ pl/ostype/Darwin.pl | 5 +- pl/rules.pl | 6 +- src/backend/cocoa.m | 364 ++++++++++++++++++++++++++++++++++++ src/core.c | 4 + src/lowlevel.c | 87 ++++----- 8 files changed, 451 insertions(+), 70 deletions(-) create mode 100644 include/Mw/LowLevel/Cocoa.h create mode 100644 src/backend/cocoa.m diff --git a/Makefile.pl b/Makefile.pl index cf5c55438..ded79b02e 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -220,10 +220,9 @@ foreach my $l (@library_targets) { my $s = $l; my $o = $object_suffix; $o =~ s/\./\\\./g; - - if ($l =~ /appkit/) { + + if ($l =~ /cocoa/) { $s =~ s/$o$/.m/; - } else { $s =~ s/$o$/.c/; } @@ -254,7 +253,7 @@ if(param_get("examples")) { print(OUT "${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" ); - if (grep(/^appkit$/, @backends)) { + if (grep(/^cocoa$/, @backends)) { print(OUT " \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); @@ -262,7 +261,7 @@ if(param_get("examples")) { print(OUT " \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); - } + } print(OUT "${s}${object_suffix}: ${s}.c\n"); print(OUT " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index e3cf6438e..96ff8e849 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -27,7 +27,7 @@ enum MwLLBackends { MwLLBackendX11 = 0, MwLLBackendGDI, MwLLBackendWayland, - MwLLBackendAppKit, + MwLLBackendCocoa, }; struct _MwLLCommon { @@ -62,8 +62,8 @@ struct _MwLLCommonPixmap { #ifdef USE_WAYLAND #include #endif -#ifdef USE_APPKIT -#include +#ifdef USE_COCOA +#include #endif union _MwLL { @@ -77,8 +77,8 @@ union _MwLL { #ifdef USE_WAYLAND struct _MwLLWayland wayland; #endif -#ifdef USE_APPKIT - struct _MwLLAppKit appkit; +#ifdef USE_COCOA + struct _MwLLCocoa cocoa; #endif }; @@ -93,8 +93,8 @@ union _MwLLColor { #ifdef USE_WAYLAND struct _MwLLWaylandColor wayland; #endif -#ifdef USE_APPKIT - struct _MwLLAppKitColor appkit; +#ifdef USE_COCOA + struct _MwLLCocoaColor cocoa; #endif }; @@ -109,8 +109,8 @@ union _MwLLPixmap { #ifdef USE_WAYLAND struct _MwLLWaylandPixmap wayland; #endif -#ifdef USE_APPKIT - struct _MwLLAppKitPixmap appkit; +#ifdef USE_COCOA + struct _MwLLCocoaPixmap cocoa; #endif }; #endif diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h new file mode 100644 index 000000000..1ff4c1ef5 --- /dev/null +++ b/include/Mw/LowLevel/Cocoa.h @@ -0,0 +1,28 @@ +/*! + * @file Mw/LowLevel/Cocoa.h + * @brief Work in progress Cocoa Backend + * @warning This is used internally. + */ +#ifndef __MW_LOWLEVEL_COCOA_H__ +#define __MW_LOWLEVEL_COCOA_H__ + +#include +#include +#include + +MWDECL int MwLLCocoaCallInit(void); + +struct _MwLLCocoa { + struct _MwLLCommon common; + void* real; +}; + +struct _MwLLCocoaColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLCocoaPixmap { + struct _MwLLCommonPixmap common; +}; + +#endif diff --git a/pl/ostype/Darwin.pl b/pl/ostype/Darwin.pl index 675bd75c2..72cfe275f 100644 --- a/pl/ostype/Darwin.pl +++ b/pl/ostype/Darwin.pl @@ -1,8 +1,9 @@ $library_suffix = ".dylib"; set_shared_flag("-dynamiclib"); -use_backend("appkit"); +use_backend("cocoa"); add_cflags("-DSTBI_NO_THREAD_LOCALS"); +add_ldflags("-framework Cocoa -lobjc"); -1; \ No newline at end of file +1; diff --git a/pl/rules.pl b/pl/rules.pl index 2299e0d97..73f4c6177 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -46,9 +46,9 @@ if (grep(/^wayland$/, @backends)) { $gl_libs = "-lGL -lGLU"; } -if (grep(/^appkit$/, @backends)) { - add_cflags("-DUSE_APPKIT"); - new_object("src/backend/appkit.m"); +if (grep(/^cocoa$/, @backends)) { + add_cflags("-DUSE_COCOA"); + new_object("src/backend/cocoa.m"); $gl_libs = "-lGL -lGLU"; } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m new file mode 100644 index 000000000..396016493 --- /dev/null +++ b/src/backend/cocoa.m @@ -0,0 +1,364 @@ +#ifndef USE_COCOA +#define USE_COCOA +#endif + +#import +#include +#import + +#include + +#include "../../external/stb_ds.h" + +@interface MilskoCocoa : NSObject { + NSApplication *application; + NSWindow *window; +} + ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height; +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; +- (void)setX:(int)x Y:(int)y; +- (void)setW:(int)w H:(int)h; +- (int)pending; +- (void)getNextEvent; +- (void)setTitle:(const char *)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; +- (void)setIcon:(MwLLPixmap)pixmap; +- (void)forceRender; +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; +- (void)detachWithPoint:(MwPoint *)point; +- (void)show:(int)show; +- (void)makePopupWithParent:(MwLL)parent; +- (void)setSizeHintsWithMinX:(int)minx + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; +- (void)makeBorderless:(int)toggle; +- (void)focus; +- (void)grabPointer:(int)toggle; +- (void)setClipboard:(const char *)text; +- (void)makeToolWindow; +- (void)getCursorCoord:(MwPoint *)point; +- (void)getScreenSize:(MwRect *)rect; +- (void)destroy; + +@end + +@implementation MilskoCocoa + ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height { + MilskoCocoa *c = [MilskoCocoa alloc]; + bool centerX = false, centerY = false; + + if (x == MwDEFAULT) { + x = 0; + centerX = true; + } + if (y == MwDEFAULT) { + y = 0; + centerY = true; + } + c->application = [NSApplication sharedApplication]; + + NSRect rect = NSMakeRect(x, y, width, height); + + c->window = [[[NSWindow alloc] + initWithContentRect:rect + styleMask:parent == NULL + ? (NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask) + : NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO] autorelease]; + [c->window makeKeyAndOrderFront:c->application]; + + if (parent != NULL) { + [c->window setBackgroundColor:[NSColor blueColor]]; + + MilskoCocoa *p = parent->cocoa.real; + [p->window addChildWindow:c->window ordered:NSWindowAbove]; + } + + return c; +} +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color { +}; +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { +}; +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { +}; +- (void)setX:(int)x Y:(int)y { +}; +- (void)setW:(int)w H:(int)h { +}; +- (int)pending { + return 1; +}; +- (void)getNextEvent { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = [self->application nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]; + + if (event != nil) { + printf("got event: %p\n", event); + } + [pool release]; +}; +- (void)setTitle:(const char *)title { +}; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect { +}; +- (void)setIcon:(MwLLPixmap)pixmap { +}; +- (void)forceRender { +}; +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { +}; +- (void)detachWithPoint:(MwPoint *)point { +}; +- (void)show:(int)show { +}; +- (void)makePopupWithParent:(MwLL)parent { +}; +- (void)setSizeHintsWithMinX:(int)minx + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { +}; +- (void)makeBorderless:(int)toggle { +}; +- (void)focus { +}; +- (void)grabPointer:(int)toggle { +}; +- (void)setClipboard:(const char *)text { +}; +- (void)getClipboard { +}; +- (void)makeToolWindow { +}; +- (void)getCursorCoord:(MwPoint *)point { +}; +- (void)getScreenSize:(MwRect *)rect { +}; +- (void)destroy { + [self->window dealloc]; +} +@end + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; + + r = malloc(sizeof(*r)); + + MwLLCreateCommon(r); + + MilskoCocoa *o = + [MilskoCocoa newWithParent:parent x:x y:y width:width height:height]; + r->cocoa.real = o; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MilskoCocoa *h = handle->cocoa.real; + + [h destroy]; + [h dealloc]; + + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, + MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; +} + +static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h lineWithPoints:points color:color]; +} + +static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; + + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, + unsigned int *height) { + MilskoCocoa *h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; +} + +static void MwLLSetXYImpl(MwLL handle, int x, int y) { + MilskoCocoa *h = handle->cocoa.real; + [h setX:x Y:y]; +} + +static void MwLLSetWHImpl(MwLL handle, int w, int height) { + MilskoCocoa *h = handle->cocoa.real; + [h setW:w H:height]; +} + +static void MwLLFreeColorImpl(MwLLColor color) { free(color); } + +static int MwLLPendingImpl(MwLL handle) { + MilskoCocoa *h = handle->cocoa.real; + return [h pending]; +} + +static void MwLLNextEventImpl(MwLL handle) { + + MilskoCocoa *h = handle->cocoa.real; + [h getNextEvent]; +} + +static void MwLLSetTitleImpl(MwLL handle, const char *title) { + MilskoCocoa *h = handle->cocoa.real; + [h setTitle:title]; +} + +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, + int width, int height) { + (void)handle; + + MwLLPixmap r = malloc(sizeof(*r)); + + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + r->common.width = width; + r->common.height = height; + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { (void)r; } + +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { free(pixmap); } + +static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { + MilskoCocoa *h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; +} + +static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { + MilskoCocoa *h = handle->cocoa.real; + [h setIcon:pixmap]; +} + +static void MwLLForceRenderImpl(MwLL handle) { + MilskoCocoa *h = handle->cocoa.real; + [h forceRender]; +} + +static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { + MilskoCocoa *h = handle->cocoa.real; + [h setCursor:image mask:mask]; +} + +static void MwLLDetachImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h detachWithPoint:point]; +} + +static void MwLLShowImpl(MwLL handle, int show) { + MilskoCocoa *h = handle->cocoa.real; + [h show:show]; +} + +static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + MilskoCocoa *h = handle->cocoa.real; + [h makePopupWithParent:parent]; +} + +static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, + int maxy) { + MilskoCocoa *h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; +} + +static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + MilskoCocoa *h = handle->cocoa.real; + [h makeBorderless:toggle]; +} + +static void MwLLFocusImpl(MwLL handle) { + MilskoCocoa *h = handle->cocoa.real; + [h focus]; +} + +static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + MilskoCocoa *h = handle->cocoa.real; + [h grabPointer:toggle]; +} + +static void MwLLSetClipboardImpl(MwLL handle, const char *text) { + MilskoCocoa *h = handle->cocoa.real; + [h setClipboard:text]; +} + +static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } + +static void MwLLMakeToolWindowImpl(MwLL handle) { + + MilskoCocoa *h = handle->cocoa.real; + [h makeToolWindow]; +} + +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h getCursorCoord:point]; +} + +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { + MilskoCocoa *h = handle->cocoa.real; + [h getScreenSize:rect]; +} + +static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } + +static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } + +static int MwLLCocoaCallInitImpl(void) { return 0; } + +#include "call.c" +CALL(Cocoa); diff --git a/src/core.c b/src/core.c index 52a8f23e6..d8e0c2d02 100644 --- a/src/core.c +++ b/src/core.c @@ -123,6 +123,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->children = NULL; if(widget_class != NULL) { + printf("%p\n", MwLLCreate); if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) { free(h->name); free(h); @@ -729,6 +730,9 @@ MwWidget MwGetParent(MwWidget handle) { typedef int (*call_t)(void); int MwLibraryInit(void) { call_t calls[] = { +#ifdef USE_COCOA + MwLLCocoaCallInit, +#endif #ifdef USE_WAYLAND MwLLWaylandCallInit, #endif diff --git a/src/lowlevel.c b/src/lowlevel.c index c3a20c4c0..8f8a4d932 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -1,70 +1,55 @@ #include -/* Older GCC doesn't like this part of the code because of common sections. - What are common sections? This question is so obscure and unknown - that newer GCC actually compiles with -fno-common by default because - not enough people ever figured this out. But when compiling under - older Mac OS X. specifically the gcc that comes with tigerbrew (this - has not yet been tried under XCode 10.5), this comes up. Furthermore, - adding -fno-common to either the cflags or ldflags doesn't seem to fix this. - But what does fix it is using GNU attributes. So...yeah, sure, we'll just do - this.*/ -#ifdef __APPLE__ -#define NOCOMMON __attribute__((nocommon)) -#else -#define NOCOMMON -#endif +MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height) = NULL; +void (*MwLLDestroy)(MwLL handle) = NULL; -NOCOMMON MwLL (*MwLLCreate)(MwLL parent, int x, int y, int width, int height); -NOCOMMON void (*MwLLDestroy)(MwLL handle); +void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color) = NULL; +void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color) = NULL; -NOCOMMON void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color); -NOCOMMON void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color); +void (*MwLLBeginDraw)(MwLL handle) = NULL; +void (*MwLLEndDraw)(MwLL handle) = NULL; -NOCOMMON void (*MwLLBeginDraw)(MwLL handle); -NOCOMMON void (*MwLLEndDraw)(MwLL handle); +MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b) = NULL; +void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b) = NULL; +void (*MwLLFreeColor)(MwLLColor color) = NULL; -NOCOMMON MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b); -NOCOMMON void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b); -NOCOMMON void (*MwLLFreeColor)(MwLLColor color); +void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) = NULL; +void (*MwLLSetXY)(MwLL handle, int x, int y) = NULL; +void (*MwLLSetWH)(MwLL handle, int w, int h) = NULL; -NOCOMMON void (*MwLLGetXYWH)(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h); -NOCOMMON void (*MwLLSetXY)(MwLL handle, int x, int y); -NOCOMMON void (*MwLLSetWH)(MwLL handle, int w, int h); +void (*MwLLSetTitle)(MwLL handle, const char* title) = NULL; -NOCOMMON void (*MwLLSetTitle)(MwLL handle, const char* title); +int (*MwLLPending)(MwLL handle) = NULL; +void (*MwLLNextEvent)(MwLL handle) = NULL; -NOCOMMON int (*MwLLPending)(MwLL handle); -NOCOMMON void (*MwLLNextEvent)(MwLL handle); +MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height) = NULL; +void (*MwLLPixmapUpdate)(MwLLPixmap pixmap) = NULL; +void (*MwLLDestroyPixmap)(MwLLPixmap pixmap) = NULL; +void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap) = NULL; +void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap) = NULL; -NOCOMMON MwLLPixmap (*MwLLCreatePixmap)(MwLL handle, unsigned char* data, int width, int height); -NOCOMMON void (*MwLLPixmapUpdate)(MwLLPixmap pixmap); -NOCOMMON void (*MwLLDestroyPixmap)(MwLLPixmap pixmap); -NOCOMMON void (*MwLLDrawPixmap)(MwLL handle, MwRect* rect, MwLLPixmap pixmap); -NOCOMMON void (*MwLLSetIcon)(MwLL handle, MwLLPixmap pixmap); +void (*MwLLForceRender)(MwLL handle) = NULL; -NOCOMMON void (*MwLLForceRender)(MwLL handle); +void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask) = NULL; +void (*MwLLDetach)(MwLL handle, MwPoint* point) = NULL; +void (*MwLLShow)(MwLL handle, int show) = NULL; -NOCOMMON void (*MwLLSetCursor)(MwLL handle, MwCursor* image, MwCursor* mask); -NOCOMMON void (*MwLLDetach)(MwLL handle, MwPoint* point); -NOCOMMON void (*MwLLShow)(MwLL handle, int show); +void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy) = NULL; +void (*MwLLMakeBorderless)(MwLL handle, int toggle) = NULL; +void (*MwLLMakeToolWindow)(MwLL handle) = NULL; +void (*MwLLMakePopup)(MwLL handle, MwLL parent) = NULL; -NOCOMMON void (*MwLLSetSizeHints)(MwLL handle, int minx, int miny, int maxx, int maxy); -NOCOMMON void (*MwLLMakeBorderless)(MwLL handle, int toggle); -NOCOMMON void (*MwLLMakeToolWindow)(MwLL handle); -NOCOMMON void (*MwLLMakePopup)(MwLL handle, MwLL parent); +void (*MwLLBeginStateChange)(MwLL handle) = NULL; +void (*MwLLEndStateChange)(MwLL handle) = NULL; -NOCOMMON void (*MwLLBeginStateChange)(MwLL handle); -NOCOMMON void (*MwLLEndStateChange)(MwLL handle); +void (*MwLLFocus)(MwLL handle) = NULL; +void (*MwLLGrabPointer)(MwLL handle, int toggle) = NULL; -NOCOMMON void (*MwLLFocus)(MwLL handle); -NOCOMMON void (*MwLLGrabPointer)(MwLL handle, int toggle); +void (*MwLLSetClipboard)(MwLL handle, const char* text) = NULL; +void (*MwLLGetClipboard)(MwLL handle) = NULL; -NOCOMMON void (*MwLLSetClipboard)(MwLL handle, const char* text); -NOCOMMON void (*MwLLGetClipboard)(MwLL handle); - -NOCOMMON void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); -NOCOMMON void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; +void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; void MwLLCreateCommon(MwLL handle) { handle->common.handler = malloc(sizeof(*handle->common.handler)); From c61e26f0289153bb3f31b1359e83095a1338fbd4 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 12 Jan 2026 06:04:45 +0900 Subject: [PATCH 093/409] yeah --- CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 37e23d98f..dbb7a5aa6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") USE_GDI ) list(APPEND LIBRARIES gdi32) + target_link_options( + Mw + PRIVATE + -static-libgcc + ) else() find_package(PkgConfig) pkg_check_modules(X11 REQUIRED x11) From e8f743ed84f413c157209e8d97f6355f80dddeb3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 12 Jan 2026 06:24:48 +0900 Subject: [PATCH 094/409] better --- CMakeLists.txt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbb7a5aa6..62892d48c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option(USE_STB_TRUETYPE "Use stb_truetype" OFF) option(USE_FREETYPE2 "Use FreeType 2" ON) option(BUILD_SHARED "Build a shared library" ON) option(BUILD_STATIC "Build a static library" OFF) +option(INSTALL_HEADERS "Install headers" ON) file( GLOB @@ -219,11 +220,14 @@ install( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -install( - DIRECTORY include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING PATTERN "*.h" -) + +if(INSTALL_HEADERS) + install( + DIRECTORY include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.h" + ) +endif() if(BUILD_EXAMPLES) add_subdirectory(examples) From 7e32866c0a91a7896cb741a060456aa50be1f70a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 12 Jan 2026 06:28:43 +0900 Subject: [PATCH 095/409] fix cmake --- CMakeLists.txt | 52 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62892d48c..f695c1d8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,16 +9,16 @@ include(GNUInstallDirs) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -option(TRY_OPENGL "Try to compile OpenGL widget or not" ON) -option(TRY_VULKAN "Try to compile Vulkan widget or not" ON) -option(CLASSIC_THEME "Use classic theme" OFF) -option(BUILD_EXAMPLES "Build examples" OFF) -option(USE_STB_IMAGE "Use stb_image" ON) -option(USE_STB_TRUETYPE "Use stb_truetype" OFF) -option(USE_FREETYPE2 "Use FreeType 2" ON) -option(BUILD_SHARED "Build a shared library" ON) -option(BUILD_STATIC "Build a static library" OFF) -option(INSTALL_HEADERS "Install headers" ON) +option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" ON) +option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" ON) +option(MW_CLASSIC_THEME "Use classic theme" OFF) +option(MW_BUILD_EXAMPLES "Build examples" OFF) +option(MW_USE_STB_IMAGE "Use stb_image" ON) +option(MW_USE_STB_TRUETYPE "Use stb_truetype" OFF) +option(MW_USE_FREETYPE2 "Use FreeType 2" ON) +option(MW_BUILD_SHARED "Build a shared library" ON) +option(MW_BUILD_STATIC "Build a static library" OFF) +option(MW_INSTALL_HEADERS "Install headers" ON) file( GLOB @@ -29,11 +29,11 @@ file( list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") -if(NOT USE_STB_IMAGE) +if(NOT MW_USE_STB_IMAGE) list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c") endif() -if(NOT USE_STB_TRUETYPE) +if(NOT MW_USE_STB_TRUETYPE) list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_truetype.c") endif() @@ -42,10 +42,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/pkg/include") endif() -if(TRY_OPENGL) +if(MW_TRY_OPENGL) check_include_files(GL/gl.h HAVE_GL_GL_H) if(HAVE_GL_GL_H) - set(BUILD_OPENGL ON) + set(MW_BUILD_OPENGL ON) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") message(STATUS "OpenGL widget has been enabled") else() @@ -53,10 +53,10 @@ if(TRY_OPENGL) endif() endif() -if(TRY_OPENGL) +if(MW_TRY_VULKAN) check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) if(HAVE_VULKAN_VULKAN_H) - set(BUILD_VULKAN ON) + set(MW_BUILD_VULKAN ON) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") message(STATUS "Vulkan widget has been enabled") else() @@ -64,13 +64,13 @@ if(TRY_OPENGL) endif() endif() -if(BUILD_STATIC) +if(MW_BUILD_STATIC) message(STATUS "Building Milsko as a static library") add_library( Mw ${SOURCES} ) -elseif(BUILD_SHARED) +elseif(MW_BUILD_SHARED) message(STATUS "Building Milsko as a shared library") add_library( Mw @@ -81,7 +81,7 @@ else() message(ERROR "Must either build a shared library or a static library") endif() -if(USE_STB_IMAGE) +if(MW_USE_STB_IMAGE) target_compile_definitions( Mw PRIVATE @@ -96,7 +96,7 @@ else() target_sources( Mw PRIVATE - ${IMAGE_SOURCES} + ${MW_IMAGE_SOURCES} ) target_include_directories( Mw @@ -105,7 +105,7 @@ else() ) endif() -if(USE_STB_TRUETYPE) +if(MW_USE_STB_TRUETYPE) target_compile_definitions( Mw PRIVATE @@ -113,7 +113,7 @@ if(USE_STB_TRUETYPE) ) endif() -if(USE_FREETYPE2) +if(MW_USE_FREETYPE2) target_compile_definitions( Mw PRIVATE @@ -133,7 +133,7 @@ target_include_directories( include ) -if(CLASSIC_THEME) +if(MW_CLASSIC_THEME) target_compile_definitions( Mw PRIVATE @@ -197,7 +197,7 @@ target_link_libraries( ${LIBRARIES} ) -if(BUILD_VULKAN) +if(MW_BUILD_VULKAN) check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER) if(HAS_VK_ENUM_STRING_HELPER) target_compile_definitions( @@ -221,7 +221,7 @@ install( ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) -if(INSTALL_HEADERS) +if(MW_INSTALL_HEADERS) install( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} @@ -229,6 +229,6 @@ if(INSTALL_HEADERS) ) endif() -if(BUILD_EXAMPLES) +if(MW_BUILD_EXAMPLES) add_subdirectory(examples) endif() From a0d1bada8ff03aacca93dfc393e7838c703a60b6 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 12 Jan 2026 18:50:55 +0900 Subject: [PATCH 096/409] probably left debug code --- src/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core.c b/src/core.c index d8e0c2d02..769de6884 100644 --- a/src/core.c +++ b/src/core.c @@ -123,7 +123,6 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->children = NULL; if(widget_class != NULL) { - printf("%p\n", MwLLCreate); if((h->lowlevel = MwLLCreate(parent == NULL ? NULL : parent->lowlevel, x, y, width, height)) == NULL) { free(h->name); free(h); From eb50af2b815f7241d79233cd38c8a0186b3d2a6b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 13 Jan 2026 01:00:28 +0900 Subject: [PATCH 097/409] manpage says usleep is obsolete but i dont care --- src/abstract/time.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/abstract/time.c b/src/abstract/time.c index 2fbc58428..550f47a6c 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -46,11 +46,14 @@ long MwTimeGetTick(void) { } void MwTimeSleep(int ms) { +#if 0 struct timespec ts; ts.tv_sec = ms / 1000; - ts.tv_nsec = (ms % 1000) * 1000 * 1000; + ts.tv_nsec = (ms % 1000) * 1000000; nanosleep(&ts, NULL); +#endif + usleep(ms * 100); } #endif From ca4adf5f394a52c51179a38356751881200230dd Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 13:04:30 -0700 Subject: [PATCH 098/409] cocoa: fill a bunch of no-brainer functions, i haven't actually tested this yet and won't until I get home but I assume the worst case scenario is that I fucked up the syntax --- include/Mw/LowLevel/AppKit.h | 27 ------------ include/Mw/LowLevel/Cocoa.h | 1 + src/backend/cocoa.m | 83 ++++++++++++++++++++++++++++++++++-- 3 files changed, 80 insertions(+), 31 deletions(-) delete mode 100644 include/Mw/LowLevel/AppKit.h diff --git a/include/Mw/LowLevel/AppKit.h b/include/Mw/LowLevel/AppKit.h deleted file mode 100644 index 4a6c8e53c..000000000 --- a/include/Mw/LowLevel/AppKit.h +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * @file Mw/LowLevel/AppKit.h - * @brief Work in progress AppKit Backend - * @warning This is used internally. - */ -#ifndef __MW_LOWLEVEL_APPKIT_H__ -#define __MW_LOWLEVEL_APPKIT_H__ - -#include -#include -#include - -MWDECL int MwLLAppKitCallInit(void); - -struct _MwLLAppKit { - struct _MwLLCommon common; -}; - -struct _MwLLAppKitColor { - struct _MwLLCommonColor common; -}; - -struct _MwLLAppKitPixmap { - struct _MwLLCommonPixmap common; -}; - -#endif diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 1ff4c1ef5..4ff9f494e 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -23,6 +23,7 @@ struct _MwLLCocoaColor { struct _MwLLCocoaPixmap { struct _MwLLCommonPixmap common; + void* real; }; #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 396016493..bd2320ba5 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -3,13 +3,44 @@ #endif #import -#include +#import #import #include #include "../../external/stb_ds.h" +@interface MilskoCocoaPixmap : NSObject { + NSImage *image; +} ++ (MilskoCocoaPixmap*)newWithWidth:(int)width + height:(int)height; +- (void)updateWithData(void *); +- (void)destroy; +@end + +@implementation MilskoCocoaPixmap + ++ (MilskoCocoaPixmap*)newWithWidth:(int)width + height:(int)height { + MilskoCocoaPixmap * p = [MilskoCocoaPixmap alloc]; + NSSize sz; + + sz.width = width; + sz.height = height; + + p->image = [NSImage initWithSize:sz]; + + return p; +} +- (void)updateWithData(void *) { +} +- (void)destroy { + [self->image dealloc]; +} +@end + + @interface MilskoCocoa : NSObject { NSApplication *application; NSWindow *window; @@ -101,10 +132,24 @@ - (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; - (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { + NSRect frame = self->window->frame; + + *x = frame.origin.x; + *y = frame.origin.y; + *w = frame.size.x; + *h = frame.size.y; }; - (void)setX:(int)x Y:(int)y { + NSPoint p; + p.x = x; + p.y = y; + [self->window setFrameTopLeftPoint p]; }; - (void)setW:(int)w H:(int)h { + NSSize s; + s.w = w; + s.h = h; + [self->window setFrameSize s]; }; - (int)pending { return 1; @@ -122,6 +167,9 @@ [pool release]; }; - (void)setTitle:(const char *)title { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [self->window setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect { }; @@ -143,10 +191,21 @@ MaxY:(int)maxy { }; - (void)makeBorderless:(int)toggle { + NSWindowStyleMask mask = self->window.styleMask; + if(mask & NSBorderlessWindowMask) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window setStyleMask:mask]; }; - (void)focus { + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { + /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do this manually */ }; - (void)setClipboard:(const char *)text { }; @@ -155,8 +214,16 @@ - (void)makeToolWindow { }; - (void)getCursorCoord:(MwPoint *)point { + NSPoint p = self->window->mouseLocation; + point->x = p.x; + point->y = p.y; }; - (void)getScreenSize:(MwRect *)rect { + NSScreen * screen = self->window->screen; + rect->x = screen->frame.origin.x; + rect->y = screen->frame.origin.y; + rect->width = screen->frame.size.x; + rect->height = screen->frame.size.y; }; - (void)destroy { [self->window dealloc]; @@ -185,7 +252,6 @@ static void MwLLDestroyImpl(MwLL handle) { MilskoCocoa *h = handle->cocoa.real; [h destroy]; - [h dealloc]; MwLLDestroyCommon(handle); @@ -267,13 +333,22 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, r->common.width = width; r->common.height = height; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + MwLLPixmapUpdate(r); return r; } -static void MwLLPixmapUpdateImpl(MwLLPixmap r) { (void)r; } +static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; +} -static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { free(pixmap); } +static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p destroy]; + free(pixmap); +} static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { MilskoCocoa *h = handle->cocoa.real; From a70f3dbb5951dae7358c8f48848cdbd7f9c3308a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 13:07:35 -0700 Subject: [PATCH 099/409] remove old appkit.m file that somehow got here --- src/backend/appkit.m | 214 ------------------------------------------- 1 file changed, 214 deletions(-) delete mode 100644 src/backend/appkit.m diff --git a/src/backend/appkit.m b/src/backend/appkit.m deleted file mode 100644 index 6deea7c75..000000000 --- a/src/backend/appkit.m +++ /dev/null @@ -1,214 +0,0 @@ -#include - -#include "../../external/stb_ds.h" - -static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; - - r = malloc(sizeof(*r)); - - - MwLLCreateCommon(r); - - return r; -} - -static void MwLLDestroyImpl(MwLL handle) { - MwLLDestroyCommon(handle); - - free(handle); -} - -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - (void)points; - (void)points_count; - (void)color; -} - -static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - (void)handle; - (void)points; - (void)color; -} - -static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; -} - -static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; - - c->common.red = r; - c->common.green = g; - c->common.blue = b; -} - -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) { - (void)handle; - (void)x; - (void)y; -} - -static void MwLLSetWHImpl(MwLL handle, int w, int h) { - (void)handle; - (void)w; - (void)h; -} - -static void MwLLFreeColorImpl(MwLLColor color) { - free(color); -} - -static int MwLLPendingImpl(MwLL handle) { - (void)handle; - return 0; -} - -static void MwLLNextEventImpl(MwLL handle) { - (void)handle; -} - -static void MwLLSetTitleImpl(MwLL handle, const char* title) { - (void)title; - (void)handle; -} - -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { - (void)handle; - - MwLLPixmap r = malloc(sizeof(*r)); - - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); - - r->common.width = width; - r->common.height = height; - - MwLLPixmapUpdate(r); - return r; -} - -static void MwLLPixmapUpdateImpl(MwLLPixmap r) { - (void)r; -} - -static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - free(pixmap); -} - -static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - (void)handle; - (void)rect; - (void)pixmap; -} - -static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - (void)handle; - (void)pixmap; -} - -static void MwLLForceRenderImpl(MwLL handle) { - (void)handle; -} - -static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - (void)handle; - (void)image; - (void)mask; -} - -static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - (void)handle; - (void)point; -} - -static void MwLLShowImpl(MwLL handle, int show) { - (void)handle; - (void)show; -} - -static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - (void)handle; - (void)parent; -} - -static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - (void)handle; - (void)minx; - (void)miny; - (void)maxx; - (void)maxy; -} - -static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - (void)handle; - (void)toggle; -} - -static void MwLLFocusImpl(MwLL handle) { - (void)handle; -} - -static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - (void)handle; - (void)toggle; -} - -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { - (void)handle; - (void)text; -} - -static void MwLLGetClipboardImpl(MwLL handle) { - (void)handle; -} - -static void MwLLMakeToolWindowImpl(MwLL handle) { - (void)handle; -} - -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - (void)handle; - (void)point; -} - -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - (void)handle; - (void)rect; -} - -static void MwLLBeginStateChangeImpl(MwLL handle) { - MwLLShow(handle, 0); -} - -static void MwLLEndStateChangeImpl(MwLL handle) { - MwLLShow(handle, 1); -} - -static int MwLLAppKitCallInitImpl(void) { - return 0; -} - -#include "call.c" -CALL(AppKit); From 31cc8e5a0d2660503cb1a98f6e0b0714d061f72a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 15:13:59 -0700 Subject: [PATCH 100/409] cocoa: fix syntax errors. Also allow cmake to compile it (untested) --- .gitignore | 1 + CMakeLists.txt | 17 +++++++++++++ src/backend/cocoa.m | 61 ++++++++++++++++++++++----------------------- 3 files changed, 48 insertions(+), 31 deletions(-) diff --git a/.gitignore b/.gitignore index 9b18b9c39..153abcca4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ examples/*/*.exe /Makefile /build compile_flags.txt +.cache diff --git a/CMakeLists.txt b/CMakeLists.txt index f695c1d8e..650d6d1ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -158,6 +158,23 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows") PRIVATE -static-libgcc ) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_sources( + Mw + PRIVATE + src/backend/cocoa.m + ) + target_compile_definitions( + Mw + PRIVATE + USE_COCOA + ) + list(APPEND LIBRARIES objc) + target_link_options( + Mw + PRIVATE + -framework Cocoa + ) else() find_package(PkgConfig) pkg_check_modules(X11 REQUIRED x11) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index bd2320ba5..1f098a0c9 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -13,34 +13,31 @@ @interface MilskoCocoaPixmap : NSObject { NSImage *image; } -+ (MilskoCocoaPixmap*)newWithWidth:(int)width - height:(int)height; -- (void)updateWithData(void *); ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(void *)data; - (void)destroy; @end @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap*)newWithWidth:(int)width - height:(int)height { - MilskoCocoaPixmap * p = [MilskoCocoaPixmap alloc]; ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; NSSize sz; sz.width = width; sz.height = height; - p->image = [NSImage initWithSize:sz]; + p->image = [[NSImage alloc] initWithSize:sz]; return p; } -- (void)updateWithData(void *) { +- (void)updateWithData:(void *)data { } - (void)destroy { [self->image dealloc]; } @end - @interface MilskoCocoa : NSObject { NSApplication *application; NSWindow *window; @@ -132,24 +129,24 @@ - (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; - (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { - NSRect frame = self->window->frame; + NSRect frame = [self->window frame]; - *x = frame.origin.x; - *y = frame.origin.y; - *w = frame.size.x; - *h = frame.size.y; + *x = frame.origin.x; + *y = frame.origin.y; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSPoint p; - p.x = x; - p.y = y; - [self->window setFrameTopLeftPoint p]; + NSPoint p; + p.x = x; + p.y = y; + [self->window setFrameTopLeftPoint:p]; }; - (void)setW:(int)w H:(int)h { - NSSize s; - s.w = w; - s.h = h; - [self->window setFrameSize s]; + NSSize s; + s.width = w; + s.height = h; + [self->window setFrameSize:s]; }; - (int)pending { return 1; @@ -168,7 +165,8 @@ }; - (void)setTitle:(const char *)title { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [self->window setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; [pool release]; }; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect { @@ -192,7 +190,7 @@ }; - (void)makeBorderless:(int)toggle { NSWindowStyleMask mask = self->window.styleMask; - if(mask & NSBorderlessWindowMask) { + if (mask & NSBorderlessWindowMask) { mask ^= NSBorderlessWindowMask; mask |= NSTitledWindowMask; } else { @@ -205,7 +203,8 @@ [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do this manually */ + /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do + * this manually */ }; - (void)setClipboard:(const char *)text { }; @@ -214,16 +213,16 @@ - (void)makeToolWindow { }; - (void)getCursorCoord:(MwPoint *)point { - NSPoint p = self->window->mouseLocation; + NSPoint p = [NSEvent mouseLocation]; point->x = p.x; point->y = p.y; }; - (void)getScreenSize:(MwRect *)rect { - NSScreen * screen = self->window->screen; - rect->x = screen->frame.origin.x; - rect->y = screen->frame.origin.y; - rect->width = screen->frame.size.x; - rect->height = screen->frame.size.y; + NSScreen *screen = [self->window screen]; + rect->x = screen.frame.origin.x; + rect->y = screen.frame.origin.y; + rect->width = screen.frame.size.width; + rect->height = screen.frame.size.height; }; - (void)destroy { [self->window dealloc]; From e45a1f6ad8e5d5bc76cf24c0e813f75b968d6880 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 15:30:05 -0700 Subject: [PATCH 101/409] cocoa: more fixes --- src/backend/cocoa.m | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1f098a0c9..5d2895c07 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,5 +1,7 @@ #ifndef USE_COCOA #define USE_COCOA +#include +#include #endif #import @@ -41,6 +43,7 @@ @interface MilskoCocoa : NSObject { NSApplication *application; NSWindow *window; + NSRect rect; } + (MilskoCocoa *)newWithParent:(MwLL)parent @@ -100,22 +103,20 @@ } c->application = [NSApplication sharedApplication]; - NSRect rect = NSMakeRect(x, y, width, height); + c->rect = NSMakeRect(x, y, width, height); - c->window = [[[NSWindow alloc] - initWithContentRect:rect + c->window = [[NSWindow alloc] + initWithContentRect:c->rect styleMask:parent == NULL ? (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) : NSBorderlessWindowMask backing:NSBackingStoreBuffered - defer:NO] autorelease]; + defer:NO]; [c->window makeKeyAndOrderFront:c->application]; if (parent != NULL) { - [c->window setBackgroundColor:[NSColor blueColor]]; - MilskoCocoa *p = parent->cocoa.real; [p->window addChildWindow:c->window ordered:NSWindowAbove]; } @@ -140,13 +141,16 @@ NSPoint p; p.x = x; p.y = y; - [self->window setFrameTopLeftPoint:p]; + NSRect frame = [self->window frame]; + frame.origin.x = x; + frame.origin.y = y; + [self->window setFrame: frame display: YES animate: true]; }; - (void)setW:(int)w H:(int)h { - NSSize s; - s.width = w; - s.height = h; - [self->window setFrameSize:s]; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; + [self->window setFrame: frame display: YES animate: true]; }; - (int)pending { return 1; @@ -189,7 +193,7 @@ MaxY:(int)maxy { }; - (void)makeBorderless:(int)toggle { - NSWindowStyleMask mask = self->window.styleMask; + uint32_t mask = [self->window styleMask]; if (mask & NSBorderlessWindowMask) { mask ^= NSBorderlessWindowMask; mask |= NSTitledWindowMask; @@ -197,7 +201,10 @@ mask |= NSBorderlessWindowMask; mask ^= NSTitledWindowMask; } - [self->window setStyleMask:mask]; + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { [self->window makeMainWindow]; @@ -219,10 +226,10 @@ }; - (void)getScreenSize:(MwRect *)rect { NSScreen *screen = [self->window screen]; - rect->x = screen.frame.origin.x; - rect->y = screen.frame.origin.y; - rect->width = screen.frame.size.width; - rect->height = screen.frame.size.height; + rect->x = [screen frame].origin.x; + rect->y = [screen frame].origin.y; + rect->width = [screen frame].size.width; + rect->height = [screen frame].size.height; }; - (void)destroy { [self->window dealloc]; From efcc176c0428a2fd8ce2a3f87ef5bb9ce4feabbf Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 15:31:22 -0700 Subject: [PATCH 102/409] cocoa: more fixes --- src/backend/cocoa.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 5d2895c07..4e0b0c315 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -224,12 +224,12 @@ point->x = p.x; point->y = p.y; }; -- (void)getScreenSize:(MwRect *)rect { +- (void)getScreenSize:(MwRect *)_rect { NSScreen *screen = [self->window screen]; - rect->x = [screen frame].origin.x; - rect->y = [screen frame].origin.y; - rect->width = [screen frame].size.width; - rect->height = [screen frame].size.height; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { [self->window dealloc]; From 69c95d5752f390d81e42eac4f7f04ac75adbbdbc Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 18:18:05 -0700 Subject: [PATCH 103/409] wayland: more fix --- include/Mw/LowLevel/Wayland.h | 6 +- src/backend/wayland.c | 107 ++++++++++++++++++++++++---------- 2 files changed, 80 insertions(+), 33 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index cd9642484..b711e1666 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -186,8 +186,6 @@ struct _MwLLWayland { MwBool force_render; - MwBool disabled; - struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; @@ -198,6 +196,10 @@ struct _MwLLWayland { IOI_XD: This sounds like a hilariously rare edge case, so it's almost funnier that this happened with 100% certainty for me and I spent day(s) trying to figure out what was happening. */ pthread_mutex_t eventsMutex; + uint32_t last_time; + + MwLL currentlyHeldWidget; + cairo_surface_t* cs; cairo_t* cairo; }; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 9169a10bd..e049bbea6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,13 +1,17 @@ #include #include +#include #include #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include #include #include +#include /* TODO: * - MwLLGrabPointerImpl @@ -371,7 +375,7 @@ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 n } static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp); + // zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp); } /* `wl_pointer.enter` callback */ @@ -410,6 +414,15 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time self->wayland.events_pending += 1; + /* Only draw once every 10 milliseconds */ + if((self->wayland.last_time + 10) <= time) { + if(!self->wayland.always_render) { + MwLLDispatch(self, draw, NULL); + self->wayland.events_pending += 1; + } + self->wayland.last_time = time; + } + WAYLAND_EVENT_OP_END(self); /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ @@ -442,15 +455,29 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri switch(state) { case WL_POINTER_BUTTON_STATE_PRESSED: MwLLDispatch(self, down, &p); + if(self->wayland.parent != NULL) { + self->wayland.parent->wayland.currentlyHeldWidget = self; + } break; case WL_POINTER_BUTTON_STATE_RELEASED: - MwLLDispatch(self, up, &p); + if(self->wayland.parent != NULL) { + if(self->wayland.parent->wayland.currentlyHeldWidget != NULL) { + MwLLDispatch(self->wayland.parent->wayland.currentlyHeldWidget, up, &p); + self->wayland.parent->wayland.currentlyHeldWidget = NULL; + } + } else { + MwLLDispatch(self, up, &p); + } break; } } if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); + if(self->wayland.parent != NULL) { + MwLLDispatch(self->wayland.parent, draw, NULL); + self->wayland.parent->wayland.events_pending += 1; + } self->wayland.events_pending += 1; } @@ -628,6 +655,9 @@ static void keyboard_key(void* data, if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); + if(self->wayland.parent != NULL) { + MwLLDispatch(self->wayland.parent, draw, NULL); + } self->wayland.events_pending += 1; } @@ -745,15 +775,14 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { ((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(ll->wayland.registry, name, &wl_seat_interface, 1); - wl_seat_add_listener(proto->context, proto->listener, ll); + wl_seat_add_listener(wl_registry_bind(ll->wayland.registry, name, &wl_seat_interface, 1), proto->listener, ll); return proto; } static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { free(data->listener); - wl_seat_destroy(data->context); + // wl_seat_destroy(data->context); } /* wl_output setup function */ @@ -802,7 +831,7 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa } static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - xdg_wm_base_destroy(data->context); + // xdg_wm_base_destroy(data->context); free(data->listener); } @@ -829,8 +858,8 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { zxdg_decoration_manager_v1_context_t* context = data->context; - zxdg_decoration_manager_v1_destroy(context->manager); - zxdg_toplevel_decoration_v1_destroy(context->decoration); + // zxdg_decoration_manager_v1_destroy(context->manager); + // zxdg_toplevel_decoration_v1_destroy(context->decoration); } /* `xdg_toplevel.close` callback */ @@ -1007,7 +1036,7 @@ static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { free(data->listener); - xdg_toplevel_icon_manager_v1_destroy(data->context); + // xdg_toplevel_icon_manager_v1_destroy(data->context); } /* Standard Wayland event loop. */ @@ -1149,8 +1178,8 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Perform the initial commit and wait for the first configure event */ wl_surface_commit(r->wayland.framebuffer.surface); - event_loop(r); while(!r->wayland.configured) { + event_loop(r); } /* setup decorations if we can */ @@ -1184,8 +1213,14 @@ static void destroy_toplevel(MwLL r) { xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); + xkb_keymap_unref(r->wayland.toplevel->xkb_keymap); + + xkb_state_unref(r->wayland.toplevel->xkb_state); + xkb_context_unref(r->wayland.toplevel->xkb_context); + free(r->wayland.toplevel); + wl_registry_destroy(r->wayland.registry); wl_display_disconnect(r->wayland.display); @@ -1369,6 +1404,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_toplevel(r, x, y); } else { setup_sublevel(parent, r, x, y); + MwLLDispatch(parent, draw, NULL); + parent->wayland.events_pending += 1; } framebuffer_setup(&r->wayland); @@ -1399,6 +1436,16 @@ static void MwLLDestroyImpl(MwLL handle) { event_loop(handle); + /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ + tv.tv_sec = 0; + tv.tv_usec = 1000; + do { + select_ret = select(1, NULL, NULL, NULL, &tv); + } while((select_ret == -1) && (errno == EINTR)); + + pthread_mutex_unlock(&handle->wayland.eventsMutex); + pthread_mutex_destroy(&handle->wayland.eventsMutex); + framebuffer_destroy(&handle->wayland); buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); @@ -1424,29 +1471,14 @@ static void MwLLDestroyImpl(MwLL handle) { for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); - handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + if(ctx != NULL) { + handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); + } shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); } shfree(handle->wayland.wl_protocol_map); shfree(handle->wayland.wl_protocol_setup_map); - if(handle->wayland.pointer != NULL) { - wl_pointer_destroy(handle->wayland.pointer); - } - if(handle->wayland.keyboard != NULL) { - wl_keyboard_destroy(handle->wayland.keyboard); - } - - /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ - tv.tv_sec = 0; - tv.tv_usec = 500; - do { - select_ret = select(1, NULL, NULL, NULL, &tv); - } while((select_ret == -1) && (errno == EINTR)); - - pthread_mutex_unlock(&handle->wayland.eventsMutex); - pthread_mutex_destroy(&handle->wayland.eventsMutex); - free(handle); } @@ -1471,6 +1503,11 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { region_setup(handle); MwLLDispatch(handle, draw, NULL); + handle->wayland.events_pending += 1; + if(handle->wayland.parent != NULL) { + MwLLDispatch(handle->wayland.parent, draw, NULL); + handle->wayland.parent->wayland.events_pending += 1; + } } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -1490,12 +1527,13 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } refresh: - MwLLDispatch(handle, draw, NULL); region_setup(handle); framebuffer_destroy(&handle->wayland); framebuffer_setup(&handle->wayland); - MwLLDispatch(handle, draw, NULL); + if(handle->wayland.parent != NULL) { + MwLLDispatch(handle->wayland.parent, draw, NULL); + } } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { @@ -1576,7 +1614,14 @@ static int MwLLPendingImpl(MwLL handle) { timeout.tv_nsec = 10; timeout.tv_sec = 0; - return handle->wayland.force_render || handle->wayland.events_pending || wl_display_dispatch_timeout(handle->wayland.display, &timeout); + if(handle->wayland.force_render) { + return 1; + } + if(handle->wayland.events_pending) { + return 1; + } + + return wl_display_dispatch_timeout(handle->wayland.display, &timeout); } static void MwLLNextEventImpl(MwLL handle) { From 14e55b7f5316aa80d54ec4126090a877f2cc282a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 18:48:22 -0700 Subject: [PATCH 104/409] wayland: fix weird regression --- src/backend/wayland.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index e049bbea6..21ced85d6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -465,9 +465,8 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self->wayland.parent->wayland.currentlyHeldWidget, up, &p); self->wayland.parent->wayland.currentlyHeldWidget = NULL; } - } else { - MwLLDispatch(self, up, &p); } + MwLLDispatch(self, up, &p); break; } } @@ -1504,10 +1503,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { MwLLDispatch(handle, draw, NULL); handle->wayland.events_pending += 1; - if(handle->wayland.parent != NULL) { - MwLLDispatch(handle->wayland.parent, draw, NULL); - handle->wayland.parent->wayland.events_pending += 1; - } } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -1531,6 +1526,7 @@ refresh: framebuffer_destroy(&handle->wayland); framebuffer_setup(&handle->wayland); + MwLLDispatch(handle, draw, NULL); if(handle->wayland.parent != NULL) { MwLLDispatch(handle->wayland.parent, draw, NULL); } From d340c64ca3f93f7ab4258c0c7706e11048da3d51 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 18:50:33 -0700 Subject: [PATCH 105/409] wayland: fix weird regressiong --- src/backend/wayland.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 21ced85d6..1e32e2cd9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -465,8 +465,9 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self->wayland.parent->wayland.currentlyHeldWidget, up, &p); self->wayland.parent->wayland.currentlyHeldWidget = NULL; } + } else { + MwLLDispatch(self, up, &p); } - MwLLDispatch(self, up, &p); break; } } @@ -1403,8 +1404,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { setup_toplevel(r, x, y); } else { setup_sublevel(parent, r, x, y); - MwLLDispatch(parent, draw, NULL); - parent->wayland.events_pending += 1; } framebuffer_setup(&r->wayland); @@ -1413,6 +1412,9 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { region_setup(r); MwLLForceRender(r); + if(parent != NULL) { + MwLLForceRender(parent); + } return r; } @@ -1527,9 +1529,6 @@ refresh: framebuffer_destroy(&handle->wayland); framebuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); - if(handle->wayland.parent != NULL) { - MwLLDispatch(handle->wayland.parent, draw, NULL); - } } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { From 32f09a9af2855a2f14ac72fa7f5bdbf20b62f016 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 12 Jan 2026 19:21:21 -0700 Subject: [PATCH 106/409] wayland: don't do parent draws on every event when we do'nt need to --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 22 +++++----------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index b711e1666..0375ecebd 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 diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1e32e2cd9..7acc03891 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -412,17 +412,14 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - self->wayland.events_pending += 1; - - /* Only draw once every 10 milliseconds */ - if((self->wayland.last_time + 10) <= time) { - if(!self->wayland.always_render) { - MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; - } + /* Only draw once every 50 milliseconds */ + if((self->wayland.last_time + 50) <= time) { + MwLLDispatch(self, draw, NULL); self->wayland.last_time = time; } + self->wayland.events_pending += 1; + WAYLAND_EVENT_OP_END(self); /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ @@ -474,10 +471,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); - if(self->wayland.parent != NULL) { - MwLLDispatch(self->wayland.parent, draw, NULL); - self->wayland.parent->wayland.events_pending += 1; - } self->wayland.events_pending += 1; } @@ -655,9 +648,6 @@ static void keyboard_key(void* data, if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); - if(self->wayland.parent != NULL) { - MwLLDispatch(self->wayland.parent, draw, NULL); - } self->wayland.events_pending += 1; } @@ -943,8 +933,6 @@ static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_proto } static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { - fsync(buffer->fd); - wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); wl_surface_commit(buffer->surface); } From 85994d42f15f164f6e147a557333c0fd33b1c734 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 15 Jan 2026 05:16:14 +0900 Subject: [PATCH 107/409] fix issue #5 --- Makefile.pl | 72 ++++++++++++++++---------------- include/Mw/TypeDefs.h | 3 ++ pl/ostype/Darwin.pl | 2 +- pl/utils.pl | 2 +- src/backend/x11.c | 2 +- src/core.c | 97 +++++++++++++++++++++++++++---------------- 6 files changed, 104 insertions(+), 74 deletions(-) diff --git a/Makefile.pl b/Makefile.pl index ded79b02e..f710f2774 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -45,7 +45,7 @@ param_set("vulkan", 0); param_set("vulkan-string-helper", 1); param_set("shared", 1); param_set("static", 1); -param_set("examples", 1); +param_set("examples", 1); my %features = ( "classic-theme" => "use classic theme", @@ -221,11 +221,12 @@ foreach my $l (@library_targets) { my $o = $object_suffix; $o =~ s/\./\\\./g; - if ($l =~ /cocoa/) { - $s =~ s/$o$/.m/; - } else { - $s =~ s/$o$/.c/; - } + if ($l =~ /cocoa/) { + $s =~ s/$o$/.m/; + } + else { + $s =~ s/$o$/.c/; + } if ($l =~ /^external\//) { $warn = ""; @@ -236,37 +237,38 @@ foreach my $l (@library_targets) { } print(OUT "\n"); print(OUT "\n"); -if(param_get("examples")) { - print(OUT "examples: " . join(" ", @examples_targets) . "\n"); - print(OUT "\n"); - foreach my $l (@examples_targets) { - my $libs = ""; - my $s = $l; - my $o = $executable_suffix; - $o =~ s/\./\\\./g; - $s =~ s/$o$//; +if (param_get("examples")) { + print(OUT "examples: " . join(" ", @examples_targets) . "\n"); + print(OUT "\n"); + foreach my $l (@examples_targets) { + my $libs = ""; + my $s = $l; + my $o = $executable_suffix; + $o =~ s/\./\\\./g; + $s =~ s/$o$//; - if (defined($examples_libs{$l})) { - $libs = $examples_libs{$l}; - } + if (defined($examples_libs{$l})) { + $libs = $examples_libs{$l}; + } - print(OUT - "${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" - ); - if (grep(/^cocoa$/, @backends)) { - print(OUT - " \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" - ); - } else { - print(OUT - " \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" - ); - } - print(OUT "${s}${object_suffix}: ${s}.c\n"); - print(OUT - " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" - ); - } + print(OUT +"${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" + ); + if (grep(/^cocoa$/, @backends)) { + print(OUT +" \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } + else { + print(OUT +" \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" + ); + } + print(OUT "${s}${object_suffix}: ${s}.c\n"); + print(OUT +" \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" + ); + } } print(OUT "\n"); print(OUT "clean:\n"); diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 6434f5236..d175c2b36 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -101,6 +101,9 @@ struct _MwWidget { MwWidget* tick_list; int destroyed; + + void* root_font; + void* root_boldfont; }; #endif diff --git a/pl/ostype/Darwin.pl b/pl/ostype/Darwin.pl index 72cfe275f..c786eb87f 100644 --- a/pl/ostype/Darwin.pl +++ b/pl/ostype/Darwin.pl @@ -1,4 +1,4 @@ -$library_suffix = ".dylib"; +$library_suffix = ".dylib"; set_shared_flag("-dynamiclib"); use_backend("cocoa"); diff --git a/pl/utils.pl b/pl/utils.pl index 264e6797f..f2f722b05 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -41,7 +41,7 @@ sub new_example { } sub set_shared_flag { - @shared = $_[0]; + @shared = $_[0]; } sub new_object { diff --git a/src/backend/x11.c b/src/backend/x11.c index ce6dae0e1..f7c6fe4bd 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -158,7 +158,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->x11.top = 0; r->x11.toplevel = 0; } - r->x11.window = XCreateSimpleWindow(r->x11.display, p, px, py, width, height, 0, 0, WhitePixel(r->x11.display, DefaultScreen(r->x11.display))); + r->x11.window = XCreateSimpleWindow(r->x11.display, p, px, py, width, height, 0, 0, WhitePixel(r->x11.display, DefaultScreen(r->x11.display))); sh.flags = PWinGravity; sh.win_gravity = StaticGravity; diff --git a/src/core.c b/src/core.c index 769de6884..9ec87b2bd 100644 --- a/src/core.c +++ b/src/core.c @@ -114,6 +114,19 @@ static void llclipboardhandler(MwLL handle, void* data) { MwDispatchUserHandler(h, MwNclipboardHandler, data); } +/* if both of them are true + * 1. widget class is not NULL + * 2. parent is NULL + * or parent's widget class is NULL + * + * most likely this widget is first *visible* widget + * + * this macro is not used anywhere else - we could expose it if we have to + * + * (nishi) + */ +#define IsFirstVisible(handle) ((handle)->widget_class != NULL && ((handle)->parent == NULL || (handle)->parent->widget_class == NULL)) + MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { MwWidget h = malloc(sizeof(*h)); @@ -186,6 +199,17 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, MwAddTickList(h); } +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) + if(IsFirstVisible(h)) { + h->root_font = MwFontLoad(MwTTFData, MwTTFDataSize); + h->root_boldfont = MwFontLoad(MwBoldTTFData, MwBoldTTFDataSize); + } else +#endif + { + h->root_font = NULL; + h->root_boldfont = NULL; + } + if(h->parent != NULL) MwDispatch(h->parent, children_update); return h; @@ -250,6 +274,9 @@ static void MwFreeWidget(MwWidget handle) { arrfree(handle->destroy_queue); arrfree(handle->tick_list); + if(handle->root_font != NULL) MwFontFree(handle->root_font); + if(handle->root_boldfont != NULL) MwFontFree(handle->root_boldfont); + free(handle); } @@ -507,8 +534,41 @@ const char* MwGetText(MwWidget handle, const char* key) { return shget(handle->text, key); } +static void* inherit_void(MwWidget handle, const char* key) { + void* v; + + if(handle->parent != NULL && (v = MwGetVoid(handle->parent, key)) != NULL) { + return v; + } + return NULL; +} + void* MwGetVoid(MwWidget handle, const char* key) { - return shget(handle->data, key); + void* v = shget(handle->data, key); + + if(v != NULL) return v; + +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) + if(strcmp(key, MwNfont) == 0 || strcmp(key, MwNboldFont) == 0) { + v = inherit_void(handle, key); + + if(v == NULL) { + MwWidget w = handle; + + while(w != NULL && v == NULL) { + if(strcmp(key, MwNfont) == 0) { + v = w->root_font; + } else { + v = w->root_boldfont; + } + + w = w->parent; + } + } + } +#endif + + return v; } void MwVaApply(MwWidget handle, ...) { @@ -576,43 +636,8 @@ void MwVaListApply(MwWidget handle, va_list va) { } } -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) -static void set_font(MwWidget handle) { - void* f; - MwWidget h = handle; - while(h != NULL) { - if((f = MwGetVoid(h, MwNfont)) != NULL) { - MwSetVoid(handle, MwNfont, f); - return; - } - h = h->parent; - } - f = MwFontLoad(MwTTFData, MwTTFDataSize); - MwSetVoid(handle, MwNfont, f); -} - -static void set_boldfont(MwWidget handle) { - void* f; - MwWidget h = handle; - while(h != NULL) { - if((f = MwGetVoid(h, MwNboldFont)) != NULL) { - MwSetVoid(handle, MwNboldFont, f); - return; - } - h = h->parent; - } - f = MwFontLoad(MwBoldTTFData, MwBoldTTFDataSize); - MwSetVoid(handle, MwNboldFont, f); -} -#endif - void MwSetDefault(MwWidget handle) { if(handle->lowlevel != NULL) MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); - -#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) - set_font(handle); - set_boldfont(handle); -#endif } void MwHideCursor(MwWidget handle) { From 3dec3ff0da021faabe2f186eb2c4b4826d77dff4 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 15 Jan 2026 05:16:47 +0900 Subject: [PATCH 108/409] format --- include/Mw/LowLevel/Cocoa.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 4ff9f494e..06afe7815 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -23,7 +23,7 @@ struct _MwLLCocoaColor { struct _MwLLCocoaPixmap { struct _MwLLCommonPixmap common; - void* real; + void* real; }; #endif From e2f34df4e33fb0bb347b752fff93af5a48161056 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 15 Jan 2026 05:31:04 +0900 Subject: [PATCH 109/409] format objective c files --- .clang-format | 1 - Makefile.pl | 2 +- src/backend/cocoa.m | 502 +++++++++++++++++++++++--------------------- 3 files changed, 261 insertions(+), 244 deletions(-) diff --git a/.clang-format b/.clang-format index beacb203a..376186b37 100644 --- a/.clang-format +++ b/.clang-format @@ -1,5 +1,4 @@ --- -Language: Cpp UseTab: Always TabWidth: 8 AlignConsecutiveAssignments: diff --git a/Makefile.pl b/Makefile.pl index f710f2774..519781ecd 100755 --- a/Makefile.pl +++ b/Makefile.pl @@ -184,7 +184,7 @@ print(OUT " cp -rf include \$(DESTDIR)\$(PREFIX)/\n"); print(OUT "\n"); print(OUT "format:\n"); print(OUT -" clang-format --verbose -i `find src include examples -name \"*.c\" -or -name \"*.h\"`\n" +" clang-format --verbose -i `find src include examples -name \"*.c\" -or -name \"*.h\" -or -name \"*.m\"`\n" ); print(OUT " perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl Makefile.pl -name \"*.pl\"`\n" diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 4e0b0c315..6d118f34e 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -13,433 +13,451 @@ #include "../../external/stb_ds.h" @interface MilskoCocoaPixmap : NSObject { - NSImage *image; + NSImage* image; } -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(void *)data; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(void*)data; - (void)destroy; @end @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; - NSSize sz; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; + NSSize sz; - sz.width = width; - sz.height = height; + sz.width = width; + sz.height = height; - p->image = [[NSImage alloc] initWithSize:sz]; + p->image = [[NSImage alloc] initWithSize:sz]; - return p; + return p; } -- (void)updateWithData:(void *)data { +- (void)updateWithData:(void*)data { } - (void)destroy { - [self->image dealloc]; + [self->image dealloc]; } @end @interface MilskoCocoa : NSObject { - NSApplication *application; - NSWindow *window; - NSRect rect; + NSApplication* application; + NSWindow* window; + NSRect rect; } -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height; -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; - (void)getNextEvent; -- (void)setTitle:(const char *)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; +- (void)setTitle:(const char*)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; - (void)setIcon:(MwLLPixmap)pixmap; - (void)forceRender; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; -- (void)detachWithPoint:(MwPoint *)point; +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; +- (void)detachWithPoint:(MwPoint*)point; - (void)show:(int)show; - (void)makePopupWithParent:(MwLL)parent; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; - (void)makeBorderless:(int)toggle; - (void)focus; - (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char *)text; +- (void)setClipboard:(const char*)text; - (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint *)point; -- (void)getScreenSize:(MwRect *)rect; +- (void)getCursorCoord:(MwPoint*)point; +- (void)getScreenSize:(MwRect*)rect; - (void)destroy; @end @implementation MilskoCocoa -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height { - MilskoCocoa *c = [MilskoCocoa alloc]; - bool centerX = false, centerY = false; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height { + MilskoCocoa* c = [MilskoCocoa alloc]; + bool centerX = false, centerY = false; - if (x == MwDEFAULT) { - x = 0; - centerX = true; - } - if (y == MwDEFAULT) { - y = 0; - centerY = true; - } - c->application = [NSApplication sharedApplication]; + if(x == MwDEFAULT) { + x = 0; + centerX = true; + } + if(y == MwDEFAULT) { + y = 0; + centerY = true; + } + c->application = [NSApplication sharedApplication]; - c->rect = NSMakeRect(x, y, width, height); + c->rect = NSMakeRect(x, y, width, height); - c->window = [[NSWindow alloc] - initWithContentRect:c->rect - styleMask:parent == NULL - ? (NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | - NSResizableWindowMask) - : NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - [c->window makeKeyAndOrderFront:c->application]; + c->window = [[NSWindow alloc] + initWithContentRect:c->rect + styleMask:parent == NULL + ? (NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | + NSResizableWindowMask) + : NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [c->window makeKeyAndOrderFront:c->application]; - if (parent != NULL) { - MilskoCocoa *p = parent->cocoa.real; - [p->window addChildWindow:c->window ordered:NSWindowAbove]; - } + if(parent != NULL) { + MilskoCocoa* p = parent->cocoa.real; + [p->window addChildWindow:c->window ordered:NSWindowAbove]; + } - return c; + return c; } -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color { +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color { }; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { }; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { - NSRect frame = [self->window frame]; +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { + NSRect frame = [self->window frame]; - *x = frame.origin.x; - *y = frame.origin.y; - *w = frame.size.width; - *h = frame.size.height; + *x = frame.origin.x; + *y = frame.origin.y; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSPoint p; - p.x = x; - p.y = y; - NSRect frame = [self->window frame]; - frame.origin.x = x; - frame.origin.y = y; - [self->window setFrame: frame display: YES animate: true]; + NSPoint p; + p.x = x; + p.y = y; + NSRect frame = [self->window frame]; + frame.origin.x = x; + frame.origin.y = y; + [self->window setFrame:frame display:YES animate:true]; }; - (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; - [self->window setFrame: frame display: YES animate: true]; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; + [self->window setFrame:frame display:YES animate:true]; }; - (int)pending { - return 1; + return 1; }; - (void)getNextEvent { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [self->application nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* event = [self->application nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]; - if (event != nil) { - printf("got event: %p\n", event); - } - [pool release]; + if(event != nil) { + printf("got event: %p\n", event); + } + [pool release]; }; -- (void)setTitle:(const char *)title { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; +- (void)setTitle:(const char*)title { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect { +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect { }; - (void)setIcon:(MwLLPixmap)pixmap { }; - (void)forceRender { }; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { }; -- (void)detachWithPoint:(MwPoint *)point { +- (void)detachWithPoint:(MwPoint*)point { }; - (void)show:(int)show { }; - (void)makePopupWithParent:(MwLL)parent { }; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { }; - (void)makeBorderless:(int)toggle { - uint32_t mask = [self->window styleMask]; - if (mask & NSBorderlessWindowMask) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; + uint32_t mask = [self->window styleMask]; + if(mask & NSBorderlessWindowMask) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { - [self->window makeMainWindow]; + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do - * this manually */ + /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do + * this manually */ }; -- (void)setClipboard:(const char *)text { +- (void)setClipboard:(const char*)text { }; - (void)getClipboard { }; - (void)makeToolWindow { }; -- (void)getCursorCoord:(MwPoint *)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; +- (void)getCursorCoord:(MwPoint*)point { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; }; -- (void)getScreenSize:(MwRect *)_rect { - NSScreen *screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; +- (void)getScreenSize:(MwRect*)_rect { + NSScreen* screen = [self->window screen]; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { - [self->window dealloc]; + [self->window dealloc]; } @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; - r = malloc(sizeof(*r)); + r = malloc(sizeof(*r)); - MwLLCreateCommon(r); + MwLLCreateCommon(r); - MilskoCocoa *o = - [MilskoCocoa newWithParent:parent x:x y:y width:width height:height]; - r->cocoa.real = o; + MilskoCocoa* o = + [MilskoCocoa newWithParent:parent + x:x + y:y + width:width + height:height]; + r->cocoa.real = o; - return r; + return r; } static void MwLLDestroyImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; + MilskoCocoa* h = handle->cocoa.real; - [h destroy]; + [h destroy]; - MwLLDestroyCommon(handle); + MwLLDestroyCommon(handle); - free(handle); + free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, - MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; } -static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h lineWithPoints:points color:color]; +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, + MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; + (void)handle; - c->common.red = r; - c->common.green = g; - c->common.blue = b; + c->common.red = r; + c->common.green = g; + c->common.blue = b; } -static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, - unsigned int *height) { - MilskoCocoa *h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, + unsigned int* height) { + MilskoCocoa* h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa *h = handle->cocoa.real; - [h setX:x Y:y]; + MilskoCocoa* h = handle->cocoa.real; + [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa *h = handle->cocoa.real; - [h setW:w H:height]; + MilskoCocoa* h = handle->cocoa.real; + [h setW:w H:height]; } -static void MwLLFreeColorImpl(MwLLColor color) { free(color); } +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} static int MwLLPendingImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - return [h pending]; + MilskoCocoa* h = handle->cocoa.real; + return [h pending]; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h getNextEvent]; + MilskoCocoa* h = handle->cocoa.real; + [h getNextEvent]; } -static void MwLLSetTitleImpl(MwLL handle, const char *title) { - MilskoCocoa *h = handle->cocoa.real; - [h setTitle:title]; +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + MilskoCocoa* h = handle->cocoa.real; + [h setTitle:title]; } -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, - int width, int height) { - (void)handle; +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, + int width, int height) { + (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + MwLLPixmap r = malloc(sizeof(*r)); - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - r->common.width = width; - r->common.height = height; + r->common.width = width; + r->common.height = height; - r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; - MwLLPixmapUpdate(r); - return r; + MwLLPixmapUpdate(r); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p destroy]; - free(pixmap); + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p destroy]; + free(pixmap); } -static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + MilskoCocoa* h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h setIcon:pixmap]; + MilskoCocoa* h = handle->cocoa.real; + [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h forceRender]; + MilskoCocoa* h = handle->cocoa.real; + [h forceRender]; } -static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { - MilskoCocoa *h = handle->cocoa.real; - [h setCursor:image mask:mask]; +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + MilskoCocoa* h = handle->cocoa.real; + [h setCursor:image mask:mask]; } -static void MwLLDetachImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h detachWithPoint:point]; +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa *h = handle->cocoa.real; - [h show:show]; + MilskoCocoa* h = handle->cocoa.real; + [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa *h = handle->cocoa.real; - [h makePopupWithParent:parent]; + MilskoCocoa* h = handle->cocoa.real; + [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, - int maxy) { - MilskoCocoa *h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + int maxy) { + MilskoCocoa* h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeBorderless:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h focus]; + MilskoCocoa* h = handle->cocoa.real; + [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h grabPointer:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h grabPointer:toggle]; } -static void MwLLSetClipboardImpl(MwLL handle, const char *text) { - MilskoCocoa *h = handle->cocoa.real; - [h setClipboard:text]; +static void MwLLSetClipboardImpl(MwLL handle, const char* text) { + MilskoCocoa* h = handle->cocoa.real; + [h setClipboard:text]; } -static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } +static void MwLLGetClipboardImpl(MwLL handle) { + (void)handle; +} static void MwLLMakeToolWindowImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeToolWindow]; + MilskoCocoa* h = handle->cocoa.real; + [h makeToolWindow]; } -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h getCursorCoord:point]; +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h getCursorCoord:point]; } -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { - MilskoCocoa *h = handle->cocoa.real; - [h getScreenSize:rect]; +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + MilskoCocoa* h = handle->cocoa.real; + [h getScreenSize:rect]; } -static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} -static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} -static int MwLLCocoaCallInitImpl(void) { return 0; } +static int MwLLCocoaCallInitImpl(void) { + return 0; +} #include "call.c" CALL(Cocoa); From a71096711542833ac1ecdf96369738560884f157 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 14 Jan 2026 13:47:49 -0700 Subject: [PATCH 110/409] cocoa: move interfaces to header (guarded by ifdef __OBJC__) --- include/Mw/LowLevel/Cocoa.h | 61 +++++++++++++++++++++++++++++++++++-- src/backend/cocoa.m | 51 ------------------------------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 06afe7815..868d6addd 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -10,11 +10,67 @@ #include #include +#ifdef __OBJC__ +@interface MilskoCocoaPixmap : NSObject { + NSImage* image; +} ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(void*)data; +- (void)destroy; +@end +@interface MilskoCocoa : NSObject { + NSApplication* application; + NSWindow* window; + NSRect rect; +} + ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; +- (void)setX:(int)x Y:(int)y; +- (void)setW:(int)w H:(int)h; +- (int)pending; +- (void)getNextEvent; +- (void)setTitle:(const char*)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; +- (void)setIcon:(MwLLPixmap)pixmap; +- (void)forceRender; +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; +- (void)detachWithPoint:(MwPoint*)point; +- (void)show:(int)show; +- (void)makePopupWithParent:(MwLL)parent; +- (void)setSizeHintsWithMinX:(int)minx + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; +- (void)makeBorderless:(int)toggle; +- (void)focus; +- (void)grabPointer:(int)toggle; +- (void)setClipboard:(const char*)text; +- (void)makeToolWindow; +- (void)getCursorCoord:(MwPoint*)point; +- (void)getScreenSize:(MwRect*)rect; +- (void)destroy; + +@end +#define OBJC(x) x +#else +#define OBJC(x) void* +#endif + MWDECL int MwLLCocoaCallInit(void); struct _MwLLCocoa { struct _MwLLCommon common; - void* real; + OBJC(MilskoCocoa*) + real; }; struct _MwLLCocoaColor { @@ -23,7 +79,8 @@ struct _MwLLCocoaColor { struct _MwLLCocoaPixmap { struct _MwLLCommonPixmap common; - void* real; + OBJC(MilskoCocoaPixmap*) + real; }; #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 6d118f34e..b5ccd4093 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -12,14 +12,6 @@ #include "../../external/stb_ds.h" -@interface MilskoCocoaPixmap : NSObject { - NSImage* image; -} -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(void*)data; -- (void)destroy; -@end - @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { @@ -40,49 +32,6 @@ } @end -@interface MilskoCocoa : NSObject { - NSApplication* application; - NSWindow* window; - NSRect rect; -} - -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height; -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; -- (void)setX:(int)x Y:(int)y; -- (void)setW:(int)w H:(int)h; -- (int)pending; -- (void)getNextEvent; -- (void)setTitle:(const char*)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; -- (void)setIcon:(MwLLPixmap)pixmap; -- (void)forceRender; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; -- (void)detachWithPoint:(MwPoint*)point; -- (void)show:(int)show; -- (void)makePopupWithParent:(MwLL)parent; -- (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; -- (void)makeBorderless:(int)toggle; -- (void)focus; -- (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char*)text; -- (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint*)point; -- (void)getScreenSize:(MwRect*)rect; -- (void)destroy; - -@end - @implementation MilskoCocoa + (MilskoCocoa*)newWithParent:(MwLL)parent From 04f1a94cb5fa7992f77af8d890d10a2290376206 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 14 Jan 2026 17:13:12 -0700 Subject: [PATCH 111/409] cocoa: attempted drawing --- include/Mw/LowLevel.h | 7 +- include/Mw/LowLevel/Cocoa.h | 39 ++++++++++- src/backend/cocoa.m | 127 +++++++++++++++++++++++++++++------- 3 files changed, 144 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 96ff8e849..6bea6cd3c 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -6,6 +6,7 @@ #ifndef __MW_LOWLEVEL_H__ #define __MW_LOWLEVEL_H__ +#include "Mw/BaseTypes.h" #include typedef struct _MwLLHandler* MwLLHandler; @@ -40,9 +41,9 @@ struct _MwLLCommon { }; struct _MwLLCommonColor { - int red; - int green; - int blue; + MwU8 red; + MwU8 green; + MwU8 blue; }; struct _MwLLCommonPixmap { diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 868d6addd..2d1d9bdea 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -11,17 +11,50 @@ #include #ifdef __OBJC__ + +#import +#import +#import + +#ifdef __APPLE__ +#import +#else +#import +#endif + @interface MilskoCocoaPixmap : NSObject { + int width; + int height; + NSData* data; NSImage* image; } + + (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; - (void)updateWithData:(void*)data; - (void)destroy; + +/* using @property to create instance variables fucks up 10.4 gcc for some reason? */ +- (NSImage*)image; + @end + +@interface MilskoCocoaView : NSView { + CGContextRef cg; + CGColorSpaceRef space; + CGDataProviderRef provider; + MwU32* buf; + float width; + float height; +} + +- (CGContextRef)context; +@end + @interface MilskoCocoa : NSObject { - NSApplication* application; - NSWindow* window; - NSRect rect; + NSApplication* application; + NSWindow* window; + NSRect rect; + MilskoCocoaView* view; } + (MilskoCocoa*)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index b5ccd4093..cd45ae294 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,34 +1,40 @@ -#ifndef USE_COCOA -#define USE_COCOA -#include -#include -#endif - -#import -#import -#import - +#include #include +#include +#include +#include #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; - NSSize sz; - sz.width = width; - sz.height = height; - - p->image = [[NSImage alloc] initWithSize:sz]; + p->width = width; + p->height = height; + p->data = NULL; + p->image = NULL; return p; } -- (void)updateWithData:(void*)data { +- (void)updateWithData:(void*)_data { + [self destroy]; + + self->data = [NSData dataWithBytes:_data length:self->width * self->height * 4]; + self->image = [[NSImage alloc] initWithData:self->data]; } - (void)destroy { - [self->image dealloc]; + if(self->data != NULL) { + [self->data dealloc]; + } + if(self->image != NULL) { + [self->image dealloc]; + } +} +- (NSImage*)image { + return self->image; } @end @@ -68,13 +74,32 @@ if(parent != NULL) { MilskoCocoa* p = parent->cocoa.real; [p->window addChildWindow:c->window ordered:NSWindowAbove]; + } else { + [c->application activateIgnoringOtherApps:true]; } + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->window setContentView:c->view]; + return c; } - (void)polygonWithPoints:(MwPoint*)points points_count:(int)points_count color:(MwLLColor)color { + int i; + CGContextRef cg = [self->view context]; + + CGContextSetRGBFillColor(cg, color->common.red / 255., color->common.blue / 255., color->common.green / 255., 1); + CGContextBeginPath(cg); + for(i = 0; i < points_count; i++) { + CGContextMoveToPoint(cg, points[i].x, points[i].y); + if(i < points_count - 1) { + CGContextAddLineToPoint(cg, points[i + 1].x, points[i + 1].y); + } + } + CGContextFillPath(cg); + + // [self->view setNeedsDisplay:true]; }; - (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { }; @@ -105,15 +130,22 @@ return 1; }; - (void)getNextEvent { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSEvent* event = [self->application nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + NSEvent* event = [self->application nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]; if(event != nil) { printf("got event: %p\n", event); } + + [self->application sendEvent:event]; + + /* this should be in the draw functions but it's here for now for testing */ + [self->view setNeedsDisplay:true]; + [pool release]; }; - (void)setTitle:(const char*)title { @@ -122,7 +154,9 @@ setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect { +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [[p image] drawAtPoint:NSMakePoint(_rect->x, _rect->y) fromRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) operation:NSCompositeClear fraction:1.0]; }; - (void)setIcon:(MwLLPixmap)pixmap { }; @@ -183,6 +217,53 @@ - (void)destroy { [self->window dealloc]; } + +@end + +@implementation MilskoCocoaView +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + self->width = frame.size.width; + self->height = frame.size.height; + self->buf = malloc(self->width * self->height * 4); + self->space = CGColorSpaceCreateDeviceRGB(); + self->cg = CGBitmapContextCreate(self->buf, + self->width, + self->height, + CHAR_BIT, + self->width * sizeof(uint32_t), + self->space, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast); + assert(self->cg); + printf("%p\n", self->cg); + return self; +} + +- (CGContextRef)context { + return self->cg; +} + +- (void)drawRect:(NSRect)dirtyRect { + [super drawRect:dirtyRect]; + if(self) { + + CGImageRef img = CGBitmapContextCreateImage(self->cg); + if(!img) { + return; + } + printf("printed image\n"); + + CGContextDrawImage([[NSGraphicsContext currentContext] graphicsPort], CGRectMake(0, 0, self->width, self->height), img); + CGImageRelease(img); + } + // printf("%0.2f %0.2f %0.2f %0.2f\n", dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); +} + +- (void)destroy { + free(self->buf); + CGContextRelease(self->cg); + CGColorSpaceRelease(self->space); +} + @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { From b458613f87b1cfcf05e0cf102688814861010d9f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 20 Jan 2026 14:05:03 +0900 Subject: [PATCH 112/409] update --- src/abstract/time.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/abstract/time.c b/src/abstract/time.c index 550f47a6c..727997894 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -46,7 +46,10 @@ long MwTimeGetTick(void) { } void MwTimeSleep(int ms) { -#if 0 +#ifdef __NetBSD__ + usleep(ms * 100); +#else + /* i don't know why this method does not work well on netbsd */ struct timespec ts; ts.tv_sec = ms / 1000; @@ -54,6 +57,5 @@ void MwTimeSleep(int ms) { nanosleep(&ts, NULL); #endif - usleep(ms * 100); } #endif From 8d86f185f2a7882a98977e3e0d88c637f166d1a0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 23 Jan 2026 13:57:05 +0900 Subject: [PATCH 113/409] use milsko's typedefs instead in cocoa --- include/Mw/MachDep.h | 1 + src/backend/cocoa.m | 11 ++++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index c8cb06052..bc34270b5 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -45,6 +45,7 @@ #include #include #include +#include #endif #ifdef __APPLE__ diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index cd45ae294..42c38a57c 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,11 +1,8 @@ -#include #include -#include -#include -#include + +#include #include "../../external/stb_ds.h" -#include "Mw/BaseTypes.h" @implementation MilskoCocoaPixmap @@ -176,7 +173,7 @@ MaxY:(int)maxy { }; - (void)makeBorderless:(int)toggle { - uint32_t mask = [self->window styleMask]; + MwU32 mask = [self->window styleMask]; if(mask & NSBorderlessWindowMask) { mask ^= NSBorderlessWindowMask; mask |= NSTitledWindowMask; @@ -231,7 +228,7 @@ self->width, self->height, CHAR_BIT, - self->width * sizeof(uint32_t), + self->width * sizeof(MwU32), self->space, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast); assert(self->cg); printf("%p\n", self->cg); From 5413332506b2929c30c169a3f68934252d39cfff Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 23 Jan 2026 15:29:32 +0900 Subject: [PATCH 114/409] introduce MwWidget->berserk --- include/Mw/TypeDefs.h | 2 ++ src/abstract/time.c | 5 ----- src/core.c | 3 ++- src/widget/opengl.c | 42 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index d175c2b36..d6bd1da88 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -104,6 +104,8 @@ struct _MwWidget { void* root_font; void* root_boldfont; + + int berserk; }; #endif diff --git a/src/abstract/time.c b/src/abstract/time.c index 727997894..1050c46d3 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -46,16 +46,11 @@ long MwTimeGetTick(void) { } void MwTimeSleep(int ms) { -#ifdef __NetBSD__ - usleep(ms * 100); -#else - /* i don't know why this method does not work well on netbsd */ struct timespec ts; ts.tv_sec = ms / 1000; ts.tv_nsec = (ms % 1000) * 1000000; nanosleep(&ts, NULL); -#endif } #endif diff --git a/src/core.c b/src/core.c index 9ec87b2bd..78d2a9468 100644 --- a/src/core.c +++ b/src/core.c @@ -154,6 +154,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->destroyed = 0; h->dark_theme = 0; h->bgcolor = NULL; + h->berserk = 0; if(parent == NULL) arrput(h->tick_list, h); @@ -392,7 +393,7 @@ void MwLoop(MwWidget handle) { more = over % (wait / 2); t = (tick + wait - more) - (t2 = MwTimeGetTick()); if(t > 0) { - MwTimeSleep(t); + if(!handle->berserk) MwTimeSleep(t); tick = MwTimeGetTick(); over -= more; } else { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 0dedd7fed..8738b5d6a 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -56,7 +56,9 @@ typedef struct waylandopengl { #endif static int create(MwWidget handle) { - void* r = NULL; + void* r = NULL; + MwWidget w = handle; + #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { PIXELFORMATDESCRIPTOR pfd; @@ -210,10 +212,16 @@ static int create(MwWidget handle) { MwSetDefault(handle); + while(w->parent != NULL) w = w->parent; + + w->berserk++; + return 0; } static void destroy(MwWidget handle) { + MwWidget w = handle; + #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { gdiopengl_t* o = handle->internal; @@ -241,22 +249,48 @@ static void destroy(MwWidget handle) { } #endif + while(w->parent != NULL) w = w->parent; + + w->berserk++; + free(handle->internal); } static void mwOpenGLMakeCurrentImpl(MwWidget handle) { + /* these swap interval functions belonging here actually stink! */ + #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; + gdiopengl_t* o = handle->internal; + void (*swap_interval_ext)(int) = NULL; o->wglMakeCurrent(o->dc, o->gl); + + if((swap_interval_ext = MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { + swap_interval_ext(1); + } } #endif #ifdef USE_X11 if(handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t* o = handle->internal; + x11opengl_t* o = handle->internal; + void (*swap_interval_ext)(Display*, GLXDrawable, int) = NULL; + void (*swap_interval_mesa)(unsigned int) = NULL; + void (*swap_interval_sgi)(int) = NULL; o->glXMakeCurrent(handle->lowlevel->x11.display, handle->lowlevel->x11.window, o->gl); + + if((swap_interval_ext = MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { + swap_interval_ext(handle->lowlevel->x11.display, handle->lowlevel->x11.window, 1); + } + + if((swap_interval_mesa = MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { + swap_interval_mesa(1); + } + + if((swap_interval_sgi = MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { + swap_interval_sgi(1); + } } #endif #ifdef USE_WAYLAND @@ -266,6 +300,8 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); } + + eglSwapInterval(o->egl_display, 1); } #endif } From 836b13e62ee1115de4560e362f8f6688397bc8a6 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 17:02:40 +0900 Subject: [PATCH 115/409] add RPN calculator demo --- examples/basic/calculator.c | 185 ++++++++++++++++++++++++++++++++++++ pl/rules.pl | 1 + 2 files changed, 186 insertions(+) create mode 100644 examples/basic/calculator.c diff --git a/examples/basic/calculator.c b/examples/basic/calculator.c new file mode 100644 index 000000000..27f7ad4bb --- /dev/null +++ b/examples/basic/calculator.c @@ -0,0 +1,185 @@ +#include + +MwWidget widgets[18]; +MwWidget inp; + +/* probably enough for most tasks */ +double stack[512]; +int sp = 0; + +static void resize(MwWidget handle, void* client, void* user) { + int ww = MwGetInteger(handle, MwNwidth); + int wh = MwGetInteger(handle, MwNheight) - MwGetInteger(inp, MwNheight); + int i; + + MwVaApply(inp, + MwNwidth, ww, + NULL); + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) { + int x = i % 4; + int y = i / 4; + if(widgets[i] != NULL) { + MwVaApply(widgets[i], + MwNwidth, ww / 4, + MwNheight, wh / 5, + MwNx, ww / 4 * x, + MwNy, wh / 5 * y + MwGetInteger(inp, MwNheight), + NULL); + } + } +} + +static void activate(MwWidget handle, void* client, void* user) { + const char* n = MwGetText(handle, MwNtext); + + if(('0' <= n[0] && n[0] <= '9') || n[0] == '.') { + const char* s = MwGetText(inp, MwNtext); + char* r; + + if(n[0] == '.' && s != NULL) { + int i; + for(i = 0; s[i] != 0; i++) { + if(s[i] == '.') return; + } + } + + if(s == NULL) s = ""; + + r = MwStringConcat(s, n); + MwVaApply(inp, + MwNtext, r, + NULL); + free(r); + } else if(n[0] == 'E') { + const char* s = MwGetText(inp, MwNtext); + + if(s != NULL) { + stack[sp++] = atof(s); + + MwVaApply(inp, + MwNtext, "", + NULL); + } + } else if(n[0] == 'C') { + MwVaApply(inp, + MwNtext, "", + NULL); + } else if(n[0] == '+' || n[0] == '-' || n[0] == '*' || n[0] == '/') { + if(sp >= 2) { + double sv = stack[--sp]; + double fv = stack[--sp]; + double v; + char buf[256]; + + if(n[0] == '+') { + v = fv + sv; + } else if(n[0] == '-') { + v = fv - sv; + } else if(n[0] == '*') { + v = fv * sv; + } else if(n[0] == '/') { + v = fv / sv; + } + + sprintf(buf, "%g", v); + + MwVaApply(inp, + MwNtext, buf, + NULL); + } + } +} + +int main() { + MwWidget w; + int i; + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) widgets[i] = NULL; + + MwLibraryInit(); + + w = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 150, 150, + MwNtitle, "Calculator", + NULL); + + inp = MwCreateWidget(MwEntryClass, "entry", w, 0, 0, 0, 24); + + widgets[0] = MwVaCreateWidget(MwButtonClass, "7", w, 0, 0, 0, 0, + MwNtext, "7", + NULL); + + widgets[1] = MwVaCreateWidget(MwButtonClass, "8", w, 0, 0, 0, 0, + MwNtext, "8", + NULL); + + widgets[2] = MwVaCreateWidget(MwButtonClass, "9", w, 0, 0, 0, 0, + MwNtext, "9", + NULL); + + widgets[3] = MwVaCreateWidget(MwButtonClass, "/", w, 0, 0, 0, 0, + MwNtext, "/", + NULL); + + widgets[4] = MwVaCreateWidget(MwButtonClass, "4", w, 0, 0, 0, 0, + MwNtext, "4", + NULL); + + widgets[5] = MwVaCreateWidget(MwButtonClass, "5", w, 0, 0, 0, 0, + MwNtext, "5", + NULL); + + widgets[6] = MwVaCreateWidget(MwButtonClass, "6", w, 0, 0, 0, 0, + MwNtext, "6", + NULL); + + widgets[7] = MwVaCreateWidget(MwButtonClass, "*", w, 0, 0, 0, 0, + MwNtext, "*", + NULL); + + widgets[8] = MwVaCreateWidget(MwButtonClass, "1", w, 0, 0, 0, 0, + MwNtext, "1", + NULL); + + widgets[9] = MwVaCreateWidget(MwButtonClass, "2", w, 0, 0, 0, 0, + MwNtext, "2", + NULL); + + widgets[10] = MwVaCreateWidget(MwButtonClass, "3", w, 0, 0, 0, 0, + MwNtext, "3", + NULL); + + widgets[11] = MwVaCreateWidget(MwButtonClass, "-", w, 0, 0, 0, 0, + MwNtext, "-", + NULL); + + widgets[12] = MwVaCreateWidget(MwButtonClass, "0", w, 0, 0, 0, 0, + MwNtext, "0", + NULL); + + widgets[13] = MwVaCreateWidget(MwButtonClass, ".", w, 0, 0, 0, 0, + MwNtext, ".", + NULL); + + widgets[16] = MwVaCreateWidget(MwButtonClass, "E", w, 0, 0, 0, 0, + MwNtext, "E", + NULL); + + widgets[15] = MwVaCreateWidget(MwButtonClass, "+", w, 0, 0, 0, 0, + MwNtext, "+", + NULL); + + widgets[17] = MwVaCreateWidget(MwButtonClass, "C", w, 0, 0, 0, 0, + MwNtext, "C", + NULL); + + for(i = 0; i < sizeof(widgets) / sizeof(widgets[0]); i++) { + if(widgets[i] != NULL) MwAddUserHandler(widgets[i], MwNactivateHandler, activate, NULL); + } + + MwAddUserHandler(w, MwNresizeHandler, resize, NULL); + + resize(w, NULL, NULL); + + MwLoop(w); +} diff --git a/pl/rules.pl b/pl/rules.pl index 73f4c6177..59605a803 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -128,6 +128,7 @@ new_example("examples/basic/treeview"); new_example("examples/basic/box"); new_example("examples/basic/clipboard"); new_example("examples/basic/sevensegment"); +new_example("examples/basic/calculator"); if (param_get("opengl")) { new_example("examples/gldemos/boing", $gl_libs); From 8b28b3e1b0207ae061caebda0a6f62ce68ffb1be Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 17:34:25 +0900 Subject: [PATCH 116/409] might be functional --- include/Mw/LowLevel.h | 1 + include/Mw/LowLevel/GDI.h | 1 + src/backend/gdi.c | 23 ++++++++++++++++++++++- src/core.c | 8 ++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 6bea6cd3c..b54832885 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -163,6 +163,7 @@ struct _MwLLHandler { void (*focus_in)(MwLL handle, void* data); void (*focus_out)(MwLL handle, void* data); void (*clipboard)(MwLL handle, void* data); + void (*dark_theme)(MwLL handle, void* data); }; #ifdef __cplusplus diff --git a/include/Mw/LowLevel/GDI.h b/include/Mw/LowLevel/GDI.h index 1bf997c23..c695cbd13 100644 --- a/include/Mw/LowLevel/GDI.h +++ b/include/Mw/LowLevel/GDI.h @@ -22,6 +22,7 @@ struct _MwLLGDI { int grabbed; int force_render; int get_clipboard; + int get_darktheme; }; struct _MwLLGDIColor { diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 764e9838d..20c47b26f 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -8,6 +8,17 @@ typedef struct userdata { int max_set; } userdata_t; +static void detect_darktheme(MwLL handle){ + DWORD dw; + DWORD sz = sizeof(dw); + + if(RegGetValue(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, &dw, &sz) == ERROR_SUCCESS){ + int t = dw ? 0 : 1; + + MwLLDispatch(handle, dark_theme, &t); + } +} + static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { userdata_t* u = (userdata_t*)GetWindowLongPtr(hWnd, GWLP_USERDATA); @@ -205,6 +216,10 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } else if(msg == WM_USER) { InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); + } else if(msg == WM_WININICHANGE){ + char* s = (char*)lp; + + if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); } else { return DefWindowProc(hWnd, msg, wp, lp); } @@ -238,6 +253,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.type = MwLLBackendGDI; r->gdi.get_clipboard = 1; + r->gdi.get_darktheme = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); @@ -384,7 +400,7 @@ static int MwLLPendingImpl(MwLL handle) { (void)handle; - if(handle->gdi.get_clipboard) return 1; + if(handle->gdi.get_clipboard || handle->gdi.get_darktheme) return 1; return PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE) ? 1 : 0; } @@ -411,6 +427,11 @@ static void MwLLNextEventImpl(MwLL handle) { handle->gdi.get_clipboard = 0; } + if(handle->gdi.get_darktheme){ + detect_darktheme(handle); + + handle->gdi.get_clipboard = 0; + } while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { GetMessage(&msg, handle->gdi.hWnd, 0, 0); TranslateMessage(&msg); diff --git a/src/core.c b/src/core.c index 78d2a9468..9d0d18bee 100644 --- a/src/core.c +++ b/src/core.c @@ -127,6 +127,13 @@ static void llclipboardhandler(MwLL handle, void* data) { */ #define IsFirstVisible(handle) ((handle)->widget_class != NULL && ((handle)->parent == NULL || (handle)->parent->widget_class == NULL)) +static void lldarkthemehandler(MwLL handle, void* data){ + MwWidget h = (MwWidget)handle->common.user; + int* ptr = data; + + if(IsFirstVisible(h)) MwToggleDarkTheme(h, *ptr); +} + MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { MwWidget h = malloc(sizeof(*h)); @@ -171,6 +178,7 @@ MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, h->lowlevel->common.handler->focus_in = llfocusinhandler; h->lowlevel->common.handler->focus_out = llfocusouthandler; h->lowlevel->common.handler->clipboard = llclipboardhandler; + h->lowlevel->common.handler->dark_theme = lldarkthemehandler; } if(parent != NULL) arrput(parent->children, h); From 18457ccbcb28b4c542f19b7201647e6189ff4373 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 17:36:21 +0900 Subject: [PATCH 117/409] tiny fix --- src/backend/gdi.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 20c47b26f..5c4febe17 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -218,8 +218,11 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { UpdateWindow(hWnd); } else if(msg == WM_WININICHANGE){ char* s = (char*)lp; + LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); - if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); + if(!(style & WS_CHILD)){ + if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); + } } else { return DefWindowProc(hWnd, msg, wp, lp); } From 0cecae2dd16e4073b81bfbc72a2140e6f6feccbd Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 17:58:30 +0900 Subject: [PATCH 118/409] better registry function --- src/backend/gdi.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 5c4febe17..e985c8bbb 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -11,12 +11,22 @@ typedef struct userdata { static void detect_darktheme(MwLL handle){ DWORD dw; DWORD sz = sizeof(dw); + int err, t; + HKEY hkey; + DWORD type; - if(RegGetValue(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", "AppsUseLightTheme", RRF_RT_REG_DWORD, NULL, &dw, &sz) == ERROR_SUCCESS){ - int t = dw ? 0 : 1; + err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_QUERY_VALUE, &hkey); + if(err != ERROR_SUCCESS) return; - MwLLDispatch(handle, dark_theme, &t); + err = RegQueryValueEx(hkey, "AppsUseLightTheme", NULL, &type, (PBYTE)&dw, &sz); + if(err != ERROR_SUCCESS || type != REG_DWORD){ + RegCloseKey(hkey); + return; } + + t = dw ? 0 : 1; + + MwLLDispatch(handle, dark_theme, &t); } static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { From ae96b127e1b06f7d6e990a3da4985ac688c8fad9 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 17:58:52 +0900 Subject: [PATCH 119/409] fix leak --- src/backend/gdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index e985c8bbb..c1e0fb781 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -19,8 +19,8 @@ static void detect_darktheme(MwLL handle){ if(err != ERROR_SUCCESS) return; err = RegQueryValueEx(hkey, "AppsUseLightTheme", NULL, &type, (PBYTE)&dw, &sz); + RegCloseKey(hkey); if(err != ERROR_SUCCESS || type != REG_DWORD){ - RegCloseKey(hkey); return; } From 5e492ee5b418b8edb8ec0b0db959689eada09473 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:00:44 +0900 Subject: [PATCH 120/409] oops --- src/backend/gdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index c1e0fb781..ae6a7a629 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -443,7 +443,7 @@ static void MwLLNextEventImpl(MwLL handle) { if(handle->gdi.get_darktheme){ detect_darktheme(handle); - handle->gdi.get_clipboard = 0; + handle->gdi.get_darktheme = 0; } while(PeekMessage(&msg, handle->gdi.hWnd, 0, 0, PM_NOREMOVE)) { GetMessage(&msg, handle->gdi.hWnd, 0, 0); From 64c3cdb4a511b0b9efcd538a4c1bc82cbbda7dc8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:03:16 +0900 Subject: [PATCH 121/409] MwSetDarkTheme instead of MwToggleDarkTheme --- examples/basic/example.c | 2 +- include/Mw/Core.h | 2 +- milsko.xml | 2 +- src/backend/gdi.c | 2 +- src/core.c | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/basic/example.c b/examples/basic/example.c index 614b4e37a..9cc89db49 100644 --- a/examples/basic/example.c +++ b/examples/basic/example.c @@ -17,7 +17,7 @@ void handler_dark(MwWidget handle, void* user_data, void* call_data) { (void)call_data; toggle = toggle ? 0 : 1; - MwToggleDarkTheme(window, toggle); + MwSetDarkTheme(window, toggle); } void resize(MwWidget handle, void* user_data, void* call_data) { diff --git a/include/Mw/Core.h b/include/Mw/Core.h index cd7cabd19..aba19e115 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -296,7 +296,7 @@ MWDECL void MwHideCursor(MwWidget handle); * @param handle Widget * @param toggle Toggle */ -MWDECL void MwToggleDarkTheme(MwWidget handle, int toggle); +MWDECL void MwSetDarkTheme(MwWidget handle, int toggle); /*! * @brief Gets the parent widget diff --git a/milsko.xml b/milsko.xml index dc980cd8d..bc73f0e2b 100644 --- a/milsko.xml +++ b/milsko.xml @@ -353,7 +353,7 @@ - + diff --git a/src/backend/gdi.c b/src/backend/gdi.c index ae6a7a629..373ef8758 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -266,7 +266,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.type = MwLLBackendGDI; r->gdi.get_clipboard = 1; - r->gdi.get_darktheme = 1; + if(parent == NULL) r->gdi.get_darktheme = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); diff --git a/src/core.c b/src/core.c index 9d0d18bee..55f667dbb 100644 --- a/src/core.c +++ b/src/core.c @@ -131,7 +131,7 @@ static void lldarkthemehandler(MwLL handle, void* data){ MwWidget h = (MwWidget)handle->common.user; int* ptr = data; - if(IsFirstVisible(h)) MwToggleDarkTheme(h, *ptr); + if(IsFirstVisible(h)) MwSetDarkTheme(h, *ptr); } MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { @@ -747,7 +747,7 @@ static void force_render_all(MwWidget handle) { if(handle->lowlevel != NULL) MwForceRender(handle); } -void MwToggleDarkTheme(MwWidget handle, int toggle) { +void MwSetDarkTheme(MwWidget handle, int toggle) { int old = handle->dark_theme; if(old != toggle) { handle->dark_theme = toggle; From 65c872710a81f95850b92fd64c5a5a0fd2e0332d Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:12:36 +0900 Subject: [PATCH 122/409] it should be working now, closes #6 --- src/backend/gdi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 373ef8758..79822e710 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -663,6 +663,8 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { rc2.bottom -= rc2.top; SetWindowPos(handle->gdi.hWnd, HWND_TOPMOST, rc.left, rc.top, rc2.right == 0 ? 1 : rc2.right, rc2.bottom == 0 ? 1 : rc2.bottom, SWP_FRAMECHANGED | SWP_NOACTIVATE); + + handle->gdi.get_darktheme = 1; } static void MwLLShowImpl(MwLL handle, int show) { From 9544404f7c0851b7f96e310008c3ce2f723cb1f0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:46:12 +0900 Subject: [PATCH 123/409] fix warning --- src/core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core.c b/src/core.c index 55f667dbb..0c1b4718b 100644 --- a/src/core.c +++ b/src/core.c @@ -543,6 +543,7 @@ const char* MwGetText(MwWidget handle, const char* key) { return shget(handle->text, key); } +#if defined(USE_STB_TRUETYPE) || defined(USE_FREETYPE2) static void* inherit_void(MwWidget handle, const char* key) { void* v; @@ -551,6 +552,7 @@ static void* inherit_void(MwWidget handle, const char* key) { } return NULL; } +#endif void* MwGetVoid(MwWidget handle, const char* key) { void* v = shget(handle->data, key); From 626294c95f9c208c1b65dd22c49c9a5ca7c4d9ea Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:50:03 +0900 Subject: [PATCH 124/409] format --- src/backend/gdi.c | 32 ++++++++++++++++---------------- src/core.c | 6 +++--- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 79822e710..4601b79da 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -8,11 +8,11 @@ typedef struct userdata { int max_set; } userdata_t; -static void detect_darktheme(MwLL handle){ +static void detect_darktheme(MwLL handle) { DWORD dw; DWORD sz = sizeof(dw); - int err, t; - HKEY hkey; + int err, t; + HKEY hkey; DWORD type; err = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", 0, KEY_QUERY_VALUE, &hkey); @@ -20,10 +20,10 @@ static void detect_darktheme(MwLL handle){ err = RegQueryValueEx(hkey, "AppsUseLightTheme", NULL, &type, (PBYTE)&dw, &sz); RegCloseKey(hkey); - if(err != ERROR_SUCCESS || type != REG_DWORD){ + if(err != ERROR_SUCCESS || type != REG_DWORD) { return; } - + t = dw ? 0 : 1; MwLLDispatch(handle, dark_theme, &t); @@ -226,11 +226,11 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { } else if(msg == WM_USER) { InvalidateRect(hWnd, NULL, FALSE); UpdateWindow(hWnd); - } else if(msg == WM_WININICHANGE){ - char* s = (char*)lp; + } else if(msg == WM_WININICHANGE) { + char* s = (char*)lp; LPARAM style = GetWindowLongPtr(hWnd, GWL_STYLE); - - if(!(style & WS_CHILD)){ + + if(!(style & WS_CHILD)) { if(s != NULL && strcmp(s, "ImmersiveColorSet") == 0) detect_darktheme(u->ll); } } else { @@ -267,12 +267,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->gdi.get_clipboard = 1; if(parent == NULL) r->gdi.get_darktheme = 1; - r->gdi.force_render = 0; - r->gdi.grabbed = 0; - r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); - r->gdi.hInstance = wc.hInstance; - r->gdi.cursor = NULL; - r->gdi.icon = NULL; + r->gdi.force_render = 0; + r->gdi.grabbed = 0; + r->gdi.hWnd = CreateWindow("milsko", "Milsko", parent == NULL ? (WS_OVERLAPPEDWINDOW) : (WS_CHILD | WS_VISIBLE), x == MwDEFAULT ? CW_USEDEFAULT : x, y == MwDEFAULT ? CW_USEDEFAULT : y, width, height, parent == NULL ? NULL : parent->gdi.hWnd, 0, wc.hInstance, NULL); + r->gdi.hInstance = wc.hInstance; + r->gdi.cursor = NULL; + r->gdi.icon = NULL; u->ll = r; u->min_set = 0; @@ -440,7 +440,7 @@ static void MwLLNextEventImpl(MwLL handle) { handle->gdi.get_clipboard = 0; } - if(handle->gdi.get_darktheme){ + if(handle->gdi.get_darktheme) { detect_darktheme(handle); handle->gdi.get_darktheme = 0; diff --git a/src/core.c b/src/core.c index 0c1b4718b..b157bbb6b 100644 --- a/src/core.c +++ b/src/core.c @@ -127,9 +127,9 @@ static void llclipboardhandler(MwLL handle, void* data) { */ #define IsFirstVisible(handle) ((handle)->widget_class != NULL && ((handle)->parent == NULL || (handle)->parent->widget_class == NULL)) -static void lldarkthemehandler(MwLL handle, void* data){ - MwWidget h = (MwWidget)handle->common.user; - int* ptr = data; +static void lldarkthemehandler(MwLL handle, void* data) { + MwWidget h = (MwWidget)handle->common.user; + int* ptr = data; if(IsFirstVisible(h)) MwSetDarkTheme(h, *ptr); } From bbb20f081ef347f074912091e0f641b8104fc69a Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 27 Jan 2026 18:51:57 +0900 Subject: [PATCH 125/409] add MwNdarkThemeHandler --- include/Mw/StringDefs.h | 1 + src/core.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 5d6896598..db597889f 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -72,5 +72,6 @@ #define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */ #define MwNdrawHandler "Cdraw" /* NULL */ #define MwNclipboardHandler "Cclipboard" /* char* */ +#define MwNdarkThemeHandler "CdarkTheme" /* int* */ #endif diff --git a/src/core.c b/src/core.c index b157bbb6b..6985a02ee 100644 --- a/src/core.c +++ b/src/core.c @@ -131,7 +131,11 @@ static void lldarkthemehandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; int* ptr = data; - if(IsFirstVisible(h)) MwSetDarkTheme(h, *ptr); + if(IsFirstVisible(h)) { + MwSetDarkTheme(h, *ptr); + + MwDispatchUserHandler(h, MwNdarkThemeHandler, data); + } } MwWidget MwCreateWidget(MwClass widget_class, const char* name, MwWidget parent, int x, int y, unsigned int width, unsigned int height) { From ad5aa03d11a9c14ec978da1ab03a157cfb435b2c Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sat, 31 Jan 2026 20:42:09 +0900 Subject: [PATCH 126/409] remove non required headers --- src/backend/wayland.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 7acc03891..19f6386c7 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,12 +5,9 @@ #include #include "../../external/stb_ds.h" -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" #include #include -#include #include /* TODO: From 7ad4d8202460de860aa7bb5c94129ce1265a290e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 2 Feb 2026 23:02:42 +0900 Subject: [PATCH 127/409] c89 --- src/backend/wayland.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 19f6386c7..7d8faeee1 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -431,13 +431,14 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { + int i; switch(button) { case BTN_LEFT: p.button = MwLLMouseLeft; break; case BTN_MIDDLE: p.button = MwLLMouseMiddle; - for(int i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { + for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { wl_clipboard_read( self->wayland.clipboard_devices[i]); } @@ -624,7 +625,8 @@ static void keyboard_key(void* data, if((self->wayland.mod_state & 4) == 4) { /* clipboard paste */ if(key == 'V') { - for(int i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { + int i; + for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { wl_clipboard_read( self->wayland.clipboard_devices[i]); } @@ -1851,12 +1853,14 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { strcpy(handle->wayland.clipboard_buffer, text); if(handle->wayland.supports_zwp) { - for(int i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { + int i; + for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); } } else { - for(int i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { + int i; + for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); } From 5bc06dc8512e806dfa6364d5849acf61f7190322 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 3 Feb 2026 23:24:34 +0900 Subject: [PATCH 128/409] testing jenkins --- Jenkinsfile | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 000000000..4a3c003b7 --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,16 @@ +pipeline { + agent { + label "built-in" + } + stages { + stage("Build document") { + steps { + } + post { + always { + notifyDiscord() + } + } + } + } +} From 12f7312d407326915fbe92e6235fc2edf8ce0971 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 3 Feb 2026 23:27:27 +0900 Subject: [PATCH 129/409] testing jenkins --- Jenkinsfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Jenkinsfile b/Jenkinsfile index 4a3c003b7..719f14695 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,6 +5,7 @@ pipeline { stages { stage("Build document") { steps { + sh("echo Testing testing...") } post { always { From 282283609c01ca5e1dc0c901de4a59875daa91d3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 3 Feb 2026 23:43:08 +0900 Subject: [PATCH 130/409] i wonder if doc gets generated --- Jenkinsfile | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 719f14695..8a51a786f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,12 +5,9 @@ pipeline { stages { stage("Build document") { steps { - sh("echo Testing testing...") - } - post { - always { - notifyDiscord() - } + sh("doxygen") + sh("rm -rf /var/www/milsko-doxygen") + sh("mv doxygen/html /var/www/milsko-doxygen") } } } From c308bd9324c6d3d953af71c9bb297e97bab93715 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 3 Feb 2026 23:46:24 +0900 Subject: [PATCH 131/409] test --- Jenkinsfile | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8a51a786f..8c9eb9d2c 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -10,5 +10,30 @@ pipeline { sh("mv doxygen/html /var/www/milsko-doxygen") } } + stage("Build") { + parallel { + stage("Build for Linux 64-bit") { + steps { + sh("./Makefile.pl --enable-opengl --enable-vulkan --without-vulkan-string-helper") + sh("make clean") + sh("make -j4") + } + } + stage("Build for Windows 32-bit") { + steps { + sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") + sh("make clean") + sh("make -j4") + } + } + stage("Build for Windows 64-bit") { + steps { + sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") + sh("make clean") + sh("make -j4") + } + } + } + } } } From 4a092e71d2aed7d1887ebbf970ab364cdd70b0f4 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 4 Feb 2026 00:02:21 +0900 Subject: [PATCH 132/409] testing --- Jenkinsfile | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 8c9eb9d2c..7b7426169 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,6 +9,11 @@ pipeline { sh("rm -rf /var/www/milsko-doxygen") sh("mv doxygen/html /var/www/milsko-doxygen") } + post { + always { + notifyDiscord() + } + } } stage("Build") { parallel { @@ -34,6 +39,11 @@ pipeline { } } } + post { + always { + notifyDiscord() + } + } } } } From 3329184993d395e033029eaa1faed6a94401a1e6 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 4 Feb 2026 00:06:31 +0900 Subject: [PATCH 133/409] unused --- Koakumafile | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100755 Koakumafile diff --git a/Koakumafile b/Koakumafile deleted file mode 100755 index 92cb41be5..000000000 --- a/Koakumafile +++ /dev/null @@ -1,24 +0,0 @@ -# vim: syntax=tcl - -proc run {project_name} { - if { "$project_name" == "MilskoDoxygen" } { - RunCommand "doxygen" - RunCommand "rm -rf /var/www/milsko-doxygen" - RunCommand "mv doxygen/html /var/www/milsko-doxygen" - } else { - foreach target {"Linux" "Win32" "Win64"} { - if { [file exists "Makefile"] == 1 } { - RunCommand "make distclean" - } - if { "$target" == "Linux" } { - RunCommand "./Makefile.pl --enable-opengl --enable-vulkan --without-vulkan-string-helper" - } elseif { "$target" == "Win32" } { - RunCommand "./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32" - } elseif { "$target" == "Win64" } { - RunCommand "./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32" - } - RunCommand "make clean" - RunCommand "make -j4" - } - } -} From 280ba93cf1f9a32609a375b6a07529c70c0a749b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 4 Feb 2026 00:21:31 +0900 Subject: [PATCH 134/409] hmm --- Jenkinsfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 7b7426169..74776380f 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -18,6 +18,9 @@ pipeline { stage("Build") { parallel { stage("Build for Linux 64-bit") { + agent { + label "built-in" + } steps { sh("./Makefile.pl --enable-opengl --enable-vulkan --without-vulkan-string-helper") sh("make clean") @@ -25,6 +28,9 @@ pipeline { } } stage("Build for Windows 32-bit") { + agent { + label "built-in" + } steps { sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") sh("make clean") @@ -32,6 +38,9 @@ pipeline { } } stage("Build for Windows 64-bit") { + agent { + label "built-in" + } steps { sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") sh("make clean") From c04f751a4f77f18c0482dd5932ba3491af680575 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 4 Feb 2026 00:25:49 +0900 Subject: [PATCH 135/409] msvc --- Jenkinsfile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 74776380f..67b12d48b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -47,6 +47,15 @@ pipeline { sh("make -j4") } } + stage("Build for Windows 64-bit (MSVC)") { + agent { + label "2012r2" + } + steps { + sh("nmake -f NTMakefile clean") + sh("nmake") + } + } } post { always { From d7db903695348ed79945af1ac842b26fffdbb211 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 4 Feb 2026 00:30:22 +0900 Subject: [PATCH 136/409] msvc --- Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 67b12d48b..58736fdb2 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -52,8 +52,8 @@ pipeline { label "2012r2" } steps { - sh("nmake -f NTMakefile clean") - sh("nmake") + bat("nmake -f NTMakefile clean") + bat("nmake -f NTMakefile") } } } From 11fec984cf24c1497c6310095268986a12469fd6 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 6 Feb 2026 22:05:13 +0900 Subject: [PATCH 137/409] fix --- src/widget/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 8738b5d6a..ae8781785 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -251,7 +251,7 @@ static void destroy(MwWidget handle) { while(w->parent != NULL) w = w->parent; - w->berserk++; + w->berserk--; free(handle->internal); } From efa43456c18c0615a4aae8575afd032c2e0bf9c8 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 3 Mar 2026 23:24:28 -0700 Subject: [PATCH 138/409] significant macos progress, now compiles/runs on monetery --- README.txt | 46 +-- include/Mw/LowLevel/Cocoa.h | 104 +++--- src/backend/cocoa.m | 661 ++++++++++++++++++++---------------- 3 files changed, 438 insertions(+), 373 deletions(-) diff --git a/README.txt b/README.txt index 32e8630d3..744e7a8e8 100644 --- a/README.txt +++ b/README.txt @@ -1,23 +1,25 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) +Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) - This document contains a brief summary of the contents of this source -distributions and building instructions for Milsko GUI Toolkit. + This document contains a brief summary of the contents of this source +distributions and building instructions for Milsko GUI Toolkit. Requirements - Milsko requires the Windows environment with GDI (so anything NT or 9x) or -the Unix-like environment with X11 for runtime. + Milsko requires either + * A Windows environment with GDI (so anything NT or 9x) + * A Mac OS environment with Cocoa (10.4 is the minimum tested) + * Unix-like environment with X11 for runtime. - To build Milsko for Windows, you must have one of following compilers: - * Visual C++ 6.0 or newer - * Borland C++ 5.5 or newer - * Open Watcom 2.0 or newer - * MinGW-w64 + To build Milsko for Windows, you must have one of following compilers: + * Visual C++ 6.0 or newer + * Borland C++ 5.5 or newer + * Open Watcom 2.0 or newer + * MinGW-w64 - and for Unix-like: - * GNU C Compiler - * Clang + and for Unix-like/Mac OS: + * GNU C Compiler + * Clang Contents @@ -39,31 +41,31 @@ the Unix-like environment with X11 for runtime. Building Milsko - Building Milsko depends on the platform you use, and the compiler you use. + Building Milsko depends on the platform you use, and the compiler you use. A. Visual C++ ------------- -1) Run `nmake -f NTMakefile'. +1) Run `nmake -f NTMakefile'. B. Borland C++ -------------- -1) Run `make -f BorMakefile'. +1) Run `make -f BorMakefile'. C. Open Watcom -------------- -1) Run `wmake -f WatMakefile'. +1) Run `wmake -f WatMakefile'. D. MinGW-w64/GCC/Clang ---------------------- -1) Determine if you need Vulkan and/or OpenGL. +1) Determine if you need Vulkan and/or OpenGL. -2) Run `./Makefile.pl'. - For help, run `./Makefile.pl --help'. +2) Run `./Makefile.pl'. + For help, run `./Makefile.pl --help'. -3) Run `make'. +3) Run `make'. - -- Nishi (nishi@nishi.boats) + -- Nishi (nishi@nishi.boats) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 2d1d9bdea..d22f65396 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -11,10 +11,9 @@ #include #ifdef __OBJC__ - -#import #import #import +#import #ifdef __APPLE__ #import @@ -23,97 +22,104 @@ #endif @interface MilskoCocoaPixmap : NSObject { - int width; - int height; - NSData* data; - NSImage* image; + MwBool valid; + int width; + int height; + NSData *data; + NSImage *image; + NSBitmapImageRep *rep; } -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(void*)data; ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(unsigned char *)data; - (void)destroy; -/* using @property to create instance variables fucks up 10.4 gcc for some reason? */ -- (NSImage*)image; +/* using @property to create instance variables fucks up 10.4 gcc for some + * reason? */ +- (NSImage *)image; @end @interface MilskoCocoaView : NSView { - CGContextRef cg; - CGColorSpaceRef space; - CGDataProviderRef provider; - MwU32* buf; - float width; - float height; + NSBitmapImageRep *rep; + NSGraphicsContext *context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + unsigned char *buf; + float width; + float height; } -- (CGContextRef)context; +- (NSGraphicsContext *)context; @end @interface MilskoCocoa : NSObject { - NSApplication* application; - NSWindow* window; - NSRect rect; - MilskoCocoaView* view; + NSApplication *application; + NSEvent *lastEvent; + NSWindow *window; + NSRect rect; + MilskoCocoaView *view; + MwLL parent; } -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height; -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height; +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; - (void)getNextEvent; -- (void)setTitle:(const char*)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; +- (void)setTitle:(const char *)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; - (void)setIcon:(MwLLPixmap)pixmap; - (void)forceRender; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; -- (void)detachWithPoint:(MwPoint*)point; +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; +- (void)detachWithPoint:(MwPoint *)point; - (void)show:(int)show; - (void)makePopupWithParent:(MwLL)parent; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; - (void)makeBorderless:(int)toggle; - (void)focus; - (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char*)text; +- (void)setClipboard:(const char *)text; - (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint*)point; -- (void)getScreenSize:(MwRect*)rect; +- (void)getCursorCoord:(MwPoint *)point; +- (void)getScreenSize:(MwRect *)rect; - (void)destroy; @end #define OBJC(x) x #else -#define OBJC(x) void* +#define OBJC(x) void * #endif MWDECL int MwLLCocoaCallInit(void); struct _MwLLCocoa { - struct _MwLLCommon common; - OBJC(MilskoCocoa*) - real; + struct _MwLLCommon common; + OBJC(MilskoCocoa *) + real; }; struct _MwLLCocoaColor { - struct _MwLLCommonColor common; + struct _MwLLCommonColor common; }; struct _MwLLCocoaPixmap { - struct _MwLLCommonPixmap common; - OBJC(MilskoCocoaPixmap*) - real; + struct _MwLLCommonPixmap common; + OBJC(MilskoCocoaPixmap *) + real; }; #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 42c38a57c..1e069cc2b 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,490 +1,547 @@ #include - -#include - -#include "../../external/stb_ds.h" +#include +#include @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; - p->width = width; - p->height = height; - p->data = NULL; - p->image = NULL; - - return p; + p->width = width; + p->height = height; + p->data = NULL; + p->image = NULL; + return p; } -- (void)updateWithData:(void*)_data { - [self destroy]; +- (void)updateWithData:(unsigned char *)_data { + [self destroy]; - self->data = [NSData dataWithBytes:_data length:self->width * self->height * 4]; - self->image = [[NSImage alloc] initWithData:self->data]; + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&_data + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + + assert(self->rep); + self->data = [NSData dataWithBytes:[self->rep bitmapData] + length:self->width * self->height * 4]; + assert(self->data); + self->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(self->image); + [self->image addRepresentation:self->rep]; } - (void)destroy { - if(self->data != NULL) { - [self->data dealloc]; - } - if(self->image != NULL) { - [self->image dealloc]; - } + if (self->data != NULL) { + [self->data dealloc]; + } + if (self->image != NULL) { + [self->image dealloc]; + } } -- (NSImage*)image { - return self->image; +- (NSImage *)image { + return self->image; } @end @implementation MilskoCocoa -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height { - MilskoCocoa* c = [MilskoCocoa alloc]; - bool centerX = false, centerY = false; ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height { + MilskoCocoa *c = [MilskoCocoa alloc]; + bool centerX = false, centerY = false; - if(x == MwDEFAULT) { - x = 0; - centerX = true; - } - if(y == MwDEFAULT) { - y = 0; - centerY = true; - } - c->application = [NSApplication sharedApplication]; + if (x == MwDEFAULT) { + x = 0; + centerX = true; + } + if (y == MwDEFAULT) { + y = 0; + centerY = true; + } + c->application = [NSApplication sharedApplication]; - c->rect = NSMakeRect(x, y, width, height); + c->rect = NSMakeRect(x, y, width, height); - c->window = [[NSWindow alloc] - initWithContentRect:c->rect - styleMask:parent == NULL - ? (NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | - NSResizableWindowMask) - : NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - [c->window makeKeyAndOrderFront:c->application]; + if (parent == NULL) { + c->window = [[NSWindow alloc] + initWithContentRect:c->rect + styleMask:(NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + } else { + NSWindow *parentWindow = parent->cocoa.real->window; - if(parent != NULL) { - MilskoCocoa* p = parent->cocoa.real; - [p->window addChildWindow:c->window ordered:NSWindowAbove]; - } else { - [c->application activateIgnoringOtherApps:true]; - } + c->rect = [parentWindow frameRectForContentRect:c->rect]; + c->rect.origin.y = + y - + [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - [c->window setContentView:c->view]; + c->window = [[NSWindow alloc] initWithContentRect:c->rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + } - return c; + [c->window makeKeyAndOrderFront:c->application]; + + if (parent != NULL) { + MilskoCocoa *p = parent->cocoa.real; + [p->window addChildWindow:c->window ordered:NSWindowAbove]; + } else { + [c->application activateIgnoringOtherApps:true]; + } + + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->window setContentView:c->view]; + + c->parent = parent; + + return c; } -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color { - int i; - CGContextRef cg = [self->view context]; +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color { + int i; + CGContextRef cg = [self->view context]; - CGContextSetRGBFillColor(cg, color->common.red / 255., color->common.blue / 255., color->common.green / 255., 1); - CGContextBeginPath(cg); - for(i = 0; i < points_count; i++) { - CGContextMoveToPoint(cg, points[i].x, points[i].y); - if(i < points_count - 1) { - CGContextAddLineToPoint(cg, points[i + 1].x, points[i + 1].y); - } - } - CGContextFillPath(cg); + [self->view lockFocus]; - // [self->view setNeedsDisplay:true]; + CGContextSetRGBFillColor(cg, color->common.red / 255., + color->common.blue / 255., + color->common.green / 255., 1); + CGContextBeginPath(cg); + for (i = 0; i < points_count; i++) { + CGContextMoveToPoint(cg, points[i].x, points[i].y); + if (i < points_count - 1) { + CGContextAddLineToPoint(cg, points[i + 1].x, points[i + 1].y); + } + } + CGContextFillPath(cg); + [self->view unlockFocus]; + + [self->view setNeedsDisplay:true]; }; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { - NSRect frame = [self->window frame]; +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { + NSRect frame = [self->window frame]; - *x = frame.origin.x; - *y = frame.origin.y; - *w = frame.size.width; - *h = frame.size.height; + *x = frame.origin.x; + *y = frame.origin.y - frame.size.height; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSPoint p; - p.x = x; - p.y = y; - NSRect frame = [self->window frame]; - frame.origin.x = x; - frame.origin.y = y; - [self->window setFrame:frame display:YES animate:true]; + NSRect frame = [self->window frame]; + + frame.origin.x = x; + frame.origin.y = y; + + if (self->parent) { + NSWindow *parentWindow = self->parent->cocoa.real->window; + frame = [parentWindow contentRectForFrameRect:frame]; + frame.origin.y = + [parentWindow contentRectForFrameRect:parentWindow.frame].size.height - + y; + } + + [self->window setFrame:frame display:YES animate:false]; }; - (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; - [self->window setFrame:frame display:YES animate:true]; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; + + if (self->parent) { + NSWindow *parentWindow = self->parent->cocoa.real->window; + // frame = [parentWindow contentRectForFrameRect:frame]; + } + + [self->window setFrame:frame display:YES animate:false]; }; - (int)pending { - return 1; + self->lastEvent = + [self->application nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]; + return self->lastEvent != NULL; }; - (void)getNextEvent { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent* event = [self->application nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; + if (self->lastEvent != nil) { + // printf("got event: %ld\n", self->lastEvent.type); + } - if(event != nil) { - printf("got event: %p\n", event); - } + [self->application sendEvent:self->lastEvent]; - [self->application sendEvent:event]; + /* this should be in the draw functions but it's here for now for testing */ + [self->view setNeedsDisplay:true]; - /* this should be in the draw functions but it's here for now for testing */ - [self->view setNeedsDisplay:true]; - - [pool release]; + [pool release]; }; -- (void)setTitle:(const char*)title { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; +- (void)setTitle:(const char *)title { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [[p image] drawAtPoint:NSMakePoint(_rect->x, _rect->y) fromRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) operation:NSCompositeClear fraction:1.0]; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)_rect { + MilskoCocoaPixmap *p = pixmap->cocoa.real; + NSGraphicsContext *ctx = [self->view context]; + if (ctx) { + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; + + [[NSColor redColor] setFill]; + [[p image] drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, + _rect->height) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0 + respectFlipped:NO + hints:nil]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } }; - (void)setIcon:(MwLLPixmap)pixmap { }; - (void)forceRender { }; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { }; -- (void)detachWithPoint:(MwPoint*)point { +- (void)detachWithPoint:(MwPoint *)point { }; - (void)show:(int)show { }; - (void)makePopupWithParent:(MwLL)parent { }; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { }; - (void)makeBorderless:(int)toggle { - MwU32 mask = [self->window styleMask]; - if(mask & NSBorderlessWindowMask) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; + MwU32 mask = [self->window styleMask]; + if (mask & NSBorderlessWindowMask) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { - [self->window makeMainWindow]; + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do - * this manually */ + /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do + * this manually */ }; -- (void)setClipboard:(const char*)text { +- (void)setClipboard:(const char *)text { }; - (void)getClipboard { }; - (void)makeToolWindow { }; -- (void)getCursorCoord:(MwPoint*)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; +- (void)getCursorCoord:(MwPoint *)point { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; }; -- (void)getScreenSize:(MwRect*)_rect { - NSScreen* screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; +- (void)getScreenSize:(MwRect *)_rect { + NSScreen *screen = [self->window screen]; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { - [self->window dealloc]; + [self->window dealloc]; } @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - self = [super initWithFrame:frame]; - self->width = frame.size.width; - self->height = frame.size.height; - self->buf = malloc(self->width * self->height * 4); - self->space = CGColorSpaceCreateDeviceRGB(); - self->cg = CGBitmapContextCreate(self->buf, - self->width, - self->height, - CHAR_BIT, - self->width * sizeof(MwU32), - self->space, kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedLast); - assert(self->cg); - printf("%p\n", self->cg); - return self; + self = [super initWithFrame:frame]; + self->width = frame.size.width; + self->height = frame.size.height; + self->buf = malloc(self->width * self->height * 4); + self->space = CGColorSpaceCreateDeviceRGB(); + + if (width == 0 || height == 0) { + self->rep = NULL; + self->context = NULL; + } else { + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:width * 4 + bitsPerPixel:32]; + assert(self->rep); + + self->context = + [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; + assert(self->context); + } + + return self; } -- (CGContextRef)context { - return self->cg; +- (NSGraphicsContext *)context { + return self->context; } - (void)drawRect:(NSRect)dirtyRect { - [super drawRect:dirtyRect]; - if(self) { + [super drawRect:dirtyRect]; + if (!self->rep) { + return; + } + [self->rep drawInRect:NSMakeRect(0, 0, self->width, self->height)]; - CGImageRef img = CGBitmapContextCreateImage(self->cg); - if(!img) { - return; - } - printf("printed image\n"); - - CGContextDrawImage([[NSGraphicsContext currentContext] graphicsPort], CGRectMake(0, 0, self->width, self->height), img); - CGImageRelease(img); - } - // printf("%0.2f %0.2f %0.2f %0.2f\n", dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height); + unsigned char *pixels = [self->rep bitmapData]; } - (void)destroy { - free(self->buf); - CGContextRelease(self->cg); - CGColorSpaceRelease(self->space); + free(self->buf); + CGColorSpaceRelease(self->space); } @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; - r = malloc(sizeof(*r)); + r = malloc(sizeof(*r)); - MwLLCreateCommon(r); + MwLLCreateCommon(r); - MilskoCocoa* o = - [MilskoCocoa newWithParent:parent - x:x - y:y - width:width - height:height]; - r->cocoa.real = o; + MilskoCocoa *o = + [MilskoCocoa newWithParent:parent x:x y:y width:width height:height]; + r->cocoa.real = o; - return r; + return r; } static void MwLLDestroyImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; + MilskoCocoa *h = handle->cocoa.real; - [h destroy]; + [h destroy]; - MwLLDestroyCommon(handle); + MwLLDestroyCommon(handle); - free(handle); + free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; +static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, + MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; } -static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, - MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; -} - -static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h lineWithPoints:points color:color]; +static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; + (void)handle; - c->common.red = r; - c->common.green = g; - c->common.blue = b; + c->common.red = r; + c->common.green = g; + c->common.blue = b; } -static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, - unsigned int* height) { - MilskoCocoa* h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; +static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, + unsigned int *height) { + MilskoCocoa *h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa* h = handle->cocoa.real; - [h setX:x Y:y]; + MilskoCocoa *h = handle->cocoa.real; + [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa* h = handle->cocoa.real; - [h setW:w H:height]; + MilskoCocoa *h = handle->cocoa.real; + [h setW:w H:height]; } -static void MwLLFreeColorImpl(MwLLColor color) { - free(color); -} +static void MwLLFreeColorImpl(MwLLColor color) { free(color); } static int MwLLPendingImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - return [h pending]; + MilskoCocoa *h = handle->cocoa.real; + if ([h pending]) { + MwLLDispatch(handle, draw, NULL); + return 1; + }; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h getNextEvent]; + MilskoCocoa *h = handle->cocoa.real; + [h getNextEvent]; } -static void MwLLSetTitleImpl(MwLL handle, const char* title) { - MilskoCocoa* h = handle->cocoa.real; - [h setTitle:title]; +static void MwLLSetTitleImpl(MwLL handle, const char *title) { + MilskoCocoa *h = handle->cocoa.real; + [h setTitle:title]; } -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, - int width, int height) { - (void)handle; +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, + int width, int height) { + (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + MwLLPixmap r = malloc(sizeof(*r)); - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - r->common.width = width; - r->common.height = height; + r->common.width = width; + r->common.height = height; - r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; - MwLLPixmapUpdate(r); - return r; + MwLLPixmapUpdate(r); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p destroy]; - free(pixmap); + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p destroy]; + free(pixmap); } -static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; +static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { + MilskoCocoa *h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; + MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h setIcon:pixmap]; + MilskoCocoa *h = handle->cocoa.real; + [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h forceRender]; + MilskoCocoa *h = handle->cocoa.real; + [h forceRender]; } -static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - MilskoCocoa* h = handle->cocoa.real; - [h setCursor:image mask:mask]; +static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { + MilskoCocoa *h = handle->cocoa.real; + [h setCursor:image mask:mask]; } -static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h detachWithPoint:point]; +static void MwLLDetachImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa* h = handle->cocoa.real; - [h show:show]; + MilskoCocoa *h = handle->cocoa.real; + [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa* h = handle->cocoa.real; - [h makePopupWithParent:parent]; + MilskoCocoa *h = handle->cocoa.real; + [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, - int maxy) { - MilskoCocoa* h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + int maxy) { + MilskoCocoa *h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h makeBorderless:toggle]; + MilskoCocoa *h = handle->cocoa.real; + [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h focus]; + MilskoCocoa *h = handle->cocoa.real; + [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h grabPointer:toggle]; + MilskoCocoa *h = handle->cocoa.real; + [h grabPointer:toggle]; } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { - MilskoCocoa* h = handle->cocoa.real; - [h setClipboard:text]; +static void MwLLSetClipboardImpl(MwLL handle, const char *text) { + MilskoCocoa *h = handle->cocoa.real; + [h setClipboard:text]; } -static void MwLLGetClipboardImpl(MwLL handle) { - (void)handle; -} +static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } static void MwLLMakeToolWindowImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h makeToolWindow]; + MilskoCocoa *h = handle->cocoa.real; + [h makeToolWindow]; } -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h getCursorCoord:point]; +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h getCursorCoord:point]; } -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - MilskoCocoa* h = handle->cocoa.real; - [h getScreenSize:rect]; +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { + MilskoCocoa *h = handle->cocoa.real; + [h getScreenSize:rect]; } -static void MwLLBeginStateChangeImpl(MwLL handle) { - MwLLShow(handle, 0); -} +static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } -static void MwLLEndStateChangeImpl(MwLL handle) { - MwLLShow(handle, 1); -} +static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } -static int MwLLCocoaCallInitImpl(void) { - return 0; -} +static int MwLLCocoaCallInitImpl(void) { return 0; } #include "call.c" CALL(Cocoa); From cc2d3008d0d263d6c7f73ddc895e849fbed5a144 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 00:02:14 -0700 Subject: [PATCH 139/409] mac: implement polygon function --- src/backend/cocoa.m | 48 ++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1e069cc2b..3117ba58b 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,4 @@ +#include "Mw/BaseTypes.h" #include #include #include @@ -97,6 +98,7 @@ if (parent != NULL) { MilskoCocoa *p = parent->cocoa.real; [p->window addChildWindow:c->window ordered:NSWindowAbove]; + [c->window setHasShadow:MwFALSE]; } else { [c->application activateIgnoringOtherApps:true]; } @@ -111,25 +113,40 @@ - (void)polygonWithPoints:(MwPoint *)points points_count:(int)points_count color:(MwLLColor)color { - int i; - CGContextRef cg = [self->view context]; + NSGraphicsContext *ctx = [self->view context]; + if (ctx) { + int i; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSColor *nscolor = [NSColor colorWithRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; - [self->view lockFocus]; + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - CGContextSetRGBFillColor(cg, color->common.red / 255., - color->common.blue / 255., - color->common.green / 255., 1); - CGContextBeginPath(cg); - for (i = 0; i < points_count; i++) { - CGContextMoveToPoint(cg, points[i].x, points[i].y); - if (i < points_count - 1) { - CGContextAddLineToPoint(cg, points[i + 1].x, points[i + 1].y); + [nscolor setFill]; + for (i = 0; i < points_count; i++) { + if (i == 0) { + [path moveToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } else { + [path lineToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } } - } - CGContextFillPath(cg); - [self->view unlockFocus]; - [self->view setNeedsDisplay:true]; + [path closePath]; + [path fill]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + + [nscolor dealloc]; + } }; - (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; @@ -204,7 +221,6 @@ [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:ctx]; - [[NSColor redColor] setFill]; [[p image] drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) fromRect:NSZeroRect From b3735fa36420a43e1be0b0bb747cb16884035189 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 5 Mar 2026 04:09:01 +0900 Subject: [PATCH 140/409] rename Makefile.pl to configure --- Jenkinsfile | 6 +++--- README.txt | 46 +++++++++++++++++++--------------------- Makefile.pl => configure | 2 +- tools/readme.pl | 4 ++-- 4 files changed, 28 insertions(+), 30 deletions(-) rename Makefile.pl => configure (98%) diff --git a/Jenkinsfile b/Jenkinsfile index 58736fdb2..5588f1be3 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -22,7 +22,7 @@ pipeline { label "built-in" } steps { - sh("./Makefile.pl --enable-opengl --enable-vulkan --without-vulkan-string-helper") + sh("./configure --enable-opengl --enable-vulkan --without-vulkan-string-helper") sh("make clean") sh("make -j4") } @@ -32,7 +32,7 @@ pipeline { label "built-in" } steps { - sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") + sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=i686-w64-mingw32") sh("make clean") sh("make -j4") } @@ -42,7 +42,7 @@ pipeline { label "built-in" } steps { - sh("./Makefile.pl --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") + sh("./configure --enable-opengl --enable-stb-truetype --disable-freetype2 --cross --target=Windows --host=x86_64-w64-mingw32") sh("make clean") sh("make -j4") } diff --git a/README.txt b/README.txt index 744e7a8e8..f69b63652 100644 --- a/README.txt +++ b/README.txt @@ -1,25 +1,23 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) +Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) - This document contains a brief summary of the contents of this source -distributions and building instructions for Milsko GUI Toolkit. + This document contains a brief summary of the contents of this source +distributions and building instructions for Milsko GUI Toolkit. Requirements - Milsko requires either - * A Windows environment with GDI (so anything NT or 9x) - * A Mac OS environment with Cocoa (10.4 is the minimum tested) - * Unix-like environment with X11 for runtime. + Milsko requires the Windows environment with GDI (so anything NT or 9x) or +the Unix-like environment with X11 for runtime. - To build Milsko for Windows, you must have one of following compilers: - * Visual C++ 6.0 or newer - * Borland C++ 5.5 or newer - * Open Watcom 2.0 or newer - * MinGW-w64 + To build Milsko for Windows, you must have one of following compilers: + * Visual C++ 6.0 or newer + * Borland C++ 5.5 or newer + * Open Watcom 2.0 or newer + * MinGW-w64 - and for Unix-like/Mac OS: - * GNU C Compiler - * Clang + and for Unix-like: + * GNU C Compiler + * Clang Contents @@ -41,31 +39,31 @@ distributions and building instructions for Milsko GUI Toolkit. Building Milsko - Building Milsko depends on the platform you use, and the compiler you use. + Building Milsko depends on the platform you use, and the compiler you use. A. Visual C++ ------------- -1) Run `nmake -f NTMakefile'. +1) Run `nmake -f NTMakefile'. B. Borland C++ -------------- -1) Run `make -f BorMakefile'. +1) Run `make -f BorMakefile'. C. Open Watcom -------------- -1) Run `wmake -f WatMakefile'. +1) Run `wmake -f WatMakefile'. D. MinGW-w64/GCC/Clang ---------------------- -1) Determine if you need Vulkan and/or OpenGL. +1) Determine if you need Vulkan and/or OpenGL. -2) Run `./Makefile.pl'. - For help, run `./Makefile.pl --help'. +2) Run `./configure'. + For help, run `./configure --help'. -3) Run `make'. +3) Run `make'. - -- Nishi (nishi@nishi.boats) + -- Nishi (nishi@nishi.boats) diff --git a/Makefile.pl b/configure similarity index 98% rename from Makefile.pl rename to configure index 519781ecd..5ffbe544d 100755 --- a/Makefile.pl +++ b/configure @@ -187,7 +187,7 @@ print(OUT " clang-format --verbose -i `find src include examples -name \"*.c\" -or -name \"*.h\" -or -name \"*.m\"`\n" ); print(OUT -" perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl Makefile.pl -name \"*.pl\"`\n" +" perltidy -b -bext=\"/\" --paren-tightness=2 `find tools pl configure -name \"*.pl\"`\n" ); print(OUT "\n"); print(OUT "lib:"); diff --git a/tools/readme.pl b/tools/readme.pl index 573d9573e..c511f794e 100755 --- a/tools/readme.pl +++ b/tools/readme.pl @@ -105,8 +105,8 @@ l("1) Run `wmake -f WatMakefile'."); h("D. MinGW-w64/GCC/Clang"); l("1) Determine if you need Vulkan and/or OpenGL."); l(""); -l("2) Run `./Makefile.pl'."); -l(" For help, run `./Makefile.pl --help'."); +l("2) Run `./configure'."); +l(" For help, run `./configure --help'."); l(""); l("3) Run `make'."); l(""); From e09eccbf5fba81ef0ca2756979cb623833aec6d5 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:59:28 -0600 Subject: [PATCH 141/409] refactor font.c into an MwFL section (#9) Reviewed-on: https://gitea.nishi.boats/pyrite-dev/milsko/pulls/9 Co-authored-by: IoIxD Co-committed-by: IoIxD --- BorMakefile | 12 +- CMakeLists.txt | 2 +- NTMakefile | 12 +- WatMakefile | 26 +-- include/Mw/LowLevel.h | 26 +++ pl/rules.pl | 3 +- src/core.c | 2 + src/text.c | 384 --------------------------------- src/{ => text}/font/boldfont.c | 0 src/{ => text}/font/boldttf.c | 0 src/{ => text}/font/font.c | 0 src/{ => text}/font/ttf.c | 0 src/text/ft2.c | 139 ++++++++++++ src/text/stbtt.c | 141 ++++++++++++ src/text/text.c | 158 ++++++++++++++ 15 files changed, 489 insertions(+), 416 deletions(-) delete mode 100644 src/text.c rename src/{ => text}/font/boldfont.c (100%) rename src/{ => text}/font/boldttf.c (100%) rename src/{ => text}/font/font.c (100%) rename src/{ => text}/font/ttf.c (100%) create mode 100644 src/text/ft2.c create mode 100644 src/text/stbtt.c create mode 100644 src/text/text.c diff --git a/BorMakefile b/BorMakefile index 59551b5fd..b6d062778 100644 --- a/BorMakefile +++ b/BorMakefile @@ -27,10 +27,6 @@ clean: del /f /q src\dialog\messagebox.obj del /f /q src\draw.obj del /f /q src\error.obj - del /f /q src\font\boldfont.obj - del /f /q src\font\boldttf.obj - del /f /q src\font\font.obj - del /f /q src\font\ttf.obj del /f /q src\icon\back.obj del /f /q src\icon\clock.obj del /f /q src\icon\computer.obj @@ -49,7 +45,9 @@ clean: del /f /q src\icon\warning.obj del /f /q src\lowlevel.obj del /f /q src\string.obj - del /f /q src\text.obj + del /f /q src\text\ft2.obj + del /f /q src\text\stbtt.obj + del /f /q src\text\text.obj del /f /q src\unicode.obj del /f /q src\widget\box.obj del /f /q src\widget\button.obj @@ -74,8 +72,8 @@ clean: del /f /q src\Mw.dll del /f /q src\Mw.lib -src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\font\boldfont.obj src\font\boldttf.obj src\font\font.obj src\font\ttf.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) -e$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\font\boldfont.obj src\font\boldttf.obj src\font\font.obj src\font\ttf.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj -lopengl32.lib -lgdi32.lib -luser32.lib +src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(LDFLAGS) -e$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj -lopengl32.lib -lgdi32.lib -luser32.lib implib src\Mw.lib src\Mw.dll .c.obj: diff --git a/CMakeLists.txt b/CMakeLists.txt index 650d6d1ea..09a5bd90c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ option(MW_INSTALL_HEADERS "Install headers" ON) file( GLOB SOURCES - src/*.c src/cursor/*.c src/icon/*.c src/text.c src/widget/*.c src/math/*.c src/font/*.c src/dialog/*.c src/abstract/*.c external/*.c + src/*.c src/cursor/*.c src/icon/*.c src/widget/*.c src/text/*.c src/text/font/*.c src/dialog/*.c src/abstract/*.c external/*.c ) list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") diff --git a/NTMakefile b/NTMakefile index 265418a7a..7ba162df7 100644 --- a/NTMakefile +++ b/NTMakefile @@ -27,10 +27,6 @@ clean: del /f /q src\dialog\messagebox.obj del /f /q src\draw.obj del /f /q src\error.obj - del /f /q src\font\boldfont.obj - del /f /q src\font\boldttf.obj - del /f /q src\font\font.obj - del /f /q src\font\ttf.obj del /f /q src\icon\back.obj del /f /q src\icon\clock.obj del /f /q src\icon\computer.obj @@ -49,7 +45,9 @@ clean: del /f /q src\icon\warning.obj del /f /q src\lowlevel.obj del /f /q src\string.obj - del /f /q src\text.obj + del /f /q src\text\ft2.obj + del /f /q src\text\stbtt.obj + del /f /q src\text\text.obj del /f /q src\unicode.obj del /f /q src\widget\box.obj del /f /q src\widget\button.obj @@ -74,8 +72,8 @@ clean: del /f /q src\Mw.dll del /f /q src\Mw.lib -src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\font\boldfont.obj src\font\boldttf.obj src\font\font.obj src\font\ttf.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) /OUT:$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\font\boldfont.obj src\font\boldttf.obj src\font\font.obj src\font\ttf.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib user32.lib +src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(LDFLAGS) /OUT:$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib user32.lib .c.obj: diff --git a/WatMakefile b/WatMakefile index dc7b12119..d8dbf5e98 100644 --- a/WatMakefile +++ b/WatMakefile @@ -26,10 +26,6 @@ clean: .SYMBOLIC %erase src/dialog/messagebox.obj %erase src/draw.obj %erase src/error.obj - %erase src/font/boldfont.obj - %erase src/font/boldttf.obj - %erase src/font/font.obj - %erase src/font/ttf.obj %erase src/icon/back.obj %erase src/icon/clock.obj %erase src/icon/computer.obj @@ -48,7 +44,9 @@ clean: .SYMBOLIC %erase src/icon/warning.obj %erase src/lowlevel.obj %erase src/string.obj - %erase src/text.obj + %erase src/text/ft2.obj + %erase src/text/stbtt.obj + %erase src/text/text.obj %erase src/unicode.obj %erase src/widget/box.obj %erase src/widget/button.obj @@ -73,8 +71,8 @@ clean: .SYMBOLIC %erase src/Mw.dll %erase src/Mw.lib -src/Mw.dll: external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/error.obj src/font/boldfont.obj src/font/boldttf.obj src/font/font.obj src/font/ttf.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(LDFLAGS) option implib=src/Mw.lib name $@ file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/error.obj file src/font/boldfont.obj file src/font/boldttf.obj file src/font/font.obj file src/font/ttf.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library user32.lib +src/Mw.dll: external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/error.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/ft2.obj src/text/stbtt.obj src/text/text.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(LDFLAGS) option implib=src/Mw.lib name $@ file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/error.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/ft2.obj file src/text/stbtt.obj file src/text/text.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library user32.lib @@ -120,14 +118,6 @@ src/draw.obj: src/draw.c $(CC) $(CFLAGS) -fo=$@ $< src/error.obj: src/error.c $(CC) $(CFLAGS) -fo=$@ $< -src/font/boldfont.obj: src/font/boldfont.c - $(CC) $(CFLAGS) -fo=$@ $< -src/font/boldttf.obj: src/font/boldttf.c - $(CC) $(CFLAGS) -fo=$@ $< -src/font/font.obj: src/font/font.c - $(CC) $(CFLAGS) -fo=$@ $< -src/font/ttf.obj: src/font/ttf.c - $(CC) $(CFLAGS) -fo=$@ $< src/icon/back.obj: src/icon/back.c $(CC) $(CFLAGS) -fo=$@ $< src/icon/clock.obj: src/icon/clock.c @@ -164,7 +154,11 @@ src/lowlevel.obj: src/lowlevel.c $(CC) $(CFLAGS) -fo=$@ $< src/string.obj: src/string.c $(CC) $(CFLAGS) -fo=$@ $< -src/text.obj: src/text.c +src/text/ft2.obj: src/text/ft2.c + $(CC) $(CFLAGS) -fo=$@ $< +src/text/stbtt.obj: src/text/stbtt.c + $(CC) $(CFLAGS) -fo=$@ $< +src/text/text.obj: src/text/text.c $(CC) $(CFLAGS) -fo=$@ $< src/unicode.obj: src/unicode.c $(CC) $(CFLAGS) -fo=$@ $< diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index b54832885..dcab28d16 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -18,10 +18,12 @@ typedef struct _MwLLCommonPixmap* MwLLCommonPixmap; typedef union _MwLL* MwLL; typedef union _MwLLColor* MwLLColor; typedef union _MwLLPixmap* MwLLPixmap; +typedef struct _MwFLFont* MwFLFont; #else typedef void* MwLL; typedef void* MwLLColor; typedef void* MwLLPixmap; +typedef void* MwFLFont; #endif enum MwLLBackends { @@ -166,6 +168,14 @@ struct _MwLLHandler { void (*dark_theme)(MwLL handle, void* data); }; +struct _MwLLTextDispatchTable { + int (*drawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); + int (*textWidth)(MwWidget handle, const char* text); + int (*textHeight)(MwWidget handle, int count); + void* (*fontLoad)(unsigned char* data, unsigned int size); + void (*fontFree)(void* handle); +}; + #ifdef __cplusplus extern "C" { #endif @@ -225,6 +235,22 @@ MWDECL void (*MwLLGetClipboard)(MwLL handle); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +/*font renderer */ +MWDECL void MwFLSetup(); + +#ifdef USE_FREETYPE2 +MWDECL int MWFL_FT2Setup(); +#endif +#ifdef USE_STB_TRUETYPE +MWDECL int MwFL_STBTTSetup(); +#endif + +MWDECL int (*MwFLDrawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); +MWDECL int (*MwFLTextWidth)(MwWidget handle, const char* text); +MWDECL int (*MwFLTextHeight)(MwWidget handle, int count); +MWDECL void* (*MwFLFontLoad)(unsigned char* data, unsigned int size); +MWDECL void (*MwFLFontFree)(void* handle); + #ifdef __cplusplus } #endif diff --git a/pl/rules.pl b/pl/rules.pl index 59605a803..d4784e102 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -76,8 +76,9 @@ if (param_get("vulkan") && param_get("vulkan-string-helper")) { } new_object("src/icon/*.c"); -new_object("src/font/*.c"); new_object("src/cursor/*.c"); +new_object("src/text/*.c"); +new_object("src/text/font/*.c"); new_object("src/widget/box.c"); new_object("src/widget/button.c"); diff --git a/src/core.c b/src/core.c index 6985a02ee..9902a30e7 100644 --- a/src/core.c +++ b/src/core.c @@ -784,6 +784,8 @@ int MwLibraryInit(void) { NULL}; int i; + MwFLSetup(); + for(i = 0; calls[i] != NULL; i++) { if(calls[i]() == 0) return 0; } diff --git a/src/text.c b/src/text.c deleted file mode 100644 index c0e00c6db..000000000 --- a/src/text.c +++ /dev/null @@ -1,384 +0,0 @@ -#include - -#if defined(USE_FREETYPE2) -#include -#include FT_FREETYPE_H - -typedef struct ttf { - FT_Library library; - FT_Face face; - void* data; -} ttf_t; - -#define TTF -#elif defined(USE_STB_TRUETYPE) -#include "../external/stb_truetype.h" - -typedef struct ttf { - stbtt_fontinfo font; - void* data; - float scale; - int ascent; - int descent; -} ttf_t; - -#define TTF -#endif - -#define FontWidth 7 -#define FontHeight 14 - -static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - int i = 0, x, y, sx, sy; - int tw, th; - unsigned char* px; - MwRect r; - MwLLPixmap p; - - if(strlen(text) == 0) text = " "; - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - - sx = 0; - sy = 0; - - while(text[i] != 0) { - int out; - i += MwUTF8ToUTF32(text + i, &out); - - if(out > 0xff) { - out = 0; - } - - if(out == '\n') { - sx = 0; - sy += FontHeight; - } else { - for(y = 0; y < FontHeight; y++) { - for(x = 0; x < FontWidth; x++) { - unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; - if((bold ? MwBoldFontData : MwFontData)[out].data[y] & (1 << ((FontWidth - 1) - x))) { - ppx[0] = color->common.red; - ppx[1] = color->common.green; - ppx[2] = color->common.blue; - ppx[3] = 255; - } else { - ppx[0] = 0; - ppx[1] = 0; - ppx[2] = 0; - ppx[3] = 0; - } - } - } - sx += FontWidth; - } - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); -} - -#if defined(USE_STB_TRUETYPE) -static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); - unsigned char* px; - int tw, th; - MwRect r; - MwLLPixmap p; - int ax, lsb; - int x = 0, y = 0; - if(ttf == NULL) return 1; - - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - while(text[0] != 0) { - int c; - int x0, y0, x1, y1, cx, cy; - int ow, oh; - unsigned char* out; - - text += MwUTF8ToUTF32(text, &c); - if(c == '\n') { - x = 0; - y += (ttf->ascent - ttf->descent) * ttf->scale; - continue; - } - - stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); - - stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); - ow = x1 - x0; - oh = y1 - y0; - out = malloc(ow * oh); - stbtt_MakeCodepointBitmap(&ttf->font, out, ow, oh, ow, ttf->scale, ttf->scale, c); - - for(cy = 0; cy < oh; cy++) { - for(cx = 0; cx < ow; cx++) { - int ox = x + (lsb * ttf->scale) + cx; - int oy = y + (ttf->ascent * ttf->scale) + y0 + cy; - unsigned char* opx = &px[(oy * tw + ox) * 4]; - - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = out[cy * ow + cx]; - } - } - - x += ax * ttf->scale; - - free(out); - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); - - return 0; -} - -static int ttf_MwTextWidth(MwWidget handle, const char* text) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - int ax, lsb; - int tw = 0; - if(ttf == NULL) return -1; - - while(text[0] != 0) { - int c; - text += MwUTF8ToUTF32(text, &c); - - stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); - - tw += ax * ttf->scale; - } - - return tw; -} - -static int ttf_MwTextHeight(MwWidget handle, int count) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - if(ttf == NULL) return -1; - - return (ttf->ascent - ttf->descent) * ttf->scale * count; -} -#elif defined(USE_FREETYPE2) -static int ttf_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - ttf_t* ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); - int tw, th; - unsigned char* px; - MwLLPixmap p; - MwRect r; - int x = 0, y = 0; - if(ttf == NULL) return 1; - - tw = MwTextWidth(handle, text); - th = MwTextHeight(handle, text); - px = malloc(tw * th * 4); - - memset(px, 0, tw * th * 4); - while(text[0] != 0) { - int c; - FT_Bitmap* bmp; - int cy, cx; - int l = MwUTF8ToUTF32(text, &c); - if(l <= 0) break; - text += l; - - if(c == '\n') { - x = 0; - y += ttf->face->height * 14 / ttf->face->units_per_EM; - continue; - } - - FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); - bmp = &ttf->face->glyph->bitmap; - - for(cy = 0; cy < bmp->rows; cy++) { - for(cx = 0; cx < bmp->width; cx++) { - int ox = x + cx + ttf->face->glyph->bitmap_left; - int oy = y + (ttf->face->height * 14 / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * 14 / ttf->face->units_per_EM); - unsigned char* opx = &px[(oy * tw + ox) * 4]; - - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = bmp->buffer[cy * bmp->pitch + cx]; - } - } - - x += ttf->face->glyph->metrics.horiAdvance / 64; - } - - p = MwLoadRaw(handle, px, tw, th); - r.x = point->x; - r.y = point->y - th / 2; - r.width = tw; - r.height = th; - - if(align == MwALIGNMENT_CENTER) { - r.x -= tw / 2; - } else if(align == MwALIGNMENT_END) { - r.x -= tw; - } - - MwLLDrawPixmap(handle->lowlevel, &r, p); - MwLLDestroyPixmap(p); - free(px); - - return 0; -} - -static int ttf_MwTextWidth(MwWidget handle, const char* text) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - int tw = 0, mtw = 0; - if(ttf == NULL) return -1; - - while(text[0] != 0) { - int c; - int l = MwUTF8ToUTF32(text, &c); - if(l <= 0) break; - text += l; - if(c == '\n') { - tw = 0; - continue; - } - - FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); - - tw += ttf->face->glyph->metrics.horiAdvance / 64; - if(tw > mtw) mtw = tw; - } - - return mtw; -} - -static int ttf_MwTextHeight(MwWidget handle, int count) { - ttf_t* ttf = MwGetVoid(handle, MwNfont); - if(ttf == NULL) return -1; - - return (ttf->face->height * 14 / ttf->face->units_per_EM) * count; -} -#endif - -void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { - if(strlen(text) == 0) return; -#ifdef TTF - if(MwGetInteger(handle, MwNbitmapFont) || ttf_MwDrawText(handle, point, text, bold, align, color)) -#endif - bitmap_MwDrawText(handle, point, text, bold, align, color); -} - -int MwTextWidth(MwWidget handle, const char* text) { - /* TODO: check newline */ -#ifdef TTF - int st; - - if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextWidth(handle, text)) != -1) return st; -#else - (void)handle; - -#endif - return MwUTF8Length(text) * FontWidth; -} - -int MwTextHeight(MwWidget handle, const char* text) { - int c = 1; - int i = 0; -#ifdef TTF - int st; -#endif - - (void)handle; - (void)text; - - while(text[i] != 0) { - int out; - int l = MwUTF8ToUTF32(text + i, &out); - if(l == 0) break; - i += l; - - if(out == '\n') c++; - } -#ifdef TTF - if(!MwGetInteger(handle, MwNbitmapFont) && (st = ttf_MwTextHeight(handle, c)) != -1) return st; -#endif - return FontHeight * c; -} - -void* MwFontLoad(unsigned char* data, unsigned int size) { -#if defined(USE_FREETYPE2) - ttf_t* ttf = malloc(sizeof(*ttf)); - ttf->data = malloc(size); - memcpy(ttf->data, data, size); - FT_Init_FreeType(&ttf->library); - FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); - - FT_Set_Pixel_Sizes(ttf->face, 0, 14); - - return ttf; -#elif defined(USE_STB_TRUETYPE) - ttf_t* ttf = malloc(sizeof(*ttf)); - ttf->data = malloc(size); - memcpy(ttf->data, data, size); - stbtt_InitFont(&ttf->font, ttf->data, 0); - - ttf->scale = stbtt_ScaleForPixelHeight(&ttf->font, 16); - stbtt_GetFontVMetrics(&ttf->font, &ttf->ascent, &ttf->descent, 0); - - return ttf; -#else - (void)data; - (void)size; - return NULL; -#endif -} - -void MwFontFree(void* handle) { -#if defined(USE_FREETYPE2) - ttf_t* ttf = handle; - - FT_Done_Face(ttf->face); - FT_Done_FreeType(ttf->library); - - free(ttf->data); - free(ttf); -#elif defined(USE_STB_TRUETYPE) - ttf_t* ttf = handle; - - free(ttf->data); - free(ttf); -#else - (void)handle; -#endif -} diff --git a/src/font/boldfont.c b/src/text/font/boldfont.c similarity index 100% rename from src/font/boldfont.c rename to src/text/font/boldfont.c diff --git a/src/font/boldttf.c b/src/text/font/boldttf.c similarity index 100% rename from src/font/boldttf.c rename to src/text/font/boldttf.c diff --git a/src/font/font.c b/src/text/font/font.c similarity index 100% rename from src/font/font.c rename to src/text/font/font.c diff --git a/src/font/ttf.c b/src/text/font/ttf.c similarity index 100% rename from src/font/ttf.c rename to src/text/font/ttf.c diff --git a/src/text/ft2.c b/src/text/ft2.c new file mode 100644 index 000000000..a5fb92027 --- /dev/null +++ b/src/text/ft2.c @@ -0,0 +1,139 @@ +#ifdef USE_FREETYPE2 +#include + +#include +#include FT_FREETYPE_H + +struct _MwFLFont { + FT_Library library; + FT_Face face; + void* data; +}; +static int ft2_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + MwFLFont ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); + int tw, th; + unsigned char* px; + MwLLPixmap p; + MwRect r; + int x = 0, y = 0; + if(ttf == NULL) return 1; + + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c; + FT_Bitmap* bmp; + int cy, cx; + int l = MwUTF8ToUTF32(text, &c); + if(l <= 0) break; + text += l; + + if(c == '\n') { + x = 0; + y += ttf->face->height * 14 / ttf->face->units_per_EM; + continue; + } + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + bmp = &ttf->face->glyph->bitmap; + + for(cy = 0; cy < bmp->rows; cy++) { + for(cx = 0; cx < bmp->width; cx++) { + int ox = x + cx + ttf->face->glyph->bitmap_left; + int oy = y + (ttf->face->height * 14 / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * 14 / ttf->face->units_per_EM); + unsigned char* opx = &px[(oy * tw + ox) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = bmp->buffer[cy * bmp->pitch + cx]; + } + } + + x += ttf->face->glyph->metrics.horiAdvance / 64; + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int ft2_MwTextWidth(MwWidget handle, const char* text) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + int tw = 0, mtw = 0; + if(ttf == NULL) return -1; + + while(text[0] != 0) { + int c; + int l = MwUTF8ToUTF32(text, &c); + if(l <= 0) break; + text += l; + if(c == '\n') { + tw = 0; + continue; + } + + FT_Load_Char(ttf->face, c, FT_LOAD_RENDER); + + tw += ttf->face->glyph->metrics.horiAdvance / 64; + if(tw > mtw) mtw = tw; + } + + return mtw; +} + +static int ft2_MwTextHeight(MwWidget handle, int count) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + if(ttf == NULL) return -1; + + return (ttf->face->height * 14 / ttf->face->units_per_EM) * count; +} + +static void* ft2_MwFontLoad(unsigned char* data, unsigned int size) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + FT_Init_FreeType(&ttf->library); + FT_New_Memory_Face(ttf->library, ttf->data, size, 0, &ttf->face); + + FT_Set_Pixel_Sizes(ttf->face, 0, 14); + + return ttf; +} + +static void ft2_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + FT_Done_Face(ttf->face); + FT_Done_FreeType(ttf->library); + + free(ttf->data); + free(ttf); +} + +int MWFL_FT2Setup() { + MwFLDrawText = ft2_MwDrawText; + MwFLTextWidth = ft2_MwTextWidth; + MwFLTextHeight = ft2_MwTextHeight; + MwFLFontLoad = ft2_MwFontLoad; + MwFLFontFree = ft2_MwFontFree; + return 0; +} +#endif diff --git a/src/text/stbtt.c b/src/text/stbtt.c new file mode 100644 index 000000000..fb5e783e9 --- /dev/null +++ b/src/text/stbtt.c @@ -0,0 +1,141 @@ +#ifdef USE_STB_TRUETYPE +#include +#include + +#include "../../external/stb_truetype.h" + +struct _MwFLFont { + stbtt_fontinfo font; + void* data; + float scale; + int ascent; + int descent; +}; + +static int stbtt_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + MwFLFont ttf = MwGetVoid(handle, bold ? MwNboldFont : MwNfont); + unsigned char* px; + int tw, th; + MwRect r; + MwLLPixmap p; + int ax, lsb; + int x = 0, y = 0; + if(ttf == NULL) return 1; + + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + while(text[0] != 0) { + int c; + int x0, y0, x1, y1, cx, cy; + int ow, oh; + unsigned char* out; + + text += MwUTF8ToUTF32(text, &c); + if(c == '\n') { + x = 0; + y += (ttf->ascent - ttf->descent) * ttf->scale; + continue; + } + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + stbtt_GetCodepointBitmapBox(&ttf->font, c, ttf->scale, ttf->scale, &x0, &y0, &x1, &y1); + ow = x1 - x0; + oh = y1 - y0; + out = malloc(ow * oh); + stbtt_MakeCodepointBitmap(&ttf->font, out, ow, oh, ow, ttf->scale, ttf->scale, c); + + for(cy = 0; cy < oh; cy++) { + for(cx = 0; cx < ow; cx++) { + int ox = x + (lsb * ttf->scale) + cx; + int oy = y + (ttf->ascent * ttf->scale) + y0 + cy; + unsigned char* opx = &px[(oy * tw + ox) * 4]; + + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + opx[3] = out[cy * ow + cx]; + } + } + + x += ax * ttf->scale; + + free(out); + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); + + return 0; +} + +static int stbtt_MwTextWidth(MwWidget handle, const char* text) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + int ax, lsb; + int tw = 0; + if(ttf == NULL) return -1; + + while(text[0] != 0) { + int c; + text += MwUTF8ToUTF32(text, &c); + + stbtt_GetCodepointHMetrics(&ttf->font, c, &ax, &lsb); + + tw += ax * ttf->scale; + } + + return tw; +} + +static int stbtt_MwTextHeight(MwWidget handle, int count) { + MwFLFont ttf = MwGetVoid(handle, MwNfont); + if(ttf == NULL) return -1; + + return (ttf->ascent - ttf->descent) * ttf->scale * count; +} + +static void* stbtt_MwFontLoad(unsigned char* data, unsigned int size) { + MwFLFont ttf = malloc(sizeof(*ttf)); + ttf->data = malloc(size); + memcpy(ttf->data, data, size); + stbtt_InitFont(&ttf->font, ttf->data, 0); + + ttf->scale = stbtt_ScaleForPixelHeight(&ttf->font, 16); + stbtt_GetFontVMetrics(&ttf->font, &ttf->ascent, &ttf->descent, 0); + + return ttf; +} + +static void stbtt_MwFontFree(void* handle) { + MwFLFont ttf = handle; + + free(ttf->data); + free(ttf); +} + +int MwFL_STBTTSetup() { + MwFLDrawText = stbtt_MwDrawText; + MwFLTextWidth = stbtt_MwTextWidth; + MwFLTextHeight = stbtt_MwTextHeight; + MwFLFontLoad = stbtt_MwFontLoad; + MwFLFontFree = stbtt_MwFontFree; + return 0; +} + +#endif diff --git a/src/text/text.c b/src/text/text.c new file mode 100644 index 000000000..e25d28b21 --- /dev/null +++ b/src/text/text.c @@ -0,0 +1,158 @@ +#include + +int (*MwFLDrawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) = NULL; +int (*MwFLTextWidth)(MwWidget handle, const char* text) = NULL; +int (*MwFLTextHeight)(MwWidget handle, int count) = NULL; +void* (*MwFLFontLoad)(unsigned char* data, unsigned int size) = NULL; +void (*MwFLFontFree)(void* handle) = NULL; + +#if defined(USE_FREETYPE2) || defined(USE_STB_TRUETYPE) +#define TTF +#endif + +#define FontWidth 7 +#define FontHeight 14 + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); + +void MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + if(strlen(text) == 0) return; +#ifdef TTF + if(MwFLDrawText) + if(MwGetInteger(handle, MwNbitmapFont) || MwFLDrawText(handle, point, text, bold, align, color)) +#endif + bitmap_MwDrawText(handle, point, text, bold, align, color); +} + +int MwTextWidth(MwWidget handle, const char* text) { + /* TODO: check newline */ +#ifdef TTF + int st; + + if(MwFLTextWidth) + if(!MwGetInteger(handle, MwNbitmapFont) && (st = MwFLTextWidth(handle, text)) != -1) return st; +#else + (void)handle; + +#endif + return MwUTF8Length(text) * FontWidth; +} + +int MwTextHeight(MwWidget handle, const char* text) { + int c = 1; + int i = 0; +#ifdef TTF + int st; +#endif + + (void)handle; + (void)text; + + while(text[i] != 0) { + int out; + int l = MwUTF8ToUTF32(text + i, &out); + if(l == 0) break; + i += l; + + if(out == '\n') c++; + } +#ifdef TTF + if(MwFLTextHeight) + if(!MwGetInteger(handle, MwNbitmapFont) && (st = MwFLTextHeight(handle, c)) != -1) return st; +#endif + return FontHeight * c; +} + +void* MwFontLoad(unsigned char* data, unsigned int size) { + if(MwFLFontLoad) + return MwFLFontLoad(data, size); + return NULL; +} + +void MwFontFree(void* handle) { + if(MwFLFontFree) + return MwFLFontFree(handle); +} + +static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { + int i = 0, x, y, sx, sy; + int tw, th; + unsigned char* px; + MwRect r; + MwLLPixmap p; + + if(strlen(text) == 0) text = " "; + tw = MwTextWidth(handle, text); + th = MwTextHeight(handle, text); + px = malloc(tw * th * 4); + + memset(px, 0, tw * th * 4); + + sx = 0; + sy = 0; + + while(text[i] != 0) { + int out; + i += MwUTF8ToUTF32(text + i, &out); + + if(out > 0xff) { + out = 0; + } + + if(out == '\n') { + sx = 0; + sy += FontHeight; + } else { + for(y = 0; y < FontHeight; y++) { + for(x = 0; x < FontWidth; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + if((bold ? MwBoldFontData : MwFontData)[out].data[y] & (1 << ((FontWidth - 1) - x))) { + ppx[0] = color->common.red; + ppx[1] = color->common.green; + ppx[2] = color->common.blue; + ppx[3] = 255; + } else { + ppx[0] = 0; + ppx[1] = 0; + ppx[2] = 0; + ppx[3] = 0; + } + } + } + sx += FontWidth; + } + } + + p = MwLoadRaw(handle, px, tw, th); + r.x = point->x; + r.y = point->y - th / 2; + r.width = tw; + r.height = th; + + if(align == MwALIGNMENT_CENTER) { + r.x -= tw / 2; + } else if(align == MwALIGNMENT_END) { + r.x -= tw; + } + + MwLLDrawPixmap(handle->lowlevel, &r, p); + MwLLDestroyPixmap(p); + free(px); +} + +typedef int (*call_t)(); +void MwFLSetup() { + call_t calls[] = { +#ifdef USE_FREETYPE2 + MWFL_FT2Setup, +#endif +#ifdef USE_STB_TRUETYPE + MwFL_STBTTSetup, +#endif + NULL}; + int i; + + for(i = 0; calls[i] != NULL; i++) { + if(calls[i]() == 0) return; + } +} From de1e8da6f92e06d9545cd5d5a2fa18cc34a94912 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:05:38 -0700 Subject: [PATCH 142/409] fix generated mkfiles --- tools/genmk.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/genmk.pl b/tools/genmk.pl index 77545d8f9..1cd0a9ed8 100755 --- a/tools/genmk.pl +++ b/tools/genmk.pl @@ -147,7 +147,7 @@ scan("src/icon"); scan("src/cursor"); scan("src/widget"); scan("src/text"); -scan("src/font"); +scan("src/text/font"); scan("src/dialog"); scan("src/abstract"); push(@cfiles, "src/backend/gdi.c"); From 890294cd55ced334ba1866bacb2dd9b7d839b20c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:18:01 -0700 Subject: [PATCH 143/409] update macos readme --- README.txt | 53 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/README.txt b/README.txt index f69b63652..b116f7c10 100644 --- a/README.txt +++ b/README.txt @@ -1,23 +1,25 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) +Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) - This document contains a brief summary of the contents of this source -distributions and building instructions for Milsko GUI Toolkit. + This document contains a brief summary of the contents of this source +distributions and building instructions for Milsko GUI Toolkit. Requirements - Milsko requires the Windows environment with GDI (so anything NT or 9x) or -the Unix-like environment with X11 for runtime. + Milsko requires either + * A Windows environment with GDI (so anything NT or 9x) + * A MacOS environment with XCode Tools, including perl and Make + * A Unix-like environment with X11 for runtime. - To build Milsko for Windows, you must have one of following compilers: - * Visual C++ 6.0 or newer - * Borland C++ 5.5 or newer - * Open Watcom 2.0 or newer - * MinGW-w64 + To build Milsko for Windows, you must have one of following compilers: + * Visual C++ 6.0 or newer + * Borland C++ 5.5 or newer + * Open Watcom 2.0 or newer + * MinGW-w64 - and for Unix-like: - * GNU C Compiler - * Clang + and for Unix-like and MacOS: + * GNU C Compiler + * Clang Contents @@ -39,31 +41,38 @@ the Unix-like environment with X11 for runtime. Building Milsko - Building Milsko depends on the platform you use, and the compiler you use. + Building Milsko depends on the platform you use, and the compiler you use. A. Visual C++ ------------- -1) Run `nmake -f NTMakefile'. +1) Run `nmake -f NTMakefile'. B. Borland C++ -------------- -1) Run `make -f BorMakefile'. +1) Run `make -f BorMakefile'. C. Open Watcom -------------- -1) Run `wmake -f WatMakefile'. +1) Run `wmake -f WatMakefile'. D. MinGW-w64/GCC/Clang ---------------------- -1) Determine if you need Vulkan and/or OpenGL. +1) Determine if you need Vulkan and/or OpenGL. -2) Run `./configure'. - For help, run `./configure --help'. +2) Run `./configure'. + For help, run `./configure --help'. -3) Run `make'. +3) Run `make'. - -- Nishi (nishi@nishi.boats) +E. MacOS +---------------------- + +Currently there is not an .xcodeproj file. The plan for the future is +to write something that automatically generates it, so for now, you +just follow step D + + -- Nishi (nishi@nishi.boats) From 5eeba311aba93af501ba5531c884141f2650aa04 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:22:00 -0700 Subject: [PATCH 144/409] i fixed the makefiles but forgot to run the script --- BorMakefile | 8 ++++++-- NTMakefile | 8 ++++++-- WatMakefile | 16 ++++++++++++++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/BorMakefile b/BorMakefile index b6d062778..f8eaced63 100644 --- a/BorMakefile +++ b/BorMakefile @@ -45,6 +45,10 @@ clean: del /f /q src\icon\warning.obj del /f /q src\lowlevel.obj del /f /q src\string.obj + del /f /q src\text\font\boldfont.obj + del /f /q src\text\font\boldttf.obj + del /f /q src\text\font\font.obj + del /f /q src\text\font\ttf.obj del /f /q src\text\ft2.obj del /f /q src\text\stbtt.obj del /f /q src\text\text.obj @@ -72,8 +76,8 @@ clean: del /f /q src\Mw.dll del /f /q src\Mw.lib -src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) -e$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj -lopengl32.lib -lgdi32.lib -luser32.lib +src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(LDFLAGS) -e$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj -lopengl32.lib -lgdi32.lib -luser32.lib implib src\Mw.lib src\Mw.dll .c.obj: diff --git a/NTMakefile b/NTMakefile index 7ba162df7..3177f0487 100644 --- a/NTMakefile +++ b/NTMakefile @@ -45,6 +45,10 @@ clean: del /f /q src\icon\warning.obj del /f /q src\lowlevel.obj del /f /q src\string.obj + del /f /q src\text\font\boldfont.obj + del /f /q src\text\font\boldttf.obj + del /f /q src\text\font\font.obj + del /f /q src\text\font\ttf.obj del /f /q src\text\ft2.obj del /f /q src\text\stbtt.obj del /f /q src\text\text.obj @@ -72,8 +76,8 @@ clean: del /f /q src\Mw.dll del /f /q src\Mw.lib -src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj - $(LD) $(LDFLAGS) /OUT:$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib user32.lib +src\Mw.dll: external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj + $(LD) $(LDFLAGS) /OUT:$@ external\stb_ds.obj external\stb_image.obj external\stb_truetype.obj src\abstract\directory.obj src\abstract\dynamic.obj src\abstract\time.obj src\backend\gdi.obj src\color.obj src\core.obj src\cursor\arrow.obj src\cursor\cross.obj src\cursor\default.obj src\cursor\hidden.obj src\cursor\text.obj src\default.obj src\dialog\colorpicker.obj src\dialog\directorychooser.obj src\dialog\filechooser.obj src\dialog\messagebox.obj src\draw.obj src\error.obj src\icon\back.obj src\icon\clock.obj src\icon\computer.obj src\icon\directory.obj src\icon\down.obj src\icon\error.obj src\icon\file.obj src\icon\forward.obj src\icon\info.obj src\icon\left.obj src\icon\news.obj src\icon\note.obj src\icon\right.obj src\icon\search.obj src\icon\up.obj src\icon\warning.obj src\lowlevel.obj src\string.obj src\text\font\boldfont.obj src\text\font\boldttf.obj src\text\font\font.obj src\text\font\ttf.obj src\text\ft2.obj src\text\stbtt.obj src\text\text.obj src\unicode.obj src\widget\box.obj src\widget\button.obj src\widget\checkbox.obj src\widget\combobox.obj src\widget\entry.obj src\widget\frame.obj src\widget\image.obj src\widget\label.obj src\widget\listbox.obj src\widget\menu.obj src\widget\numberentry.obj src\widget\opengl.obj src\widget\progressbar.obj src\widget\radiobox.obj src\widget\scrollbar.obj src\widget\separator.obj src\widget\submenu.obj src\widget\treeview.obj src\widget\viewport.obj src\widget\window.obj opengl32.lib gdi32.lib user32.lib .c.obj: diff --git a/WatMakefile b/WatMakefile index d8dbf5e98..5177e0509 100644 --- a/WatMakefile +++ b/WatMakefile @@ -44,6 +44,10 @@ clean: .SYMBOLIC %erase src/icon/warning.obj %erase src/lowlevel.obj %erase src/string.obj + %erase src/text/font/boldfont.obj + %erase src/text/font/boldttf.obj + %erase src/text/font/font.obj + %erase src/text/font/ttf.obj %erase src/text/ft2.obj %erase src/text/stbtt.obj %erase src/text/text.obj @@ -71,8 +75,8 @@ clean: .SYMBOLIC %erase src/Mw.dll %erase src/Mw.lib -src/Mw.dll: external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/error.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/ft2.obj src/text/stbtt.obj src/text/text.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj - $(LD) $(LDFLAGS) option implib=src/Mw.lib name $@ file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/error.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/ft2.obj file src/text/stbtt.obj file src/text/text.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library user32.lib +src/Mw.dll: external/stb_ds.obj external/stb_image.obj external/stb_truetype.obj src/abstract/directory.obj src/abstract/dynamic.obj src/abstract/time.obj src/backend/gdi.obj src/color.obj src/core.obj src/cursor/arrow.obj src/cursor/cross.obj src/cursor/default.obj src/cursor/hidden.obj src/cursor/text.obj src/default.obj src/dialog/colorpicker.obj src/dialog/directorychooser.obj src/dialog/filechooser.obj src/dialog/messagebox.obj src/draw.obj src/error.obj src/icon/back.obj src/icon/clock.obj src/icon/computer.obj src/icon/directory.obj src/icon/down.obj src/icon/error.obj src/icon/file.obj src/icon/forward.obj src/icon/info.obj src/icon/left.obj src/icon/news.obj src/icon/note.obj src/icon/right.obj src/icon/search.obj src/icon/up.obj src/icon/warning.obj src/lowlevel.obj src/string.obj src/text/font/boldfont.obj src/text/font/boldttf.obj src/text/font/font.obj src/text/font/ttf.obj src/text/ft2.obj src/text/stbtt.obj src/text/text.obj src/unicode.obj src/widget/box.obj src/widget/button.obj src/widget/checkbox.obj src/widget/combobox.obj src/widget/entry.obj src/widget/frame.obj src/widget/image.obj src/widget/label.obj src/widget/listbox.obj src/widget/menu.obj src/widget/numberentry.obj src/widget/opengl.obj src/widget/progressbar.obj src/widget/radiobox.obj src/widget/scrollbar.obj src/widget/separator.obj src/widget/submenu.obj src/widget/treeview.obj src/widget/viewport.obj src/widget/window.obj + $(LD) $(LDFLAGS) option implib=src/Mw.lib name $@ file external/stb_ds.obj file external/stb_image.obj file external/stb_truetype.obj file src/abstract/directory.obj file src/abstract/dynamic.obj file src/abstract/time.obj file src/backend/gdi.obj file src/color.obj file src/core.obj file src/cursor/arrow.obj file src/cursor/cross.obj file src/cursor/default.obj file src/cursor/hidden.obj file src/cursor/text.obj file src/default.obj file src/dialog/colorpicker.obj file src/dialog/directorychooser.obj file src/dialog/filechooser.obj file src/dialog/messagebox.obj file src/draw.obj file src/error.obj file src/icon/back.obj file src/icon/clock.obj file src/icon/computer.obj file src/icon/directory.obj file src/icon/down.obj file src/icon/error.obj file src/icon/file.obj file src/icon/forward.obj file src/icon/info.obj file src/icon/left.obj file src/icon/news.obj file src/icon/note.obj file src/icon/right.obj file src/icon/search.obj file src/icon/up.obj file src/icon/warning.obj file src/lowlevel.obj file src/string.obj file src/text/font/boldfont.obj file src/text/font/boldttf.obj file src/text/font/font.obj file src/text/font/ttf.obj file src/text/ft2.obj file src/text/stbtt.obj file src/text/text.obj file src/unicode.obj file src/widget/box.obj file src/widget/button.obj file src/widget/checkbox.obj file src/widget/combobox.obj file src/widget/entry.obj file src/widget/frame.obj file src/widget/image.obj file src/widget/label.obj file src/widget/listbox.obj file src/widget/menu.obj file src/widget/numberentry.obj file src/widget/opengl.obj file src/widget/progressbar.obj file src/widget/radiobox.obj file src/widget/scrollbar.obj file src/widget/separator.obj file src/widget/submenu.obj file src/widget/treeview.obj file src/widget/viewport.obj file src/widget/window.obj library clib3r.lib library opengl32.lib library gdi32.lib library user32.lib @@ -154,6 +158,14 @@ src/lowlevel.obj: src/lowlevel.c $(CC) $(CFLAGS) -fo=$@ $< src/string.obj: src/string.c $(CC) $(CFLAGS) -fo=$@ $< +src/text/font/boldfont.obj: src/text/font/boldfont.c + $(CC) $(CFLAGS) -fo=$@ $< +src/text/font/boldttf.obj: src/text/font/boldttf.c + $(CC) $(CFLAGS) -fo=$@ $< +src/text/font/font.obj: src/text/font/font.c + $(CC) $(CFLAGS) -fo=$@ $< +src/text/font/ttf.obj: src/text/font/ttf.c + $(CC) $(CFLAGS) -fo=$@ $< src/text/ft2.obj: src/text/ft2.c $(CC) $(CFLAGS) -fo=$@ $< src/text/stbtt.obj: src/text/stbtt.c From 2e4e2a1c7fffd2e603043ce8637863a0854cc15a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:31:25 -0700 Subject: [PATCH 145/409] Remove xcodetools note --- README.txt | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/README.txt b/README.txt index b116f7c10..8fa1a37bc 100644 --- a/README.txt +++ b/README.txt @@ -8,7 +8,7 @@ distributions and building instructions for Milsko GUI Toolkit. Milsko requires either * A Windows environment with GDI (so anything NT or 9x) - * A MacOS environment with XCode Tools, including perl and Make + * A MacOS environment with Xcode Tools * A Unix-like environment with X11 for runtime. To build Milsko for Windows, you must have one of following compilers: @@ -68,11 +68,4 @@ D. MinGW-w64/GCC/Clang 3) Run `make'. -E. MacOS ----------------------- - -Currently there is not an .xcodeproj file. The plan for the future is -to write something that automatically generates it, so for now, you -just follow step D - -- Nishi (nishi@nishi.boats) From f9c35cded4c3ec8bb3ffa60417fe46c2ebc76e81 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 4 Mar 2026 13:32:39 -0700 Subject: [PATCH 146/409] macos note in readme should just be the version, my bad --- README.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.txt b/README.txt index 8fa1a37bc..d4522abe5 100644 --- a/README.txt +++ b/README.txt @@ -8,7 +8,7 @@ distributions and building instructions for Milsko GUI Toolkit. Milsko requires either * A Windows environment with GDI (so anything NT or 9x) - * A MacOS environment with Xcode Tools + * A MacOS environment with Cocoa (10.4 or above supported) * A Unix-like environment with X11 for runtime. To build Milsko for Windows, you must have one of following compilers: From 0832533c514e97120cc20cd36793155792d4af2f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 16:52:19 -0700 Subject: [PATCH 147/409] Oops the readme is generated --- README.txt | 48 ++++++++++++++++++++++++------------------------ tools/readme.pl | 8 +++++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/README.txt b/README.txt index d4522abe5..dc9d6bf2f 100644 --- a/README.txt +++ b/README.txt @@ -1,25 +1,25 @@ -Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) +Greetings - Welcome to the Milsko GUI Toolkit (Version pre-1.0) - This document contains a brief summary of the contents of this source -distributions and building instructions for Milsko GUI Toolkit. + This document contains a brief summary of the contents of this source +distributions and building instructions for Milsko GUI Toolkit. Requirements - Milsko requires either - * A Windows environment with GDI (so anything NT or 9x) - * A MacOS environment with Cocoa (10.4 or above supported) - * A Unix-like environment with X11 for runtime. + Milsko requires either + * A Windows environment with GDI (so anything NT or 9x) + * A MacOS environment with Cocoa (10.4 or above supported) + * A Unix-like environment with X11 for runtime. - To build Milsko for Windows, you must have one of following compilers: - * Visual C++ 6.0 or newer - * Borland C++ 5.5 or newer - * Open Watcom 2.0 or newer - * MinGW-w64 + To build Milsko for Windows, you must have one of following compilers: + * Visual C++ 6.0 or newer + * Borland C++ 5.5 or newer + * Open Watcom 2.0 or newer + * MinGW-w64 - and for Unix-like and MacOS: - * GNU C Compiler - * Clang + and for Unix-like and MacOS: + * GNU C Compiler + * Clang Contents @@ -41,31 +41,31 @@ distributions and building instructions for Milsko GUI Toolkit. Building Milsko - Building Milsko depends on the platform you use, and the compiler you use. + Building Milsko depends on the platform you use, and the compiler you use. A. Visual C++ ------------- -1) Run `nmake -f NTMakefile'. +1) Run `nmake -f NTMakefile'. B. Borland C++ -------------- -1) Run `make -f BorMakefile'. +1) Run `make -f BorMakefile'. C. Open Watcom -------------- -1) Run `wmake -f WatMakefile'. +1) Run `wmake -f WatMakefile'. D. MinGW-w64/GCC/Clang ---------------------- -1) Determine if you need Vulkan and/or OpenGL. +1) Determine if you need Vulkan and/or OpenGL. -2) Run `./configure'. - For help, run `./configure --help'. +2) Run `./configure'. + For help, run `./configure --help'. -3) Run `make'. +3) Run `make'. - -- Nishi (nishi@nishi.boats) + -- Nishi (nishi@nishi.boats) diff --git a/tools/readme.pl b/tools/readme.pl index c511f794e..7070312dd 100755 --- a/tools/readme.pl +++ b/tools/readme.pl @@ -59,8 +59,10 @@ l(""); c("Requirements"); l(""); l( -" Milsko requires the Windows environment with GDI (so anything NT or 9x) or the Unix-like environment with X11 for runtime." -); +" Milsko requires either"); +l(" * A Windows environment with GDI (so anything NT or 9x)"); +l(" * A MacOS environment with Cocoa (10.4 or above supported)"); +l(" * A Unix-like environment with X11 for runtime."); l(""); l(" To build Milsko for Windows, you must have one of following compilers:"); l(" * Visual C++ 6.0 or newer"); @@ -68,7 +70,7 @@ l(" * Borland C++ 5.5 or newer"); l(" * Open Watcom 2.0 or newer"); l(" * MinGW-w64"); l(""); -l(" and for Unix-like:"); +l(" and for Unix-like and MacOS:"); l(" * GNU C Compiler"); l(" * Clang"); l(""); From 943500a7ecaa938d8d4070bd37820f688fbecf76 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 19:34:19 -0700 Subject: [PATCH 148/409] mac: got a bunch of events handled. failed to get resizing working though --- include/Mw/LowLevel/Cocoa.h | 28 +++- src/backend/cocoa.m | 267 +++++++++++++++++++++++++++++++----- 2 files changed, 261 insertions(+), 34 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index d22f65396..2659b3c16 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -21,6 +21,21 @@ #import #endif +@interface MilskoCocoaWindowDelegate : NSObject { + NSWindow *w; +} +- (instancetype)initWithWin:(NSWindow *)win; +@end + +@interface MilskoFakePointer : NSView { + void *ptr; +} + +- (void)setPointer:(void *)ptr; +- (void *)pointer; + +@end + @interface MilskoCocoaPixmap : NSObject { MwBool valid; int width; @@ -46,28 +61,34 @@ MwBool valid; CGColorSpaceRef space; CGDataProviderRef provider; - unsigned char *buf; float width; float height; } - (NSGraphicsContext *)context; +- (void)destroy; +- (NSBitmapImageRep *)getRep; + @end @interface MilskoCocoa : NSObject { NSApplication *application; NSEvent *lastEvent; + MwBool _forceRender; NSWindow *window; NSRect rect; MilskoCocoaView *view; MwLL parent; + MilskoFakePointer *handle; + MwBool doWHResize; } + (MilskoCocoa *)newWithParent:(MwLL)parent x:(int)x y:(int)y width:(int)width - height:(int)height; + height:(int)height + handle:(MwLL)handle; - (void)polygonWithPoints:(MwPoint *)points points_count:(int)points_count color:(MwLLColor)color; @@ -97,6 +118,9 @@ - (void)getCursorCoord:(MwPoint *)point; - (void)getScreenSize:(MwRect *)rect; - (void)destroy; +- (void)setHandle:(MwLL)h; + +- (NSWindow *)parentWindow; @end #define OBJC(x) x diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 3117ba58b..5d6f5c6ca 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,7 +1,6 @@ #include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include -#include -#include @implementation MilskoCocoaPixmap @@ -56,7 +55,8 @@ x:(int)x y:(int)y width:(int)width - height:(int)height { + height:(int)height + handle:(MwLL)r { MilskoCocoa *c = [MilskoCocoa alloc]; bool centerX = false, centerY = false; @@ -92,6 +92,8 @@ backing:NSBackingStoreBuffered defer:NO]; } + c->window.delegate = + [[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]; [c->window makeKeyAndOrderFront:c->application]; @@ -100,14 +102,20 @@ [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; } else { - [c->application activateIgnoringOtherApps:true]; + // [c->application activateIgnoringOtherApps:true]; } c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; + [c->window setContentView:c->view]; c->parent = parent; + c->_forceRender = MwTRUE; + return c; } - (void)polygonWithPoints:(MwPoint *)points @@ -154,7 +162,8 @@ NSRect frame = [self->window frame]; *x = frame.origin.x; - *y = frame.origin.y - frame.size.height; + *y = frame.origin.y; + *w = frame.size.width; *h = frame.size.height; }; @@ -165,11 +174,12 @@ frame.origin.y = y; if (self->parent) { - NSWindow *parentWindow = self->parent->cocoa.real->window; - frame = [parentWindow contentRectForFrameRect:frame]; - frame.origin.y = - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height - - y; + NSWindow *parentWindow = [self parentWindow]; + CGFloat ny; + NSRect realFrame = parentWindow.frame; + NSRect correctedFrame = [parentWindow contentRectForFrameRect:realFrame]; + ny = (correctedFrame.size.height - y); + frame.origin.y = ny; } [self->window setFrame:frame display:YES animate:false]; @@ -178,11 +188,7 @@ NSRect frame = [self->window frame]; frame.size.width = w; frame.size.height = h; - - if (self->parent) { - NSWindow *parentWindow = self->parent->cocoa.real->window; - // frame = [parentWindow contentRectForFrameRect:frame]; - } + self->rect = frame; [self->window setFrame:frame display:YES animate:false]; }; @@ -192,22 +198,144 @@ untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES]; + if (_forceRender) { + _forceRender = MwFALSE; + return 1; + } return self->lastEvent != NULL; }; - (void)getNextEvent { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - if (self->lastEvent != nil) { + NSWindow *win = [self->lastEvent window]; + NSWindow *parentWindow = [self parentWindow]; + NSRect realFrame = parentWindow.frame; + NSRect correctedFrame = + [parentWindow frameRectForContentRect:parentWindow.frame]; + CGFloat offset = realFrame.size.height - correctedFrame.size.height; + MwLL h; + + if ([win contentView].subviews.count == 0) { + NSLog(@"[WARNING] no subviews on this window, cannot process events.\n"); + return; + } + + h = [((MilskoFakePointer *)[win contentView].subviews[0]) pointer]; + switch (self->lastEvent.type) { + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: { + MwLLMouse mouse = {}; + MwBool isDown = MwTRUE; + switch (self->lastEvent.type) { + case NSEventTypeLeftMouseUp: + isDown = MwFALSE; + case NSEventTypeLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSEventTypeRightMouseUp: + isDown = MwFALSE; + case NSEventTypeRightMouseDown: + mouse.button = MwLLMouseRight; + break; + case NSEventTypeOtherMouseUp: + isDown = MwFALSE; + case NSEventTypeOtherMouseDown: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = [lastEvent locationInWindow].x; + mouse.point.y = [win contentRectForFrameRect:win.frame].size.height - + [lastEvent locationInWindow].y; + + if (isDown) { + MwLLDispatch(h, down, &mouse); + } else { + MwLLDispatch(h, up, &mouse); + } + break; + } + + break; + case NSEventTypeMouseMoved: { + MwPoint pos; + pos.x = [lastEvent locationInWindow].x; + pos.y = [win contentRectForFrameRect:win.frame].size.height - + [lastEvent locationInWindow].y; + MwLLDispatch(h, move, &pos); + break; + } + case NSEventTypeLeftMouseDragged: + MwLLDispatch(h, focus_in, NULL); + break; + case NSEventTypeRightMouseDragged: + MwLLDispatch(h, focus_out, NULL); + break; + case NSEventTypeMouseEntered: + break; + case NSEventTypeMouseExited: + break; + case NSEventTypeKeyDown: + [win interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; + break; + case NSEventTypeKeyUp: + [win interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; + break; + case NSEventTypeFlagsChanged: + break; + case NSEventTypeAppKitDefined: + break; + case NSEventTypeSystemDefined: + break; + case NSEventTypeApplicationDefined: + break; + case NSEventTypePeriodic: + break; + case NSEventTypeCursorUpdate: + break; + case NSEventTypeScrollWheel: + break; + case NSEventTypeTabletPoint: + break; + case NSEventTypeTabletProximity: + break; + break; + case NSEventTypeOtherMouseDragged: + break; + case NSEventTypeGesture: + break; + case NSEventTypeMagnify: + break; + case NSEventTypeSwipe: + break; + case NSEventTypeRotate: + break; + case NSEventTypeBeginGesture: + break; + case NSEventTypeEndGesture: + break; + case NSEventTypeSmartMagnify: + break; + case NSEventTypeQuickLook: + break; + case NSEventTypePressure: + break; + case NSEventTypeDirectTouch: + break; + case NSEventTypeChangeMode: + break; + }; // printf("got event: %ld\n", self->lastEvent.type); + [self->application sendEvent:self->lastEvent]; } - [self->application sendEvent:self->lastEvent]; - - /* this should be in the draw functions but it's here for now for testing */ [self->view setNeedsDisplay:true]; - - [pool release]; }; + - (void)setTitle:(const char *)title { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [self->window @@ -237,6 +365,7 @@ - (void)setIcon:(MwLLPixmap)pixmap { }; - (void)forceRender { + _forceRender = MwTRUE; }; - (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { }; @@ -269,8 +398,8 @@ [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - /* MacOS didn't have a "pointer grab" function until 10.13.2 so I need to do - * this manually */ + /* MacOS didn't have a "pointer grab" function + * until 10.13.2 so I need to do this manually */ }; - (void)setClipboard:(const char *)text { }; @@ -294,14 +423,23 @@ [self->window dealloc]; } +- (void)setDoWHResize:(MwBool)d { + doWHResize = d; +}; + +- (NSWindow *)parentWindow { + NSWindow *topmostWindow = self->window; + while (topmostWindow.parentWindow) + topmostWindow = topmostWindow.parentWindow; + return topmostWindow; +} @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { + width = frame.size.width; + height = frame.size.height; self = [super initWithFrame:frame]; - self->width = frame.size.width; - self->height = frame.size.height; - self->buf = malloc(self->width * self->height * 4); self->space = CGColorSpaceCreateDeviceRGB(); if (width == 0 || height == 0) { @@ -333,23 +471,84 @@ return self->context; } +- (NSBitmapImageRep *)getRep { + return self->rep; +} + - (void)drawRect:(NSRect)dirtyRect { + NSSize sz = [self->rep size]; + unsigned char *pixels; [super drawRect:dirtyRect]; if (!self->rep) { return; } - [self->rep drawInRect:NSMakeRect(0, 0, self->width, self->height)]; - unsigned char *pixels = [self->rep bitmapData]; + [self->rep drawInRect:NSMakeRect(0, 0, width, height)]; + + pixels = [self->rep bitmapData]; } - (void)destroy { - free(self->buf); CGColorSpaceRelease(self->space); } +- (void)setFrameSize:(NSSize)newSize { + [super setFrameSize:newSize]; + if (newSize.width != 0 && newSize.height != 0) { + // [self->rep setSize:newSize]; + // width = newSize.width; + // height = newSize.height; + // [self->context setImageInterpolation:NSImageInterpolationHigh]; + } +} + +- (void)displayRect:(NSRect)rect { +}; +@end + +@implementation MilskoFakePointer +- (void)viewDidMoveToSuperview { +} +- (void)setPointer:(void *)pointer { + self.frame = *(NSRect *)&pointer; + self->ptr = pointer; +}; +- (void *)pointer { + return self->ptr; +}; + +- (void)drawRect:(NSRect)dirtyRect { + /* explicitly do nothing */ +} + +- (void)destroy { +} + @end +@implementation MilskoCocoaWindowDelegate + +- (NSSize)windowWillResize:(NSWindow *)win toSize:(NSSize)frameSize; +{ + if (win.contentView.subviews.count >= 1) { + MilskoFakePointer *ptr = win.contentView.subviews[0]; + MwLL h = [ptr pointer]; + + // MwLLDispatch(h, resize, NULL); + MwLLDispatch(h, draw, NULL); + } + return frameSize; +} + +- (void)windowDidResize:(NSNotification *)notification { +} + +- (instancetype)initWithWin:(NSWindow *)win { + self->w = win; + return self; +} + +@end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; (void)x; @@ -361,8 +560,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLCreateCommon(r); - MilskoCocoa *o = - [MilskoCocoa newWithParent:parent x:x y:y width:width height:height]; + MilskoCocoa *o = [MilskoCocoa newWithParent:parent + x:x + y:y + width:width + height:height + handle:r]; r->cocoa.real = o; return r; From b585ad69b74542fbcd6a2784dc6f2af5ec8991e1 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 20:44:25 -0700 Subject: [PATCH 149/409] code cleanup --- include/Mw/LowLevel/Cocoa.h | 1 - src/backend/cocoa.m | 19 +++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 2659b3c16..22bb29c2f 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -80,7 +80,6 @@ MilskoCocoaView *view; MwLL parent; MilskoFakePointer *handle; - MwBool doWHResize; } + (MilskoCocoa *)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 5d6f5c6ca..b9d108008 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -162,7 +162,7 @@ NSRect frame = [self->window frame]; *x = frame.origin.x; - *y = frame.origin.y; + *y = frame.origin.y - frame.size.height; *w = frame.size.width; *h = frame.size.height; @@ -175,11 +175,9 @@ if (self->parent) { NSWindow *parentWindow = [self parentWindow]; - CGFloat ny; - NSRect realFrame = parentWindow.frame; - NSRect correctedFrame = [parentWindow contentRectForFrameRect:realFrame]; - ny = (correctedFrame.size.height - y); - frame.origin.y = ny; + NSRect correctedFrame = + [parentWindow contentRectForFrameRect:parentWindow.frame]; + frame.origin.y = (correctedFrame.size.height - y); } [self->window setFrame:frame display:YES animate:false]; @@ -423,10 +421,6 @@ [self->window dealloc]; } -- (void)setDoWHResize:(MwBool)d { - doWHResize = d; -}; - - (NSWindow *)parentWindow { NSWindow *topmostWindow = self->window; while (topmostWindow.parentWindow) @@ -477,7 +471,6 @@ - (void)drawRect:(NSRect)dirtyRect { NSSize sz = [self->rep size]; - unsigned char *pixels; [super drawRect:dirtyRect]; if (!self->rep) { return; @@ -485,7 +478,7 @@ [self->rep drawInRect:NSMakeRect(0, 0, width, height)]; - pixels = [self->rep bitmapData]; + [self->rep bitmapData]; } - (void)destroy { @@ -507,8 +500,6 @@ @end @implementation MilskoFakePointer -- (void)viewDidMoveToSuperview { -} - (void)setPointer:(void *)pointer { self.frame = *(NSRect *)&pointer; self->ptr = pointer; From f700e90d23d5752585a728c54ecf35d4d93dbb0f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 20:47:55 -0700 Subject: [PATCH 150/409] did some code cleanup --- include/Mw/LowLevel/Cocoa.h | 1 - src/backend/cocoa.m | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 22bb29c2f..a36dbfdea 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -117,7 +117,6 @@ - (void)getCursorCoord:(MwPoint *)point; - (void)getScreenSize:(MwRect *)rect; - (void)destroy; -- (void)setHandle:(MwLL)h; - (NSWindow *)parentWindow; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index b9d108008..23e9373c2 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,7 +1,8 @@ -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" #include +#pragma clang push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { @@ -92,8 +93,8 @@ backing:NSBackingStoreBuffered defer:NO]; } - c->window.delegate = - [[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]; + c->window.delegate = (id)[[MilskoCocoaWindowDelegate alloc] + initWithWin:c->window]; [c->window makeKeyAndOrderFront:c->application]; @@ -625,10 +626,10 @@ static int MwLLPendingImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); return 1; }; + return 0; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; [h getNextEvent]; } From db577bb01f5488e1dfa441a0826cd06916e36823 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 22:56:04 -0700 Subject: [PATCH 151/409] mac opengl support. proper coordinate flipping --- examples/gldemos/cube.c | 113 +++---- include/Mw/LowLevel/Cocoa.h | 1 + include/Mw/Widget/OpenGL.h | 21 +- pl/rules.pl | 9 +- src/backend/cocoa.m | 80 +++-- src/widget/opengl.c | 590 +++++++++++++++++++----------------- src/widget/opengl_cocoa.m | 128 ++++++++ 7 files changed, 581 insertions(+), 361 deletions(-) create mode 100644 src/widget/opengl_cocoa.m diff --git a/examples/gldemos/cube.c b/examples/gldemos/cube.c index c1ba9917d..2d1954c5a 100644 --- a/examples/gldemos/cube.c +++ b/examples/gldemos/cube.c @@ -1,78 +1,89 @@ #define TITLE "cube" #include "glutlayer.c" +#if defined(__APPLE__) +#include +#include +#else +#include #include +#endif static double deg = 0; static void draw(void) { - int i; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + int i; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glPushMatrix(); - glRotatef(deg, 1, 0, 0); - glRotatef(deg, 0, 1, 0); - glRotatef(deg, 0, 0, 1); + glPushMatrix(); + glRotatef(deg, 1, 0, 0); + glRotatef(deg, 0, 1, 0); + glRotatef(deg, 0, 0, 1); - for(i = 0; i < 6; i++) { - if(i == 0) glColor3f(1, 0, 0); - if(i == 1) glColor3f(0, 1, 0); - if(i == 2) glColor3f(1, 1, 0); - if(i == 3) glColor3f(0, 0, 1); - if(i == 4) glColor3f(1, 0, 1); - if(i == 5) glColor3f(0, 1, 1); + for (i = 0; i < 6; i++) { + if (i == 0) + glColor3f(1, 0, 0); + if (i == 1) + glColor3f(0, 1, 0); + if (i == 2) + glColor3f(1, 1, 0); + if (i == 3) + glColor3f(0, 0, 1); + if (i == 4) + glColor3f(1, 0, 1); + if (i == 5) + glColor3f(0, 1, 1); - glBegin(GL_QUADS); - glNormal3f(0, 1, 0); - glVertex3f(-1, 1, -1); - glVertex3f(-1, 1, 1); - glVertex3f(1, 1, 1); - glVertex3f(1, 1, -1); - glEnd(); + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-1, 1, -1); + glVertex3f(-1, 1, 1); + glVertex3f(1, 1, 1); + glVertex3f(1, 1, -1); + glEnd(); - if(i < 3) glRotatef(90, 0, 0, 1); - if(i == 3) glRotatef(90, 1, 0, 0); - if(i == 4) glRotatef(180, 0, 0, 1); - } - glPopMatrix(); + if (i < 3) + glRotatef(90, 0, 0, 1); + if (i == 3) + glRotatef(90, 1, 0, 0); + if (i == 4) + glRotatef(180, 0, 0, 1); + } + glPopMatrix(); } -static void idle(void) { - deg += 1.0; -} +static void idle(void) { deg += 1.0; } static void reshape(int width, int height) { - GLfloat lpos[4]; + GLfloat lpos[4]; - lpos[0] = 1; - lpos[1] = 1; - lpos[2] = 1; - lpos[3] = 0; + lpos[0] = 1; + lpos[1] = 1; + lpos[2] = 1; + lpos[3] = 0; - glViewport(0, 0, width, height); + glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60, (double)width / height, 1, 100); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60, (double)width / height, 1, 100); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0); - glLightfv(GL_LIGHT0, GL_POSITION, lpos); + glLightfv(GL_LIGHT0, GL_POSITION, lpos); } static void init(void) { - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_CULL_FACE); - glEnable(GL_NORMALIZE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_CULL_FACE); + glEnable(GL_NORMALIZE); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); } -static void key(int k) { - (void)k; -} +static void key(int k) { (void)k; } diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index a36dbfdea..91679db7e 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -119,6 +119,7 @@ - (void)destroy; - (NSWindow *)parentWindow; +- (NSView *)getView; @end #define OBJC(x) x diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index 26f44abf5..c3fab76ed 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -5,17 +5,24 @@ #ifndef __MW_WIDGET_OPENGL_H__ #define __MW_WIDGET_OPENGL_H__ +#include #include #include -#include #if !defined(MW_OPENGL_NO_INCLUDE) && !defined(__gl_h_) #ifdef _WIN32 #include +#elif defined(__APPLE__) #else #include #endif +#if defined(__APPLE__) +#include +#include +#else #include +#include +#endif #ifndef GLAPIENTRY #define GLAPIENTRY APIENTRY @@ -36,7 +43,7 @@ MWDECL MwClass MwOpenGLClass; * @param handle Widget */ MwInline void MwOpenGLMakeCurrent(MwWidget handle) { - MwVaWidgetExecute(handle, "mwOpenGLMakeCurrent", NULL); + MwVaWidgetExecute(handle, "mwOpenGLMakeCurrent", NULL); } /*! @@ -45,10 +52,10 @@ MwInline void MwOpenGLMakeCurrent(MwWidget handle) { * @param name Name * @return Procedure */ -MwInline void* MwOpenGLGetProcAddress(MwWidget handle, const char* name) { - void* out; - MwVaWidgetExecute(handle, "mwOpenGLGetProcAddress", &out, name); - return out; +MwInline void *MwOpenGLGetProcAddress(MwWidget handle, const char *name) { + void *out; + MwVaWidgetExecute(handle, "mwOpenGLGetProcAddress", &out, name); + return out; } /*! @@ -56,7 +63,7 @@ MwInline void* MwOpenGLGetProcAddress(MwWidget handle, const char* name) { * @param handle Widget */ MwInline void MwOpenGLSwapBuffer(MwWidget handle) { - MwVaWidgetExecute(handle, "mwOpenGLSwapBuffer", NULL); + MwVaWidgetExecute(handle, "mwOpenGLSwapBuffer", NULL); } #ifdef __cplusplus diff --git a/pl/rules.pl b/pl/rules.pl index d4784e102..45bb6daf3 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -50,7 +50,14 @@ if (grep(/^cocoa$/, @backends)) { add_cflags("-DUSE_COCOA"); new_object("src/backend/cocoa.m"); - $gl_libs = "-lGL -lGLU"; + if (param_get("opengl")) { + new_object("src/widget/opengl_cocoa.m"); + } + + # tim cook my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this + add_cflags("-DGL_SILENCE_DEPRECATION"); + + $gl_libs = "-framework OpenGL"; } if (param_get("stb-image")) { diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 23e9373c2..700ebdb88 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -3,6 +3,29 @@ #pragma clang push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +static CGRect rectFlip(CGRect originFrame) { + NSScreen *zeroScreen = NSScreen.screens[0]; + double screenHeight = zeroScreen.frame.size.height; + double originY = originFrame.origin.y; + double frameHeight = originFrame.size.height; + double destinationY = screenHeight - (originY + frameHeight); + CGRect destinationFrame = originFrame; + destinationFrame.origin.y = destinationY; + if (destinationFrame.origin.x < 0) + destinationFrame.origin.x = 0; + if (destinationFrame.origin.y < 0) + destinationFrame.origin.y = 0; + if (destinationFrame.size.width < 0) + destinationFrame.size.width = 0; + if (destinationFrame.size.height < 0) + destinationFrame.size.height = 0; + return destinationFrame; +} + +static CGPoint pointFlip(CGPoint point) { + return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; +} + @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { @@ -70,8 +93,7 @@ centerY = true; } c->application = [NSApplication sharedApplication]; - - c->rect = NSMakeRect(x, y, width, height); + c->rect = rectFlip(NSMakeRect(x, y, width, height)); if (parent == NULL) { c->window = [[NSWindow alloc] @@ -81,12 +103,12 @@ backing:NSBackingStoreBuffered defer:NO]; } else { + double offset = 0; NSWindow *parentWindow = parent->cocoa.real->window; - - c->rect = [parentWindow frameRectForContentRect:c->rect]; - c->rect.origin.y = - y - + offset = + [parentWindow frameRectForContentRect:parentWindow.frame].size.height - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; + c->rect.origin.y -= offset; c->window = [[NSWindow alloc] initWithContentRect:c->rect styleMask:NSBorderlessWindowMask @@ -160,10 +182,10 @@ - (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; - (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { - NSRect frame = [self->window frame]; + NSRect frame = rectFlip([self->window frame]); *x = frame.origin.x; - *y = frame.origin.y - frame.size.height; + *y = frame.origin.y; *w = frame.size.width; *h = frame.size.height; @@ -174,12 +196,17 @@ frame.origin.x = x; frame.origin.y = y; - if (self->parent) { - NSWindow *parentWindow = [self parentWindow]; - NSRect correctedFrame = - [parentWindow contentRectForFrameRect:parentWindow.frame]; - frame.origin.y = (correctedFrame.size.height - y); + frame = rectFlip(frame); + + if (parent) { + double offset = 0; + NSWindow *parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:parentWindow.frame].size.height - + [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; + frame.origin.y -= offset; } + [self->view setFrameSize:frame.size]; [self->window setFrame:frame display:YES animate:false]; }; @@ -187,8 +214,10 @@ NSRect frame = [self->window frame]; frame.size.width = w; frame.size.height = h; + self->rect = frame; + [self->view setFrameSize:frame.size]; [self->window setFrame:frame display:YES animate:false]; }; - (int)pending { @@ -207,10 +236,6 @@ if (self->lastEvent != nil) { NSWindow *win = [self->lastEvent window]; NSWindow *parentWindow = [self parentWindow]; - NSRect realFrame = parentWindow.frame; - NSRect correctedFrame = - [parentWindow frameRectForContentRect:parentWindow.frame]; - CGFloat offset = realFrame.size.height - correctedFrame.size.height; MwLL h; if ([win contentView].subviews.count == 0) { @@ -228,6 +253,7 @@ case NSEventTypeOtherMouseUp: { MwLLMouse mouse = {}; MwBool isDown = MwTRUE; + CGPoint mousePoint = pointFlip([lastEvent locationInWindow]); switch (self->lastEvent.type) { case NSEventTypeLeftMouseUp: isDown = MwFALSE; @@ -247,9 +273,8 @@ default: break; } - mouse.point.x = [lastEvent locationInWindow].x; - mouse.point.y = [win contentRectForFrameRect:win.frame].size.height - - [lastEvent locationInWindow].y; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; if (isDown) { MwLLDispatch(h, down, &mouse); @@ -428,6 +453,10 @@ topmostWindow = topmostWindow.parentWindow; return topmostWindow; } + +- (NSView *)getView { + return view; +} @end @implementation MilskoCocoaView @@ -471,13 +500,13 @@ } - (void)drawRect:(NSRect)dirtyRect { - NSSize sz = [self->rep size]; + NSSize sz = self->rep.size; [super drawRect:dirtyRect]; if (!self->rep) { return; } - [self->rep drawInRect:NSMakeRect(0, 0, width, height)]; + [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; [self->rep bitmapData]; } @@ -488,12 +517,7 @@ - (void)setFrameSize:(NSSize)newSize { [super setFrameSize:newSize]; - if (newSize.width != 0 && newSize.height != 0) { - // [self->rep setSize:newSize]; - // width = newSize.width; - // height = newSize.height; - // [self->context setImageInterpolation:NSImageInterpolationHigh]; - } + [self->rep setSize:newSize]; } - (void)displayRect:(NSRect)rect { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index ae8781785..0f9c5c24f 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,44 +1,49 @@ +#ifndef __APPLE__ + #include #include #ifdef USE_GDI -typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); -typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); -typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); -typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); +typedef HGLRC(WINAPI *MWwglCreateContext)(HDC); +typedef BOOL(WINAPI *MWwglMakeCurrent)(HDC, HGLRC); +typedef PROC(WINAPI *MWwglGetProcAddress)(LPCSTR); +typedef BOOL(WINAPI *MWwglDeleteContext)(HGLRC); typedef struct gdiopengl { - HDC dc; - HGLRC gl; + HDC dc; + HGLRC gl; - void* lib; + void *lib; - MWwglCreateContext wglCreateContext; - MWwglMakeCurrent wglMakeCurrent; - MWwglDeleteContext wglDeleteContext; - MWwglGetProcAddress wglGetProcAddress; + MWwglCreateContext wglCreateContext; + MWwglMakeCurrent wglMakeCurrent; + MWwglDeleteContext wglDeleteContext; + MWwglGetProcAddress wglGetProcAddress; } gdiopengl_t; #endif #ifdef USE_X11 -typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, int* attribList); -typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, GLXContext shareList, Bool direct); -typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); -typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, GLXContext ctx); -typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); -typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); +typedef XVisualInfo *(*MWglXChooseVisual)(Display *dpy, int screen, + int *attribList); +typedef GLXContext (*MWglXCreateContext)(Display *dpy, XVisualInfo *vis, + GLXContext shareList, Bool direct); +typedef void (*MWglXDestroyContext)(Display *dpy, GLXContext ctx); +typedef Bool (*MWglXMakeCurrent)(Display *dpy, GLXDrawable drawable, + GLXContext ctx); +typedef void (*MWglXSwapBuffers)(Display *dpy, GLXDrawable drawable); +typedef void *(*MWglXGetProcAddress)(const GLubyte *procname); typedef struct x11opengl { - XVisualInfo* visual; - GLXContext gl; + XVisualInfo *visual; + GLXContext gl; - void* lib; + void *lib; - MWglXChooseVisual glXChooseVisual; - MWglXCreateContext glXCreateContext; - MWglXDestroyContext glXDestroyContext; - MWglXMakeCurrent glXMakeCurrent; - MWglXSwapBuffers glXSwapBuffers; - MWglXGetProcAddress glXGetProcAddress; + MWglXChooseVisual glXChooseVisual; + MWglXCreateContext glXCreateContext; + MWglXDestroyContext glXDestroyContext; + MWglXMakeCurrent glXMakeCurrent; + MWglXSwapBuffers glXSwapBuffers; + MWglXGetProcAddress glXGetProcAddress; } x11opengl_t; #endif @@ -47,348 +52,385 @@ typedef struct x11opengl { #include typedef struct waylandopengl { - EGLNativeWindowType egl_window_native; - EGLDisplay egl_display; - EGLContext egl_context; - EGLSurface egl_surface; - EGLConfig egl_config; + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; } waylandopengl_t; #endif static int create(MwWidget handle) { - void* r = NULL; - MwWidget w = handle; + void *r = NULL; + MwWidget w = handle; #ifdef USE_GDI - if(handle->lowlevel->common.type == MwLLBackendGDI) { - PIXELFORMATDESCRIPTOR pfd; - int pf; - gdiopengl_t* o = r = malloc(sizeof(*o)); + if (handle->lowlevel->common.type == MwLLBackendGDI) { + PIXELFORMATDESCRIPTOR pfd; + int pf; + gdiopengl_t *o = r = malloc(sizeof(*o)); - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.cDepthBits = 32; - pfd.cColorBits = 32; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cDepthBits = 32; + pfd.cColorBits = 32; - o->dc = GetDC(handle->lowlevel->gdi.hWnd); + o->dc = GetDC(handle->lowlevel->gdi.hWnd); - pf = ChoosePixelFormat(o->dc, &pfd); - SetPixelFormat(o->dc, pf, &pfd); + pf = ChoosePixelFormat(o->dc, &pfd); + SetPixelFormat(o->dc, pf, &pfd); - o->lib = MwDynamicOpen("opengl32.dll"); + o->lib = MwDynamicOpen("opengl32.dll"); - o->wglCreateContext = (MWwglCreateContext)(void*)MwDynamicSymbol(o->lib, "wglCreateContext"); - o->wglMakeCurrent = (MWwglMakeCurrent)(void*)MwDynamicSymbol(o->lib, "wglMakeCurrent"); - o->wglDeleteContext = (MWwglDeleteContext)(void*)MwDynamicSymbol(o->lib, "wglDeleteContext"); - o->wglGetProcAddress = (MWwglGetProcAddress)(void*)MwDynamicSymbol(o->lib, "wglGetProcAddress"); + o->wglCreateContext = + (MWwglCreateContext)(void *)MwDynamicSymbol(o->lib, "wglCreateContext"); + o->wglMakeCurrent = + (MWwglMakeCurrent)(void *)MwDynamicSymbol(o->lib, "wglMakeCurrent"); + o->wglDeleteContext = + (MWwglDeleteContext)(void *)MwDynamicSymbol(o->lib, "wglDeleteContext"); + o->wglGetProcAddress = (MWwglGetProcAddress)(void *)MwDynamicSymbol( + o->lib, "wglGetProcAddress"); - o->gl = o->wglCreateContext(o->dc); - } + o->gl = o->wglCreateContext(o->dc); + } #endif #ifdef USE_X11 - if(handle->lowlevel->common.type == MwLLBackendX11) { - int attribs[5]; - const char* glpath[] = { - "libGL.so", - "/usr/local/lib/libGL.so", - "/usr/X11R7/lib/libGL.so", - "/usr/pkg/lib/libGL.so"}; - int glincr = 0; - x11opengl_t* o = r = malloc(sizeof(*o)); + if (handle->lowlevel->common.type == MwLLBackendX11) { + int attribs[5]; + const char *glpath[] = {"libGL.so", "/usr/local/lib/libGL.so", + "/usr/X11R7/lib/libGL.so", "/usr/pkg/lib/libGL.so"}; + int glincr = 0; + x11opengl_t *o = r = malloc(sizeof(*o)); - attribs[0] = GLX_RGBA; - attribs[1] = GLX_DOUBLEBUFFER; - attribs[2] = GLX_DEPTH_SIZE; - attribs[3] = 24; - attribs[4] = None; + attribs[0] = GLX_RGBA; + attribs[1] = GLX_DOUBLEBUFFER; + attribs[2] = GLX_DEPTH_SIZE; + attribs[3] = 24; + attribs[4] = None; - while(glpath[glincr] != NULL && (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL); + while (glpath[glincr] != NULL && + (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL) + ; - o->glXChooseVisual = (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); - o->glXCreateContext = (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); - o->glXDestroyContext = (MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext"); - o->glXMakeCurrent = (MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent"); - o->glXSwapBuffers = (MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers"); - o->glXGetProcAddress = (MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress"); + o->glXChooseVisual = + (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); + o->glXCreateContext = + (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); + o->glXDestroyContext = + (MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext"); + o->glXMakeCurrent = + (MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent"); + o->glXSwapBuffers = + (MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers"); + o->glXGetProcAddress = + (MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress"); - /* XXX: fix this */ - o->visual = o->glXChooseVisual(handle->lowlevel->x11.display, DefaultScreen(handle->lowlevel->x11.display), attribs); - o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL, GL_TRUE); - } + /* XXX: fix this */ + o->visual = o->glXChooseVisual(handle->lowlevel->x11.display, + DefaultScreen(handle->lowlevel->x11.display), + attribs); + o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL, + GL_TRUE); + } #endif #ifdef USE_WAYLAND - if(handle->lowlevel->common.type == MwLLBackendWayland) { - int err; - EGLint numConfigs; - EGLint majorVersion; - EGLint minorVersion; - EGLContext context; - EGLSurface surface; - EGLint fbAttribs[] = - { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_DEPTH_SIZE, 24, - 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; - waylandopengl_t* o = r = malloc(sizeof(*o)); - MwLL topmost_parent = handle->lowlevel->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; + if (handle->lowlevel->common.type == MwLLBackendWayland) { + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = {EGL_SURFACE_TYPE, + EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + 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; + waylandopengl_t *o = r = malloc(sizeof(*o)); + MwLL topmost_parent = handle->lowlevel->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; - while(topmost_parent->wayland.parent != NULL) { - topmost_parent = topmost_parent->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; - } + while (topmost_parent->wayland.parent != NULL) { + topmost_parent = topmost_parent->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; + } - display = eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->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; - } + display = + eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->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; - } + /* 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, &o->egl_config, 1, &numConfigs) != EGL_TRUE) || (numConfigs != 1)) { - printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); - return MwFALSE; - } + /* Choose config */ + if ((eglChooseConfig(display, fbAttribs, &o->egl_config, 1, &numConfigs) != + EGL_TRUE) || + (numConfigs != 1)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return MwFALSE; + } - o->egl_window_native = - (EGLNativeWindowType)wl_egl_window_create(handle->lowlevel->wayland.framebuffer.surface, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); - if(!o->egl_window_native) { - printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); - return MwFALSE; - } + o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create( + handle->lowlevel->wayland.framebuffer.surface, + handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + if (!o->egl_window_native) { + printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); + return MwFALSE; + } - /* Create a surface */ - surface = eglCreateWindowSurface(display, o->egl_config, o->egl_window_native, NULL); - if(surface == EGL_NO_SURFACE) { - printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); - return MwFALSE; - } + /* Create a surface */ + surface = eglCreateWindowSurface(display, o->egl_config, + o->egl_window_native, NULL); + if (surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return MwFALSE; + } - eglBindAPI(EGL_OPENGL_API); + eglBindAPI(EGL_OPENGL_API); - /* Create a GL context */ - context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, contextAttribs); - if(context == EGL_NO_CONTEXT) { - printf("ERROR: eglCreateContext, %0X\n", eglGetError()); - return MwFALSE; - } + /* Create a GL context */ + context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, + contextAttribs); + if (context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return MwFALSE; + } - if(!eglMakeCurrent(display, surface, surface, context)) { - printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); - } + if (!eglMakeCurrent(display, surface, surface, context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } - o->egl_display = display; - o->egl_surface = surface; - o->egl_context = context; - } + o->egl_display = display; + o->egl_surface = surface; + o->egl_context = context; + } #endif - handle->internal = r; - handle->lowlevel->common.copy_buffer = 0; + handle->internal = r; + handle->lowlevel->common.copy_buffer = 0; - MwSetDefault(handle); + MwSetDefault(handle); - while(w->parent != NULL) w = w->parent; + while (w->parent != NULL) + w = w->parent; - w->berserk++; + w->berserk++; - return 0; + return 0; } static void destroy(MwWidget handle) { - MwWidget w = handle; + MwWidget w = handle; #ifdef USE_GDI - if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t *o = handle->internal; - o->wglMakeCurrent(NULL, NULL); - DeleteDC(o->dc); - o->wglDeleteContext(o->gl); + o->wglMakeCurrent(NULL, NULL); + DeleteDC(o->dc); + o->wglDeleteContext(o->gl); - MwDynamicClose(o->lib); - } + MwDynamicClose(o->lib); + } #endif #ifdef USE_X11 - if(handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t *o = handle->internal; - o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL); - o->glXDestroyContext(handle->lowlevel->x11.display, o->gl); + o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL); + o->glXDestroyContext(handle->lowlevel->x11.display, o->gl); - MwDynamicClose(o->lib); - } + MwDynamicClose(o->lib); + } #endif #ifdef USE_WAYLAND - if(handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ - } + if (handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ + } #endif - while(w->parent != NULL) w = w->parent; + while (w->parent != NULL) + w = w->parent; - w->berserk--; + w->berserk--; - free(handle->internal); + free(handle->internal); } static void mwOpenGLMakeCurrentImpl(MwWidget handle) { - /* these swap interval functions belonging here actually stink! */ + /* these swap interval functions belonging here actually stink! */ #ifdef USE_GDI - if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; - void (*swap_interval_ext)(int) = NULL; + if (handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t *o = handle->internal; + void (*swap_interval_ext)(int) = NULL; - o->wglMakeCurrent(o->dc, o->gl); + o->wglMakeCurrent(o->dc, o->gl); - if((swap_interval_ext = MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { - swap_interval_ext(1); - } - } + if ((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { + swap_interval_ext(1); + } + } #endif #ifdef USE_X11 - if(handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t* o = handle->internal; - void (*swap_interval_ext)(Display*, GLXDrawable, int) = NULL; - void (*swap_interval_mesa)(unsigned int) = NULL; - void (*swap_interval_sgi)(int) = NULL; + if (handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t *o = handle->internal; + void (*swap_interval_ext)(Display *, GLXDrawable, int) = NULL; + void (*swap_interval_mesa)(unsigned int) = NULL; + void (*swap_interval_sgi)(int) = NULL; - o->glXMakeCurrent(handle->lowlevel->x11.display, handle->lowlevel->x11.window, o->gl); + o->glXMakeCurrent(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, o->gl); - if((swap_interval_ext = MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { - swap_interval_ext(handle->lowlevel->x11.display, handle->lowlevel->x11.window, 1); - } + if ((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { + swap_interval_ext(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, 1); + } - if((swap_interval_mesa = MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { - swap_interval_mesa(1); - } + if ((swap_interval_mesa = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { + swap_interval_mesa(1); + } - if((swap_interval_sgi = MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { - swap_interval_sgi(1); - } - } + if ((swap_interval_sgi = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { + swap_interval_sgi(1); + } + } #endif #ifdef USE_WAYLAND - if(handle->lowlevel->common.type == MwLLBackendWayland) { - waylandopengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t *o = handle->internal; - if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, o->egl_context)) { - printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); - } + if (!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, + o->egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + } - eglSwapInterval(o->egl_display, 1); - } + eglSwapInterval(o->egl_display, 1); + } #endif } static void mwOpenGLSwapBufferImpl(MwWidget handle) { #ifdef USE_GDI - if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t *o = handle->internal; - SwapBuffers(o->dc); - } + SwapBuffers(o->dc); + } #endif #ifdef USE_X11 - if(handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t *o = handle->internal; - o->glXSwapBuffers(handle->lowlevel->x11.display, handle->lowlevel->x11.window); - } + o->glXSwapBuffers(handle->lowlevel->x11.display, + handle->lowlevel->x11.window); + } #endif #ifdef USE_WAYLAND - if(handle->lowlevel->common.type == MwLLBackendWayland) { - waylandopengl_t* o = handle->internal; - eglSwapInterval(o->egl_display, 0); - if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { - printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); - }; - wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, 0, 0); - MwLLForceRender(handle->lowlevel); - } + if (handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t *o = handle->internal; + eglSwapInterval(o->egl_display, 0); + if (!eglSwapBuffers(o->egl_display, o->egl_surface)) { + printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); + }; + wl_egl_window_resize((struct wl_egl_window *)o->egl_window_native, + handle->lowlevel->wayland.ww, + handle->lowlevel->wayland.wh, 0, 0); + MwLLForceRender(handle->lowlevel); + } #endif } -static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { +static void *mwOpenGLGetProcAddressImpl(MwWidget handle, const char *name) { #ifdef USE_GDI - if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t *o = handle->internal; - return o->wglGetProcAddress(name); - } + return o->wglGetProcAddress(name); + } #endif #ifdef USE_X11 - if(handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t* o = handle->internal; + if (handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t *o = handle->internal; - return o->glXGetProcAddress((const GLubyte*)name); - } + return o->glXGetProcAddress((const GLubyte *)name); + } #endif #ifdef USE_WAYLAND - if(handle->lowlevel->common.type == MwLLBackendWayland) { - return eglGetProcAddress(name); - } + if (handle->lowlevel->common.type == MwLLBackendWayland) { + return eglGetProcAddress(name); + } #endif - return NULL; + return NULL; } -static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { - if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { - mwOpenGLMakeCurrentImpl(handle); - } - if(strcmp(name, "mwOpenGLSwapBuffer") == 0) { - mwOpenGLSwapBufferImpl(handle); - } - if(strcmp(name, "mwOpenGLGetProcAddress") == 0) { - const char* _name = va_arg(va, const char*); - *(void**)out = mwOpenGLGetProcAddressImpl(handle, _name); - } +static void func_handler(MwWidget handle, const char *name, void *out, + va_list va) { + if (strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if (strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if (strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char *_name = va_arg(va, const char *); + *(void **)out = mwOpenGLGetProcAddressImpl(handle, _name); + } } -MwClassRec MwOpenGLClassRec = { - create, /* create */ - destroy, /* destroy */ - NULL, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - NULL, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - func_handler, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, - NULL, - NULL, - NULL}; +MwClassRec MwOpenGLClassRec = {create, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, NULL, NULL, NULL}; MwClass MwOpenGLClass = &MwOpenGLClassRec; + +#endif \ No newline at end of file diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m new file mode 100644 index 000000000..88e17e396 --- /dev/null +++ b/src/widget/opengl_cocoa.m @@ -0,0 +1,128 @@ +#include "Mw/Core.h" +#include "Mw/StringDefs.h" +#include +#include +#import + +@interface MacOpenGLWidget : NSObject { + NSOpenGLPixelFormat *pixelFormat; + NSOpenGLContext *glc; +} + +- (MacOpenGLWidget *)initWithView:(NSView *)view; +- (void)destroy; +- (void)makeCurrent; +- (void)swapBuffer; +- (void *)getProcAddressWithName:(const char *)name; + +@end + +static int create(MwWidget handle) { + void *r = NULL; + MwWidget w = handle; + + int x = MwGetInteger(w, MwNx); + int y = MwGetInteger(w, MwNy); + int width = MwGetInteger(w, MwNwidth); + int height = MwGetInteger(w, MwNheight); + + printf("%d %d\n", width, height); + + MacOpenGLWidget *o = r = [[MacOpenGLWidget alloc] + initWithView:[handle->lowlevel->cocoa.real getView]]; + + handle->internal = r; + handle->lowlevel->common.copy_buffer = 0; + + MwSetDefault(handle); + + while (w->parent != NULL) + w = w->parent; + + w->berserk++; + + return 0; +} + +static void destroy(MwWidget handle) { + [(MacOpenGLWidget *)handle->internal destroy]; +} + +static void mwOpenGLMakeCurrentImpl(MwWidget handle) { + [(MacOpenGLWidget *)handle->internal makeCurrent]; +} + +static void mwOpenGLSwapBufferImpl(MwWidget handle) { + [(MacOpenGLWidget *)handle->internal swapBuffer]; +} + +static void *mwOpenGLGetProcAddressImpl(MwWidget handle, const char *name) { + return [(MacOpenGLWidget *)handle->internal getProcAddressWithName:name]; +} + +static void func_handler(MwWidget handle, const char *name, void *out, + va_list va) { + if (strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if (strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if (strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char *_name = va_arg(va, const char *); + *(void **)out = mwOpenGLGetProcAddressImpl(handle, _name); + } +} + +@implementation MacOpenGLWidget + +- (MacOpenGLWidget *)initWithView:(NSView *)view { + NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAStencilSize, 8, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, 0}; + self->pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; + self->glc = + [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; + [self->glc setView:view]; + return self; +}; +- (void)destroy { +}; +- (void)makeCurrent { + [self->glc makeCurrentContext]; +}; +- (void)swapBuffer { + [self->glc flushBuffer]; +}; +- (void *)getProcAddressWithName:(const char *)name { + if (NSIsSymbolNameDefined(name)) { + return NSAddressOfSymbol(NSLookupAndBindSymbol(name)); + } else { + return NULL; + } +}; + +@end + +MwClassRec MwOpenGLClassRec = {create, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; \ No newline at end of file From 39db13fa486d7cadd3d2233f523a807e5e076ef4 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 4 Mar 2026 23:06:56 -0700 Subject: [PATCH 152/409] mac: center window when MwDEFAULT is passed --- src/backend/cocoa.m | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 700ebdb88..0b230ebc6 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -82,15 +82,12 @@ static CGPoint pointFlip(CGPoint point) { height:(int)height handle:(MwLL)r { MilskoCocoa *c = [MilskoCocoa alloc]; - bool centerX = false, centerY = false; if (x == MwDEFAULT) { - x = 0; - centerX = true; + x = ([NSScreen mainScreen].frame.size.width / 2.) - (width / 2.); } if (y == MwDEFAULT) { - y = 0; - centerY = true; + y = ([NSScreen mainScreen].frame.size.height / 2.) - (height / 2.); } c->application = [NSApplication sharedApplication]; c->rect = rectFlip(NSMakeRect(x, y, width, height)); @@ -108,6 +105,9 @@ static CGPoint pointFlip(CGPoint point) { offset = [parentWindow frameRectForContentRect:parentWindow.frame].size.height - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; + + c->rect.origin.x += parentWindow.frame.origin.x; + c->rect.origin.y -= parentWindow.frame.origin.y - offset; c->rect.origin.y -= offset; c->window = [[NSWindow alloc] initWithContentRect:c->rect @@ -204,7 +204,15 @@ static CGPoint pointFlip(CGPoint point) { offset = [parentWindow frameRectForContentRect:parentWindow.frame].size.height - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; - frame.origin.y -= offset; + + if (x < parentWindow.frame.origin.x) { + frame.origin.x += parentWindow.frame.origin.x; + } + + if (y < parentWindow.frame.origin.y) { + frame.origin.y -= parentWindow.frame.origin.y - offset; + frame.origin.y -= offset; + } } [self->view setFrameSize:frame.size]; From e2bcd7b9e93c8dd860d36588d5c48d2228100c56 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 5 Mar 2026 19:29:43 -0700 Subject: [PATCH 153/409] mac: keyboard events and other nice refactors. they get sent to the opengl window but the callback isn't fired for some reason --- include/Mw/LowLevel/Cocoa.h | 3 + src/backend/cocoa.m | 748 +++++++++++++++++++++++++++++------- src/widget/opengl_cocoa.m | 18 +- 3 files changed, 622 insertions(+), 147 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 91679db7e..35bc5641c 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -96,6 +96,7 @@ - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; +- (void)eventProcess:(NSEvent *)ev; - (void)getNextEvent; - (void)setTitle:(const char *)title; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; @@ -120,6 +121,8 @@ - (NSWindow *)parentWindow; - (NSView *)getView; +- (NSWindow *)getWindow; +- (MilskoFakePointer *)getHandle; @end #define OBJC(x) x diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 0b230ebc6..7c566a8b0 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -125,7 +125,9 @@ static CGPoint pointFlip(CGPoint point) { [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; } else { - // [c->application activateIgnoringOtherApps:true]; + [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; + [c->application activateIgnoringOtherApps:true]; + [c->window makeFirstResponder:c->view]; } c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; @@ -229,144 +231,586 @@ static CGPoint pointFlip(CGPoint point) { [self->window setFrame:frame display:YES animate:false]; }; - (int)pending { - self->lastEvent = - [self->application nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; if (_forceRender) { _forceRender = MwFALSE; return 1; } + + self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; return self->lastEvent != NULL; }; + - (void)getNextEvent { - if (self->lastEvent != nil) { - NSWindow *win = [self->lastEvent window]; - NSWindow *parentWindow = [self parentWindow]; - MwLL h; + int i; + NSEvent *ev; - if ([win contentView].subviews.count == 0) { - NSLog(@"[WARNING] no subviews on this window, cannot process events.\n"); - return; - } + [self eventProcess:lastEvent]; - h = [((MilskoFakePointer *)[win contentView].subviews[0]) pointer]; - switch (self->lastEvent.type) { - case NSEventTypeLeftMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeOtherMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseUp: { - MwLLMouse mouse = {}; - MwBool isDown = MwTRUE; - CGPoint mousePoint = pointFlip([lastEvent locationInWindow]); - switch (self->lastEvent.type) { - case NSEventTypeLeftMouseUp: - isDown = MwFALSE; - case NSEventTypeLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSEventTypeRightMouseUp: - isDown = MwFALSE; - case NSEventTypeRightMouseDown: - mouse.button = MwLLMouseRight; - break; - case NSEventTypeOtherMouseUp: - isDown = MwFALSE; - case NSEventTypeOtherMouseDown: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + while ((ev = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES])) { + [self eventProcess:ev]; + } +}; - if (isDown) { - MwLLDispatch(h, down, &mouse); - } else { - MwLLDispatch(h, up, &mouse); - } - break; - } - - break; - case NSEventTypeMouseMoved: { - MwPoint pos; - pos.x = [lastEvent locationInWindow].x; - pos.y = [win contentRectForFrameRect:win.frame].size.height - - [lastEvent locationInWindow].y; - MwLLDispatch(h, move, &pos); - break; - } - case NSEventTypeLeftMouseDragged: - MwLLDispatch(h, focus_in, NULL); - break; - case NSEventTypeRightMouseDragged: - MwLLDispatch(h, focus_out, NULL); - break; - case NSEventTypeMouseEntered: - break; - case NSEventTypeMouseExited: - break; - case NSEventTypeKeyDown: - [win interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; - break; - case NSEventTypeKeyUp: - [win interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; - break; - case NSEventTypeFlagsChanged: - break; - case NSEventTypeAppKitDefined: - break; - case NSEventTypeSystemDefined: - break; - case NSEventTypeApplicationDefined: - break; - case NSEventTypePeriodic: - break; - case NSEventTypeCursorUpdate: - break; - case NSEventTypeScrollWheel: - break; - case NSEventTypeTabletPoint: - break; - case NSEventTypeTabletProximity: - break; - break; - case NSEventTypeOtherMouseDragged: - break; - case NSEventTypeGesture: - break; - case NSEventTypeMagnify: - break; - case NSEventTypeSwipe: - break; - case NSEventTypeRotate: - break; - case NSEventTypeBeginGesture: - break; - case NSEventTypeEndGesture: - break; - case NSEventTypeSmartMagnify: - break; - case NSEventTypeQuickLook: - break; - case NSEventTypePressure: - break; - case NSEventTypeDirectTouch: - break; - case NSEventTypeChangeMode: - break; - }; - // printf("got event: %ld\n", self->lastEvent.type); - [self->application sendEvent:self->lastEvent]; +- (void)eventProcess:(NSEvent *)ev { + NSWindow *win = [ev window]; + NSWindow *parentWindow = [self parentWindow]; + MwLL h; + MwBool doSendEvent = MwTRUE; + if (!win) { + return; } - [self->view setNeedsDisplay:true]; -}; + if ([win contentView].subviews.count == 0) { + printf("no subviews on %p\n", win); + return; + } else { + h = [((MilskoFakePointer *)[win contentView].subviews[0]) pointer]; + } + + switch (ev.type) { + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: { + MwLLMouse mouse = {}; + MwBool isDown = MwTRUE; + CGPoint mousePoint = pointFlip([ev locationInWindow]); + switch (ev.type) { + case NSEventTypeLeftMouseUp: + isDown = MwFALSE; + case NSEventTypeLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSEventTypeRightMouseUp: + isDown = MwFALSE; + case NSEventTypeRightMouseDown: + mouse.button = MwLLMouseRight; + break; + case NSEventTypeOtherMouseUp: + isDown = MwFALSE; + case NSEventTypeOtherMouseDown: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + + if (isDown) { + MwLLDispatch(h, down, &mouse); + } else { + MwLLDispatch(h, up, &mouse); + } + break; + } + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDragged: + case NSEventTypeMouseMoved: { + MwPoint pos; + pos.x = [ev locationInWindow].x; + pos.y = [win contentRectForFrameRect:win.frame].size.height - + [ev locationInWindow].y; + MwLLDispatch(h, move, &pos); + break; + } + case NSEventTypeMouseEntered: + MwLLDispatch(h, focus_in, NULL); + break; + case NSEventTypeMouseExited: + MwLLDispatch(h, focus_out, NULL); + break; + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: { + int ch; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_ANSI_KeypadDecimal = 0x41, + kVK_ANSI_KeypadMultiply = 0x43, + kVK_ANSI_KeypadPlus = 0x45, + kVK_ANSI_KeypadClear = 0x47, + kVK_ANSI_KeypadDivide = 0x4B, + kVK_ANSI_KeypadEnter = 0x4C, + kVK_ANSI_KeypadMinus = 0x4E, + kVK_ANSI_KeypadEquals = 0x51, + kVK_ANSI_Keypad0 = 0x52, + kVK_ANSI_Keypad1 = 0x53, + kVK_ANSI_Keypad2 = 0x54, + kVK_ANSI_Keypad3 = 0x55, + kVK_ANSI_Keypad4 = 0x56, + kVK_ANSI_Keypad5 = 0x57, + kVK_ANSI_Keypad6 = 0x58, + kVK_ANSI_Keypad7 = 0x59, + kVK_ANSI_Keypad8 = 0x5B, + kVK_ANSI_Keypad9 = 0x5C, + kVK_Return = 0x24, + kVK_Tab = 0x30, + kVK_Space = 0x31, + kVK_Delete = 0x33, + kVK_Escape = 0x35, + kVK_Command = 0x37, + kVK_Shift = 0x38, + kVK_CapsLock = 0x39, + kVK_Option = 0x3A, + kVK_Control = 0x3B, + kVK_RightCommand = 0x36, + kVK_RightShift = 0x3C, + kVK_RightOption = 0x3D, + kVK_RightControl = 0x3E, + kVK_Function = 0x3F, + kVK_F17 = 0x40, + kVK_VolumeUp = 0x48, + kVK_VolumeDown = 0x49, + kVK_Mute = 0x4A, + kVK_F18 = 0x4F, + kVK_F19 = 0x50, + kVK_F20 = 0x5A, + kVK_F5 = 0x60, + kVK_F6 = 0x61, + kVK_F7 = 0x62, + kVK_F3 = 0x63, + kVK_F8 = 0x64, + kVK_F9 = 0x65, + kVK_F11 = 0x67, + kVK_F13 = 0x69, + kVK_F16 = 0x6A, + kVK_F14 = 0x6B, + kVK_F10 = 0x6D, + kVK_F12 = 0x6F, + kVK_F15 = 0x71, + kVK_Help = 0x72, + kVK_Home = 0x73, + kVK_PageUp = 0x74, + kVK_ForwardDelete = 0x75, + kVK_F4 = 0x76, + kVK_End = 0x77, + kVK_F2 = 0x78, + kVK_PageDown = 0x79, + kVK_F1 = 0x7A, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; + // [view.nextResponder + // interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; + switch (ev.keyCode) { + case kVK_ANSI_A: + ch = 'a'; + break; + case kVK_ANSI_B: + ch = 'b'; + break; + case kVK_ANSI_C: + ch = 'c'; + break; + case kVK_ANSI_D: + ch = 'd'; + break; + case kVK_ANSI_E: + ch = 'e'; + break; + case kVK_ANSI_F: + ch = 'f'; + break; + case kVK_ANSI_G: + ch = 'g'; + break; + case kVK_ANSI_H: + ch = 'h'; + break; + case kVK_ANSI_I: + ch = 'i'; + break; + case kVK_ANSI_J: + ch = 'j'; + break; + case kVK_ANSI_K: + ch = 'k'; + break; + case kVK_ANSI_L: + ch = 'l'; + break; + case kVK_ANSI_M: + ch = 'm'; + break; + case kVK_ANSI_N: + ch = 'n'; + break; + case kVK_ANSI_O: + ch = 'o'; + break; + case kVK_ANSI_P: + ch = 'p'; + break; + case kVK_ANSI_Q: + ch = 'q'; + break; + case kVK_ANSI_R: + ch = 'r'; + break; + case kVK_ANSI_S: + ch = 's'; + break; + case kVK_ANSI_T: + ch = 't'; + break; + case kVK_ANSI_U: + ch = 'u'; + break; + case kVK_ANSI_V: + ch = 'v'; + break; + case kVK_ANSI_W: + ch = 'w'; + break; + case kVK_ANSI_X: + ch = 'x'; + break; + case kVK_ANSI_Y: + ch = 'y'; + break; + case kVK_ANSI_Z: + ch = 'z'; + break; + case kVK_ANSI_0: + ch = '0'; + break; + case kVK_ANSI_1: + ch = '1'; + break; + case kVK_ANSI_2: + ch = '2'; + break; + case kVK_ANSI_3: + ch = '3'; + break; + case kVK_ANSI_4: + ch = '4'; + break; + case kVK_ANSI_5: + ch = '5'; + break; + case kVK_ANSI_6: + ch = '6'; + break; + case kVK_ANSI_7: + ch = '7'; + break; + case kVK_ANSI_8: + ch = '8'; + break; + case kVK_ANSI_9: + ch = '9'; + break; + + // case kVK_ANSI_Keypad0: + // ch = MwLLKey; + // break; + // case kVK_ANSI_Keypad1: + // ch = keypad1; + // break; + // case kVK_ANSI_Keypad2: + // ch = keypad2; + // break; + // case kVK_ANSI_Keypad3: + // ch = keypad3; + // break; + // case kVK_ANSI_Keypad4: + // ch = keypad4; + // break; + // case kVK_ANSI_Keypad5: + // ch = keypad5; + // break; + // case kVK_ANSI_Keypad6: + // ch = keypad6; + // break; + // case kVK_ANSI_Keypad7: + // ch = keypad7; + // break; + // case kVK_ANSI_Keypad8: + // ch = keypad8; + // break; + // case kVK_ANSI_Keypad9: + // ch = keypad9; + // break; + // case kVK_ANSI_KeypadClear: + // ch = keypadClear; + // break; + // case kVK_ANSI_KeypadDivide: + // ch = keypadDivide; + // break; + // case kVK_ANSI_KeypadEnter: + // ch = keypadEnter; + // break; + // case kVK_ANSI_KeypadEquals: + // ch = keypadEquals; + // break; + // case kVK_ANSI_KeypadMinus: + // ch = keypadMinus; + // break; + // case kVK_ANSI_KeypadPlus: + // ch = keypadPlus; + // break; + // case kVK_PageDown: + // ch = MwLLKey; + // break; + // case kVK_PageUp: + // ch = pageUp; + // break; + // case kVK_End: + // ch = end; + // break; + // case kVK_Home: + // ch = home; + // break; + + // case kVK_F1: + // ch = f1; + // break; + // case kVK_F2: + // ch = f2; + // break; + // case kVK_F3: + // ch = f3; + // break; + // case kVK_F4: + // ch = f4; + // break; + // case kVK_F5: + // ch = f5; + // break; + // case kVK_F6: + // ch = f6; + // break; + // case kVK_F7: + // ch = f7; + // break; + // case kVK_F8: + // ch = f8; + // break; + // case kVK_F9: + // ch = f9; + // break; + // case kVK_F10: + // ch = f10; + // break; + // case kVK_F11: + // ch = f11; + // break; + // case kVK_F12: + // ch = f12; + // break; + // case kVK_F13: + // ch = f13; + // break; + // case kVK_F14: + // ch = f14; + // break; + // case kVK_F15: + // ch = f15; + // break; + // case kVK_F16: + // ch = f16; + // break; + // case kVK_F17: + // ch = f17; + // break; + // case kVK_F18: + // ch = f18; + // break; + // case kVK_F19: + // ch = f19; + // break; + // case kVK_F20: + // ch = f20; + // break; + // case kVK_ANSI_KeypadDecimal: + // ch = decimal; + // break; + + case kVK_ANSI_Quote: + ch = '\"'; + break; + case kVK_ANSI_Grave: + ch = '`'; + break; + case kVK_ANSI_Backslash: + ch = '/'; + break; + case kVK_ANSI_Comma: + ch = ','; + break; + // case kVK_Delete: + // ch = delete; + // break; + // case kVK_ANSI_Equal: + // ch = equals; + // break; + case kVK_Escape: + ch = MwLLKeyEscape; + break; + // case kVK_ANSI_LeftBracket: + // ch = leftBracket; + // break; + // case kVK_ANSI_Minus: + // ch = minus; + // break; + // case kVK_ANSI_KeypadMultiply: + // ch = multiply; + // break; + // case kVK_ANSI_Period: + // ch = period; + // break; + case kVK_Return: + ch = MwLLKeyEnter; + break; + // case kVK_ANSI_RightBracket: + // ch = rightBracket; + // break; + case kVK_ANSI_Semicolon: + ch = ';'; + break; + case kVK_ANSI_Slash: + ch = '\\'; + break; + case kVK_Space: + ch = ' '; + break; + // case kVK_Tab: + // ch = tab; + // break; + + // case kVK_Mute: + // ch = mute; + // break; + // case kVK_VolumeDown: + // ch = volumeDown; + // break; + // case kVK_VolumeUp: + // ch = volumeUp; + // break; + + // case kVK_Command: + // ch = MwLLKey; + // break; + // case kVK_RightCommand: + // ch = rightCommand; + // break; + case kVK_Control: + ch = MwLLKeyControl; + break; + case kVK_RightControl: + ch = MwLLKeyControl; + break; + // case kVK_Function: + // ch = function; + // break; + // case kVK_Option: + // ch = option; + // break; + // case kVK_RightOption: + // ch = rightOption; + // break; + case kVK_Shift: + ch = MwLLKeyLeftShift; + break; + case kVK_RightShift: + ch = MwLLKeyRightShift; + break; + + case kVK_DownArrow: + ch = MwLLKeyDown; + break; + case kVK_LeftArrow: + ch = MwLLKeyLeft; + break; + case kVK_RightArrow: + ch = MwLLKeyRight; + break; + case kVK_UpArrow: + ch = MwLLKeyUp; + break; + } + switch (ev.type) { + case NSEventTypeKeyDown: + MwLLDispatch(h, key, &ch); + break; + case NSEventTypeKeyUp: + MwLLDispatch(h, key_released, &ch); + break; + default: + break; + } + doSendEvent = MwFALSE; + break; + } + case NSEventTypeCursorUpdate: + break; + case NSEventTypeScrollWheel: + break; + default: + break; + }; + if (doSendEvent) { + [win sendEvent:ev]; + } +} - (void)setTitle:(const char *)title { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; @@ -465,6 +909,13 @@ static CGPoint pointFlip(CGPoint point) { - (NSView *)getView { return view; } +- (NSWindow *)getWindow { + return window; +} + +- (MilskoFakePointer *)getHandle { + return handle; +} @end @implementation MilskoCocoaView @@ -530,23 +981,6 @@ static CGPoint pointFlip(CGPoint point) { - (void)displayRect:(NSRect)rect { }; -@end - -@implementation MilskoFakePointer -- (void)setPointer:(void *)pointer { - self.frame = *(NSRect *)&pointer; - self->ptr = pointer; -}; -- (void *)pointer { - return self->ptr; -}; - -- (void)drawRect:(NSRect)dirtyRect { - /* explicitly do nothing */ -} - -- (void)destroy { -} @end @@ -567,11 +1001,37 @@ static CGPoint pointFlip(CGPoint point) { - (void)windowDidResize:(NSNotification *)notification { } +// This will close/terminate the application when the main window is closed. +- (void)windowWillClose:(NSNotification *)notification { + // MilskoCocoa *window = notification.object; + // MwLL handle = [window getHandle].pointer; + // MwLLDispatch(handle, close, NULL); + [NSApp terminate:nil]; +} + - (instancetype)initWithWin:(NSWindow *)win { self->w = win; return self; } +@end + +@implementation MilskoFakePointer +- (void)setPointer:(void *)pointer { + self.frame = *(NSRect *)&pointer; + self->ptr = pointer; +}; +- (void *)pointer { + return self->ptr; +}; + +- (void)drawRect:(NSRect)dirtyRect { + /* explicitly do nothing */ +} + +- (void)destroy { +} + @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index 88e17e396..c33e3754d 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -1,3 +1,4 @@ +#include "Mw/BaseTypes.h" #include "Mw/Core.h" #include "Mw/StringDefs.h" #include @@ -28,10 +29,8 @@ static int create(MwWidget handle) { printf("%d %d\n", width, height); - MacOpenGLWidget *o = r = [[MacOpenGLWidget alloc] + handle->internal = [[MacOpenGLWidget alloc] initWithView:[handle->lowlevel->cocoa.real getView]]; - - handle->internal = r; handle->lowlevel->common.copy_buffer = 0; MwSetDefault(handle); @@ -96,6 +95,19 @@ static void func_handler(MwWidget handle, const char *name, void *out, [self->glc makeCurrentContext]; }; - (void)swapBuffer { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [pool release]; + [self->glc flushBuffer]; }; - (void *)getProcAddressWithName:(const char *)name { From 9be36b0755e7c69c9b1188d8e9168e285f66648a Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 5 Mar 2026 20:19:19 -0700 Subject: [PATCH 154/409] mac: have key events get sent to parent --- src/backend/cocoa.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 7c566a8b0..d9add8e3b 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -247,7 +247,9 @@ static CGPoint pointFlip(CGPoint point) { int i; NSEvent *ev; - [self eventProcess:lastEvent]; + if (lastEvent) { + [self eventProcess:lastEvent]; + } while ((ev = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] @@ -262,6 +264,8 @@ static CGPoint pointFlip(CGPoint point) { NSWindow *parentWindow = [self parentWindow]; MwLL h; MwBool doSendEvent = MwTRUE; + MwLL this = self->handle.pointer; + if (!win) { return; } @@ -789,10 +793,10 @@ static CGPoint pointFlip(CGPoint point) { } switch (ev.type) { case NSEventTypeKeyDown: - MwLLDispatch(h, key, &ch); + MwLLDispatch(this, key, &ch); break; case NSEventTypeKeyUp: - MwLLDispatch(h, key_released, &ch); + MwLLDispatch(this, key_released, &ch); break; default: break; From 9d7a75394ce111724e0cf86cff00f82eb97c6a31 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 5 Mar 2026 21:58:22 -0700 Subject: [PATCH 155/409] mac: implement clipboard (At the cost of making the pending function a crime against god) --- include/Mw/LowLevel/Cocoa.h | 3 ++ src/backend/cocoa.m | 56 ++++++++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 35bc5641c..c0974d46b 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -80,6 +80,8 @@ MilskoCocoaView *view; MwLL parent; MilskoFakePointer *handle; + NSUInteger strHash; + MwBool pendingTicker; } + (MilskoCocoa *)newWithParent:(MwLL)parent @@ -118,6 +120,7 @@ - (void)getCursorCoord:(MwPoint *)point; - (void)getScreenSize:(MwRect *)rect; - (void)destroy; +- (void)sendClipboardEvent; - (NSWindow *)parentWindow; - (NSView *)getView; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index d9add8e3b..47e44e780 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,5 @@ +#include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include #pragma clang push @@ -140,6 +142,7 @@ static CGPoint pointFlip(CGPoint point) { c->parent = parent; c->_forceRender = MwTRUE; + c->strHash = 0; return c; } @@ -235,12 +238,23 @@ static CGPoint pointFlip(CGPoint point) { _forceRender = MwFALSE; return 1; } - +// Apple does not give you a reliable way to tell when events are coming. I +// found this out by accident by stumbling upon a comment wxWidget's code, +// thought I could figure out something better, and I ended up with the same +// solution they tried and can confirm it doesn't work. +// Thanks Tim Cook. +#if 0 self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + + return self->lastEvent != NULL; +#endif + // And unlike wxWidgets we can't just return 1, so instead we alternate + // between such. + return (self->pendingTicker = !self->pendingTicker); }; - (void)getNextEvent { @@ -257,6 +271,8 @@ static CGPoint pointFlip(CGPoint point) { dequeue:YES])) { [self eventProcess:ev]; } + + [self sendClipboardEvent]; }; - (void)eventProcess:(NSEvent *)ev { @@ -816,6 +832,39 @@ static CGPoint pointFlip(CGPoint point) { } } +- (void)sendClipboardEvent { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSArray *items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; + + if ([pasteboard canReadItemWithDataConformingToTypes:items]) { + char *data = NULL; + size_t size = 0; + for (NSPasteboardItem *item in [pasteboard pasteboardItems]) { + for (NSString *it in items) { + NSString *itemData = [item stringForType:(NSString *)it]; + if (itemData != NULL) { + if (strHash != 0 && strHash != [itemData hash]) { + char *text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], [itemData length]); + MwLLDispatch(this, clipboard, text); + printf("%s -> %p\n", text, this); + free(text); + } + strHash = [itemData hash]; + } + } + } + } + + [pool release]; +} + - (void)setTitle:(const char *)title { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [self->window @@ -882,6 +931,11 @@ static CGPoint pointFlip(CGPoint point) { * until 10.13.2 so I need to do this manually */ }; - (void)setClipboard:(const char *)text { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + [pasteboard declareTypes:@[ NSPasteboardTypeString ] owner:nil]; + [pasteboard setString:@(text) forType:NSPasteboardTypeString]; + [pool release]; }; - (void)getClipboard { }; From ea046f3a52f524a9f3ff5f8aedebcfbe0d92d8bf Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 5 Mar 2026 22:41:09 -0700 Subject: [PATCH 156/409] mac: fix memory leaks somewhat. --- include/Mw/LowLevel/Cocoa.h | 2 -- src/backend/cocoa.m | 49 +++++++++++++++++-------------------- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index c0974d46b..889cdf707 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -40,7 +40,6 @@ MwBool valid; int width; int height; - NSData *data; NSImage *image; NSBitmapImageRep *rep; } @@ -73,7 +72,6 @@ @interface MilskoCocoa : NSObject { NSApplication *application; - NSEvent *lastEvent; MwBool _forceRender; NSWindow *window; NSRect rect; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 47e44e780..93f68d77d 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -35,11 +35,11 @@ static CGPoint pointFlip(CGPoint point) { p->width = width; p->height = height; - p->data = NULL; p->image = NULL; return p; } - (void)updateWithData:(unsigned char *)_data { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [self destroy]; self->rep = @@ -53,21 +53,17 @@ static CGPoint pointFlip(CGPoint point) { colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(int)width * 4 bitsPerPixel:32]; - assert(self->rep); - self->data = [NSData dataWithBytes:[self->rep bitmapData] - length:self->width * self->height * 4]; - assert(self->data); + [self->rep retain]; self->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; assert(self->image); [self->image addRepresentation:self->rep]; + [self->image retain]; + [pool release]; } - (void)destroy { - if (self->data != NULL) { - [self->data dealloc]; - } if (self->image != NULL) { - [self->image dealloc]; + [self->image release]; } } - (NSImage *)image { @@ -84,6 +80,7 @@ static CGPoint pointFlip(CGPoint point) { height:(int)height handle:(MwLL)r { MilskoCocoa *c = [MilskoCocoa alloc]; + [c retain]; if (x == MwDEFAULT) { x = ([NSScreen mainScreen].frame.size.width / 2.) - (width / 2.); @@ -121,6 +118,7 @@ static CGPoint pointFlip(CGPoint point) { initWithWin:c->window]; [c->window makeKeyAndOrderFront:c->application]; + [c->window retain]; if (parent != NULL) { MilskoCocoa *p = parent->cocoa.real; @@ -149,6 +147,7 @@ static CGPoint pointFlip(CGPoint point) { - (void)polygonWithPoints:(MwPoint *)points points_count:(int)points_count color:(MwLLColor)color { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSGraphicsContext *ctx = [self->view context]; if (ctx) { int i; @@ -180,9 +179,8 @@ static CGPoint pointFlip(CGPoint point) { [NSGraphicsContext restoreGraphicsState]; [self->view setNeedsDisplay:YES]; - - [nscolor dealloc]; } + [pool release]; }; - (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { }; @@ -258,13 +256,9 @@ static CGPoint pointFlip(CGPoint point) { }; - (void)getNextEvent { - int i; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEvent *ev; - if (lastEvent) { - [self eventProcess:lastEvent]; - } - while ((ev = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode @@ -273,9 +267,11 @@ static CGPoint pointFlip(CGPoint point) { } [self sendClipboardEvent]; + [pool release]; }; - (void)eventProcess:(NSEvent *)ev { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSWindow *win = [ev window]; NSWindow *parentWindow = [self parentWindow]; MwLL h; @@ -283,11 +279,13 @@ static CGPoint pointFlip(CGPoint point) { MwLL this = self->handle.pointer; if (!win) { + [pool release]; return; } if ([win contentView].subviews.count == 0) { printf("no subviews on %p\n", win); + [pool release]; return; } else { h = [((MilskoFakePointer *)[win contentView].subviews[0]) pointer]; @@ -756,16 +754,6 @@ static CGPoint pointFlip(CGPoint point) { // ch = tab; // break; - // case kVK_Mute: - // ch = mute; - // break; - // case kVK_VolumeDown: - // ch = volumeDown; - // break; - // case kVK_VolumeUp: - // ch = volumeUp; - // break; - // case kVK_Command: // ch = MwLLKey; // break; @@ -830,6 +818,8 @@ static CGPoint pointFlip(CGPoint point) { if (doSendEvent) { [win sendEvent:ev]; } + + [pool release]; } - (void)sendClipboardEvent { @@ -872,6 +862,7 @@ static CGPoint pointFlip(CGPoint point) { [pool release]; }; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)_rect { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; MilskoCocoaPixmap *p = pixmap->cocoa.real; NSGraphicsContext *ctx = [self->view context]; if (ctx) { @@ -890,6 +881,7 @@ static CGPoint pointFlip(CGPoint point) { [self->view setNeedsDisplay:YES]; } + [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { }; @@ -954,7 +946,7 @@ static CGPoint pointFlip(CGPoint point) { _rect->height = [screen frame].size.height; }; - (void)destroy { - [self->window dealloc]; + [self->window release]; } - (NSWindow *)parentWindow { @@ -1017,15 +1009,18 @@ static CGPoint pointFlip(CGPoint point) { } - (void)drawRect:(NSRect)dirtyRect { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSSize sz = self->rep.size; [super drawRect:dirtyRect]; if (!self->rep) { + [pool release]; return; } [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; [self->rep bitmapData]; + [pool release]; } - (void)destroy { From 306f7916419317398adaf36e50ba4f8435407147 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 5 Mar 2026 22:52:25 -0700 Subject: [PATCH 157/409] mac: apple doesn't give us a reliable way to check if events are pending but we have to do the nextEventMatching trick anyways because the alternating pending implementation breaks opengl. --- include/Mw/LowLevel/Cocoa.h | 2 +- src/backend/cocoa.m | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 889cdf707..58401b2e4 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -79,7 +79,7 @@ MwLL parent; MilskoFakePointer *handle; NSUInteger strHash; - MwBool pendingTicker; + NSEvent *lastEvent; } + (MilskoCocoa *)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 93f68d77d..0f21dd382 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -236,23 +236,12 @@ static CGPoint pointFlip(CGPoint point) { _forceRender = MwFALSE; return 1; } -// Apple does not give you a reliable way to tell when events are coming. I -// found this out by accident by stumbling upon a comment wxWidget's code, -// thought I could figure out something better, and I ended up with the same -// solution they tried and can confirm it doesn't work. -// Thanks Tim Cook. -#if 0 self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; - return self->lastEvent != NULL; -#endif - // And unlike wxWidgets we can't just return 1, so instead we alternate - // between such. - return (self->pendingTicker = !self->pendingTicker); }; - (void)getNextEvent { From 0fde05fa03e3ff051c90a93f2278a468f2615654 Mon Sep 17 00:00:00 2001 From: Nishi Date: Sun, 8 Mar 2026 07:06:12 +0900 Subject: [PATCH 158/409] fix some parts --- include/Mw/LowLevel.h | 8 ++++---- src/text/ft2.c | 2 +- src/text/stbtt.c | 3 +-- src/text/text.c | 4 ++-- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index dcab28d16..9766d052f 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -235,14 +235,14 @@ MWDECL void (*MwLLGetClipboard)(MwLL handle); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); -/*font renderer */ -MWDECL void MwFLSetup(); +/* font renderer */ +MWDECL void MwFLSetup(void); #ifdef USE_FREETYPE2 -MWDECL int MWFL_FT2Setup(); +MWDECL int MWFL_FT2Setup(void); #endif #ifdef USE_STB_TRUETYPE -MWDECL int MwFL_STBTTSetup(); +MWDECL int MwFL_STBTTSetup(void); #endif MWDECL int (*MwFLDrawText)(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color); diff --git a/src/text/ft2.c b/src/text/ft2.c index a5fb92027..c30f3da0f 100644 --- a/src/text/ft2.c +++ b/src/text/ft2.c @@ -128,7 +128,7 @@ static void ft2_MwFontFree(void* handle) { free(ttf); } -int MWFL_FT2Setup() { +int MWFL_FT2Setup(void) { MwFLDrawText = ft2_MwDrawText; MwFLTextWidth = ft2_MwTextWidth; MwFLTextHeight = ft2_MwTextHeight; diff --git a/src/text/stbtt.c b/src/text/stbtt.c index fb5e783e9..ab9d539cd 100644 --- a/src/text/stbtt.c +++ b/src/text/stbtt.c @@ -1,5 +1,4 @@ #ifdef USE_STB_TRUETYPE -#include #include #include "../../external/stb_truetype.h" @@ -129,7 +128,7 @@ static void stbtt_MwFontFree(void* handle) { free(ttf); } -int MwFL_STBTTSetup() { +int MwFL_STBTTSetup(void) { MwFLDrawText = stbtt_MwDrawText; MwFLTextWidth = stbtt_MwTextWidth; MwFLTextHeight = stbtt_MwTextHeight; diff --git a/src/text/text.c b/src/text/text.c index e25d28b21..8d19de838 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -140,8 +140,8 @@ static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, free(px); } -typedef int (*call_t)(); -void MwFLSetup() { +typedef int (*call_t)(void); +void MwFLSetup(void) { call_t calls[] = { #ifdef USE_FREETYPE2 MWFL_FT2Setup, From 4319ea25b5b27bdbad0c8b85059c2106f691f735 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sun, 8 Mar 2026 16:05:57 -0700 Subject: [PATCH 159/409] mac: fix a bunch of memory leaks --- include/Mw/LowLevel/Cocoa.h | 3 + src/backend/cocoa.m | 727 +++++++++++------------------------- 2 files changed, 220 insertions(+), 510 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 58401b2e4..0ebe7751b 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -40,6 +40,7 @@ MwBool valid; int width; int height; + unsigned char *buf; NSImage *image; NSBitmapImageRep *rep; } @@ -97,6 +98,8 @@ - (void)setW:(int)w H:(int)h; - (int)pending; - (void)eventProcess:(NSEvent *)ev; +- (void)handleKeyEvent:(NSEvent *)ev; +- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll; - (void)getNextEvent; - (void)setTitle:(const char *)title; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 0f21dd382..c3cfc3f88 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,6 +1,7 @@ #include "Mw/BaseTypes.h" #include "Mw/LowLevel.h" #include +#include #pragma clang push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -36,14 +37,11 @@ static CGPoint pointFlip(CGPoint point) { p->width = width; p->height = height; p->image = NULL; - return p; -} -- (void)updateWithData:(unsigned char *)_data { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [self destroy]; - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&_data + p->buf = malloc(width * height * 4); + + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf pixelsWide:(int)width pixelsHigh:(int)height bitsPerSample:8 @@ -53,18 +51,22 @@ static CGPoint pointFlip(CGPoint point) { colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(int)width * 4 bitsPerPixel:32]; - assert(self->rep); - [self->rep retain]; - self->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - assert(self->image); - [self->image addRepresentation:self->rep]; - [self->image retain]; - [pool release]; + assert(p->rep); + + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; + + return p; +} +- (void)updateWithData:(unsigned char *)_data { + memcpy(self->buf, _data, width * height * 4); } - (void)destroy { - if (self->image != NULL) { - [self->image release]; - } + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image dealloc]; + [self->rep dealloc]; } - (NSImage *)image { return self->image; @@ -175,6 +177,7 @@ static CGPoint pointFlip(CGPoint point) { [path closePath]; [path fill]; + [nscolor release]; [NSGraphicsContext restoreGraphicsState]; @@ -186,6 +189,7 @@ static CGPoint pointFlip(CGPoint point) { }; - (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { NSRect frame = rectFlip([self->window frame]); + frame = rectFlip(frame); *x = frame.origin.x; *y = frame.origin.y; @@ -232,8 +236,11 @@ static CGPoint pointFlip(CGPoint point) { [self->window setFrame:frame display:YES animate:false]; }; - (int)pending { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = MwFALSE; if (_forceRender) { _forceRender = MwFALSE; + [pool release]; return 1; } self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask @@ -241,11 +248,12 @@ static CGPoint pointFlip(CGPoint point) { inMode:NSDefaultRunLoopMode dequeue:YES]; - return self->lastEvent != NULL; + isPending = self->lastEvent != NULL; + [pool release]; + return isPending; }; - (void)getNextEvent { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEvent *ev; while ((ev = [self->window nextEventMatchingMask:NSAnyEventMask @@ -253,10 +261,10 @@ static CGPoint pointFlip(CGPoint point) { inMode:NSDefaultRunLoopMode dequeue:YES])) { [self eventProcess:ev]; + [ev release]; } [self sendClipboardEvent]; - [pool release]; }; - (void)eventProcess:(NSEvent *)ev { @@ -265,7 +273,6 @@ static CGPoint pointFlip(CGPoint point) { NSWindow *parentWindow = [self parentWindow]; MwLL h; MwBool doSendEvent = MwTRUE; - MwLL this = self->handle.pointer; if (!win) { [pool release]; @@ -287,37 +294,7 @@ static CGPoint pointFlip(CGPoint point) { case NSEventTypeLeftMouseUp: case NSEventTypeRightMouseUp: case NSEventTypeOtherMouseUp: { - MwLLMouse mouse = {}; - MwBool isDown = MwTRUE; - CGPoint mousePoint = pointFlip([ev locationInWindow]); - switch (ev.type) { - case NSEventTypeLeftMouseUp: - isDown = MwFALSE; - case NSEventTypeLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSEventTypeRightMouseUp: - isDown = MwFALSE; - case NSEventTypeRightMouseDown: - mouse.button = MwLLMouseRight; - break; - case NSEventTypeOtherMouseUp: - isDown = MwFALSE; - case NSEventTypeOtherMouseDown: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; - - if (isDown) { - MwLLDispatch(h, down, &mouse); - } else { - MwLLDispatch(h, up, &mouse); - } - break; + [self handleMouseEvent:ev ll:h]; } case NSEventTypeLeftMouseDragged: case NSEventTypeRightMouseDragged: @@ -338,464 +315,8 @@ static CGPoint pointFlip(CGPoint point) { break; case NSEventTypeKeyDown: case NSEventTypeKeyUp: { - int ch; - enum { - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_ANSI_KeypadDecimal = 0x41, - kVK_ANSI_KeypadMultiply = 0x43, - kVK_ANSI_KeypadPlus = 0x45, - kVK_ANSI_KeypadClear = 0x47, - kVK_ANSI_KeypadDivide = 0x4B, - kVK_ANSI_KeypadEnter = 0x4C, - kVK_ANSI_KeypadMinus = 0x4E, - kVK_ANSI_KeypadEquals = 0x51, - kVK_ANSI_Keypad0 = 0x52, - kVK_ANSI_Keypad1 = 0x53, - kVK_ANSI_Keypad2 = 0x54, - kVK_ANSI_Keypad3 = 0x55, - kVK_ANSI_Keypad4 = 0x56, - kVK_ANSI_Keypad5 = 0x57, - kVK_ANSI_Keypad6 = 0x58, - kVK_ANSI_Keypad7 = 0x59, - kVK_ANSI_Keypad8 = 0x5B, - kVK_ANSI_Keypad9 = 0x5C, - kVK_Return = 0x24, - kVK_Tab = 0x30, - kVK_Space = 0x31, - kVK_Delete = 0x33, - kVK_Escape = 0x35, - kVK_Command = 0x37, - kVK_Shift = 0x38, - kVK_CapsLock = 0x39, - kVK_Option = 0x3A, - kVK_Control = 0x3B, - kVK_RightCommand = 0x36, - kVK_RightShift = 0x3C, - kVK_RightOption = 0x3D, - kVK_RightControl = 0x3E, - kVK_Function = 0x3F, - kVK_F17 = 0x40, - kVK_VolumeUp = 0x48, - kVK_VolumeDown = 0x49, - kVK_Mute = 0x4A, - kVK_F18 = 0x4F, - kVK_F19 = 0x50, - kVK_F20 = 0x5A, - kVK_F5 = 0x60, - kVK_F6 = 0x61, - kVK_F7 = 0x62, - kVK_F3 = 0x63, - kVK_F8 = 0x64, - kVK_F9 = 0x65, - kVK_F11 = 0x67, - kVK_F13 = 0x69, - kVK_F16 = 0x6A, - kVK_F14 = 0x6B, - kVK_F10 = 0x6D, - kVK_F12 = 0x6F, - kVK_F15 = 0x71, - kVK_Help = 0x72, - kVK_Home = 0x73, - kVK_PageUp = 0x74, - kVK_ForwardDelete = 0x75, - kVK_F4 = 0x76, - kVK_End = 0x77, - kVK_F2 = 0x78, - kVK_PageDown = 0x79, - kVK_F1 = 0x7A, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E - }; - // [view.nextResponder - // interpretKeyEvents:[NSArray arrayWithObject:lastEvent]]; - switch (ev.keyCode) { - case kVK_ANSI_A: - ch = 'a'; - break; - case kVK_ANSI_B: - ch = 'b'; - break; - case kVK_ANSI_C: - ch = 'c'; - break; - case kVK_ANSI_D: - ch = 'd'; - break; - case kVK_ANSI_E: - ch = 'e'; - break; - case kVK_ANSI_F: - ch = 'f'; - break; - case kVK_ANSI_G: - ch = 'g'; - break; - case kVK_ANSI_H: - ch = 'h'; - break; - case kVK_ANSI_I: - ch = 'i'; - break; - case kVK_ANSI_J: - ch = 'j'; - break; - case kVK_ANSI_K: - ch = 'k'; - break; - case kVK_ANSI_L: - ch = 'l'; - break; - case kVK_ANSI_M: - ch = 'm'; - break; - case kVK_ANSI_N: - ch = 'n'; - break; - case kVK_ANSI_O: - ch = 'o'; - break; - case kVK_ANSI_P: - ch = 'p'; - break; - case kVK_ANSI_Q: - ch = 'q'; - break; - case kVK_ANSI_R: - ch = 'r'; - break; - case kVK_ANSI_S: - ch = 's'; - break; - case kVK_ANSI_T: - ch = 't'; - break; - case kVK_ANSI_U: - ch = 'u'; - break; - case kVK_ANSI_V: - ch = 'v'; - break; - case kVK_ANSI_W: - ch = 'w'; - break; - case kVK_ANSI_X: - ch = 'x'; - break; - case kVK_ANSI_Y: - ch = 'y'; - break; - case kVK_ANSI_Z: - ch = 'z'; - break; - case kVK_ANSI_0: - ch = '0'; - break; - case kVK_ANSI_1: - ch = '1'; - break; - case kVK_ANSI_2: - ch = '2'; - break; - case kVK_ANSI_3: - ch = '3'; - break; - case kVK_ANSI_4: - ch = '4'; - break; - case kVK_ANSI_5: - ch = '5'; - break; - case kVK_ANSI_6: - ch = '6'; - break; - case kVK_ANSI_7: - ch = '7'; - break; - case kVK_ANSI_8: - ch = '8'; - break; - case kVK_ANSI_9: - ch = '9'; - break; - - // case kVK_ANSI_Keypad0: - // ch = MwLLKey; - // break; - // case kVK_ANSI_Keypad1: - // ch = keypad1; - // break; - // case kVK_ANSI_Keypad2: - // ch = keypad2; - // break; - // case kVK_ANSI_Keypad3: - // ch = keypad3; - // break; - // case kVK_ANSI_Keypad4: - // ch = keypad4; - // break; - // case kVK_ANSI_Keypad5: - // ch = keypad5; - // break; - // case kVK_ANSI_Keypad6: - // ch = keypad6; - // break; - // case kVK_ANSI_Keypad7: - // ch = keypad7; - // break; - // case kVK_ANSI_Keypad8: - // ch = keypad8; - // break; - // case kVK_ANSI_Keypad9: - // ch = keypad9; - // break; - // case kVK_ANSI_KeypadClear: - // ch = keypadClear; - // break; - // case kVK_ANSI_KeypadDivide: - // ch = keypadDivide; - // break; - // case kVK_ANSI_KeypadEnter: - // ch = keypadEnter; - // break; - // case kVK_ANSI_KeypadEquals: - // ch = keypadEquals; - // break; - // case kVK_ANSI_KeypadMinus: - // ch = keypadMinus; - // break; - // case kVK_ANSI_KeypadPlus: - // ch = keypadPlus; - // break; - // case kVK_PageDown: - // ch = MwLLKey; - // break; - // case kVK_PageUp: - // ch = pageUp; - // break; - // case kVK_End: - // ch = end; - // break; - // case kVK_Home: - // ch = home; - // break; - - // case kVK_F1: - // ch = f1; - // break; - // case kVK_F2: - // ch = f2; - // break; - // case kVK_F3: - // ch = f3; - // break; - // case kVK_F4: - // ch = f4; - // break; - // case kVK_F5: - // ch = f5; - // break; - // case kVK_F6: - // ch = f6; - // break; - // case kVK_F7: - // ch = f7; - // break; - // case kVK_F8: - // ch = f8; - // break; - // case kVK_F9: - // ch = f9; - // break; - // case kVK_F10: - // ch = f10; - // break; - // case kVK_F11: - // ch = f11; - // break; - // case kVK_F12: - // ch = f12; - // break; - // case kVK_F13: - // ch = f13; - // break; - // case kVK_F14: - // ch = f14; - // break; - // case kVK_F15: - // ch = f15; - // break; - // case kVK_F16: - // ch = f16; - // break; - // case kVK_F17: - // ch = f17; - // break; - // case kVK_F18: - // ch = f18; - // break; - // case kVK_F19: - // ch = f19; - // break; - // case kVK_F20: - // ch = f20; - // break; - // case kVK_ANSI_KeypadDecimal: - // ch = decimal; - // break; - - case kVK_ANSI_Quote: - ch = '\"'; - break; - case kVK_ANSI_Grave: - ch = '`'; - break; - case kVK_ANSI_Backslash: - ch = '/'; - break; - case kVK_ANSI_Comma: - ch = ','; - break; - // case kVK_Delete: - // ch = delete; - // break; - // case kVK_ANSI_Equal: - // ch = equals; - // break; - case kVK_Escape: - ch = MwLLKeyEscape; - break; - // case kVK_ANSI_LeftBracket: - // ch = leftBracket; - // break; - // case kVK_ANSI_Minus: - // ch = minus; - // break; - // case kVK_ANSI_KeypadMultiply: - // ch = multiply; - // break; - // case kVK_ANSI_Period: - // ch = period; - // break; - case kVK_Return: - ch = MwLLKeyEnter; - break; - // case kVK_ANSI_RightBracket: - // ch = rightBracket; - // break; - case kVK_ANSI_Semicolon: - ch = ';'; - break; - case kVK_ANSI_Slash: - ch = '\\'; - break; - case kVK_Space: - ch = ' '; - break; - // case kVK_Tab: - // ch = tab; - // break; - - // case kVK_Command: - // ch = MwLLKey; - // break; - // case kVK_RightCommand: - // ch = rightCommand; - // break; - case kVK_Control: - ch = MwLLKeyControl; - break; - case kVK_RightControl: - ch = MwLLKeyControl; - break; - // case kVK_Function: - // ch = function; - // break; - // case kVK_Option: - // ch = option; - // break; - // case kVK_RightOption: - // ch = rightOption; - // break; - case kVK_Shift: - ch = MwLLKeyLeftShift; - break; - case kVK_RightShift: - ch = MwLLKeyRightShift; - break; - - case kVK_DownArrow: - ch = MwLLKeyDown; - break; - case kVK_LeftArrow: - ch = MwLLKeyLeft; - break; - case kVK_RightArrow: - ch = MwLLKeyRight; - break; - case kVK_UpArrow: - ch = MwLLKeyUp; - break; - } - switch (ev.type) { - case NSEventTypeKeyDown: - MwLLDispatch(this, key, &ch); - break; - case NSEventTypeKeyUp: - MwLLDispatch(this, key_released, &ch); - break; - default: - break; - } + [self handleKeyEvent:ev]; doSendEvent = MwFALSE; - break; } case NSEventTypeCursorUpdate: break; @@ -811,6 +332,178 @@ static CGPoint pointFlip(CGPoint point) { [pool release]; } +- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll { + MwLLMouse mouse = {}; + MwBool isDown = MwTRUE; + CGPoint mousePoint = pointFlip([ev locationInWindow]); + switch (ev.type) { + case NSEventTypeLeftMouseUp: + isDown = MwFALSE; + case NSEventTypeLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSEventTypeRightMouseUp: + isDown = MwFALSE; + case NSEventTypeRightMouseDown: + mouse.button = MwLLMouseRight; + break; + case NSEventTypeOtherMouseUp: + isDown = MwFALSE; + case NSEventTypeOtherMouseDown: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + + if (isDown) { + MwLLDispatch(ll, down, &mouse); + } else { + MwLLDispatch(ll, up, &mouse); + } +} + +- (void)handleKeyEvent:(NSEvent *)ev { + int ch; + MwLL this = self->handle.pointer; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch (ev.keyCode) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwLLKeyControl) + KEY_CASE(kVK_RightControl, MwLLKeyControl) + KEY_CASE(kVK_Shift, MwLLKeyLeftShift) + KEY_CASE(kVK_RightShift, MwLLKeyRightShift) + KEY_CASE(kVK_DownArrow, MwLLKeyDown) + KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) + KEY_CASE(kVK_RightArrow, MwLLKeyRight) + KEY_CASE(kVK_UpArrow, MwLLKeyUp) + } + switch (ev.type) { + case NSEventTypeKeyDown: + MwLLDispatch(this, key, &ch); + break; + case NSEventTypeKeyUp: + MwLLDispatch(this, key_released, &ch); + break; + default: + break; + } +} + - (void)sendClipboardEvent { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; @@ -935,7 +628,14 @@ static CGPoint pointFlip(CGPoint point) { _rect->height = [screen frame].size.height; }; - (void)destroy { + if (self->lastEvent) { + [self->lastEvent release]; + [self->lastEvent dealloc]; + } + [self->handle release]; + [self->handle dealloc]; [self->window release]; + [self->window dealloc]; } - (NSWindow *)parentWindow { @@ -1014,11 +714,16 @@ static CGPoint pointFlip(CGPoint point) { - (void)destroy { CGColorSpaceRelease(self->space); + [self->rep release]; + [self->context release]; } - (void)setFrameSize:(NSSize)newSize { [super setFrameSize:newSize]; [self->rep setSize:newSize]; + + self->width = newSize.width; + self->height = newSize.height; } - (void)displayRect:(NSRect)rect { @@ -1034,7 +739,7 @@ static CGPoint pointFlip(CGPoint point) { MilskoFakePointer *ptr = win.contentView.subviews[0]; MwLL h = [ptr pointer]; - // MwLLDispatch(h, resize, NULL); + MwLLDispatch(h, resize, NULL); MwLLDispatch(h, draw, NULL); } return frameSize; @@ -1188,6 +893,7 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; MwLLPixmapUpdate(r); + free(r->common.raw); return r; } @@ -1199,6 +905,7 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { MilskoCocoaPixmap *p = pixmap->cocoa.real; [p destroy]; + [p dealloc]; free(pixmap); } From 4549e4f75b8bc30850a643146ccfc9ab0cebead3 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sun, 8 Mar 2026 17:07:48 -0700 Subject: [PATCH 160/409] mac: remove nscolor release call after realizing it's likely UB and crashes high sierra --- src/backend/cocoa.m | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index c3cfc3f88..8b4e61dac 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -177,7 +177,6 @@ static CGPoint pointFlip(CGPoint point) { [path closePath]; [path fill]; - [nscolor release]; [NSGraphicsContext restoreGraphicsState]; From 3b78872ce80919ccf251b912177329526f9048f1 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 8 Mar 2026 18:04:37 -0700 Subject: [PATCH 161/409] mac: took a detour and got it working in 10.4, before accidentally fixing the remaining memory leak I think --- include/Mw/LowLevel/Cocoa.h | 139 ++-- src/backend/cocoa.m | 1474 ++++++++++++++++++----------------- 2 files changed, 825 insertions(+), 788 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 0ebe7751b..38129e560 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -21,135 +21,136 @@ #import #endif -@interface MilskoCocoaWindowDelegate : NSObject { - NSWindow *w; +// Note: implements NSWindowDelegate +@interface MilskoCocoaWindowDelegate : NSObject { + NSWindow* w; } -- (instancetype)initWithWin:(NSWindow *)win; +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win; @end @interface MilskoFakePointer : NSView { - void *ptr; + void* ptr; } -- (void)setPointer:(void *)ptr; -- (void *)pointer; +- (void)setPointer:(void*)ptr; +- (void*)pointer; @end @interface MilskoCocoaPixmap : NSObject { - MwBool valid; - int width; - int height; - unsigned char *buf; - NSImage *image; - NSBitmapImageRep *rep; + MwBool valid; + int width; + int height; + unsigned char* buf; + NSImage* image; + NSBitmapImageRep* rep; } -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(unsigned char *)data; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(unsigned char*)data; - (void)destroy; /* using @property to create instance variables fucks up 10.4 gcc for some * reason? */ -- (NSImage *)image; +- (NSImage*)image; @end @interface MilskoCocoaView : NSView { - NSBitmapImageRep *rep; - NSGraphicsContext *context; - MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; - float width; - float height; + NSBitmapImageRep* rep; + NSGraphicsContext* context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + float width; + float height; } -- (NSGraphicsContext *)context; +- (NSGraphicsContext*)context; - (void)destroy; -- (NSBitmapImageRep *)getRep; +- (NSBitmapImageRep*)getRep; @end @interface MilskoCocoa : NSObject { - NSApplication *application; - MwBool _forceRender; - NSWindow *window; - NSRect rect; - MilskoCocoaView *view; - MwLL parent; - MilskoFakePointer *handle; - NSUInteger strHash; - NSEvent *lastEvent; + NSApplication* application; + MwBool _forceRender; + NSWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; } -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)handle; -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)handle; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; -- (void)eventProcess:(NSEvent *)ev; -- (void)handleKeyEvent:(NSEvent *)ev; -- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll; +- (void)eventProcess:(NSEvent*)ev; +- (void)handleKeyEvent:(NSEvent*)ev; +- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll; - (void)getNextEvent; -- (void)setTitle:(const char *)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; +- (void)setTitle:(const char*)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; - (void)setIcon:(MwLLPixmap)pixmap; - (void)forceRender; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; -- (void)detachWithPoint:(MwPoint *)point; +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; +- (void)detachWithPoint:(MwPoint*)point; - (void)show:(int)show; - (void)makePopupWithParent:(MwLL)parent; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; - (void)makeBorderless:(int)toggle; - (void)focus; - (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char *)text; +- (void)setClipboard:(const char*)text; - (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint *)point; -- (void)getScreenSize:(MwRect *)rect; +- (void)getCursorCoord:(MwPoint*)point; +- (void)getScreenSize:(MwRect*)rect; - (void)destroy; - (void)sendClipboardEvent; -- (NSWindow *)parentWindow; -- (NSView *)getView; -- (NSWindow *)getWindow; -- (MilskoFakePointer *)getHandle; +- (NSWindow*)parentWindow; +- (NSView*)getView; +- (NSWindow*)getWindow; +- (MilskoFakePointer*)getHandle; @end #define OBJC(x) x #else -#define OBJC(x) void * +#define OBJC(x) void* #endif MWDECL int MwLLCocoaCallInit(void); struct _MwLLCocoa { - struct _MwLLCommon common; - OBJC(MilskoCocoa *) - real; + struct _MwLLCommon common; + OBJC(MilskoCocoa*) + real; }; struct _MwLLCocoaColor { - struct _MwLLCommonColor common; + struct _MwLLCommonColor common; }; struct _MwLLCocoaPixmap { - struct _MwLLCommonPixmap common; - OBJC(MilskoCocoaPixmap *) - real; + struct _MwLLCommonPixmap common; + OBJC(MilskoCocoaPixmap*) + real; }; #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 8b4e61dac..af486249f 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,778 +1,800 @@ -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" #include #include +#ifdef __clang__ #pragma clang push #pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif -static CGRect rectFlip(CGRect originFrame) { - NSScreen *zeroScreen = NSScreen.screens[0]; - double screenHeight = zeroScreen.frame.size.height; - double originY = originFrame.origin.y; - double frameHeight = originFrame.size.height; - double destinationY = screenHeight - (originY + frameHeight); - CGRect destinationFrame = originFrame; - destinationFrame.origin.y = destinationY; - if (destinationFrame.origin.x < 0) - destinationFrame.origin.x = 0; - if (destinationFrame.origin.y < 0) - destinationFrame.origin.y = 0; - if (destinationFrame.size.width < 0) - destinationFrame.size.width = 0; - if (destinationFrame.size.height < 0) - destinationFrame.size.height = 0; - return destinationFrame; +static NSRect rectFlip(NSRect originFrame) { + NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; + double screenHeight = [zeroScreen frame].size.height; + double originY = originFrame.origin.y; + double frameHeight = originFrame.size.height; + double destinationY = screenHeight - (originY + frameHeight); + NSRect destinationFrame = originFrame; + destinationFrame.origin.y = destinationY; + if(destinationFrame.origin.x < 0) + destinationFrame.origin.x = 0; + if(destinationFrame.origin.y < 0) + destinationFrame.origin.y = 0; + if(destinationFrame.size.width < 0) + destinationFrame.size.width = 0; + if(destinationFrame.size.height < 0) + destinationFrame.size.height = 0; + return destinationFrame; } -static CGPoint pointFlip(CGPoint point) { - return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; +static NSPoint pointFlip(NSPoint point) { + return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; } @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; - p->width = width; - p->height = height; - p->image = NULL; + p->width = width; + p->height = height; + p->image = NULL; - p->buf = malloc(width * height * 4); + p->buf = malloc(width * height * 4); - p->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - assert(p->rep); + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(p->rep); - p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - assert(p->image); - [p->image addRepresentation:p->rep]; + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; - return p; + return p; } -- (void)updateWithData:(unsigned char *)_data { - memcpy(self->buf, _data, width * height * 4); +- (void)updateWithData:(unsigned char*)_data { + memcpy(self->buf, _data, width * height * 4); } - (void)destroy { - free(self->buf); - [self->image removeRepresentation:self->rep]; - [self->image dealloc]; - [self->rep dealloc]; + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image dealloc]; + [self->rep dealloc]; } -- (NSImage *)image { - return self->image; +- (NSImage*)image { + return self->image; } @end @implementation MilskoCocoa -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)r { - MilskoCocoa *c = [MilskoCocoa alloc]; - [c retain]; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)r { + MilskoCocoa* c = [MilskoCocoa alloc]; + [c retain]; - if (x == MwDEFAULT) { - x = ([NSScreen mainScreen].frame.size.width / 2.) - (width / 2.); - } - if (y == MwDEFAULT) { - y = ([NSScreen mainScreen].frame.size.height / 2.) - (height / 2.); - } - c->application = [NSApplication sharedApplication]; - c->rect = rectFlip(NSMakeRect(x, y, width, height)); + if(x == MwDEFAULT) { + x = ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); + } + if(y == MwDEFAULT) { + y = ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); + } + c->application = [NSApplication sharedApplication]; + c->rect = rectFlip(NSMakeRect(x, y, width, height)); - if (parent == NULL) { - c->window = [[NSWindow alloc] - initWithContentRect:c->rect - styleMask:(NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask) - backing:NSBackingStoreBuffered - defer:NO]; - } else { - double offset = 0; - NSWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:parentWindow.frame].size.height - - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; + if(parent == NULL) { + c->window = [[NSWindow alloc] + initWithContentRect:c->rect + styleMask:(NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + } else { + double offset = 0; + NSWindow* parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - c->rect.origin.x += parentWindow.frame.origin.x; - c->rect.origin.y -= parentWindow.frame.origin.y - offset; - c->rect.origin.y -= offset; + c->rect.origin.x += [parentWindow frame].origin.x; + c->rect.origin.y -= [parentWindow frame].origin.y - offset; + c->rect.origin.y -= offset; - c->window = [[NSWindow alloc] initWithContentRect:c->rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - } - c->window.delegate = (id)[[MilskoCocoaWindowDelegate alloc] - initWithWin:c->window]; + c->window = [[NSWindow alloc] initWithContentRect:c->rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + } + [c->window setDelegate:[[MilskoCocoaWindowDelegate alloc] + initWithWin:c->window]]; - [c->window makeKeyAndOrderFront:c->application]; - [c->window retain]; + [c->window makeKeyAndOrderFront:c->application]; + [c->window retain]; - if (parent != NULL) { - MilskoCocoa *p = parent->cocoa.real; - [p->window addChildWindow:c->window ordered:NSWindowAbove]; - [c->window setHasShadow:MwFALSE]; - } else { - [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; - [c->application activateIgnoringOtherApps:true]; - [c->window makeFirstResponder:c->view]; - } + if(parent != NULL) { + MilskoCocoa* p = parent->cocoa.real; + [p->window addChildWindow:c->window ordered:NSWindowAbove]; + [c->window setHasShadow:MwFALSE]; + } else { + [c->application activateIgnoringOtherApps:true]; + [c->window makeFirstResponder:c->view]; + } - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [c->handle setPointer:r]; - [c->view addSubview:c->handle]; + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->view retain]; + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle retain]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; - [c->window setContentView:c->view]; + [c->window setContentView:c->view]; - c->parent = parent; + c->parent = parent; - c->_forceRender = MwTRUE; - c->strHash = 0; + c->_forceRender = MwTRUE; + c->strHash = 0; - return c; + return c; } -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext *ctx = [self->view context]; - if (ctx) { - int i; - NSBezierPath *path = [NSBezierPath bezierPath]; - NSColor *nscolor = [NSColor colorWithRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + NSColor* nscolor = [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [nscolor setFill]; - for (i = 0; i < points_count; i++) { - if (i == 0) { - [path moveToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } else { - [path lineToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } - } + [nscolor setFill]; + for(i = 0; i < points_count; i++) { + if(i == 0) { + [path moveToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } else { + [path lineToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } + } - [path closePath]; - [path fill]; + [path closePath]; + [path fill]; - [NSGraphicsContext restoreGraphicsState]; + [NSGraphicsContext restoreGraphicsState]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { + (void)points; + (void)color; }; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { - NSRect frame = rectFlip([self->window frame]); - frame = rectFlip(frame); +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { + NSRect frame = rectFlip([self->window frame]); + frame = rectFlip(frame); - *x = frame.origin.x; - *y = frame.origin.y; + *x = frame.origin.x; + *y = frame.origin.y; - *w = frame.size.width; - *h = frame.size.height; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSRect frame = [self->window frame]; + NSRect frame = [self->window frame]; - frame.origin.x = x; - frame.origin.y = y; + frame.origin.x = x; + frame.origin.y = y; - frame = rectFlip(frame); + frame = rectFlip(frame); - if (parent) { - double offset = 0; - NSWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:parentWindow.frame].size.height - - [parentWindow contentRectForFrameRect:parentWindow.frame].size.height; + if(parent) { + double offset = 0; + NSWindow* parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - if (x < parentWindow.frame.origin.x) { - frame.origin.x += parentWindow.frame.origin.x; - } + if(x < [parentWindow frame].origin.x) { + frame.origin.x += [parentWindow frame].origin.x; + } - if (y < parentWindow.frame.origin.y) { - frame.origin.y -= parentWindow.frame.origin.y - offset; - frame.origin.y -= offset; - } - } - [self->view setFrameSize:frame.size]; + frame.origin.y -= [parentWindow frame].origin.y - offset; + frame.origin.y -= offset; + } + [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; + [self->window setFrame:frame display:YES animate:false]; }; - (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; - self->rect = frame; + self->rect = frame; - [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; + [self->view setFrameSize:frame.size]; + [self->window setFrame:frame display:YES animate:false]; }; - (int)pending { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - MwBool isPending = MwFALSE; - if (_forceRender) { - _forceRender = MwFALSE; - [pool release]; - return 1; - } - self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = MwFALSE; + if(_forceRender) { + _forceRender = MwFALSE; + [pool release]; + return 1; + } + self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; - isPending = self->lastEvent != NULL; - [pool release]; - return isPending; + isPending = self->lastEvent != NULL; + [pool release]; + return isPending; }; - (void)getNextEvent { - NSEvent *ev; - while ((ev = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES])) { - [self eventProcess:ev]; - [ev release]; - } + while(true) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSEvent* ev = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if(!ev) { + [pool release]; + break; + } + [self eventProcess:ev]; + [pool release]; + } - [self sendClipboardEvent]; + [self sendClipboardEvent]; }; -- (void)eventProcess:(NSEvent *)ev { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *win = [ev window]; - NSWindow *parentWindow = [self parentWindow]; - MwLL h; - MwBool doSendEvent = MwTRUE; +- (void)eventProcess:(NSEvent*)ev { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* win = [ev window]; + MwLL h; + MwBool doSendEvent = MwTRUE; - if (!win) { - [pool release]; - return; - } + if(!win) { + [pool release]; + return; + } - if ([win contentView].subviews.count == 0) { - printf("no subviews on %p\n", win); - [pool release]; - return; - } else { - h = [((MilskoFakePointer *)[win contentView].subviews[0]) pointer]; - } + if([[[win contentView] subviews] count] == 0) { + printf("no subviews on %p\n", win); + [pool release]; + return; + } else { + h = [((MilskoFakePointer*)[[[win contentView] subviews] objectAtIndex:0]) pointer]; + } - switch (ev.type) { - case NSEventTypeLeftMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeOtherMouseDown: - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseUp: { - [self handleMouseEvent:ev ll:h]; - } - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: - case NSEventTypeMouseMoved: { - MwPoint pos; - pos.x = [ev locationInWindow].x; - pos.y = [win contentRectForFrameRect:win.frame].size.height - - [ev locationInWindow].y; - MwLLDispatch(h, move, &pos); - break; - } - case NSEventTypeMouseEntered: - MwLLDispatch(h, focus_in, NULL); - break; - case NSEventTypeMouseExited: - MwLLDispatch(h, focus_out, NULL); - break; - case NSEventTypeKeyDown: - case NSEventTypeKeyUp: { - [self handleKeyEvent:ev]; - doSendEvent = MwFALSE; - } - case NSEventTypeCursorUpdate: - break; - case NSEventTypeScrollWheel: - break; - default: - break; - }; - if (doSendEvent) { - [win sendEvent:ev]; - } + switch([ev type]) { + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: { + [self handleMouseEvent:ev ll:h]; + } + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + case NSMouseMoved: { + MwPoint pos; + pos.x = [ev locationInWindow].x; + pos.y = [win contentRectForFrameRect:[win frame]].size.height - + [ev locationInWindow].y; + MwLLDispatch(h, move, &pos); + break; + } + case NSMouseEntered: + MwLLDispatch(h, focus_in, NULL); + break; + case NSMouseExited: + MwLLDispatch(h, focus_out, NULL); + break; + case NSKeyDown: + case NSKeyUp: { + [self handleKeyEvent:ev]; + doSendEvent = MwFALSE; + } + case NSCursorUpdate: + break; + case NSScrollWheel: + break; + default: + break; + }; + if(doSendEvent) { + [win sendEvent:ev]; + } - [pool release]; + [pool release]; } -- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll { - MwLLMouse mouse = {}; - MwBool isDown = MwTRUE; - CGPoint mousePoint = pointFlip([ev locationInWindow]); - switch (ev.type) { - case NSEventTypeLeftMouseUp: - isDown = MwFALSE; - case NSEventTypeLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSEventTypeRightMouseUp: - isDown = MwFALSE; - case NSEventTypeRightMouseDown: - mouse.button = MwLLMouseRight; - break; - case NSEventTypeOtherMouseUp: - isDown = MwFALSE; - case NSEventTypeOtherMouseDown: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; +- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll { + MwLLMouse mouse; + MwBool isDown = MwTRUE; + NSPoint mousePoint = pointFlip([ev locationInWindow]); + switch([ev type]) { + case NSLeftMouseUp: + isDown = MwFALSE; + case NSLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSRightMouseUp: + isDown = MwFALSE; + case NSRightMouseDown: + mouse.button = MwLLMouseRight; + break; + case NSOtherMouseUp: + isDown = MwFALSE; + case NSOtherMouseDown: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; - if (isDown) { - MwLLDispatch(ll, down, &mouse); - } else { - MwLLDispatch(ll, up, &mouse); - } + if(isDown) { + MwLLDispatch(ll, down, &mouse); + } else { + MwLLDispatch(ll, up, &mouse); + } } -- (void)handleKeyEvent:(NSEvent *)ev { - int ch; - MwLL this = self->handle.pointer; - enum { - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_Return = 0x24, - kVK_Space = 0x31, - kVK_Escape = 0x35, - kVK_Shift = 0x38, - kVK_Control = 0x3B, - kVK_RightShift = 0x3C, - kVK_RightControl = 0x3E, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E - }; -#define KEY_CASE(x, y) \ - case x: \ - ch = y; \ - break; - switch (ev.keyCode) { - KEY_CASE(kVK_ANSI_A, 'a') - KEY_CASE(kVK_ANSI_B, 'b') - KEY_CASE(kVK_ANSI_C, 'c') - KEY_CASE(kVK_ANSI_D, 'd') - KEY_CASE(kVK_ANSI_E, 'e') - KEY_CASE(kVK_ANSI_F, 'f') - KEY_CASE(kVK_ANSI_G, 'g') - KEY_CASE(kVK_ANSI_H, 'h') - KEY_CASE(kVK_ANSI_I, 'i') - KEY_CASE(kVK_ANSI_J, 'j') - KEY_CASE(kVK_ANSI_K, 'k') - KEY_CASE(kVK_ANSI_L, 'l') - KEY_CASE(kVK_ANSI_M, 'm') - KEY_CASE(kVK_ANSI_N, 'n') - KEY_CASE(kVK_ANSI_O, 'o') - KEY_CASE(kVK_ANSI_P, 'p') - KEY_CASE(kVK_ANSI_Q, 'q') - KEY_CASE(kVK_ANSI_R, 'r') - KEY_CASE(kVK_ANSI_S, 's') - KEY_CASE(kVK_ANSI_T, 't') - KEY_CASE(kVK_ANSI_U, 'u') - KEY_CASE(kVK_ANSI_V, 'v') - KEY_CASE(kVK_ANSI_W, 'w') - KEY_CASE(kVK_ANSI_X, 'x') - KEY_CASE(kVK_ANSI_Y, 'y') - KEY_CASE(kVK_ANSI_Z, 'z') - KEY_CASE(kVK_ANSI_0, '0') - KEY_CASE(kVK_ANSI_1, '1') - KEY_CASE(kVK_ANSI_2, '2') - KEY_CASE(kVK_ANSI_3, '3') - KEY_CASE(kVK_ANSI_4, '4') - KEY_CASE(kVK_ANSI_5, '5') - KEY_CASE(kVK_ANSI_6, '6') - KEY_CASE(kVK_ANSI_7, '7') - KEY_CASE(kVK_ANSI_8, '8') - KEY_CASE(kVK_ANSI_9, '9') - KEY_CASE(kVK_ANSI_Quote, '\"') - KEY_CASE(kVK_ANSI_Grave, '`') - KEY_CASE(kVK_ANSI_Backslash, '/') - KEY_CASE(kVK_ANSI_Comma, ',') - KEY_CASE(kVK_ANSI_Equal, '=') - KEY_CASE(kVK_Escape, MwLLKeyEscape) - KEY_CASE(kVK_ANSI_LeftBracket, '[') - KEY_CASE(kVK_ANSI_Minus, '-') - KEY_CASE(kVK_ANSI_Period, '.') - KEY_CASE(kVK_Return, MwLLKeyEnter) - KEY_CASE(kVK_ANSI_RightBracket, ']') - KEY_CASE(kVK_ANSI_Semicolon, ';') - KEY_CASE(kVK_ANSI_Slash, '\\') - KEY_CASE(kVK_Space, ' ') - KEY_CASE(kVK_Control, MwLLKeyControl) - KEY_CASE(kVK_RightControl, MwLLKeyControl) - KEY_CASE(kVK_Shift, MwLLKeyLeftShift) - KEY_CASE(kVK_RightShift, MwLLKeyRightShift) - KEY_CASE(kVK_DownArrow, MwLLKeyDown) - KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) - KEY_CASE(kVK_RightArrow, MwLLKeyRight) - KEY_CASE(kVK_UpArrow, MwLLKeyUp) - } - switch (ev.type) { - case NSEventTypeKeyDown: - MwLLDispatch(this, key, &ch); - break; - case NSEventTypeKeyUp: - MwLLDispatch(this, key_released, &ch); - break; - default: - break; - } +- (void)handleKeyEvent:(NSEvent*)ev { + int ch; + MwLL this = [self->handle pointer]; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch([ev keyCode]) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwLLKeyControl) + KEY_CASE(kVK_RightControl, MwLLKeyControl) + KEY_CASE(kVK_Shift, MwLLKeyLeftShift) + KEY_CASE(kVK_RightShift, MwLLKeyRightShift) + KEY_CASE(kVK_DownArrow, MwLLKeyDown) + KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) + KEY_CASE(kVK_RightArrow, MwLLKeyRight) + KEY_CASE(kVK_UpArrow, MwLLKeyUp) + } + switch([ev type]) { + case NSKeyDown: + MwLLDispatch(this, key, &ch); + break; + case NSKeyUp: + MwLLDispatch(this, key_released, &ch); + break; + default: + break; + } } - (void)sendClipboardEvent { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - NSArray *items = @[ - @"public.utf8-plain-text", - @"public.utf16-external-plain-text", - @"com.apple.traditional-mac-plain-text", - ]; - MwLL this = self->handle.pointer; + /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSArray* items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; - if ([pasteboard canReadItemWithDataConformingToTypes:items]) { - char *data = NULL; - size_t size = 0; - for (NSPasteboardItem *item in [pasteboard pasteboardItems]) { - for (NSString *it in items) { - NSString *itemData = [item stringForType:(NSString *)it]; - if (itemData != NULL) { - if (strHash != 0 && strHash != [itemData hash]) { - char *text = malloc([itemData length]); - strncpy(text, [itemData UTF8String], [itemData length]); - MwLLDispatch(this, clipboard, text); - printf("%s -> %p\n", text, this); - free(text); - } - strHash = [itemData hash]; - } - } - } - } + if([pasteboard canReadItemWithDataConformingToTypes:items]) { + char* data = NULL; + size_t size = 0; + for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { + for(NSString* it in items) { + NSString* itemData = [item stringForType:(NSString*)it]; + if(itemData != NULL) { + if(strHash != 0 && strHash != [itemData hash]) { + char* text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], [itemData length]); + MwLLDispatch(this, clipboard, text); + printf("%s -> %p\n", text, this); + free(text); + } + strHash = [itemData hash]; + } + } + } + } - [pool release]; + [pool release];*/ } -- (void)setTitle:(const char *)title { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; +- (void)setTitle:(const char*)title { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)_rect { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - MilskoCocoaPixmap *p = pixmap->cocoa.real; - NSGraphicsContext *ctx = [self->view context]; - if (ctx) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [[p image] drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, - _rect->height) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0 - respectFlipped:NO - hints:nil]; + [[p image] drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, + _rect->height) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; - [NSGraphicsContext restoreGraphicsState]; + [NSGraphicsContext restoreGraphicsState]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { + (void)pixmap; }; - (void)forceRender { - _forceRender = MwTRUE; + _forceRender = MwTRUE; }; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { + (void)image; + (void)mask; }; -- (void)detachWithPoint:(MwPoint *)point { +- (void)detachWithPoint:(MwPoint*)point { + (void)point; }; - (void)show:(int)show { + (void)show; }; -- (void)makePopupWithParent:(MwLL)parent { +- (void)makePopupWithParent:(MwLL)_parent { + (void)_parent; }; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { + (void)minx; + (void)miny; + (void)maxx; + (void)maxy; }; - (void)makeBorderless:(int)toggle { - MwU32 mask = [self->window styleMask]; - if (mask & NSBorderlessWindowMask) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; + MwU32 mask = [self->window styleMask]; + if(toggle) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { - [self->window makeMainWindow]; + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - /* MacOS didn't have a "pointer grab" function - * until 10.13.2 so I need to do this manually */ + (void)toggle; + /* MacOS didn't have a "pointer grab" function + * until 10.13.2 so I need to do this manually */ }; -- (void)setClipboard:(const char *)text { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; - [pasteboard declareTypes:@[ NSPasteboardTypeString ] owner:nil]; - [pasteboard setString:@(text) forType:NSPasteboardTypeString]; - [pool release]; +- (void)setClipboard:(const char*)text { + (void)text; + // TODO: find out how to do this while supporting 10.4 + // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] owner:nil]; + // [pasteboard setString:[NSString stringWithUTF8String:text] forType:NSPasteboardTypeString]; + // [pool release]; }; - (void)getClipboard { }; - (void)makeToolWindow { }; -- (void)getCursorCoord:(MwPoint *)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; +- (void)getCursorCoord:(MwPoint*)point { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; }; -- (void)getScreenSize:(MwRect *)_rect { - NSScreen *screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; +- (void)getScreenSize:(MwRect*)_rect { + NSScreen* screen = [self->window screen]; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { - if (self->lastEvent) { - [self->lastEvent release]; - [self->lastEvent dealloc]; - } - [self->handle release]; - [self->handle dealloc]; - [self->window release]; - [self->window dealloc]; + if(self->lastEvent) { + [self->lastEvent release]; + [self->lastEvent dealloc]; + } + [self->handle release]; + [self->handle dealloc]; + [self->window release]; + [self->window dealloc]; } -- (NSWindow *)parentWindow { - NSWindow *topmostWindow = self->window; - while (topmostWindow.parentWindow) - topmostWindow = topmostWindow.parentWindow; - return topmostWindow; +- (NSWindow*)parentWindow { + NSWindow* topmostWindow = self->window; + while([topmostWindow parentWindow]) + topmostWindow = [topmostWindow parentWindow]; + return topmostWindow; } -- (NSView *)getView { - return view; +- (NSView*)getView { + return view; } -- (NSWindow *)getWindow { - return window; +- (NSWindow*)getWindow { + return window; } -- (MilskoFakePointer *)getHandle { - return handle; +- (MilskoFakePointer*)getHandle { + return handle; } @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - width = frame.size.width; - height = frame.size.height; - self = [super initWithFrame:frame]; - self->space = CGColorSpaceCreateDeviceRGB(); + width = frame.size.width; + height = frame.size.height; + self = [super initWithFrame:frame]; + self->space = CGColorSpaceCreateDeviceRGB(); - if (width == 0 || height == 0) { - self->rep = NULL; - self->context = NULL; - } else { - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:width * 4 - bitsPerPixel:32]; - assert(self->rep); + if(width == 0 || height == 0) { + self->rep = NULL; + self->context = NULL; + } else { + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:width * 4 + bitsPerPixel:32]; + assert(self->rep); + [self->rep retain]; - self->context = - [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; - assert(self->context); - } + self->context = + [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; + assert(self->context); + [self->context retain]; + } - return self; + return self; } -- (NSGraphicsContext *)context { - return self->context; +- (NSGraphicsContext*)context { + return self->context; } -- (NSBitmapImageRep *)getRep { - return self->rep; +- (NSBitmapImageRep*)getRep { + return self->rep; } - (void)drawRect:(NSRect)dirtyRect { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSSize sz = self->rep.size; - [super drawRect:dirtyRect]; - if (!self->rep) { - [pool release]; - return; - } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSSize sz = [self->rep size]; + [super drawRect:dirtyRect]; + if(!self->rep) { + [pool release]; + return; + } - [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; + [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; - [self->rep bitmapData]; - [pool release]; + [self->rep bitmapData]; + [pool release]; } - (void)destroy { - CGColorSpaceRelease(self->space); - [self->rep release]; - [self->context release]; + CGColorSpaceRelease(self->space); + [self->rep release]; + [self->context release]; } - (void)setFrameSize:(NSSize)newSize { - [super setFrameSize:newSize]; - [self->rep setSize:newSize]; + [super setFrameSize:newSize]; + [self->rep setSize:newSize]; - self->width = newSize.width; - self->height = newSize.height; + self->width = newSize.width; + self->height = newSize.height; } - (void)displayRect:(NSRect)rect { + (void)rect; }; @end @implementation MilskoCocoaWindowDelegate -- (NSSize)windowWillResize:(NSWindow *)win toSize:(NSSize)frameSize; +- (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; { - if (win.contentView.subviews.count >= 1) { - MilskoFakePointer *ptr = win.contentView.subviews[0]; - MwLL h = [ptr pointer]; + if([[[win contentView] subviews] count] >= 1) { + MilskoFakePointer* ptr = [[[win contentView] subviews] objectAtIndex:0]; + MwLL h = [ptr pointer]; - MwLLDispatch(h, resize, NULL); - MwLLDispatch(h, draw, NULL); - } - return frameSize; + // MwLLDispatch(h, resize, NULL); + MwLLDispatch(h, draw, NULL); + } + return frameSize; } -- (void)windowDidResize:(NSNotification *)notification { +- (void)windowDidResize:(NSNotification*)notification { + (void)notification; } // This will close/terminate the application when the main window is closed. -- (void)windowWillClose:(NSNotification *)notification { - // MilskoCocoa *window = notification.object; - // MwLL handle = [window getHandle].pointer; - // MwLLDispatch(handle, close, NULL); - [NSApp terminate:nil]; +- (void)windowWillClose:(NSNotification*)notification { + (void)notification; + // MilskoCocoa *window = notification.object; + // MwLL handle = [window getHandle].pointer; + // MwLLDispatch(handle, close, NULL); + [NSApp terminate:nil]; } -- (instancetype)initWithWin:(NSWindow *)win { - self->w = win; - return self; +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { + self->w = win; + return self; } @end @implementation MilskoFakePointer -- (void)setPointer:(void *)pointer { - self.frame = *(NSRect *)&pointer; - self->ptr = pointer; +- (void)setPointer:(void*)pointer { + [self setFrame:*(NSRect*)&pointer]; + self->ptr = pointer; }; -- (void *)pointer { - return self->ptr; +- (void*)pointer { + return self->ptr; }; - (void)drawRect:(NSRect)dirtyRect { - /* explicitly do nothing */ + /* explicitly do nothing */ + (void)dirtyRect; } - (void)destroy { @@ -780,219 +802,233 @@ static CGPoint pointFlip(CGPoint point) { @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; - r = malloc(sizeof(*r)); + r = malloc(sizeof(*r)); - MwLLCreateCommon(r); + MwLLCreateCommon(r); - MilskoCocoa *o = [MilskoCocoa newWithParent:parent - x:x - y:y - width:width - height:height - handle:r]; - r->cocoa.real = o; + MilskoCocoa* o = [MilskoCocoa newWithParent:parent + x:x + y:y + width:width + height:height + handle:r]; + r->cocoa.real = o; - return r; + return r; } static void MwLLDestroyImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; + MilskoCocoa* h = handle->cocoa.real; - [h destroy]; + [h destroy]; - MwLLDestroyCommon(handle); + MwLLDestroyCommon(handle); - free(handle); + free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, - MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; } -static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h lineWithPoints:points color:color]; +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, + MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; + (void)handle; - c->common.red = r; - c->common.green = g; - c->common.blue = b; + c->common.red = r; + c->common.green = g; + c->common.blue = b; } -static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, - unsigned int *height) { - MilskoCocoa *h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, + unsigned int* height) { + MilskoCocoa* h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa *h = handle->cocoa.real; - [h setX:x Y:y]; + MilskoCocoa* h = handle->cocoa.real; + [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa *h = handle->cocoa.real; - [h setW:w H:height]; + MilskoCocoa* h = handle->cocoa.real; + [h setW:w H:height]; } -static void MwLLFreeColorImpl(MwLLColor color) { free(color); } +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} static int MwLLPendingImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - if ([h pending]) { - MwLLDispatch(handle, draw, NULL); - return 1; - }; - return 0; + MilskoCocoa* h = handle->cocoa.real; + if([h pending]) { + MwLLDispatch(handle, draw, NULL); + return 1; + }; + return 0; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h getNextEvent]; + MilskoCocoa* h = handle->cocoa.real; + [h getNextEvent]; } -static void MwLLSetTitleImpl(MwLL handle, const char *title) { - MilskoCocoa *h = handle->cocoa.real; - [h setTitle:title]; +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + MilskoCocoa* h = handle->cocoa.real; + [h setTitle:title]; } -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, - int width, int height) { - (void)handle; +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, + int width, int height) { + (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + MwLLPixmap r = malloc(sizeof(*r)); - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - r->common.width = width; - r->common.height = height; + r->common.width = width; + r->common.height = height; - r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; - MwLLPixmapUpdate(r); - free(r->common.raw); - return r; + MwLLPixmapUpdate(r); + free(r->common.raw); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p destroy]; - [p dealloc]; - free(pixmap); + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p destroy]; + [p dealloc]; + free(pixmap); } -static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; - MwLLForceRender(handle); +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + MilskoCocoa* h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; + MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h setIcon:pixmap]; + MilskoCocoa* h = handle->cocoa.real; + [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h forceRender]; + MilskoCocoa* h = handle->cocoa.real; + [h forceRender]; } -static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { - MilskoCocoa *h = handle->cocoa.real; - [h setCursor:image mask:mask]; +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + MilskoCocoa* h = handle->cocoa.real; + [h setCursor:image mask:mask]; } -static void MwLLDetachImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h detachWithPoint:point]; +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa *h = handle->cocoa.real; - [h show:show]; + MilskoCocoa* h = handle->cocoa.real; + [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa *h = handle->cocoa.real; - [h makePopupWithParent:parent]; + MilskoCocoa* h = handle->cocoa.real; + [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, - int maxy) { - MilskoCocoa *h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + int maxy) { + MilskoCocoa* h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeBorderless:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h focus]; + MilskoCocoa* h = handle->cocoa.real; + [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h grabPointer:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h grabPointer:toggle]; } -static void MwLLSetClipboardImpl(MwLL handle, const char *text) { - MilskoCocoa *h = handle->cocoa.real; - [h setClipboard:text]; +static void MwLLSetClipboardImpl(MwLL handle, const char* text) { + MilskoCocoa* h = handle->cocoa.real; + [h setClipboard:text]; } -static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } +static void MwLLGetClipboardImpl(MwLL handle) { + (void)handle; +} static void MwLLMakeToolWindowImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeToolWindow]; + MilskoCocoa* h = handle->cocoa.real; + [h makeToolWindow]; } -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h getCursorCoord:point]; +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h getCursorCoord:point]; } -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { - MilskoCocoa *h = handle->cocoa.real; - [h getScreenSize:rect]; +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + MilskoCocoa* h = handle->cocoa.real; + [h getScreenSize:rect]; } -static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} -static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} -static int MwLLCocoaCallInitImpl(void) { return 0; } +static int MwLLCocoaCallInitImpl(void) { + return 0; +} #include "call.c" CALL(Cocoa); From c20da369e868b8d00d1fecb1a49d97c723a27bf0 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sun, 8 Mar 2026 18:30:37 -0700 Subject: [PATCH 162/409] try and fail to have the app be activated without setting the activation policy --- include/Mw/LowLevel/Cocoa.h | 143 ++-- src/backend/cocoa.m | 1517 ++++++++++++++++++----------------- 2 files changed, 842 insertions(+), 818 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 38129e560..2789af904 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -21,136 +21,143 @@ #import #endif +// Note: implements NSApplicationDelegate +@interface MilskoCocoaApplicationDelegate : NSObject { + NSApplication *appl; +} +- (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)appl; +@end + // Note: implements NSWindowDelegate @interface MilskoCocoaWindowDelegate : NSObject { - NSWindow* w; + NSWindow *w; } -- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win; +- (MilskoCocoaWindowDelegate *)initWithWin:(NSWindow *)win; @end @interface MilskoFakePointer : NSView { - void* ptr; + void *ptr; } -- (void)setPointer:(void*)ptr; -- (void*)pointer; +- (void)setPointer:(void *)ptr; +- (void *)pointer; @end @interface MilskoCocoaPixmap : NSObject { - MwBool valid; - int width; - int height; - unsigned char* buf; - NSImage* image; - NSBitmapImageRep* rep; + MwBool valid; + int width; + int height; + unsigned char *buf; + NSImage *image; + NSBitmapImageRep *rep; } -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(unsigned char*)data; ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(unsigned char *)data; - (void)destroy; /* using @property to create instance variables fucks up 10.4 gcc for some * reason? */ -- (NSImage*)image; +- (NSImage *)image; @end @interface MilskoCocoaView : NSView { - NSBitmapImageRep* rep; - NSGraphicsContext* context; - MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; - float width; - float height; + NSBitmapImageRep *rep; + NSGraphicsContext *context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + float width; + float height; } -- (NSGraphicsContext*)context; +- (NSGraphicsContext *)context; - (void)destroy; -- (NSBitmapImageRep*)getRep; +- (NSBitmapImageRep *)getRep; @end @interface MilskoCocoa : NSObject { - NSApplication* application; - MwBool _forceRender; - NSWindow* window; - NSRect rect; - MilskoCocoaView* view; - MwLL parent; - MilskoFakePointer* handle; - unsigned int strHash; - NSEvent* lastEvent; + NSApplication *application; + MwBool _forceRender; + NSWindow *window; + NSRect rect; + MilskoCocoaView *view; + MwLL parent; + MilskoFakePointer *handle; + unsigned int strHash; + NSEvent *lastEvent; } -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)handle; -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)handle; +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; -- (void)eventProcess:(NSEvent*)ev; -- (void)handleKeyEvent:(NSEvent*)ev; -- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll; +- (void)eventProcess:(NSEvent *)ev; +- (void)handleKeyEvent:(NSEvent *)ev; +- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll; - (void)getNextEvent; -- (void)setTitle:(const char*)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; +- (void)setTitle:(const char *)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; - (void)setIcon:(MwLLPixmap)pixmap; - (void)forceRender; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; -- (void)detachWithPoint:(MwPoint*)point; +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; +- (void)detachWithPoint:(MwPoint *)point; - (void)show:(int)show; - (void)makePopupWithParent:(MwLL)parent; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; - (void)makeBorderless:(int)toggle; - (void)focus; - (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char*)text; +- (void)setClipboard:(const char *)text; - (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint*)point; -- (void)getScreenSize:(MwRect*)rect; +- (void)getCursorCoord:(MwPoint *)point; +- (void)getScreenSize:(MwRect *)rect; - (void)destroy; - (void)sendClipboardEvent; -- (NSWindow*)parentWindow; -- (NSView*)getView; -- (NSWindow*)getWindow; -- (MilskoFakePointer*)getHandle; +- (NSWindow *)parentWindow; +- (NSView *)getView; +- (NSWindow *)getWindow; +- (MilskoFakePointer *)getHandle; @end #define OBJC(x) x #else -#define OBJC(x) void* +#define OBJC(x) void * #endif MWDECL int MwLLCocoaCallInit(void); struct _MwLLCocoa { - struct _MwLLCommon common; - OBJC(MilskoCocoa*) - real; + struct _MwLLCommon common; + OBJC(MilskoCocoa *) + real; }; struct _MwLLCocoaColor { - struct _MwLLCommonColor common; + struct _MwLLCommonColor common; }; struct _MwLLCocoaPixmap { - struct _MwLLCommonPixmap common; - OBJC(MilskoCocoaPixmap*) - real; + struct _MwLLCommonPixmap common; + OBJC(MilskoCocoaPixmap *) + real; }; #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index af486249f..7f07ffbf4 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,4 @@ +#include "Mw/BaseTypes.h" #include #include @@ -7,794 +8,824 @@ #endif static NSRect rectFlip(NSRect originFrame) { - NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; - double screenHeight = [zeroScreen frame].size.height; - double originY = originFrame.origin.y; - double frameHeight = originFrame.size.height; - double destinationY = screenHeight - (originY + frameHeight); - NSRect destinationFrame = originFrame; - destinationFrame.origin.y = destinationY; - if(destinationFrame.origin.x < 0) - destinationFrame.origin.x = 0; - if(destinationFrame.origin.y < 0) - destinationFrame.origin.y = 0; - if(destinationFrame.size.width < 0) - destinationFrame.size.width = 0; - if(destinationFrame.size.height < 0) - destinationFrame.size.height = 0; - return destinationFrame; + NSScreen *zeroScreen = [[NSScreen screens] objectAtIndex:0]; + double screenHeight = [zeroScreen frame].size.height; + double originY = originFrame.origin.y; + double frameHeight = originFrame.size.height; + double destinationY = screenHeight - (originY + frameHeight); + NSRect destinationFrame = originFrame; + destinationFrame.origin.y = destinationY; + if (destinationFrame.origin.x < 0) + destinationFrame.origin.x = 0; + if (destinationFrame.origin.y < 0) + destinationFrame.origin.y = 0; + if (destinationFrame.size.width < 0) + destinationFrame.size.width = 0; + if (destinationFrame.size.height < 0) + destinationFrame.size.height = 0; + return destinationFrame; } static NSPoint pointFlip(NSPoint point) { - return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; + return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; } @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; ++ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; - p->width = width; - p->height = height; - p->image = NULL; + p->width = width; + p->height = height; + p->image = NULL; - p->buf = malloc(width * height * 4); + p->buf = malloc(width * height * 4); - p->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - assert(p->rep); + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(p->rep); - p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - assert(p->image); - [p->image addRepresentation:p->rep]; + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; - return p; + return p; } -- (void)updateWithData:(unsigned char*)_data { - memcpy(self->buf, _data, width * height * 4); +- (void)updateWithData:(unsigned char *)_data { + memcpy(self->buf, _data, width * height * 4); } - (void)destroy { - free(self->buf); - [self->image removeRepresentation:self->rep]; - [self->image dealloc]; - [self->rep dealloc]; + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image dealloc]; + [self->rep dealloc]; } -- (NSImage*)image { - return self->image; +- (NSImage *)image { + return self->image; } @end @implementation MilskoCocoa -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)r { - MilskoCocoa* c = [MilskoCocoa alloc]; - [c retain]; ++ (MilskoCocoa *)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)r { + MilskoCocoa *c = [MilskoCocoa alloc]; + [c retain]; - if(x == MwDEFAULT) { - x = ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); - } - if(y == MwDEFAULT) { - y = ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); - } - c->application = [NSApplication sharedApplication]; - c->rect = rectFlip(NSMakeRect(x, y, width, height)); + if (x == MwDEFAULT) { + x = ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); + } + if (y == MwDEFAULT) { + y = ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); + } + c->application = [NSApplication sharedApplication]; + c->rect = rectFlip(NSMakeRect(x, y, width, height)); - if(parent == NULL) { - c->window = [[NSWindow alloc] - initWithContentRect:c->rect - styleMask:(NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask) - backing:NSBackingStoreBuffered - defer:NO]; - } else { - double offset = 0; - NSWindow* parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + if (parent == NULL) { + c->window = [[NSWindow alloc] + initWithContentRect:c->rect + styleMask:(NSTitledWindowMask | NSClosableWindowMask | + NSMiniaturizableWindowMask | NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + } else { + double offset = 0; + NSWindow *parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]] + .size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - c->rect.origin.x += [parentWindow frame].origin.x; - c->rect.origin.y -= [parentWindow frame].origin.y - offset; - c->rect.origin.y -= offset; + c->rect.origin.x += [parentWindow frame].origin.x; + c->rect.origin.y -= [parentWindow frame].origin.y - offset; + c->rect.origin.y -= offset; - c->window = [[NSWindow alloc] initWithContentRect:c->rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - } - [c->window setDelegate:[[MilskoCocoaWindowDelegate alloc] - initWithWin:c->window]]; + c->window = [[NSWindow alloc] initWithContentRect:c->rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + } + [c->window + setDelegate:(id)[[MilskoCocoaWindowDelegate alloc] + initWithWin:c->window]]; - [c->window makeKeyAndOrderFront:c->application]; - [c->window retain]; + [c->window makeKeyAndOrderFront:c->application]; + [c->window retain]; - if(parent != NULL) { - MilskoCocoa* p = parent->cocoa.real; - [p->window addChildWindow:c->window ordered:NSWindowAbove]; - [c->window setHasShadow:MwFALSE]; - } else { - [c->application activateIgnoringOtherApps:true]; - [c->window makeFirstResponder:c->view]; - } + if (parent != NULL) { + MilskoCocoa *p = parent->cocoa.real; + [p->window addChildWindow:c->window ordered:NSWindowAbove]; + [c->window setHasShadow:MwFALSE]; + } else { + [c->application activateIgnoringOtherApps:true]; + [c->window makeFirstResponder:c->view]; + } - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - [c->view retain]; - c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [c->handle retain]; - [c->handle setPointer:r]; - [c->view addSubview:c->handle]; + [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] + initWithAppl:c->application]]; - [c->window setContentView:c->view]; + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->view retain]; + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle retain]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; - c->parent = parent; + [c->window setContentView:c->view]; - c->_forceRender = MwTRUE; - c->strHash = 0; + c->parent = parent; - return c; + c->_forceRender = MwTRUE; + c->strHash = 0; + + [c->application finishLaunching]; + + return c; } -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - int i; - NSBezierPath* path = [NSBezierPath bezierPath]; - NSColor* nscolor = [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; +- (void)polygonWithPoints:(MwPoint *)points + points_count:(int)points_count + color:(MwLLColor)color { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext *ctx = [self->view context]; + if (ctx) { + int i; + NSBezierPath *path = [NSBezierPath bezierPath]; + NSColor *nscolor = + [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [nscolor setFill]; - for(i = 0; i < points_count; i++) { - if(i == 0) { - [path moveToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } else { - [path lineToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } - } + [nscolor setFill]; + for (i = 0; i < points_count; i++) { + if (i == 0) { + [path moveToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } else { + [path lineToPoint:NSMakePoint(points[i].x, + [self->window frame].size.height - + points[i].y)]; + } + } - [path closePath]; - [path fill]; + [path closePath]; + [path fill]; - [NSGraphicsContext restoreGraphicsState]; + [NSGraphicsContext restoreGraphicsState]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { - (void)points; - (void)color; +- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { + (void)points; + (void)color; }; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { - NSRect frame = rectFlip([self->window frame]); - frame = rectFlip(frame); +- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { + NSRect frame = rectFlip([self->window frame]); + frame = rectFlip(frame); - *x = frame.origin.x; - *y = frame.origin.y; + *x = frame.origin.x; + *y = frame.origin.y; - *w = frame.size.width; - *h = frame.size.height; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSRect frame = [self->window frame]; + NSRect frame = [self->window frame]; - frame.origin.x = x; - frame.origin.y = y; + frame.origin.x = x; + frame.origin.y = y; - frame = rectFlip(frame); + frame = rectFlip(frame); - if(parent) { - double offset = 0; - NSWindow* parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + if (parent) { + double offset = 0; + NSWindow *parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]] + .size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - if(x < [parentWindow frame].origin.x) { - frame.origin.x += [parentWindow frame].origin.x; - } + if (x < [parentWindow frame].origin.x) { + frame.origin.x += [parentWindow frame].origin.x; + } - frame.origin.y -= [parentWindow frame].origin.y - offset; - frame.origin.y -= offset; - } - [self->view setFrameSize:frame.size]; + frame.origin.y -= [parentWindow frame].origin.y - offset; + frame.origin.y -= offset; + } + [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; + [self->window setFrame:frame display:YES animate:false]; + + [self forceRender]; }; - (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; - self->rect = frame; + self->rect = frame; - [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; + [self->view setFrameSize:frame.size]; + [self->window setFrame:frame display:YES animate:false]; + [self forceRender]; }; - (int)pending { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MwBool isPending = MwFALSE; - if(_forceRender) { - _forceRender = MwFALSE; - [pool release]; - return 1; - } - self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = MwFALSE; + if (_forceRender) { + _forceRender = MwFALSE; + [pool release]; + return 1; + } + self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; - isPending = self->lastEvent != NULL; - [pool release]; - return isPending; + isPending = self->lastEvent != NULL; + [pool release]; + return isPending; }; - (void)getNextEvent { - while(true) { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSEvent* ev = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if(!ev) { - [pool release]; - break; - } - [self eventProcess:ev]; - [pool release]; - } + while (true) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *ev = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + if (!ev) { + [pool release]; + break; + } + [self eventProcess:ev]; + [pool release]; + } - [self sendClipboardEvent]; + [self sendClipboardEvent]; }; -- (void)eventProcess:(NSEvent*)ev { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = [ev window]; - MwLL h; - MwBool doSendEvent = MwTRUE; +- (void)eventProcess:(NSEvent *)ev { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSWindow *win = [ev window]; + MwLL h; + MwBool doSendEvent = MwTRUE; - if(!win) { - [pool release]; - return; - } + if (!win) { + [pool release]; + return; + } - if([[[win contentView] subviews] count] == 0) { - printf("no subviews on %p\n", win); - [pool release]; - return; - } else { - h = [((MilskoFakePointer*)[[[win contentView] subviews] objectAtIndex:0]) pointer]; - } + if ([[[win contentView] subviews] count] == 0) { + printf("no subviews on %p\n", win); + [pool release]; + return; + } else { + h = [((MilskoFakePointer *)[[[win contentView] subviews] + objectAtIndex:0]) pointer]; + } - switch([ev type]) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: { - [self handleMouseEvent:ev ll:h]; - } - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - case NSMouseMoved: { - MwPoint pos; - pos.x = [ev locationInWindow].x; - pos.y = [win contentRectForFrameRect:[win frame]].size.height - - [ev locationInWindow].y; - MwLLDispatch(h, move, &pos); - break; - } - case NSMouseEntered: - MwLLDispatch(h, focus_in, NULL); - break; - case NSMouseExited: - MwLLDispatch(h, focus_out, NULL); - break; - case NSKeyDown: - case NSKeyUp: { - [self handleKeyEvent:ev]; - doSendEvent = MwFALSE; - } - case NSCursorUpdate: - break; - case NSScrollWheel: - break; - default: - break; - }; - if(doSendEvent) { - [win sendEvent:ev]; - } + switch ([ev type]) { + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: { + [self handleMouseEvent:ev ll:h]; + } + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + case NSMouseMoved: { + MwPoint pos; + pos.x = [ev locationInWindow].x; + pos.y = [win contentRectForFrameRect:[win frame]].size.height - + [ev locationInWindow].y; + MwLLDispatch(h, move, &pos); + break; + } + case NSMouseEntered: + MwLLDispatch(h, focus_in, NULL); + break; + case NSMouseExited: + MwLLDispatch(h, focus_out, NULL); + break; + case NSKeyDown: + case NSKeyUp: { + [self handleKeyEvent:ev]; + doSendEvent = MwFALSE; + } + case NSCursorUpdate: + break; + case NSScrollWheel: + break; + default: + break; + }; + if (doSendEvent) { + [win sendEvent:ev]; + } - [pool release]; + [pool release]; } -- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll { - MwLLMouse mouse; - MwBool isDown = MwTRUE; - NSPoint mousePoint = pointFlip([ev locationInWindow]); - switch([ev type]) { - case NSLeftMouseUp: - isDown = MwFALSE; - case NSLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSRightMouseUp: - isDown = MwFALSE; - case NSRightMouseDown: - mouse.button = MwLLMouseRight; - break; - case NSOtherMouseUp: - isDown = MwFALSE; - case NSOtherMouseDown: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; +- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll { + MwLLMouse mouse; + MwBool isDown = MwTRUE; + NSPoint mousePoint = pointFlip([ev locationInWindow]); + switch ([ev type]) { + case NSLeftMouseUp: + isDown = MwFALSE; + case NSLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSRightMouseUp: + isDown = MwFALSE; + case NSRightMouseDown: + mouse.button = MwLLMouseRight; + break; + case NSOtherMouseUp: + isDown = MwFALSE; + case NSOtherMouseDown: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; - if(isDown) { - MwLLDispatch(ll, down, &mouse); - } else { - MwLLDispatch(ll, up, &mouse); - } + if (isDown) { + MwLLDispatch(ll, down, &mouse); + } else { + MwLLDispatch(ll, up, &mouse); + } } -- (void)handleKeyEvent:(NSEvent*)ev { - int ch; - MwLL this = [self->handle pointer]; - enum { - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_Return = 0x24, - kVK_Space = 0x31, - kVK_Escape = 0x35, - kVK_Shift = 0x38, - kVK_Control = 0x3B, - kVK_RightShift = 0x3C, - kVK_RightControl = 0x3E, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E - }; -#define KEY_CASE(x, y) \ - case x: \ - ch = y; \ - break; - switch([ev keyCode]) { - KEY_CASE(kVK_ANSI_A, 'a') - KEY_CASE(kVK_ANSI_B, 'b') - KEY_CASE(kVK_ANSI_C, 'c') - KEY_CASE(kVK_ANSI_D, 'd') - KEY_CASE(kVK_ANSI_E, 'e') - KEY_CASE(kVK_ANSI_F, 'f') - KEY_CASE(kVK_ANSI_G, 'g') - KEY_CASE(kVK_ANSI_H, 'h') - KEY_CASE(kVK_ANSI_I, 'i') - KEY_CASE(kVK_ANSI_J, 'j') - KEY_CASE(kVK_ANSI_K, 'k') - KEY_CASE(kVK_ANSI_L, 'l') - KEY_CASE(kVK_ANSI_M, 'm') - KEY_CASE(kVK_ANSI_N, 'n') - KEY_CASE(kVK_ANSI_O, 'o') - KEY_CASE(kVK_ANSI_P, 'p') - KEY_CASE(kVK_ANSI_Q, 'q') - KEY_CASE(kVK_ANSI_R, 'r') - KEY_CASE(kVK_ANSI_S, 's') - KEY_CASE(kVK_ANSI_T, 't') - KEY_CASE(kVK_ANSI_U, 'u') - KEY_CASE(kVK_ANSI_V, 'v') - KEY_CASE(kVK_ANSI_W, 'w') - KEY_CASE(kVK_ANSI_X, 'x') - KEY_CASE(kVK_ANSI_Y, 'y') - KEY_CASE(kVK_ANSI_Z, 'z') - KEY_CASE(kVK_ANSI_0, '0') - KEY_CASE(kVK_ANSI_1, '1') - KEY_CASE(kVK_ANSI_2, '2') - KEY_CASE(kVK_ANSI_3, '3') - KEY_CASE(kVK_ANSI_4, '4') - KEY_CASE(kVK_ANSI_5, '5') - KEY_CASE(kVK_ANSI_6, '6') - KEY_CASE(kVK_ANSI_7, '7') - KEY_CASE(kVK_ANSI_8, '8') - KEY_CASE(kVK_ANSI_9, '9') - KEY_CASE(kVK_ANSI_Quote, '\"') - KEY_CASE(kVK_ANSI_Grave, '`') - KEY_CASE(kVK_ANSI_Backslash, '/') - KEY_CASE(kVK_ANSI_Comma, ',') - KEY_CASE(kVK_ANSI_Equal, '=') - KEY_CASE(kVK_Escape, MwLLKeyEscape) - KEY_CASE(kVK_ANSI_LeftBracket, '[') - KEY_CASE(kVK_ANSI_Minus, '-') - KEY_CASE(kVK_ANSI_Period, '.') - KEY_CASE(kVK_Return, MwLLKeyEnter) - KEY_CASE(kVK_ANSI_RightBracket, ']') - KEY_CASE(kVK_ANSI_Semicolon, ';') - KEY_CASE(kVK_ANSI_Slash, '\\') - KEY_CASE(kVK_Space, ' ') - KEY_CASE(kVK_Control, MwLLKeyControl) - KEY_CASE(kVK_RightControl, MwLLKeyControl) - KEY_CASE(kVK_Shift, MwLLKeyLeftShift) - KEY_CASE(kVK_RightShift, MwLLKeyRightShift) - KEY_CASE(kVK_DownArrow, MwLLKeyDown) - KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) - KEY_CASE(kVK_RightArrow, MwLLKeyRight) - KEY_CASE(kVK_UpArrow, MwLLKeyUp) - } - switch([ev type]) { - case NSKeyDown: - MwLLDispatch(this, key, &ch); - break; - case NSKeyUp: - MwLLDispatch(this, key_released, &ch); - break; - default: - break; - } +- (void)handleKeyEvent:(NSEvent *)ev { + int ch; + MwLL this = [self->handle pointer]; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch ([ev keyCode]) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwLLKeyControl) + KEY_CASE(kVK_RightControl, MwLLKeyControl) + KEY_CASE(kVK_Shift, MwLLKeyLeftShift) + KEY_CASE(kVK_RightShift, MwLLKeyRightShift) + KEY_CASE(kVK_DownArrow, MwLLKeyDown) + KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) + KEY_CASE(kVK_RightArrow, MwLLKeyRight) + KEY_CASE(kVK_UpArrow, MwLLKeyUp) + } + switch ([ev type]) { + case NSKeyDown: + MwLLDispatch(this, key, &ch); + break; + case NSKeyUp: + MwLLDispatch(this, key_released, &ch); + break; + default: + break; + } } - (void)sendClipboardEvent { - /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - NSArray* items = @[ - @"public.utf8-plain-text", - @"public.utf16-external-plain-text", - @"com.apple.traditional-mac-plain-text", - ]; - MwLL this = self->handle.pointer; + /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSArray* items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; - if([pasteboard canReadItemWithDataConformingToTypes:items]) { - char* data = NULL; - size_t size = 0; - for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { - for(NSString* it in items) { - NSString* itemData = [item stringForType:(NSString*)it]; - if(itemData != NULL) { - if(strHash != 0 && strHash != [itemData hash]) { - char* text = malloc([itemData length]); - strncpy(text, [itemData UTF8String], [itemData length]); - MwLLDispatch(this, clipboard, text); - printf("%s -> %p\n", text, this); - free(text); - } - strHash = [itemData hash]; - } - } - } - } + if([pasteboard canReadItemWithDataConformingToTypes:items]) { + char* data = NULL; + size_t size = 0; + for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { + for(NSString* it in items) { + NSString* itemData = [item + stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && + strHash != [itemData hash]) { char* text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], + [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", + text, this); free(text); + } + strHash = [itemData hash]; + } + } + } + } - [pool release];*/ + [pool release];*/ } -- (void)setTitle:(const char*)title { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; +- (void)setTitle:(const char *)title { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MilskoCocoaPixmap* p = pixmap->cocoa.real; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)_rect { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoaPixmap *p = pixmap->cocoa.real; + NSGraphicsContext *ctx = [self->view context]; + if (ctx) { + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [[p image] drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, - _rect->height) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0]; + [[p image] + drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; - [NSGraphicsContext restoreGraphicsState]; + [NSGraphicsContext restoreGraphicsState]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { - (void)pixmap; + (void)pixmap; }; - (void)forceRender { - _forceRender = MwTRUE; + NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; }; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { - (void)image; - (void)mask; +- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { + (void)image; + (void)mask; }; -- (void)detachWithPoint:(MwPoint*)point { - (void)point; +- (void)detachWithPoint:(MwPoint *)point { + (void)point; }; - (void)show:(int)show { - (void)show; + (void)show; }; - (void)makePopupWithParent:(MwLL)_parent { - (void)_parent; + (void)_parent; }; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { - (void)minx; - (void)miny; - (void)maxx; - (void)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { + (void)minx; + (void)miny; + (void)maxx; + (void)maxy; }; - (void)makeBorderless:(int)toggle { - MwU32 mask = [self->window styleMask]; - if(toggle) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; + MwU32 mask = [self->window styleMask]; + if (toggle) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { - [self->window makeMainWindow]; + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - (void)toggle; - /* MacOS didn't have a "pointer grab" function - * until 10.13.2 so I need to do this manually */ + (void)toggle; + /* MacOS didn't have a "pointer grab" function + * until 10.13.2 so I need to do this manually */ }; -- (void)setClipboard:(const char*)text { - (void)text; - // TODO: find out how to do this while supporting 10.4 - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] owner:nil]; - // [pasteboard setString:[NSString stringWithUTF8String:text] forType:NSPasteboardTypeString]; - // [pool release]; +- (void)setClipboard:(const char *)text { + (void)text; + // TODO: find out how to do this while supporting 10.4 + // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] + // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] + // forType:NSPasteboardTypeString]; [pool release]; }; - (void)getClipboard { }; - (void)makeToolWindow { }; -- (void)getCursorCoord:(MwPoint*)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; +- (void)getCursorCoord:(MwPoint *)point { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; }; -- (void)getScreenSize:(MwRect*)_rect { - NSScreen* screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; +- (void)getScreenSize:(MwRect *)_rect { + NSScreen *screen = [self->window screen]; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { - if(self->lastEvent) { - [self->lastEvent release]; - [self->lastEvent dealloc]; - } - [self->handle release]; - [self->handle dealloc]; - [self->window release]; - [self->window dealloc]; + if (self->lastEvent) { + [self->lastEvent release]; + [self->lastEvent dealloc]; + } + [self->handle release]; + [self->handle dealloc]; + [self->window release]; + [self->window dealloc]; } -- (NSWindow*)parentWindow { - NSWindow* topmostWindow = self->window; - while([topmostWindow parentWindow]) - topmostWindow = [topmostWindow parentWindow]; - return topmostWindow; +- (NSWindow *)parentWindow { + NSWindow *topmostWindow = self->window; + while ([topmostWindow parentWindow]) + topmostWindow = [topmostWindow parentWindow]; + return topmostWindow; } -- (NSView*)getView { - return view; +- (NSView *)getView { + return view; } -- (NSWindow*)getWindow { - return window; +- (NSWindow *)getWindow { + return window; } -- (MilskoFakePointer*)getHandle { - return handle; +- (MilskoFakePointer *)getHandle { + return handle; } @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - width = frame.size.width; - height = frame.size.height; - self = [super initWithFrame:frame]; - self->space = CGColorSpaceCreateDeviceRGB(); + width = frame.size.width; + height = frame.size.height; + self = [super initWithFrame:frame]; + self->space = CGColorSpaceCreateDeviceRGB(); - if(width == 0 || height == 0) { - self->rep = NULL; - self->context = NULL; - } else { - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:width * 4 - bitsPerPixel:32]; - assert(self->rep); - [self->rep retain]; + if (width == 0 || height == 0) { + self->rep = NULL; + self->context = NULL; + } else { + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:width + pixelsHigh:height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:width * 4 + bitsPerPixel:32]; + assert(self->rep); + [self->rep retain]; - self->context = - [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; - assert(self->context); - [self->context retain]; - } + self->context = + [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; + assert(self->context); + [self->context retain]; + } - return self; + return self; } -- (NSGraphicsContext*)context { - return self->context; +- (NSGraphicsContext *)context { + return self->context; } -- (NSBitmapImageRep*)getRep { - return self->rep; +- (NSBitmapImageRep *)getRep { + return self->rep; } - (void)drawRect:(NSRect)dirtyRect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSSize sz = [self->rep size]; - [super drawRect:dirtyRect]; - if(!self->rep) { - [pool release]; - return; - } + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSSize sz = [self->rep size]; + [super drawRect:dirtyRect]; + if (!self->rep) { + [pool release]; + return; + } - [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; + [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; - [self->rep bitmapData]; - [pool release]; + [self->rep bitmapData]; + [pool release]; } - (void)destroy { - CGColorSpaceRelease(self->space); - [self->rep release]; - [self->context release]; + CGColorSpaceRelease(self->space); + [self->rep release]; + [self->context release]; } - (void)setFrameSize:(NSSize)newSize { - [super setFrameSize:newSize]; - [self->rep setSize:newSize]; + [super setFrameSize:newSize]; + [self->rep setSize:newSize]; - self->width = newSize.width; - self->height = newSize.height; + self->width = newSize.width; + self->height = newSize.height; } - (void)displayRect:(NSRect)rect { - (void)rect; + (void)rect; }; @end +@implementation MilskoCocoaApplicationDelegate +- (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)_appl { + self->appl = _appl; + return self; +} +- (void)applicationDidFinishLaunching:(NSNotification *)notification { + [self->appl activateIgnoringOtherApps:MwTRUE]; +} +@end + @implementation MilskoCocoaWindowDelegate -- (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; +- (NSSize)windowWillResize:(NSWindow *)win toSize:(NSSize)frameSize; { - if([[[win contentView] subviews] count] >= 1) { - MilskoFakePointer* ptr = [[[win contentView] subviews] objectAtIndex:0]; - MwLL h = [ptr pointer]; + if ([[[win contentView] subviews] count] >= 1) { + MilskoFakePointer *ptr = [[[win contentView] subviews] objectAtIndex:0]; + MwLL h = [ptr pointer]; - // MwLLDispatch(h, resize, NULL); - MwLLDispatch(h, draw, NULL); - } - return frameSize; + // MwLLDispatch(h, resize, NULL); + MwLLDispatch(h, draw, NULL); + } + return frameSize; } -- (void)windowDidResize:(NSNotification*)notification { - (void)notification; +- (void)windowDidResize:(NSNotification *)notification { + (void)notification; } // This will close/terminate the application when the main window is closed. -- (void)windowWillClose:(NSNotification*)notification { - (void)notification; - // MilskoCocoa *window = notification.object; - // MwLL handle = [window getHandle].pointer; - // MwLLDispatch(handle, close, NULL); - [NSApp terminate:nil]; +- (void)windowWillClose:(NSNotification *)notification { + (void)notification; + // MilskoCocoa *window = notification.object; + // MwLL handle = [window getHandle].pointer; + // MwLLDispatch(handle, close, NULL); + [NSApp terminate:nil]; } -- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { - self->w = win; - return self; +- (MilskoCocoaWindowDelegate *)initWithWin:(NSWindow *)win { + self->w = win; + return self; } @end @implementation MilskoFakePointer -- (void)setPointer:(void*)pointer { - [self setFrame:*(NSRect*)&pointer]; - self->ptr = pointer; +- (void)setPointer:(void *)pointer { + [self setFrame:*(NSRect *)&pointer]; + self->ptr = pointer; }; -- (void*)pointer { - return self->ptr; +- (void *)pointer { + return self->ptr; }; - (void)drawRect:(NSRect)dirtyRect { - /* explicitly do nothing */ - (void)dirtyRect; + /* explicitly do nothing */ + (void)dirtyRect; } - (void)destroy { @@ -802,233 +833,219 @@ static NSPoint pointFlip(NSPoint point) { @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; + MwLL r; + (void)x; + (void)y; + (void)width; + (void)height; - r = malloc(sizeof(*r)); + r = malloc(sizeof(*r)); - MwLLCreateCommon(r); + MwLLCreateCommon(r); - MilskoCocoa* o = [MilskoCocoa newWithParent:parent - x:x - y:y - width:width - height:height - handle:r]; - r->cocoa.real = o; + MilskoCocoa *o = [MilskoCocoa newWithParent:parent + x:x + y:y + width:width + height:height + handle:r]; + r->cocoa.real = o; - return r; + return r; } static void MwLLDestroyImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; + MilskoCocoa *h = handle->cocoa.real; - [h destroy]; + [h destroy]; - MwLLDestroyCommon(handle); + MwLLDestroyCommon(handle); - free(handle); + free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; +static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } + +static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, + MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; } -static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, - MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; -} - -static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h lineWithPoints:points color:color]; +static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { + MilskoCocoa *h = handle->cocoa.real; + [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; + (void)handle; - c->common.red = r; - c->common.green = g; - c->common.blue = b; + c->common.red = r; + c->common.green = g; + c->common.blue = b; } -static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, - unsigned int* height) { - MilskoCocoa* h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; +static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, + unsigned int *height) { + MilskoCocoa *h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa* h = handle->cocoa.real; - [h setX:x Y:y]; + MilskoCocoa *h = handle->cocoa.real; + [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa* h = handle->cocoa.real; - [h setW:w H:height]; + MilskoCocoa *h = handle->cocoa.real; + [h setW:w H:height]; } -static void MwLLFreeColorImpl(MwLLColor color) { - free(color); -} +static void MwLLFreeColorImpl(MwLLColor color) { free(color); } static int MwLLPendingImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - if([h pending]) { - MwLLDispatch(handle, draw, NULL); - return 1; - }; - return 0; + MilskoCocoa *h = handle->cocoa.real; + if ([h pending]) { + MwLLDispatch(handle, draw, NULL); + return 1; + }; + return 0; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h getNextEvent]; + MilskoCocoa *h = handle->cocoa.real; + [h getNextEvent]; } -static void MwLLSetTitleImpl(MwLL handle, const char* title) { - MilskoCocoa* h = handle->cocoa.real; - [h setTitle:title]; +static void MwLLSetTitleImpl(MwLL handle, const char *title) { + MilskoCocoa *h = handle->cocoa.real; + [h setTitle:title]; } -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, - int width, int height) { - (void)handle; +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, + int width, int height) { + (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + MwLLPixmap r = malloc(sizeof(*r)); - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - r->common.width = width; - r->common.height = height; + r->common.width = width; + r->common.height = height; - r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; - MwLLPixmapUpdate(r); - free(r->common.raw); - return r; + MwLLPixmapUpdate(r); + free(r->common.raw); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p destroy]; - [p dealloc]; - free(pixmap); + MilskoCocoaPixmap *p = pixmap->cocoa.real; + [p destroy]; + [p dealloc]; + free(pixmap); } -static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; - MwLLForceRender(handle); +static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { + MilskoCocoa *h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; + MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h setIcon:pixmap]; + MilskoCocoa *h = handle->cocoa.real; + [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h forceRender]; + MilskoCocoa *h = handle->cocoa.real; + [h forceRender]; } -static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - MilskoCocoa* h = handle->cocoa.real; - [h setCursor:image mask:mask]; +static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { + MilskoCocoa *h = handle->cocoa.real; + [h setCursor:image mask:mask]; } -static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h detachWithPoint:point]; +static void MwLLDetachImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa* h = handle->cocoa.real; - [h show:show]; + MilskoCocoa *h = handle->cocoa.real; + [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa* h = handle->cocoa.real; - [h makePopupWithParent:parent]; + MilskoCocoa *h = handle->cocoa.real; + [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, - int maxy) { - MilskoCocoa* h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + int maxy) { + MilskoCocoa *h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h makeBorderless:toggle]; + MilskoCocoa *h = handle->cocoa.real; + [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h focus]; + MilskoCocoa *h = handle->cocoa.real; + [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h grabPointer:toggle]; + MilskoCocoa *h = handle->cocoa.real; + [h grabPointer:toggle]; } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { - MilskoCocoa* h = handle->cocoa.real; - [h setClipboard:text]; +static void MwLLSetClipboardImpl(MwLL handle, const char *text) { + MilskoCocoa *h = handle->cocoa.real; + [h setClipboard:text]; } -static void MwLLGetClipboardImpl(MwLL handle) { - (void)handle; -} +static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } static void MwLLMakeToolWindowImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h makeToolWindow]; + MilskoCocoa *h = handle->cocoa.real; + [h makeToolWindow]; } -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h getCursorCoord:point]; +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { + MilskoCocoa *h = handle->cocoa.real; + [h getCursorCoord:point]; } -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - MilskoCocoa* h = handle->cocoa.real; - [h getScreenSize:rect]; +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { + MilskoCocoa *h = handle->cocoa.real; + [h getScreenSize:rect]; } -static void MwLLBeginStateChangeImpl(MwLL handle) { - MwLLShow(handle, 0); -} +static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } -static void MwLLEndStateChangeImpl(MwLL handle) { - MwLLShow(handle, 1); -} +static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } -static int MwLLCocoaCallInitImpl(void) { - return 0; -} +static int MwLLCocoaCallInitImpl(void) { return 0; } #include "call.c" CALL(Cocoa); From 75c9af91d1848d835f6fd870bb6386ab79f870e8 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 8 Mar 2026 19:15:17 -0700 Subject: [PATCH 163/409] mac: try and fix positioning for child windows --- include/Mw/LowLevel/Cocoa.h | 2 +- src/backend/cocoa.m | 70 ++++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 2789af904..dc81195e4 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -22,7 +22,7 @@ #endif // Note: implements NSApplicationDelegate -@interface MilskoCocoaApplicationDelegate : NSObject { +@interface MilskoCocoaApplicationDelegate : NSObject { NSApplication *appl; } - (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)appl; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 7f07ffbf4..3e30503ef 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,5 +1,7 @@ #include "Mw/BaseTypes.h" +#include #include +#include #include #ifdef __clang__ @@ -102,24 +104,23 @@ static NSPoint pointFlip(NSPoint point) { backing:NSBackingStoreBuffered defer:NO]; } else { - double offset = 0; - NSWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]] - .size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + double offset = 0; + NSWindow* parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - c->rect.origin.x += [parentWindow frame].origin.x; - c->rect.origin.y -= [parentWindow frame].origin.y - offset; - c->rect.origin.y -= offset; + c->rect.origin.x += [parentWindow frame].origin.x; + c->rect.origin.y -= [parentWindow frame].origin.y - offset; + c->rect.origin.y -= offset; - c->window = [[NSWindow alloc] initWithContentRect:c->rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; + c->window = [[NSWindow alloc] initWithContentRect:c->rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; } [c->window - setDelegate:(id)[[MilskoCocoaWindowDelegate alloc] + setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; [c->window makeKeyAndOrderFront:c->application]; @@ -127,8 +128,17 @@ static NSPoint pointFlip(NSPoint point) { if (parent != NULL) { MilskoCocoa *p = parent->cocoa.real; + double offset = 0; + offset = + [p->window frameRectForContentRect:[p->window frame]].size.height - + [p->window contentRectForFrameRect:[p->window frame]].size.height; [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; + [c->window setParentWindow:p->window]; + + c->rect.origin.x += [p->window frame].origin.x; + c->rect.origin.y -= [p->window frame].origin.y - offset; + c->rect.origin.y -= offset; } else { [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; @@ -202,6 +212,11 @@ static NSPoint pointFlip(NSPoint point) { NSRect frame = rectFlip([self->window frame]); frame = rectFlip(frame); + if(parent) { + frame.origin.x -= [parent->cocoa.real->window frame].origin.x; + frame.origin.y += [parent->cocoa.real->window frame].origin.y; + } + *x = frame.origin.x; *y = frame.origin.y; @@ -216,24 +231,21 @@ static NSPoint pointFlip(NSPoint point) { frame = rectFlip(frame); - if (parent) { - double offset = 0; - NSWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]] - .size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - - if (x < [parentWindow frame].origin.x) { - frame.origin.x += [parentWindow frame].origin.x; - } + if(parent) { + double offset = 0; + NSWindow* parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + frame.origin.x += [parentWindow frame].origin.x; frame.origin.y -= [parentWindow frame].origin.y - offset; frame.origin.y -= offset; - } + } + [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; + [self->window setFrameOrigin:frame.origin]; [self forceRender]; }; @@ -583,7 +595,8 @@ static NSPoint pointFlip(NSPoint point) { (void)pixmap; }; - (void)forceRender { - NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0 @@ -593,6 +606,7 @@ static NSPoint pointFlip(NSPoint point) { data1:0 data2:0]; [NSApp postEvent:event atStart:YES]; + [pool release]; }; - (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { (void)image; From 21d5625ec70fc4a76376b9727c13ee1f0c8bca4f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sun, 8 Mar 2026 20:03:47 -0700 Subject: [PATCH 164/409] fix forceRender, at the cost of breaking the rotate example --- src/backend/cocoa.m | 28 +++++++++++++++------------- src/widget/opengl_cocoa.m | 25 ++++++++----------------- 2 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 3e30503ef..169cb1cc2 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -140,6 +140,7 @@ static NSPoint pointFlip(NSPoint point) { c->rect.origin.y -= [p->window frame].origin.y - offset; c->rect.origin.y -= offset; } else { + [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; } @@ -279,7 +280,7 @@ static NSPoint pointFlip(NSPoint point) { }; - (void)getNextEvent { - + [self eventProcess:self->lastEvent]; while (true) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSEvent *ev = [self->window nextEventMatchingMask:NSAnyEventMask @@ -595,18 +596,19 @@ static NSPoint pointFlip(NSPoint point) { (void)pixmap; }; - (void)forceRender { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined - location:NSMakePoint(0, 0) - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:0 - data1:0 - data2:0]; - [NSApp postEvent:event atStart:YES]; - [pool release]; + self->_forceRender = MwTRUE; + // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + // NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + // location:NSMakePoint(0, 0) + // modifierFlags:0 + // timestamp:0 + // windowNumber:0 + // context:nil + // subtype:0 + // data1:0 + // data2:0]; + // [NSApp postEvent:event atStart:YES]; + // [pool release]; }; - (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { (void)image; diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index c33e3754d..15c1198de 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -1,5 +1,6 @@ #include "Mw/BaseTypes.h" #include "Mw/Core.h" +#include "Mw/LowLevel/Cocoa.h" #include "Mw/StringDefs.h" #include #include @@ -8,9 +9,10 @@ @interface MacOpenGLWidget : NSObject { NSOpenGLPixelFormat *pixelFormat; NSOpenGLContext *glc; + MilskoCocoa * _win; } -- (MacOpenGLWidget *)initWithView:(NSView *)view; +- (MacOpenGLWidget *)initWithWindow:(MilskoCocoa *)w; - (void)destroy; - (void)makeCurrent; - (void)swapBuffer; @@ -30,7 +32,7 @@ static int create(MwWidget handle) { printf("%d %d\n", width, height); handle->internal = [[MacOpenGLWidget alloc] - initWithView:[handle->lowlevel->cocoa.real getView]]; + initWithWindow:handle->lowlevel->cocoa.real]; handle->lowlevel->common.copy_buffer = 0; MwSetDefault(handle); @@ -75,7 +77,7 @@ static void func_handler(MwWidget handle, const char *name, void *out, @implementation MacOpenGLWidget -- (MacOpenGLWidget *)initWithView:(NSView *)view { +- (MacOpenGLWidget *)initWithWindow:(MilskoCocoa *)w { NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { NSOpenGLPFAColorSize, 24, NSOpenGLPFAStencilSize, 8, @@ -86,7 +88,8 @@ static void func_handler(MwWidget handle, const char *name, void *out, [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; self->glc = [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - [self->glc setView:view]; + [self->glc setView:[w getView]]; + self->_win = w; return self; }; - (void)destroy { @@ -95,19 +98,7 @@ static void func_handler(MwWidget handle, const char *name, void *out, [self->glc makeCurrentContext]; }; - (void)swapBuffer { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [NSEvent otherEventWithType:NSEventTypeApplicationDefined - location:NSMakePoint(0, 0) - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:0 - data1:0 - data2:0]; - [NSApp postEvent:event atStart:YES]; - [pool release]; - + [self->_win forceRender]; [self->glc flushBuffer]; }; - (void *)getProcAddressWithName:(const char *)name { From 9eda46d981eb5d3362c6577bf3b073940eb7d48b Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sun, 8 Mar 2026 23:38:57 -0500 Subject: [PATCH 165/409] mac: remove accidental includes --- src/backend/cocoa.m | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 169cb1cc2..6ab2272ca 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,8 +1,4 @@ -#include "Mw/BaseTypes.h" -#include #include -#include -#include #ifdef __clang__ #pragma clang push From 65afd85439d95e9819867e2f37e8cfb42fcab5df Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 14:01:54 -0700 Subject: [PATCH 166/409] mac: most window functions now implemented (save for makeToolWindow) --- include/Mw/LowLevel/Cocoa.h | 17 ++-- src/backend/cocoa.m | 164 +++++++++++++++++++++++++++--------- 2 files changed, 134 insertions(+), 47 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index dc81195e4..865d774c7 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -28,11 +28,15 @@ - (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)appl; @end +@interface MilskoCocoaWindow : NSWindow { +} +@end + // Note: implements NSWindowDelegate @interface MilskoCocoaWindowDelegate : NSObject { - NSWindow *w; + MilskoCocoaWindow *w; } -- (MilskoCocoaWindowDelegate *)initWithWin:(NSWindow *)win; +- (MilskoCocoaWindowDelegate *)initWithWin:(MilskoCocoaWindow *)win; @end @interface MilskoFakePointer : NSView { @@ -82,13 +86,16 @@ @interface MilskoCocoa : NSObject { NSApplication *application; MwBool _forceRender; - NSWindow *window; + MilskoCocoaWindow *window; NSRect rect; MilskoCocoaView *view; MwLL parent; MilskoFakePointer *handle; unsigned int strHash; NSEvent *lastEvent; + + MilskoCocoaPixmap *cursorPixmap; + NSCursor *cursor; } + (MilskoCocoa *)newWithParent:(MwLL)parent @@ -131,9 +138,9 @@ - (void)destroy; - (void)sendClipboardEvent; -- (NSWindow *)parentWindow; +- (MilskoCocoaWindow *)parentWindow; - (NSView *)getView; -- (NSWindow *)getWindow; +- (MilskoCocoaWindow *)getWindow; - (MilskoFakePointer *)getHandle; @end diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 6ab2272ca..5aa52bc93 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,4 @@ +#include "Mw/BaseTypes.h" #include #ifdef __clang__ @@ -93,41 +94,43 @@ static NSPoint pointFlip(NSPoint point) { c->rect = rectFlip(NSMakeRect(x, y, width, height)); if (parent == NULL) { - c->window = [[NSWindow alloc] + c->window = [[MilskoCocoaWindow alloc] initWithContentRect:c->rect - styleMask:(NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask | NSResizableWindowMask) + styleMask:(NSTitledWindowMask | + NSTexturedBackgroundWindowMask | + NSClosableWindowMask | NSMiniaturizableWindowMask | + NSResizableWindowMask) backing:NSBackingStoreBuffered defer:NO]; } else { - double offset = 0; - NSWindow* parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + double offset = 0; + MilskoCocoaWindow *parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]] + .size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - c->rect.origin.x += [parentWindow frame].origin.x; - c->rect.origin.y -= [parentWindow frame].origin.y - offset; - c->rect.origin.y -= offset; + c->rect.origin.x += [parentWindow frame].origin.x; + c->rect.origin.y -= [parentWindow frame].origin.y - offset; + c->rect.origin.y -= offset; - c->window = [[NSWindow alloc] initWithContentRect:c->rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; + c->window = + [[MilskoCocoaWindow alloc] initWithContentRect:c->rect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; } [c->window - setDelegate:[[MilskoCocoaWindowDelegate alloc] - initWithWin:c->window]]; + setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; [c->window makeKeyAndOrderFront:c->application]; [c->window retain]; if (parent != NULL) { MilskoCocoa *p = parent->cocoa.real; - double offset = 0; - offset = - [p->window frameRectForContentRect:[p->window frame]].size.height - - [p->window contentRectForFrameRect:[p->window frame]].size.height; + double offset = 0; + offset = [p->window frameRectForContentRect:[p->window frame]].size.height - + [p->window contentRectForFrameRect:[p->window frame]].size.height; [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; [c->window setParentWindow:p->window]; @@ -139,10 +142,11 @@ static NSPoint pointFlip(NSPoint point) { [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; + [c->window makeKeyAndOrderFront:nil]; } - [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; + [c->application retain]; c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; [c->view retain]; @@ -158,6 +162,8 @@ static NSPoint pointFlip(NSPoint point) { c->_forceRender = MwTRUE; c->strHash = 0; + c->cursorPixmap = NULL; + [c->application finishLaunching]; return c; @@ -209,7 +215,7 @@ static NSPoint pointFlip(NSPoint point) { NSRect frame = rectFlip([self->window frame]); frame = rectFlip(frame); - if(parent) { + if (parent) { frame.origin.x -= [parent->cocoa.real->window frame].origin.x; frame.origin.y += [parent->cocoa.real->window frame].origin.y; } @@ -228,17 +234,18 @@ static NSPoint pointFlip(NSPoint point) { frame = rectFlip(frame); - if(parent) { - double offset = 0; - NSWindow* parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]].size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + if (parent) { + double offset = 0; + MilskoCocoaWindow *parentWindow = parent->cocoa.real->window; + offset = + [parentWindow frameRectForContentRect:[parentWindow frame]] + .size.height - + [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; frame.origin.x += [parentWindow frame].origin.x; frame.origin.y -= [parentWindow frame].origin.y - offset; frame.origin.y -= offset; - } + } [self->view setFrameSize:frame.size]; @@ -336,9 +343,11 @@ static NSPoint pointFlip(NSPoint point) { } case NSMouseEntered: MwLLDispatch(h, focus_in, NULL); + [self->cursor push]; break; case NSMouseExited: MwLLDispatch(h, focus_out, NULL); + [self->cursor pop]; break; case NSKeyDown: case NSKeyUp: { @@ -346,10 +355,12 @@ static NSPoint pointFlip(NSPoint point) { doSendEvent = MwFALSE; } case NSCursorUpdate: + [self->cursor set]; break; case NSScrollWheel: break; default: + doSendEvent = MwFALSE; break; }; if (doSendEvent) { @@ -589,7 +600,7 @@ static NSPoint pointFlip(NSPoint point) { [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { - (void)pixmap; + [self->application setApplicationIconImage:[pixmap->cocoa.real image]]; }; - (void)forceRender { self->_forceRender = MwTRUE; @@ -607,11 +618,63 @@ static NSPoint pointFlip(NSPoint point) { // [pool release]; }; - (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { - (void)image; - (void)mask; + int y, x, ys, xs; + unsigned char *di = malloc(image->width * image->height * 4); + memset(di, 0, image->width * image->height * 4); + + if (self->cursorPixmap) { + [self->cursorPixmap destroy]; + } + self->cursorPixmap = + [MilskoCocoaPixmap newWithWidth:image->width height:image->height]; + + xs = -mask->x + image->x; + ys = MwCursorDataHeight + mask->y; + ys = MwCursorDataHeight + image->y - ys; + + for (y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for (x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; + + if (d & 1) { + di[idx + 3] = 255; + }; + d = d >> 1; + } + } + for (y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for (x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; + + if (d & 1) { + px = 255; + }; + + di[idx] = px; + di[idx + 1] = px; + di[idx + 2] = px; + d = d >> 1; + } + } + + [self->cursorPixmap updateWithData:di]; + + self->cursor = [[NSCursor alloc] + initWithImage:[self->cursorPixmap image] + hotSpot:NSMakePoint(image->x, image->y + image->height)]; + [self->cursor retain]; + + [self->cursor pop]; + [self->cursor push]; + + free(di); }; - (void)detachWithPoint:(MwPoint *)point { - (void)point; + [self->window setParentWindow:NULL]; }; - (void)show:(int)show { (void)show; @@ -623,10 +686,8 @@ static NSPoint pointFlip(NSPoint point) { MinY:(int)miny MaxX:(int)maxx MaxY:(int)maxy { - (void)minx; - (void)miny; - (void)maxx; - (void)maxy; + [self->window setMinSize:NSMakeSize(minx, miny)]; + [self->window setMaxSize:NSMakeSize(maxx, maxy)]; }; - (void)makeBorderless:(int)toggle { MwU32 mask = [self->window styleMask]; @@ -659,8 +720,6 @@ static NSPoint pointFlip(NSPoint point) { // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] // forType:NSPasteboardTypeString]; [pool release]; }; -- (void)getClipboard { -}; - (void)makeToolWindow { }; - (void)getCursorCoord:(MwPoint *)point { @@ -703,6 +762,7 @@ static NSPoint pointFlip(NSPoint point) { - (MilskoFakePointer *)getHandle { return handle; } + @end @implementation MilskoCocoaView @@ -787,8 +847,15 @@ static NSPoint pointFlip(NSPoint point) { self->appl = _appl; return self; } +- (void)applicationDidBecomeActive:(NSNotification *)notification { + printf("test\n"); +} +- (void)applicationWillFinishLaunching:(NSNotification *)notification { + // printf("test\n"); + // [self->appl activateIgnoringOtherApps:MwTRUE]; +} - (void)applicationDidFinishLaunching:(NSNotification *)notification { - [self->appl activateIgnoringOtherApps:MwTRUE]; + // [self->appl activateIgnoringOtherApps:MwTRUE]; } @end @@ -806,6 +873,10 @@ static NSPoint pointFlip(NSPoint point) { return frameSize; } +- (void)windowDidBecomeMain:(NSNotification *)notification { + printf("waow\n"); +} + - (void)windowDidResize:(NSNotification *)notification { (void)notification; } @@ -842,8 +913,17 @@ static NSPoint pointFlip(NSPoint point) { - (void)destroy { } - @end + +@implementation MilskoCocoaWindow +- (BOOL)canBecomeKeyWindow { + return true; +} +- (BOOL)canBecomeMainWindow { + return true; +} +@end + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; (void)x; From 128a1ec5243ebd5e84d9d9b32fe8a47833e75147 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 15:07:46 -0700 Subject: [PATCH 167/409] mac: 'implement' tool windows --- src/backend/cocoa.m | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 5aa52bc93..56a68fd84 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -294,11 +294,15 @@ static NSPoint pointFlip(NSPoint point) { [pool release]; break; } + /* run through the switch case on ev.type, before calling sendEvent on any + * events we handle */ [self eventProcess:ev]; [pool release]; } [self sendClipboardEvent]; + + [self->application updateWindows]; }; - (void)eventProcess:(NSEvent *)ev { @@ -721,6 +725,11 @@ static NSPoint pointFlip(NSPoint point) { // forType:NSPasteboardTypeString]; [pool release]; }; - (void)makeToolWindow { + /* If my understand of what a "tool window" usually is is correct then I + * highly doubt the Mac OS has this and if they did they probably outright + * removed it along time ago is this kind of conflicts with modern UX. So + * we'll just make it borderless idgaf */ + [self makeBorderless:MwTRUE]; }; - (void)getCursorCoord:(MwPoint *)point { NSPoint p = [NSEvent mouseLocation]; From dccc402b3d2cc6cdc27a7d4895a9e50b7d4048f5 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 16:13:49 -0700 Subject: [PATCH 168/409] mac: send mouse/key to both event itself and window, evidently --- src/backend/cocoa.m | 46 +++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 56a68fd84..1260c2539 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,4 +1,3 @@ -#include "Mw/BaseTypes.h" #include #ifdef __clang__ @@ -166,6 +165,8 @@ static NSPoint pointFlip(NSPoint point) { [c->application finishLaunching]; + c->pointerLocked = MwFALSE; + return c; } - (void)polygonWithPoints:(MwPoint *)points @@ -298,10 +299,19 @@ static NSPoint pointFlip(NSPoint point) { * events we handle */ [self eventProcess:ev]; [pool release]; + [self->application updateWindows]; } [self sendClipboardEvent]; + if (self->pointerLocked && [self->window isMainWindow]) { + NSPoint pos = [window frame].origin; + pos.x += [window frame].size.width / 2; + pos.y += [window frame].size.height / 2; + + CGWarpMouseCursorPosition(pos); + } + [self->application updateWindows]; }; @@ -339,9 +349,10 @@ static NSPoint pointFlip(NSPoint point) { case NSOtherMouseDragged: case NSMouseMoved: { MwPoint pos; - pos.x = [ev locationInWindow].x; - pos.y = [win contentRectForFrameRect:[win frame]].size.height - - [ev locationInWindow].y; + NSPoint pos_translated = pointFlip([ev locationInWindow]); + pos.x = pos_translated.x; + pos.y = pos_translated.y; + printf("%d %d\n", pos.x, pos.y); MwLLDispatch(h, move, &pos); break; } @@ -355,8 +366,7 @@ static NSPoint pointFlip(NSPoint point) { break; case NSKeyDown: case NSKeyUp: { - [self handleKeyEvent:ev]; - doSendEvent = MwFALSE; + [self handleKeyEvent:ev ll:h]; } case NSCursorUpdate: [self->cursor set]; @@ -364,12 +374,9 @@ static NSPoint pointFlip(NSPoint point) { case NSScrollWheel: break; default: - doSendEvent = MwFALSE; break; }; - if (doSendEvent) { - [win sendEvent:ev]; - } + [win sendEvent:ev]; [pool release]; } @@ -378,6 +385,7 @@ static NSPoint pointFlip(NSPoint point) { MwLLMouse mouse; MwBool isDown = MwTRUE; NSPoint mousePoint = pointFlip([ev locationInWindow]); + MwLL this = [self->handle pointer]; switch ([ev type]) { case NSLeftMouseUp: isDown = MwFALSE; @@ -401,13 +409,15 @@ static NSPoint pointFlip(NSPoint point) { mouse.point.y = mousePoint.y; if (isDown) { + MwLLDispatch(this, down, &mouse); MwLLDispatch(ll, down, &mouse); } else { + MwLLDispatch(this, up, &mouse); MwLLDispatch(ll, up, &mouse); } } -- (void)handleKeyEvent:(NSEvent *)ev { +- (void)handleKeyEvent:(NSEvent *)ev ll:(MwLL)ll { int ch; MwLL this = [self->handle pointer]; enum { @@ -537,9 +547,11 @@ static NSPoint pointFlip(NSPoint point) { switch ([ev type]) { case NSKeyDown: MwLLDispatch(this, key, &ch); + MwLLDispatch(ll, key, &ch); break; case NSKeyUp: MwLLDispatch(this, key_released, &ch); + MwLLDispatch(ll, key_released, &ch); break; default: break; @@ -711,9 +723,7 @@ static NSPoint pointFlip(NSPoint point) { [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - (void)toggle; - /* MacOS didn't have a "pointer grab" function - * until 10.13.2 so I need to do this manually */ + self->pointerLocked = toggle; }; - (void)setClipboard:(const char *)text { (void)text; @@ -849,6 +859,14 @@ static NSPoint pointFlip(NSPoint point) { (void)rect; }; +- (BOOL)acceptsFirstResponder { + return MwTRUE; +} +- (BOOL)performKeyEquivalent:(NSEvent *)event { + (void)event; + return MwTRUE; +} + @end @implementation MilskoCocoaApplicationDelegate From dd67e42054cb915195d22b413c2e1144c49b7318 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 16:14:48 -0700 Subject: [PATCH 169/409] mac: remove debug prints --- include/Mw/LowLevel/Cocoa.h | 4 +++- src/backend/cocoa.m | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 865d774c7..2664b0d10 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -96,6 +96,8 @@ MilskoCocoaPixmap *cursorPixmap; NSCursor *cursor; + + MwBool pointerLocked; } + (MilskoCocoa *)newWithParent:(MwLL)parent @@ -113,7 +115,7 @@ - (void)setW:(int)w H:(int)h; - (int)pending; - (void)eventProcess:(NSEvent *)ev; -- (void)handleKeyEvent:(NSEvent *)ev; +- (void)handleKeyEvent:(NSEvent *)ev ll:(MwLL)ll; - (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll; - (void)getNextEvent; - (void)setTitle:(const char *)title; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1260c2539..9175a07c0 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -352,7 +352,6 @@ static NSPoint pointFlip(NSPoint point) { NSPoint pos_translated = pointFlip([ev locationInWindow]); pos.x = pos_translated.x; pos.y = pos_translated.y; - printf("%d %d\n", pos.x, pos.y); MwLLDispatch(h, move, &pos); break; } @@ -901,7 +900,6 @@ static NSPoint pointFlip(NSPoint point) { } - (void)windowDidBecomeMain:(NSNotification *)notification { - printf("waow\n"); } - (void)windowDidResize:(NSNotification *)notification { From 3f84b0f868f0106b01beea8174f31d7ec8374c5e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 16:19:12 -0700 Subject: [PATCH 170/409] mac: document MilskoFakePointer --- include/Mw/LowLevel/Cocoa.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 2664b0d10..5543d7e21 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -39,6 +39,18 @@ - (MilskoCocoaWindowDelegate *)initWithWin:(MilskoCocoaWindow *)win; @end +/* + So we want to associate each NSWindow with its corresponding MwLL handle. The + conventional way of doing this is through "associative pointers", however + this is a feature that Apple added in 10.6 (marketted back then as "Objective + C 2" iirc). For 10.4 compatibility, we have to do a bit of an ugly hack that + might seem like horrifically undefined behavior, but I've tested this on + both 10.4 and modern Mac OS and as long as we're careful there's no + problems: we override NSView, use NSView's "frame" property to store the + pointer, and then override functions appropriately so that this frame is never + actually used. This can then be attached to an NSWindow with addSubview and + retrieved appropriately. + */ @interface MilskoFakePointer : NSView { void *ptr; } From 4ca11145f1ffb08c200f22ad053847222375358a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 9 Mar 2026 16:35:09 -0700 Subject: [PATCH 171/409] some 10.4 fixes --- src/backend/cocoa.m | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 9175a07c0..e90d51215 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -138,7 +138,9 @@ static NSPoint pointFlip(NSPoint point) { c->rect.origin.y -= [p->window frame].origin.y - offset; c->rect.origin.y -= offset; } else { - [c->application setActivationPolicy:NSApplicationActivationPolicyRegular]; + if ([c->application respondsToSelector:@selector(setActivationPolicy:)]) { + [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; + } [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; [c->window makeKeyAndOrderFront:nil]; @@ -305,9 +307,9 @@ static NSPoint pointFlip(NSPoint point) { [self sendClipboardEvent]; if (self->pointerLocked && [self->window isMainWindow]) { - NSPoint pos = [window frame].origin; - pos.x += [window frame].size.width / 2; - pos.y += [window frame].size.height / 2; + struct CGPoint pos; + pos.x = [window frame].origin.x + [window frame].size.width / 2; + pos.y = [window frame].origin.y + [window frame].size.height / 2; CGWarpMouseCursorPosition(pos); } From a0e2ec7f57491aa7cc978ac7296f6c320168d450 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 9 Mar 2026 16:40:30 -0700 Subject: [PATCH 172/409] undo sending mouse event to both the parent and widget itself, forgot that that's exactly something we don't want to do --- src/backend/cocoa.m | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index e90d51215..fdf12c38f 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -139,7 +139,8 @@ static NSPoint pointFlip(NSPoint point) { c->rect.origin.y -= offset; } else { if ([c->application respondsToSelector:@selector(setActivationPolicy:)]) { - [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; + [c->application + setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; } [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; @@ -410,10 +411,8 @@ static NSPoint pointFlip(NSPoint point) { mouse.point.y = mousePoint.y; if (isDown) { - MwLLDispatch(this, down, &mouse); MwLLDispatch(ll, down, &mouse); } else { - MwLLDispatch(this, up, &mouse); MwLLDispatch(ll, up, &mouse); } } From 9f1b455341de321a146c6ba797d5c592b89e95e4 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 10 Mar 2026 15:33:20 -0700 Subject: [PATCH 173/409] mac: new event pumping architecture that sucks and i hate it but apple is happy with it so we're happy with it --- include/Mw/LowLevel/Cocoa.h | 1 + src/backend/cocoa.m | 47 ++++++++++--------------------------- 2 files changed, 14 insertions(+), 34 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 5543d7e21..445af0e5f 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -156,6 +156,7 @@ - (NSView *)getView; - (MilskoCocoaWindow *)getWindow; - (MilskoFakePointer *)getHandle; ++ (void)eventCanceller:(MilskoCocoa *)this; @end #define OBJC(x) x diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index fdf12c38f..edf5cfd3a 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -142,9 +142,9 @@ static NSPoint pointFlip(NSPoint point) { [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; } + [c->window makeKeyAndOrderFront:nil]; [c->application activateIgnoringOtherApps:true]; [c->window makeFirstResponder:c->view]; - [c->window makeKeyAndOrderFront:nil]; } [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; @@ -172,6 +172,13 @@ static NSPoint pointFlip(NSPoint point) { return c; } ++ (void)eventCanceller:(MilskoCocoa *)this { + this->lastEvent = [this->application currentEvent]; + [this eventProcess:this->lastEvent]; + + [[NSApplication sharedApplication] stop:nil]; +} + - (void)polygonWithPoints:(MwPoint *)points points_count:(int)points_count color:(MwLLColor)color { @@ -269,42 +276,14 @@ static NSPoint pointFlip(NSPoint point) { [self forceRender]; }; - (int)pending { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - MwBool isPending = MwFALSE; - if (_forceRender) { - _forceRender = MwFALSE; - [pool release]; - return 1; - } - self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - - isPending = self->lastEvent != NULL; - [pool release]; - return isPending; + [MilskoCocoa performSelectorOnMainThread:@selector(eventCanceller:) + withObject:self + waitUntilDone:NO]; + [self->application run]; + return 1; }; - (void)getNextEvent { - [self eventProcess:self->lastEvent]; - while (true) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *ev = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (!ev) { - [pool release]; - break; - } - /* run through the switch case on ev.type, before calling sendEvent on any - * events we handle */ - [self eventProcess:ev]; - [pool release]; - [self->application updateWindows]; - } - [self sendClipboardEvent]; if (self->pointerLocked && [self->window isMainWindow]) { From 8f379e97513a4416541960c95c6d97f34bc58ca5 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 10 Mar 2026 15:46:46 -0700 Subject: [PATCH 174/409] add comment clarifying pending --- src/backend/cocoa.m | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index edf5cfd3a..eeae8567c 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -276,6 +276,21 @@ static NSPoint pointFlip(NSPoint point) { [self forceRender]; }; - (int)pending { + /* + ok so this is a crime against god but I did in fact try the better method + of using nextEventMatchingMask and then pumping events manually. However + this gives me something that only kind of works, with strange behavior such + as the window never becoming the main window (have to make it key in order + for the menu to show up) occuring. Hours of research and digging led me down + a rabbit hole that, on all sides, pointed to "just use [NSApplication run]". + So we just to do that; of course, this is a blocking function, so we + register this function that instantly cancels it and pumps whatever event + MacOS has in store for us. We do this on loop and somehow the resulting CPU + usage is managable. + + If some Apple developer with 20 years of experience in Objective C is here: + Pls god send PR if you know how to properly do this. +*/ [MilskoCocoa performSelectorOnMainThread:@selector(eventCanceller:) withObject:self waitUntilDone:NO]; From d3c30bf6d3889de3225d70d2f0779073f710c39c Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 10 Mar 2026 16:31:27 -0700 Subject: [PATCH 175/409] mac: mouse fixing, somewwhat. also just always send events for a bit --- include/Mw/LowLevel/Cocoa.h | 1 + src/backend/cocoa.m | 17 ++++++++++++++++- src/widget/opengl_cocoa.m | 7 +++---- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 445af0e5f..bc65d9626 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -110,6 +110,7 @@ NSCursor *cursor; MwBool pointerLocked; + MwBool mouseMoved; } + (MilskoCocoa *)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index eeae8567c..8b96fe70c 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -176,6 +176,21 @@ static NSPoint pointFlip(NSPoint point) { this->lastEvent = [this->application currentEvent]; [this eventProcess:this->lastEvent]; + if (this->_forceRender) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + [NSApp postEvent:event atStart:YES]; + [pool release]; + } + [[NSApplication sharedApplication] stop:nil]; } @@ -301,7 +316,7 @@ static NSPoint pointFlip(NSPoint point) { - (void)getNextEvent { [self sendClipboardEvent]; - if (self->pointerLocked && [self->window isMainWindow]) { + if (self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { struct CGPoint pos; pos.x = [window frame].origin.x + [window frame].size.width / 2; pos.y = [window frame].origin.y + [window frame].size.height / 2; diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index 15c1198de..503fe5e7b 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -9,7 +9,7 @@ @interface MacOpenGLWidget : NSObject { NSOpenGLPixelFormat *pixelFormat; NSOpenGLContext *glc; - MilskoCocoa * _win; + MilskoCocoa *_win; } - (MacOpenGLWidget *)initWithWindow:(MilskoCocoa *)w; @@ -31,8 +31,8 @@ static int create(MwWidget handle) { printf("%d %d\n", width, height); - handle->internal = [[MacOpenGLWidget alloc] - initWithWindow:handle->lowlevel->cocoa.real]; + handle->internal = + [[MacOpenGLWidget alloc] initWithWindow:handle->lowlevel->cocoa.real]; handle->lowlevel->common.copy_buffer = 0; MwSetDefault(handle); @@ -98,7 +98,6 @@ static void func_handler(MwWidget handle, const char *name, void *out, [self->glc makeCurrentContext]; }; - (void)swapBuffer { - [self->_win forceRender]; [self->glc flushBuffer]; }; - (void *)getProcAddressWithName:(const char *)name { From d9ee157ee8664811d7fb24b09b306c6f625e6a3d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 10 Mar 2026 17:10:47 -0700 Subject: [PATCH 176/409] mac: support delayed creation of the view's context, for anything whose size starts at 0x0 --- include/Mw/LowLevel/Cocoa.h | 4 ++- src/backend/cocoa.m | 65 +++++++++++++++++++++++-------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index bc65d9626..7a8466b23 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -89,6 +89,7 @@ float height; } +- (void)initRepAndContextWithWidth:(float)w Height:(float)h; - (NSGraphicsContext *)context; - (void)destroy; - (NSBitmapImageRep *)getRep; @@ -153,9 +154,10 @@ - (void)destroy; - (void)sendClipboardEvent; -- (MilskoCocoaWindow *)parentWindow; +- (MwLL)getParent; - (NSView *)getView; - (MilskoCocoaWindow *)getWindow; + - (MilskoFakePointer *)getHandle; + (void)eventCanceller:(MilskoCocoa *)this; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 8b96fe70c..1d5d3ce5a 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -773,11 +773,8 @@ static NSPoint pointFlip(NSPoint point) { [self->window dealloc]; } -- (NSWindow *)parentWindow { - NSWindow *topmostWindow = self->window; - while ([topmostWindow parentWindow]) - topmostWindow = [topmostWindow parentWindow]; - return topmostWindow; +- (MwLL)getParent { + return self->parent; } - (NSView *)getView { @@ -804,24 +801,7 @@ static NSPoint pointFlip(NSPoint point) { self->rep = NULL; self->context = NULL; } else { - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:width - pixelsHigh:height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:width * 4 - bitsPerPixel:32]; - assert(self->rep); - [self->rep retain]; - - self->context = - [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; - assert(self->context); - [self->context retain]; + [self initRepAndContextWithWidth:width Height:height]; } return self; @@ -840,8 +820,15 @@ static NSPoint pointFlip(NSPoint point) { NSSize sz = [self->rep size]; [super drawRect:dirtyRect]; if (!self->rep) { - [pool release]; - return; + if (dirtyRect.size.width && dirtyRect.size.height) { + [self initRepAndContextWithWidth:dirtyRect.size.width + Height:dirtyRect.size.height]; + self->width = dirtyRect.size.width; + self->height = dirtyRect.size.height; + } else { + [pool release]; + return; + } } [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; @@ -850,6 +837,27 @@ static NSPoint pointFlip(NSPoint point) { [pool release]; } +- (void)initRepAndContextWithWidth:(float)w Height:(float)h { + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:w + pixelsHigh:h + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:w * 4 + bitsPerPixel:32]; + assert(self->rep); + [self->rep retain]; + + self->context = + [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; + assert(self->context); + [self->context retain]; +} + - (void)destroy { CGColorSpaceRelease(self->space); [self->rep release]; @@ -884,6 +892,7 @@ static NSPoint pointFlip(NSPoint point) { return self; } - (void)applicationDidBecomeActive:(NSNotification *)notification { + [self->appl activateIgnoringOtherApps:true]; printf("test\n"); } - (void)applicationWillFinishLaunching:(NSNotification *)notification { @@ -910,6 +919,12 @@ static NSPoint pointFlip(NSPoint point) { } - (void)windowDidBecomeMain:(NSNotification *)notification { + if ([[[w contentView] subviews] count] != 0) { + MwLL h = [((MilskoFakePointer *)[[[w contentView] subviews] + objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_in, NULL); + } + [self->w makeKeyAndOrderFront:nil]; } - (void)windowDidResize:(NSNotification *)notification { From 6c53df0fc5eed26a6cd2f8e763f4c21fc772546a Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 10 Mar 2026 20:09:37 -0700 Subject: [PATCH 177/409] correct pixmap updating (sadly memcpy'ing is not enough) --- src/backend/cocoa.m | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1d5d3ce5a..03cbe2cdc 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -60,6 +60,22 @@ static NSPoint pointFlip(NSPoint point) { } - (void)updateWithData:(unsigned char *)_data { memcpy(self->buf, _data, width * height * 4); + if (self->rep) { + [self->image removeRepresentation:self->rep]; + [self->rep release]; + } + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + [self->image addRepresentation:self->rep]; } - (void)destroy { free(self->buf); From 02faed2f04f645a07f8fa5371d19c74104360da2 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 11 Mar 2026 13:13:16 -0700 Subject: [PATCH 178/409] reduce cpu usage on event loop --- src/backend/cocoa.m | 68 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 03cbe2cdc..c7eb10477 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -188,27 +188,6 @@ static NSPoint pointFlip(NSPoint point) { return c; } -+ (void)eventCanceller:(MilskoCocoa *)this { - this->lastEvent = [this->application currentEvent]; - [this eventProcess:this->lastEvent]; - - if (this->_forceRender) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined - location:NSMakePoint(0, 0) - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:0 - data1:0 - data2:0]; - [NSApp postEvent:event atStart:YES]; - [pool release]; - } - - [[NSApplication sharedApplication] stop:nil]; -} - (void)polygonWithPoints:(MwPoint *)points points_count:(int)points_count @@ -329,7 +308,34 @@ static NSPoint pointFlip(NSPoint point) { return 1; }; ++ (void)eventCanceller:(MilskoCocoa *)this { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + location:NSMakePoint(0, 0) + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; + + this->lastEvent = [this->window currentEvent]; + [this eventProcess:this->lastEvent]; + + [NSApp postEvent:event atStart:YES]; + [pool release]; + + [[NSApplication sharedApplication] stop:nil]; + usleep(1000); +} + - (void)getNextEvent { + if (_forceRender) { + MwLL h = [self->handle pointer]; + MwLLDispatch(h, draw, NULL); + _forceRender = MwFALSE; + } [self sendClipboardEvent]; if (self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { @@ -401,10 +407,15 @@ static NSPoint pointFlip(NSPoint point) { case NSScrollWheel: break; default: + /* mute bizarre "unknown subtype" errors that flood the console */ + if (ev.subtype > 8) { + doSendEvent = false; + } break; }; - [win sendEvent:ev]; - + if (doSendEvent) { + [win sendEvent:ev]; + } [pool release]; } @@ -909,7 +920,7 @@ static NSPoint pointFlip(NSPoint point) { } - (void)applicationDidBecomeActive:(NSNotification *)notification { [self->appl activateIgnoringOtherApps:true]; - printf("test\n"); + // printf("test\n"); } - (void)applicationWillFinishLaunching:(NSNotification *)notification { // printf("test\n"); @@ -1069,14 +1080,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int height) { static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static int MwLLPendingImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - if ([h pending]) { - MwLLDispatch(handle, draw, NULL); - return 1; - }; - return 0; -} +static int MwLLPendingImpl(MwLL handle) { return [handle->cocoa.real pending]; } static void MwLLNextEventImpl(MwLL handle) { MilskoCocoa *h = handle->cocoa.real; From 13320dce78c9dfc84bedb1f85253692506a9f16b Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 11 Mar 2026 15:49:14 -0700 Subject: [PATCH 179/409] proper event handling --- include/Mw/LowLevel/Cocoa.h | 1 + src/backend/cocoa.m | 59 ++++++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 7a8466b23..c92a81a4f 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -109,6 +109,7 @@ MilskoCocoaPixmap *cursorPixmap; NSCursor *cursor; + NSModalSession modalSession; MwBool pointerLocked; MwBool mouseMoved; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index c7eb10477..5981c0c22 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -185,6 +185,7 @@ static NSPoint pointFlip(NSPoint point) { [c->application finishLaunching]; c->pointerLocked = MwFALSE; + c->modalSession = [c->application beginModalSessionForWindow:c->window]; return c; } @@ -286,26 +287,27 @@ static NSPoint pointFlip(NSPoint point) { [self forceRender]; }; - (int)pending { - /* - ok so this is a crime against god but I did in fact try the better method - of using nextEventMatchingMask and then pumping events manually. However - this gives me something that only kind of works, with strange behavior such - as the window never becoming the main window (have to make it key in order - for the menu to show up) occuring. Hours of research and digging led me down - a rabbit hole that, on all sides, pointed to "just use [NSApplication run]". - So we just to do that; of course, this is a blocking function, so we - register this function that instantly cancels it and pumps whatever event - MacOS has in store for us. We do this on loop and somehow the resulting CPU - usage is managable. + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = MwFALSE; - If some Apple developer with 20 years of experience in Objective C is here: - Pls god send PR if you know how to properly do this. -*/ - [MilskoCocoa performSelectorOnMainThread:@selector(eventCanceller:) - withObject:self - waitUntilDone:NO]; - [self->application run]; - return 1; + if (_forceRender) { + _forceRender = MwFALSE; + [pool release]; + return 1; + } + self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask + untilDate:[NSDate distantPast] + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [self->lastEvent retain]; + + if (!self->lastEvent) { + [NSApp runModalSession:self->modalSession]; + } + + isPending = self->lastEvent != NULL; + [pool release]; + return isPending; }; + (void)eventCanceller:(MilskoCocoa *)this { @@ -331,6 +333,10 @@ static NSPoint pointFlip(NSPoint point) { } - (void)getNextEvent { + NSEvent *event; + + [self eventProcess:self->lastEvent]; + if (_forceRender) { MwLL h = [self->handle pointer]; MwLLDispatch(h, draw, NULL); @@ -377,6 +383,7 @@ static NSPoint pointFlip(NSPoint point) { case NSRightMouseUp: case NSOtherMouseUp: { [self handleMouseEvent:ev ll:h]; + break; } case NSLeftMouseDragged: case NSRightMouseDragged: @@ -400,6 +407,7 @@ static NSPoint pointFlip(NSPoint point) { case NSKeyDown: case NSKeyUp: { [self handleKeyEvent:ev ll:h]; + break; } case NSCursorUpdate: [self->cursor set]; @@ -790,10 +798,6 @@ static NSPoint pointFlip(NSPoint point) { _rect->height = [screen frame].size.height; }; - (void)destroy { - if (self->lastEvent) { - [self->lastEvent release]; - [self->lastEvent dealloc]; - } [self->handle release]; [self->handle dealloc]; [self->window release]; @@ -999,6 +1003,7 @@ static NSPoint pointFlip(NSPoint point) { - (BOOL)canBecomeMainWindow { return true; } + @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -1080,7 +1085,13 @@ static void MwLLSetWHImpl(MwLL handle, int w, int height) { static void MwLLFreeColorImpl(MwLLColor color) { free(color); } -static int MwLLPendingImpl(MwLL handle) { return [handle->cocoa.real pending]; } +static int MwLLPendingImpl(MwLL handle) { + int p = [handle->cocoa.real pending]; + if (p) { + MwLLDispatch(handle, draw, NULL); + } + return p; +} static void MwLLNextEventImpl(MwLL handle) { MilskoCocoa *h = handle->cocoa.real; From 96528ca4338800b2469174ad991a6dc4afbda117 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 11 Mar 2026 20:27:51 -0700 Subject: [PATCH 180/409] mac: don't set the xywh of parent windows twice --- src/backend/cocoa.m | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 5981c0c22..cf240d8dd 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -141,7 +141,7 @@ static NSPoint pointFlip(NSPoint point) { [c->window makeKeyAndOrderFront:c->application]; [c->window retain]; - if (parent != NULL) { + if (parent) { MilskoCocoa *p = parent->cocoa.real; double offset = 0; offset = [p->window frameRectForContentRect:[p->window frame]].size.height - @@ -149,10 +149,6 @@ static NSPoint pointFlip(NSPoint point) { [p->window addChildWindow:c->window ordered:NSWindowAbove]; [c->window setHasShadow:MwFALSE]; [c->window setParentWindow:p->window]; - - c->rect.origin.x += [p->window frame].origin.x; - c->rect.origin.y -= [p->window frame].origin.y - offset; - c->rect.origin.y -= offset; } else { if ([c->application respondsToSelector:@selector(setActivationPolicy:)]) { [c->application From db5f0ed40a615965dac3eeda81d33e3421d00ef3 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 12 Mar 2026 01:10:45 -0700 Subject: [PATCH 181/409] mac: some fixes --- src/backend/cocoa.m | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index cf240d8dd..3fa41cf10 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -372,15 +372,6 @@ static NSPoint pointFlip(NSPoint point) { } switch ([ev type]) { - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: { - [self handleMouseEvent:ev ll:h]; - break; - } case NSLeftMouseDragged: case NSRightMouseDragged: case NSOtherMouseDragged: @@ -390,8 +381,18 @@ static NSPoint pointFlip(NSPoint point) { pos.x = pos_translated.x; pos.y = pos_translated.y; MwLLDispatch(h, move, &pos); + // break; + } + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: { + [self handleMouseEvent:ev ll:h]; break; } + case NSMouseEntered: MwLLDispatch(h, focus_in, NULL); [self->cursor push]; @@ -412,9 +413,6 @@ static NSPoint pointFlip(NSPoint point) { break; default: /* mute bizarre "unknown subtype" errors that flood the console */ - if (ev.subtype > 8) { - doSendEvent = false; - } break; }; if (doSendEvent) { @@ -426,22 +424,27 @@ static NSPoint pointFlip(NSPoint point) { - (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll { MwLLMouse mouse; MwBool isDown = MwTRUE; - NSPoint mousePoint = pointFlip([ev locationInWindow]); + NSPoint mousePoint = [ev locationInWindow]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; MwLL this = [self->handle pointer]; + switch ([ev type]) { case NSLeftMouseUp: isDown = MwFALSE; + case NSEventTypeLeftMouseDragged: case NSLeftMouseDown: mouse.button = MwLLMouseLeft; break; case NSRightMouseUp: isDown = MwFALSE; case NSRightMouseDown: + case NSEventTypeRightMouseDragged: mouse.button = MwLLMouseRight; break; case NSOtherMouseUp: isDown = MwFALSE; case NSOtherMouseDown: + case NSEventTypeOtherMouseDragged: mouse.button = MwLLMouseMiddle; break; default: From 43dd61ffbed7805925e8c89c04afc5e28a3375a8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sat, 14 Mar 2026 05:09:53 +0900 Subject: [PATCH 182/409] clean old things --- Jenkinsfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index 5588f1be3..e2686d3ac 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,8 +2,14 @@ pipeline { agent { label "built-in" } + options { + buildDiscarder(logRotator(numToKeepStr: '16', artifactNumToKeepStr: '16')) + } stages { stage("Build document") { + when { + branch "master" + } steps { sh("doxygen") sh("rm -rf /var/www/milsko-doxygen") From 8f04ccdb686ab4a14d853e6b9d29a11499e22b6f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sat, 14 Mar 2026 05:16:27 +0900 Subject: [PATCH 183/409] cleanup --- Jenkinsfile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index e2686d3ac..3dd036945 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,10 +1,9 @@ +discardBuilds() + pipeline { agent { label "built-in" } - options { - buildDiscarder(logRotator(numToKeepStr: '16', artifactNumToKeepStr: '16')) - } stages { stage("Build document") { when { From 3260643ada9e7c5ca0c3455c8e265d3b68da0c55 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sat, 14 Mar 2026 05:21:53 +0900 Subject: [PATCH 184/409] i wonder if this works --- Jenkinsfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 3dd036945..7921f0c67 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,3 @@ -discardBuilds() - pipeline { agent { label "built-in" From c64d7778cd479937f86f74516ebaac55a177c3ad Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 16 Mar 2026 16:08:25 -0700 Subject: [PATCH 185/409] mac: convert child windows to subviews --- include/Mw/LowLevel/Cocoa.h | 1 + src/backend/cocoa.m | 1790 +++++++++++++++++------------------ 2 files changed, 886 insertions(+), 905 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index c92a81a4f..19e0bc3c1 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -113,6 +113,7 @@ MwBool pointerLocked; MwBool mouseMoved; + } + (MilskoCocoa *)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 3fa41cf10..c05fae59e 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,3 +1,4 @@ +#include "Mw/BaseTypes.h" #include #ifdef __clang__ @@ -6,989 +7,959 @@ #endif static NSRect rectFlip(NSRect originFrame) { - NSScreen *zeroScreen = [[NSScreen screens] objectAtIndex:0]; - double screenHeight = [zeroScreen frame].size.height; - double originY = originFrame.origin.y; - double frameHeight = originFrame.size.height; - double destinationY = screenHeight - (originY + frameHeight); - NSRect destinationFrame = originFrame; - destinationFrame.origin.y = destinationY; - if (destinationFrame.origin.x < 0) - destinationFrame.origin.x = 0; - if (destinationFrame.origin.y < 0) - destinationFrame.origin.y = 0; - if (destinationFrame.size.width < 0) - destinationFrame.size.width = 0; - if (destinationFrame.size.height < 0) - destinationFrame.size.height = 0; - return destinationFrame; + NSScreen* zeroScreen = [[NSScreen screens] objectAtIndex:0]; + double screenHeight = [zeroScreen frame].size.height; + double originY = originFrame.origin.y; + double frameHeight = originFrame.size.height; + double destinationY = screenHeight - (originY + frameHeight); + NSRect destinationFrame = originFrame; + destinationFrame.origin.y = destinationY; + return destinationFrame; } static NSPoint pointFlip(NSPoint point) { - return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; + return rectFlip(NSMakeRect(point.x, point.y, 0, 0)).origin; +} + +static NSRect localRectFlip(NSRect originFrame, NSView* view) { + float viewHeight = [view bounds].size.height; + NSRect destinationFrame = NSMakeRect( + originFrame.origin.x, + [view bounds].size.height - (originFrame.origin.y + originFrame.size.height), + originFrame.size.width, + originFrame.size.height); + return destinationFrame; } @implementation MilskoCocoaPixmap -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap *p = [MilskoCocoaPixmap alloc]; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; - p->width = width; - p->height = height; - p->image = NULL; + p->width = width; + p->height = height; + p->image = NULL; - p->buf = malloc(width * height * 4); + p->buf = malloc(width * height * 4); - p->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - assert(p->rep); + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(p->rep); - p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - assert(p->image); - [p->image addRepresentation:p->rep]; + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; - return p; + return p; } -- (void)updateWithData:(unsigned char *)_data { - memcpy(self->buf, _data, width * height * 4); - if (self->rep) { - [self->image removeRepresentation:self->rep]; - [self->rep release]; - } - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - [self->image addRepresentation:self->rep]; +- (void)updateWithData:(unsigned char*)_data { + memcpy(self->buf, _data, width * height * 4); + if(self->rep) { + [self->image removeRepresentation:self->rep]; + [self->rep release]; + } + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + [self->image addRepresentation:self->rep]; } - (void)destroy { - free(self->buf); - [self->image removeRepresentation:self->rep]; - [self->image dealloc]; - [self->rep dealloc]; + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image dealloc]; + [self->rep dealloc]; } -- (NSImage *)image { - return self->image; +- (NSImage*)image { + return self->image; } @end @implementation MilskoCocoa -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)r { - MilskoCocoa *c = [MilskoCocoa alloc]; - [c retain]; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)r { + MilskoCocoa* c = [MilskoCocoa alloc]; + [c retain]; - if (x == MwDEFAULT) { - x = ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.); - } - if (y == MwDEFAULT) { - y = ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.); - } - c->application = [NSApplication sharedApplication]; - c->rect = rectFlip(NSMakeRect(x, y, width, height)); + /* + * MacOS doesn't really have a "default" window position, you're actually meant to center the window yourself, + * so if the user passes MwDEFAULT respond appropriately. Also for child windows just have it be 0. + */ + if(x == MwDEFAULT) { + x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; + } + if(y == MwDEFAULT) { + y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) : 0; + } + c->application = [NSApplication sharedApplication]; + c->rect = NSMakeRect(x, y, width, height); - if (parent == NULL) { - c->window = [[MilskoCocoaWindow alloc] - initWithContentRect:c->rect - styleMask:(NSTitledWindowMask | - NSTexturedBackgroundWindowMask | - NSClosableWindowMask | NSMiniaturizableWindowMask | - NSResizableWindowMask) - backing:NSBackingStoreBuffered - defer:NO]; - } else { - double offset = 0; - MilskoCocoaWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]] - .size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; + if(parent == NULL) { + c->window = [[MilskoCocoaWindow alloc] + initWithContentRect:rectFlip(c->rect) + styleMask:(NSTitledWindowMask | + NSTexturedBackgroundWindowMask | + NSClosableWindowMask | NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + [c->window + setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; + [c->window retain]; - c->rect.origin.x += [parentWindow frame].origin.x; - c->rect.origin.y -= [parentWindow frame].origin.y - offset; - c->rect.origin.y -= offset; + [c->window makeKeyAndOrderFront:c->application]; + [c->window makeFirstResponder:c->view]; + [c->window setAcceptsMouseMovedEvents:MwTRUE]; - c->window = - [[MilskoCocoaWindow alloc] initWithContentRect:c->rect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; - } - [c->window - setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->view retain]; + [c->window setContentView:c->view]; - [c->window makeKeyAndOrderFront:c->application]; - [c->window retain]; + if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { + [c->application + setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; + } + [c->application activateIgnoringOtherApps:true]; + [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] + initWithAppl:c->application]]; + [c->application retain]; + } else { + MilskoCocoa* p = parent->cocoa.real; - if (parent) { - MilskoCocoa *p = parent->cocoa.real; - double offset = 0; - offset = [p->window frameRectForContentRect:[p->window frame]].size.height - - [p->window contentRectForFrameRect:[p->window frame]].size.height; - [p->window addChildWindow:c->window ordered:NSWindowAbove]; - [c->window setHasShadow:MwFALSE]; - [c->window setParentWindow:p->window]; - } else { - if ([c->application respondsToSelector:@selector(setActivationPolicy:)]) { - [c->application - setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; - } - [c->window makeKeyAndOrderFront:nil]; - [c->application activateIgnoringOtherApps:true]; - [c->window makeFirstResponder:c->view]; - } - [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] - initWithAppl:c->application]]; - [c->application retain]; + c->window = p->window; - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - [c->view retain]; - c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [c->handle retain]; - [c->handle setPointer:r]; - [c->view addSubview:c->handle]; + if(parent) { + MilskoCocoa* topmost = p; + NSRect rect = localRectFlip(c->rect, p->view); + printf("%0.2f %0.2f %0.2f %0.2f\n",c->rect.origin.x, c->rect.origin.y, c->rect.size.width, c->rect.size.height); + c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; + [c->view setBounds:c->rect]; + } else { + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + } + [c->view retain]; + [c->view setNeedsDisplay:TRUE]; + [p->view addSubview:c->view]; + [p->window setContentView:p->view]; + } - [c->window setContentView:c->view]; + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle retain]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; - c->parent = parent; + c->modalSession = [c->application beginModalSessionForWindow:c->window]; + c->parent = parent; - c->_forceRender = MwTRUE; - c->strHash = 0; + c->_forceRender = MwTRUE; + c->strHash = 0; - c->cursorPixmap = NULL; + c->cursorPixmap = NULL; - [c->application finishLaunching]; + [c->application finishLaunching]; - c->pointerLocked = MwFALSE; - c->modalSession = [c->application beginModalSessionForWindow:c->window]; + c->pointerLocked = MwFALSE; - return c; + + return c; } -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext *ctx = [self->view context]; - if (ctx) { - int i; - NSBezierPath *path = [NSBezierPath bezierPath]; - NSColor *nscolor = - [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + /* whatever rect we use for coordinate flipping */ + NSRect _rect = parent ? [self->view bounds] : [self->window frame]; - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + NSColor* nscolor = + [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; - [nscolor setFill]; - for (i = 0; i < points_count; i++) { - if (i == 0) { - [path moveToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } else { - [path lineToPoint:NSMakePoint(points[i].x, - [self->window frame].size.height - - points[i].y)]; - } - } + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [path closePath]; - [path fill]; + [nscolor setFill]; + NSRectFill(self->view.bounds); + for(i = 0; i < points_count; i++) { + if(i == 0) { + [path moveToPoint:NSMakePoint(points[i].x, _rect.size.height - + points[i].y)]; + } else { + [path lineToPoint:NSMakePoint(points[i].x, _rect.size.height - + points[i].y)]; + } + } - [NSGraphicsContext restoreGraphicsState]; + [path closePath]; + [path fill]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color { - (void)points; - (void)color; +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { + (void)points; + (void)color; }; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h { - NSRect frame = rectFlip([self->window frame]); - frame = rectFlip(frame); +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { + NSRect frame; + if(parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + frame = rectFlip(frame); - if (parent) { - frame.origin.x -= [parent->cocoa.real->window frame].origin.x; - frame.origin.y += [parent->cocoa.real->window frame].origin.y; - } + *x = frame.origin.x; + *y = frame.origin.y; - *x = frame.origin.x; - *y = frame.origin.y; - - *w = frame.size.width; - *h = frame.size.height; + *w = frame.size.width; + *h = frame.size.height; }; - (void)setX:(int)x Y:(int)y { - NSRect frame = [self->window frame]; + NSRect frame; + if(parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } - frame.origin.x = x; - frame.origin.y = y; + frame.origin.x = x; + frame.origin.y = y; - frame = rectFlip(frame); - - if (parent) { - double offset = 0; - MilskoCocoaWindow *parentWindow = parent->cocoa.real->window; - offset = - [parentWindow frameRectForContentRect:[parentWindow frame]] - .size.height - - [parentWindow contentRectForFrameRect:[parentWindow frame]].size.height; - - frame.origin.x += [parentWindow frame].origin.x; - frame.origin.y -= [parentWindow frame].origin.y - offset; - frame.origin.y -= offset; - } - - [self->view setFrameSize:frame.size]; - - [self->window setFrameOrigin:frame.origin]; - - [self forceRender]; + if(!parent) { + frame = rectFlip(frame); + [self->window setFrame:frame display:TRUE animate:TRUE]; + } else { + frame = localRectFlip(frame, parent->cocoa.real->view); + [self->view setBounds:frame]; + } }; - (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; - self->rect = frame; + self->rect = frame; - [self->view setFrameSize:frame.size]; - [self->window setFrame:frame display:YES animate:false]; - [self forceRender]; + [self->view setFrameSize:frame.size]; + if(self->parent) { + [self->view setFrame:frame]; + } else { + [self->window setFrame:frame display:YES animate:false]; + } }; - (int)pending { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - MwBool isPending = MwFALSE; - - if (_forceRender) { - _forceRender = MwFALSE; - [pool release]; - return 1; - } - self->lastEvent = [self->window nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - [self->lastEvent retain]; - - if (!self->lastEvent) { - [NSApp runModalSession:self->modalSession]; - } - - isPending = self->lastEvent != NULL; - [pool release]; - return isPending; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [NSApp runModalSession:self->modalSession]; + [pool release]; + return 1; }; -+ (void)eventCanceller:(MilskoCocoa *)this { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined - location:NSMakePoint(0, 0) - modifierFlags:0 - timestamp:0 - windowNumber:0 - context:nil - subtype:0 - data1:0 - data2:0]; - - this->lastEvent = [this->window currentEvent]; - [this eventProcess:this->lastEvent]; - - [NSApp postEvent:event atStart:YES]; - [pool release]; - - [[NSApplication sharedApplication] stop:nil]; - usleep(1000); -} - - (void)getNextEvent { - NSEvent *event; + [self eventProcess:self->lastEvent]; - [self eventProcess:self->lastEvent]; + if(_forceRender) { + MwLL h = [self->handle pointer]; + MwLLDispatch(h, draw, NULL); + [self->view setNeedsDisplay:true]; + _forceRender = MwFALSE; + } + [self sendClipboardEvent]; - if (_forceRender) { - MwLL h = [self->handle pointer]; - MwLLDispatch(h, draw, NULL); - _forceRender = MwFALSE; - } - [self sendClipboardEvent]; + if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { + struct CGPoint pos; + pos.x = [window frame].origin.x + [window frame].size.width / 2; + pos.y = [window frame].origin.y + [window frame].size.height / 2; - if (self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { - struct CGPoint pos; - pos.x = [window frame].origin.x + [window frame].size.width / 2; - pos.y = [window frame].origin.y + [window frame].size.height / 2; + CGWarpMouseCursorPosition(pos); + } - CGWarpMouseCursorPosition(pos); - } - - [self->application updateWindows]; + [self->application updateWindows]; }; -- (void)eventProcess:(NSEvent *)ev { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSWindow *win = [ev window]; - MwLL h; - MwBool doSendEvent = MwTRUE; +- (void)eventProcess:(NSEvent*)ev { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSWindow* win = [ev window]; + MwLL h; + MwBool doSendEvent = MwTRUE; - if (!win) { - [pool release]; - return; - } + if(!win) { + [pool release]; + return; + } - if ([[[win contentView] subviews] count] == 0) { - printf("no subviews on %p\n", win); - [pool release]; - return; - } else { - h = [((MilskoFakePointer *)[[[win contentView] subviews] - objectAtIndex:0]) pointer]; - } + if([[[win contentView] subviews] count] == 0) { + printf("no subviews on %p\n", win); + [pool release]; + return; + } else { + h = [((MilskoFakePointer*)[[[win contentView] subviews] + objectAtIndex:0]) pointer]; + } - switch ([ev type]) { - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - case NSMouseMoved: { - MwPoint pos; - NSPoint pos_translated = pointFlip([ev locationInWindow]); - pos.x = pos_translated.x; - pos.y = pos_translated.y; - MwLLDispatch(h, move, &pos); - // break; - } - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: { - [self handleMouseEvent:ev ll:h]; - break; - } - case NSMouseEntered: - MwLLDispatch(h, focus_in, NULL); - [self->cursor push]; - break; - case NSMouseExited: - MwLLDispatch(h, focus_out, NULL); - [self->cursor pop]; - break; - case NSKeyDown: - case NSKeyUp: { - [self handleKeyEvent:ev ll:h]; - break; - } - case NSCursorUpdate: - [self->cursor set]; - break; - case NSScrollWheel: - break; - default: - /* mute bizarre "unknown subtype" errors that flood the console */ - break; - }; - if (doSendEvent) { - [win sendEvent:ev]; - } - [pool release]; + switch([ev type]) { + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + case NSMouseMoved: { + MwPoint pos; + NSPoint pos_translated = pointFlip([ev locationInWindow]); + pos.x = pos_translated.x; + pos.y = pos_translated.y; + MwLLDispatch(h, move, &pos); + break; + } + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: { + [self handleMouseEvent:ev ll:h]; + break; + } + + case NSMouseEntered: + MwLLDispatch(h, focus_in, NULL); + [self->cursor push]; + break; + case NSMouseExited: + MwLLDispatch(h, focus_out, NULL); + [self->cursor pop]; + break; + case NSKeyDown: + case NSKeyUp: { + [self handleKeyEvent:ev ll:h]; + break; + } + case NSCursorUpdate: + [self->cursor set]; + break; + case NSScrollWheel: + break; + default: + /* mute bizarre "unknown subtype" errors that flood the console */ + break; + }; + if(doSendEvent) { + [win sendEvent:ev]; + } + [pool release]; } -- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll { - MwLLMouse mouse; - MwBool isDown = MwTRUE; - NSPoint mousePoint = [ev locationInWindow]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - MwLL this = [self->handle pointer]; +- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll { + MwLLMouse mouse; + MwBool isDown = MwTRUE; + NSPoint mousePoint = [ev locationInWindow]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + MwLL this = [self->handle pointer]; - switch ([ev type]) { - case NSLeftMouseUp: - isDown = MwFALSE; - case NSEventTypeLeftMouseDragged: - case NSLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSRightMouseUp: - isDown = MwFALSE; - case NSRightMouseDown: - case NSEventTypeRightMouseDragged: - mouse.button = MwLLMouseRight; - break; - case NSOtherMouseUp: - isDown = MwFALSE; - case NSOtherMouseDown: - case NSEventTypeOtherMouseDragged: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + switch([ev type]) { + case NSLeftMouseUp: + isDown = MwFALSE; + case NSEventTypeLeftMouseDragged: + case NSLeftMouseDown: + mouse.button = MwLLMouseLeft; + break; + case NSRightMouseUp: + isDown = MwFALSE; + case NSRightMouseDown: + case NSEventTypeRightMouseDragged: + mouse.button = MwLLMouseRight; + break; + case NSOtherMouseUp: + isDown = MwFALSE; + case NSOtherMouseDown: + case NSEventTypeOtherMouseDragged: + mouse.button = MwLLMouseMiddle; + break; + default: + break; + } + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; - if (isDown) { - MwLLDispatch(ll, down, &mouse); - } else { - MwLLDispatch(ll, up, &mouse); - } + printf("%s at %d %d\n", isDown ? "down" : "up", mouse.point.x, mouse.point.y); + + if(isDown) { + MwLLDispatch(ll, down, &mouse); + } else { + MwLLDispatch(ll, up, &mouse); + } } -- (void)handleKeyEvent:(NSEvent *)ev ll:(MwLL)ll { - int ch; - MwLL this = [self->handle pointer]; - enum { - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_Return = 0x24, - kVK_Space = 0x31, - kVK_Escape = 0x35, - kVK_Shift = 0x38, - kVK_Control = 0x3B, - kVK_RightShift = 0x3C, - kVK_RightControl = 0x3E, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E - }; -#define KEY_CASE(x, y) \ - case x: \ - ch = y; \ - break; - switch ([ev keyCode]) { - KEY_CASE(kVK_ANSI_A, 'a') - KEY_CASE(kVK_ANSI_B, 'b') - KEY_CASE(kVK_ANSI_C, 'c') - KEY_CASE(kVK_ANSI_D, 'd') - KEY_CASE(kVK_ANSI_E, 'e') - KEY_CASE(kVK_ANSI_F, 'f') - KEY_CASE(kVK_ANSI_G, 'g') - KEY_CASE(kVK_ANSI_H, 'h') - KEY_CASE(kVK_ANSI_I, 'i') - KEY_CASE(kVK_ANSI_J, 'j') - KEY_CASE(kVK_ANSI_K, 'k') - KEY_CASE(kVK_ANSI_L, 'l') - KEY_CASE(kVK_ANSI_M, 'm') - KEY_CASE(kVK_ANSI_N, 'n') - KEY_CASE(kVK_ANSI_O, 'o') - KEY_CASE(kVK_ANSI_P, 'p') - KEY_CASE(kVK_ANSI_Q, 'q') - KEY_CASE(kVK_ANSI_R, 'r') - KEY_CASE(kVK_ANSI_S, 's') - KEY_CASE(kVK_ANSI_T, 't') - KEY_CASE(kVK_ANSI_U, 'u') - KEY_CASE(kVK_ANSI_V, 'v') - KEY_CASE(kVK_ANSI_W, 'w') - KEY_CASE(kVK_ANSI_X, 'x') - KEY_CASE(kVK_ANSI_Y, 'y') - KEY_CASE(kVK_ANSI_Z, 'z') - KEY_CASE(kVK_ANSI_0, '0') - KEY_CASE(kVK_ANSI_1, '1') - KEY_CASE(kVK_ANSI_2, '2') - KEY_CASE(kVK_ANSI_3, '3') - KEY_CASE(kVK_ANSI_4, '4') - KEY_CASE(kVK_ANSI_5, '5') - KEY_CASE(kVK_ANSI_6, '6') - KEY_CASE(kVK_ANSI_7, '7') - KEY_CASE(kVK_ANSI_8, '8') - KEY_CASE(kVK_ANSI_9, '9') - KEY_CASE(kVK_ANSI_Quote, '\"') - KEY_CASE(kVK_ANSI_Grave, '`') - KEY_CASE(kVK_ANSI_Backslash, '/') - KEY_CASE(kVK_ANSI_Comma, ',') - KEY_CASE(kVK_ANSI_Equal, '=') - KEY_CASE(kVK_Escape, MwLLKeyEscape) - KEY_CASE(kVK_ANSI_LeftBracket, '[') - KEY_CASE(kVK_ANSI_Minus, '-') - KEY_CASE(kVK_ANSI_Period, '.') - KEY_CASE(kVK_Return, MwLLKeyEnter) - KEY_CASE(kVK_ANSI_RightBracket, ']') - KEY_CASE(kVK_ANSI_Semicolon, ';') - KEY_CASE(kVK_ANSI_Slash, '\\') - KEY_CASE(kVK_Space, ' ') - KEY_CASE(kVK_Control, MwLLKeyControl) - KEY_CASE(kVK_RightControl, MwLLKeyControl) - KEY_CASE(kVK_Shift, MwLLKeyLeftShift) - KEY_CASE(kVK_RightShift, MwLLKeyRightShift) - KEY_CASE(kVK_DownArrow, MwLLKeyDown) - KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) - KEY_CASE(kVK_RightArrow, MwLLKeyRight) - KEY_CASE(kVK_UpArrow, MwLLKeyUp) - } - switch ([ev type]) { - case NSKeyDown: - MwLLDispatch(this, key, &ch); - MwLLDispatch(ll, key, &ch); - break; - case NSKeyUp: - MwLLDispatch(this, key_released, &ch); - MwLLDispatch(ll, key_released, &ch); - break; - default: - break; - } +- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll { + int ch; + MwLL this = [self->handle pointer]; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch([ev keyCode]) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwLLKeyControl) + KEY_CASE(kVK_RightControl, MwLLKeyControl) + KEY_CASE(kVK_Shift, MwLLKeyLeftShift) + KEY_CASE(kVK_RightShift, MwLLKeyRightShift) + KEY_CASE(kVK_DownArrow, MwLLKeyDown) + KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) + KEY_CASE(kVK_RightArrow, MwLLKeyRight) + KEY_CASE(kVK_UpArrow, MwLLKeyUp) + } + switch([ev type]) { + case NSKeyDown: + MwLLDispatch(this, key, &ch); + MwLLDispatch(ll, key, &ch); + break; + case NSKeyUp: + MwLLDispatch(this, key_released, &ch); + MwLLDispatch(ll, key_released, &ch); + break; + default: + break; + } } - (void)sendClipboardEvent { - /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - NSArray* items = @[ - @"public.utf8-plain-text", - @"public.utf16-external-plain-text", - @"com.apple.traditional-mac-plain-text", - ]; - MwLL this = self->handle.pointer; + /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSArray* items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; - if([pasteboard canReadItemWithDataConformingToTypes:items]) { - char* data = NULL; - size_t size = 0; - for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { - for(NSString* it in items) { - NSString* itemData = [item - stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && - strHash != [itemData hash]) { char* text = malloc([itemData length]); - strncpy(text, [itemData UTF8String], - [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", - text, this); free(text); - } - strHash = [itemData hash]; - } - } - } - } + if([pasteboard canReadItemWithDataConformingToTypes:items]) { + char* data = NULL; + size_t size = 0; + for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { + for(NSString* it in items) { + NSString* itemData = [item + stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && + strHash != [itemData hash]) { char* text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], + [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", + text, this); free(text); + } + strHash = [itemData hash]; + } + } + } + } - [pool release];*/ + [pool release];*/ } -- (void)setTitle:(const char *)title { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; +- (void)setTitle:(const char*)title { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [self->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; }; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)_rect { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - MilskoCocoaPixmap *p = pixmap->cocoa.real; - NSGraphicsContext *ctx = [self->view context]; - if (ctx) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; - [[p image] - drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0]; + [[p image] + drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; - [NSGraphicsContext restoreGraphicsState]; + [NSGraphicsContext restoreGraphicsState]; - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; - (void)setIcon:(MwLLPixmap)pixmap { - [self->application setApplicationIconImage:[pixmap->cocoa.real image]]; + [self->application setApplicationIconImage:[pixmap->cocoa.real image]]; }; - (void)forceRender { - self->_forceRender = MwTRUE; - // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - // NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined - // location:NSMakePoint(0, 0) - // modifierFlags:0 - // timestamp:0 - // windowNumber:0 - // context:nil - // subtype:0 - // data1:0 - // data2:0]; - // [NSApp postEvent:event atStart:YES]; - // [pool release]; + self->_forceRender = MwTRUE; + // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + // NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined + // location:NSMakePoint(0, 0) + // modifierFlags:0 + // timestamp:0 + // windowNumber:0 + // context:nil + // subtype:0 + // data1:0 + // data2:0]; + // [NSApp postEvent:event atStart:YES]; + // [pool release]; }; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask { - int y, x, ys, xs; - unsigned char *di = malloc(image->width * image->height * 4); - memset(di, 0, image->width * image->height * 4); +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { + int y, x, ys, xs; + unsigned char* di = malloc(image->width * image->height * 4); + memset(di, 0, image->width * image->height * 4); - if (self->cursorPixmap) { - [self->cursorPixmap destroy]; - } - self->cursorPixmap = - [MilskoCocoaPixmap newWithWidth:image->width height:image->height]; + if(self->cursorPixmap) { + [self->cursorPixmap destroy]; + } + self->cursorPixmap = + [MilskoCocoaPixmap newWithWidth:image->width + height:image->height]; - xs = -mask->x + image->x; - ys = MwCursorDataHeight + mask->y; - ys = MwCursorDataHeight + image->y - ys; + xs = -mask->x + image->x; + ys = MwCursorDataHeight + mask->y; + ys = MwCursorDataHeight + image->y - ys; - for (y = 0; y < mask->height; y++) { - unsigned int d = mask->data[y]; - for (x = mask->width - 1; x >= 0; x--) { - int px = 0; - int idx = ((y * mask->width) + x) * 4; + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; - if (d & 1) { - di[idx + 3] = 255; - }; - d = d >> 1; - } - } - for (y = 0; y < image->height; y++) { - unsigned int d = image->data[y]; - for (x = image->width - 1; x >= 0; x--) { - int px = 0; - int idx = ((y * image->width) + x) * 4; + if(d & 1) { + di[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; - if (d & 1) { - px = 255; - }; + if(d & 1) { + px = 255; + }; - di[idx] = px; - di[idx + 1] = px; - di[idx + 2] = px; - d = d >> 1; - } - } + di[idx] = px; + di[idx + 1] = px; + di[idx + 2] = px; + d = d >> 1; + } + } - [self->cursorPixmap updateWithData:di]; + [self->cursorPixmap updateWithData:di]; - self->cursor = [[NSCursor alloc] - initWithImage:[self->cursorPixmap image] - hotSpot:NSMakePoint(image->x, image->y + image->height)]; - [self->cursor retain]; + self->cursor = [[NSCursor alloc] + initWithImage:[self->cursorPixmap image] + hotSpot:NSMakePoint(image->x, image->y + image->height)]; + [self->cursor retain]; - [self->cursor pop]; - [self->cursor push]; + [self->cursor pop]; + [self->cursor push]; - free(di); + free(di); }; -- (void)detachWithPoint:(MwPoint *)point { - [self->window setParentWindow:NULL]; +- (void)detachWithPoint:(MwPoint*)point { + [self->window setParentWindow:NULL]; }; - (void)show:(int)show { - (void)show; + (void)show; }; - (void)makePopupWithParent:(MwLL)_parent { - (void)_parent; + (void)_parent; }; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { - [self->window setMinSize:NSMakeSize(minx, miny)]; - [self->window setMaxSize:NSMakeSize(maxx, maxy)]; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy { + [self->window setMinSize:NSMakeSize(minx, miny)]; + [self->window setMaxSize:NSMakeSize(maxx, maxy)]; }; - (void)makeBorderless:(int)toggle { - MwU32 mask = [self->window styleMask]; - if (toggle) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; + MwU32 mask = [self->window styleMask]; + if(toggle) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; }; - (void)focus { - [self->window makeMainWindow]; + [self->window makeMainWindow]; }; - (void)grabPointer:(int)toggle { - self->pointerLocked = toggle; + self->pointerLocked = toggle; }; -- (void)setClipboard:(const char *)text { - (void)text; - // TODO: find out how to do this while supporting 10.4 - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] - // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] - // forType:NSPasteboardTypeString]; [pool release]; +- (void)setClipboard:(const char*)text { + (void)text; + // TODO: find out how to do this while supporting 10.4 + // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] + // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] + // forType:NSPasteboardTypeString]; [pool release]; }; - (void)makeToolWindow { - /* If my understand of what a "tool window" usually is is correct then I - * highly doubt the Mac OS has this and if they did they probably outright - * removed it along time ago is this kind of conflicts with modern UX. So - * we'll just make it borderless idgaf */ - [self makeBorderless:MwTRUE]; + /* If my understand of what a "tool window" usually is is correct then I + * highly doubt the Mac OS has this and if they did they probably outright + * removed it along time ago is this kind of conflicts with modern UX. So + * we'll just make it borderless idgaf */ + [self makeBorderless:MwTRUE]; }; -- (void)getCursorCoord:(MwPoint *)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; +- (void)getCursorCoord:(MwPoint*)point { + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; }; -- (void)getScreenSize:(MwRect *)_rect { - NSScreen *screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; +- (void)getScreenSize:(MwRect*)_rect { + NSScreen* screen = [self->window screen]; + _rect->x = [screen frame].origin.x; + _rect->y = [screen frame].origin.y; + _rect->width = [screen frame].size.width; + _rect->height = [screen frame].size.height; }; - (void)destroy { - [self->handle release]; - [self->handle dealloc]; - [self->window release]; - [self->window dealloc]; + [self->handle release]; + [self->handle dealloc]; + [self->window release]; + [self->window dealloc]; } - (MwLL)getParent { - return self->parent; + return self->parent; } -- (NSView *)getView { - return view; +- (NSView*)getView { + return view; } -- (NSWindow *)getWindow { - return window; +- (NSWindow*)getWindow { + return window; } -- (MilskoFakePointer *)getHandle { - return handle; +- (MilskoFakePointer*)getHandle { + return handle; } @end @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - width = frame.size.width; - height = frame.size.height; - self = [super initWithFrame:frame]; - self->space = CGColorSpaceCreateDeviceRGB(); + width = frame.size.width; + height = frame.size.height; + self = [super initWithFrame:frame]; + self->space = CGColorSpaceCreateDeviceRGB(); - if (width == 0 || height == 0) { - self->rep = NULL; - self->context = NULL; - } else { - [self initRepAndContextWithWidth:width Height:height]; - } + if(width == 0 || height == 0) { + self->rep = NULL; + self->context = NULL; + } else { + [self initRepAndContextWithWidth:width Height:height]; + } - return self; + return self; } -- (NSGraphicsContext *)context { - return self->context; +- (NSGraphicsContext*)context { + return self->context; } -- (NSBitmapImageRep *)getRep { - return self->rep; +- (NSBitmapImageRep*)getRep { + return self->rep; } - (void)drawRect:(NSRect)dirtyRect { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - NSSize sz = [self->rep size]; - [super drawRect:dirtyRect]; - if (!self->rep) { - if (dirtyRect.size.width && dirtyRect.size.height) { - [self initRepAndContextWithWidth:dirtyRect.size.width - Height:dirtyRect.size.height]; - self->width = dirtyRect.size.width; - self->height = dirtyRect.size.height; - } else { - [pool release]; - return; - } - } + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSSize sz = [self->rep size]; + MwLL ll = [((MilskoFakePointer *)[[[[self window] contentView] subviews] + objectAtIndex:0]) pointer]; - [self->rep drawInRect:NSMakeRect(0, 0, sz.width, sz.height)]; + [super drawRect:dirtyRect]; + if(!self->rep) { + if(dirtyRect.size.width && dirtyRect.size.height) { + [self initRepAndContextWithWidth:dirtyRect.size.width + Height:dirtyRect.size.height]; + self->width = dirtyRect.size.width; + self->height = dirtyRect.size.height; + } else { + [pool release]; + return; + } + } - [self->rep bitmapData]; - [pool release]; + // MwLLDispatch(ll, draw, NULL); + + [self->rep drawInRect:dirtyRect]; + + for(NSView* subview in [self subviews]) { + NSRect bounds = [subview bounds]; + [subview drawRect:bounds]; + } + + [self->rep bitmapData]; + + [pool release]; } - (void)initRepAndContextWithWidth:(float)w Height:(float)h { - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL - pixelsWide:w - pixelsHigh:h - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:w * 4 - bitsPerPixel:32]; - assert(self->rep); - [self->rep retain]; + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + pixelsWide:w + pixelsHigh:h + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:w * 4 + bitsPerPixel:32]; + assert(self->rep); + [self->rep retain]; - self->context = - [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; - assert(self->context); - [self->context retain]; + self->context = + [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; + assert(self->context); + [self->context retain]; } - (void)destroy { - CGColorSpaceRelease(self->space); - [self->rep release]; - [self->context release]; + CGColorSpaceRelease(self->space); + [self->rep release]; + [self->context release]; } - (void)setFrameSize:(NSSize)newSize { - [super setFrameSize:newSize]; - [self->rep setSize:newSize]; + [super setFrameSize:newSize]; + [self->rep setSize:newSize]; - self->width = newSize.width; - self->height = newSize.height; + self->width = newSize.width; + self->height = newSize.height; } - (void)displayRect:(NSRect)rect { - (void)rect; + (void)rect; }; - (BOOL)acceptsFirstResponder { - return MwTRUE; + return MwTRUE; } -- (BOOL)performKeyEquivalent:(NSEvent *)event { - (void)event; - return MwTRUE; +- (BOOL)performKeyEquivalent:(NSEvent*)event { + (void)event; + return MwTRUE; } @end @implementation MilskoCocoaApplicationDelegate -- (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)_appl { - self->appl = _appl; - return self; +- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)_appl { + self->appl = _appl; + return self; } -- (void)applicationDidBecomeActive:(NSNotification *)notification { - [self->appl activateIgnoringOtherApps:true]; - // printf("test\n"); +- (void)applicationDidBecomeActive:(NSNotification*)notification { + [self->appl activateIgnoringOtherApps:true]; + // printf("test\n"); } -- (void)applicationWillFinishLaunching:(NSNotification *)notification { - // printf("test\n"); - // [self->appl activateIgnoringOtherApps:MwTRUE]; +- (void)applicationWillFinishLaunching:(NSNotification*)notification { + // printf("test\n"); + // [self->appl activateIgnoringOtherApps:MwTRUE]; } -- (void)applicationDidFinishLaunching:(NSNotification *)notification { - // [self->appl activateIgnoringOtherApps:MwTRUE]; +- (void)applicationDidFinishLaunching:(NSNotification*)notification { + // [self->appl activateIgnoringOtherApps:MwTRUE]; } @end @implementation MilskoCocoaWindowDelegate -- (NSSize)windowWillResize:(NSWindow *)win toSize:(NSSize)frameSize; +- (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; { - if ([[[win contentView] subviews] count] >= 1) { - MilskoFakePointer *ptr = [[[win contentView] subviews] objectAtIndex:0]; - MwLL h = [ptr pointer]; + if([[[win contentView] subviews] count] >= 1) { + MilskoFakePointer* ptr = [[[win contentView] subviews] objectAtIndex:0]; + MwLL h = [ptr pointer]; - // MwLLDispatch(h, resize, NULL); - MwLLDispatch(h, draw, NULL); - } - return frameSize; + MwLLDispatch(h, resize, NULL); + MwLLDispatch(h, draw, NULL); + } + return frameSize; } -- (void)windowDidBecomeMain:(NSNotification *)notification { - if ([[[w contentView] subviews] count] != 0) { - MwLL h = [((MilskoFakePointer *)[[[w contentView] subviews] - objectAtIndex:0]) pointer]; - MwLLDispatch(h, focus_in, NULL); - } - [self->w makeKeyAndOrderFront:nil]; +- (void)windowDidBecomeMain:(NSNotification*)notification { + if([[[w contentView] subviews] count] != 0) { + MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] + objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_in, NULL); + } + [self->w makeKeyAndOrderFront:nil]; } -- (void)windowDidResize:(NSNotification *)notification { - (void)notification; +- (void)windowDidResize:(NSNotification*)notification { + (void)notification; } // This will close/terminate the application when the main window is closed. -- (void)windowWillClose:(NSNotification *)notification { - (void)notification; - // MilskoCocoa *window = notification.object; - // MwLL handle = [window getHandle].pointer; - // MwLLDispatch(handle, close, NULL); - [NSApp terminate:nil]; +- (void)windowWillClose:(NSNotification*)notification { + (void)notification; + // MilskoCocoa *window = notification.object; + // MwLL handle = [window getHandle].pointer; + // MwLLDispatch(handle, close, NULL); + [NSApp terminate:nil]; } -- (MilskoCocoaWindowDelegate *)initWithWin:(NSWindow *)win { - self->w = win; - return self; +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { + self->w = win; + return self; } @end @implementation MilskoFakePointer -- (void)setPointer:(void *)pointer { - [self setFrame:*(NSRect *)&pointer]; - self->ptr = pointer; +- (void)setPointer:(void*)pointer { + [self setFrame:*(NSRect*)&pointer]; + self->ptr = pointer; }; -- (void *)pointer { - return self->ptr; +- (void*)pointer { + return self->ptr; }; - (void)drawRect:(NSRect)dirtyRect { - /* explicitly do nothing */ - (void)dirtyRect; + /* explicitly do nothing */ + (void)dirtyRect; } - (void)destroy { @@ -997,227 +968,236 @@ static NSPoint pointFlip(NSPoint point) { @implementation MilskoCocoaWindow - (BOOL)canBecomeKeyWindow { - return true; + return true; } - (BOOL)canBecomeMainWindow { - return true; + return true; } @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - (void)x; - (void)y; - (void)width; - (void)height; + MwLL r; + r = malloc(sizeof(*r)); - r = malloc(sizeof(*r)); + MwLLCreateCommon(r); - MwLLCreateCommon(r); + MilskoCocoa* o = [MilskoCocoa newWithParent:parent + x:x + y:y + width:width + height:height + handle:r]; + r->cocoa.real = o; - MilskoCocoa *o = [MilskoCocoa newWithParent:parent - x:x - y:y - width:width - height:height - handle:r]; - r->cocoa.real = o; - - return r; + return r; } static void MwLLDestroyImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; + MilskoCocoa* h = handle->cocoa.real; - [h destroy]; + [h destroy]; - MwLLDestroyCommon(handle); + MwLLDestroyCommon(handle); - free(handle); + free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLEndDrawImpl(MwLL handle) { (void)handle; } - -static void MwLLPolygonImpl(MwLL handle, MwPoint *points, int points_count, - MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; } -static void MwLLLineImpl(MwLL handle, MwPoint *points, MwLLColor color) { - MilskoCocoa *h = handle->cocoa.real; - [h lineWithPoints:points color:color]; +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, + MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h polygonWithPoints:points points_count:points_count color:color]; +} + +static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + MilskoCocoa* h = handle->cocoa.real; + [h lineWithPoints:points color:color]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { - MwLLColor c = malloc(sizeof(*c)); - MwLLColorUpdate(handle, c, r, g, b); - return c; + MwLLColor c = malloc(sizeof(*c)); + MwLLColorUpdate(handle, c, r, g, b); + return c; } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { - (void)handle; + (void)handle; - c->common.red = r; - c->common.green = g; - c->common.blue = b; + c->common.red = r; + c->common.green = g; + c->common.blue = b; } -static void MwLLGetXYWHImpl(MwLL handle, int *x, int *y, unsigned int *w, - unsigned int *height) { - MilskoCocoa *h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; +static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, + unsigned int* height) { + MilskoCocoa* h = handle->cocoa.real; + [h getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa *h = handle->cocoa.real; - [h setX:x Y:y]; + MilskoCocoa* h = handle->cocoa.real; + [h setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa *h = handle->cocoa.real; - [h setW:w H:height]; + MilskoCocoa* h = handle->cocoa.real; + [h setW:w H:height]; } -static void MwLLFreeColorImpl(MwLLColor color) { free(color); } +static void MwLLFreeColorImpl(MwLLColor color) { + free(color); +} static int MwLLPendingImpl(MwLL handle) { - int p = [handle->cocoa.real pending]; - if (p) { - MwLLDispatch(handle, draw, NULL); - } - return p; + int p = [handle->cocoa.real pending]; + if(p) { + MwLLDispatch(handle, draw, NULL); + } + return p; } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h getNextEvent]; + MilskoCocoa* h = handle->cocoa.real; + [h getNextEvent]; } -static void MwLLSetTitleImpl(MwLL handle, const char *title) { - MilskoCocoa *h = handle->cocoa.real; - [h setTitle:title]; +static void MwLLSetTitleImpl(MwLL handle, const char* title) { + MilskoCocoa* h = handle->cocoa.real; + [h setTitle:title]; } -static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char *data, - int width, int height) { - (void)handle; +static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, + int width, int height) { + (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + MwLLPixmap r = malloc(sizeof(*r)); - r->common.raw = malloc(4 * width * height); - memcpy(r->common.raw, data, 4 * width * height); + r->common.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); - r->common.width = width; - r->common.height = height; + r->common.width = width; + r->common.height = height; - r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; + r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; - MwLLPixmapUpdate(r); - free(r->common.raw); - return r; + MwLLPixmapUpdate(r); + free(r->common.raw); + return r; } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap *p = pixmap->cocoa.real; - [p destroy]; - [p dealloc]; - free(pixmap); + MilskoCocoaPixmap* p = pixmap->cocoa.real; + [p destroy]; + [p dealloc]; + free(pixmap); } -static void MwLLDrawPixmapImpl(MwLL handle, MwRect *rect, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; - MwLLForceRender(handle); +static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { + MilskoCocoa* h = handle->cocoa.real; + [h drawPixmap:pixmap rect:rect]; + MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa *h = handle->cocoa.real; - [h setIcon:pixmap]; + MilskoCocoa* h = handle->cocoa.real; + [h setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h forceRender]; + MilskoCocoa* h = handle->cocoa.real; + [h forceRender]; } -static void MwLLSetCursorImpl(MwLL handle, MwCursor *image, MwCursor *mask) { - MilskoCocoa *h = handle->cocoa.real; - [h setCursor:image mask:mask]; +static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { + MilskoCocoa* h = handle->cocoa.real; + [h setCursor:image mask:mask]; } -static void MwLLDetachImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h detachWithPoint:point]; +static void MwLLDetachImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa *h = handle->cocoa.real; - [h show:show]; + MilskoCocoa* h = handle->cocoa.real; + [h show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa *h = handle->cocoa.real; - [h makePopupWithParent:parent]; + MilskoCocoa* h = handle->cocoa.real; + [h makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, - int maxy) { - MilskoCocoa *h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + int maxy) { + MilskoCocoa* h = handle->cocoa.real; + [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeBorderless:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h focus]; + MilskoCocoa* h = handle->cocoa.real; + [h focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa *h = handle->cocoa.real; - [h grabPointer:toggle]; + MilskoCocoa* h = handle->cocoa.real; + [h grabPointer:toggle]; } -static void MwLLSetClipboardImpl(MwLL handle, const char *text) { - MilskoCocoa *h = handle->cocoa.real; - [h setClipboard:text]; +static void MwLLSetClipboardImpl(MwLL handle, const char* text) { + MilskoCocoa* h = handle->cocoa.real; + [h setClipboard:text]; } -static void MwLLGetClipboardImpl(MwLL handle) { (void)handle; } +static void MwLLGetClipboardImpl(MwLL handle) { + (void)handle; +} static void MwLLMakeToolWindowImpl(MwLL handle) { - MilskoCocoa *h = handle->cocoa.real; - [h makeToolWindow]; + MilskoCocoa* h = handle->cocoa.real; + [h makeToolWindow]; } -static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint *point) { - MilskoCocoa *h = handle->cocoa.real; - [h getCursorCoord:point]; +static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { + MilskoCocoa* h = handle->cocoa.real; + [h getCursorCoord:point]; } -static void MwLLGetScreenSizeImpl(MwLL handle, MwRect *rect) { - MilskoCocoa *h = handle->cocoa.real; - [h getScreenSize:rect]; +static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { + MilskoCocoa* h = handle->cocoa.real; + [h getScreenSize:rect]; } -static void MwLLBeginStateChangeImpl(MwLL handle) { MwLLShow(handle, 0); } +static void MwLLBeginStateChangeImpl(MwLL handle) { + MwLLShow(handle, 0); +} -static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } +static void MwLLEndStateChangeImpl(MwLL handle) { + MwLLShow(handle, 1); +} -static int MwLLCocoaCallInitImpl(void) { return 0; } +static int MwLLCocoaCallInitImpl(void) { + return 0; +} #include "call.c" CALL(Cocoa); From d14c17b86e9fcd9929d95b14ca0aff7d5748e446 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 17 Mar 2026 17:43:22 -0700 Subject: [PATCH 186/409] wayland fixes --- examples/basic/clipboard.c | 8 ++--- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 61 +++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index c8882d352..384cbc6fe 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -3,7 +3,7 @@ MwWidget window, instructions, text; void resize(MwWidget handle, void* user_data, void* call_data) { - unsigned int w, h, mh; + unsigned int w, h; (void)user_data; (void)call_data; @@ -12,13 +12,13 @@ void resize(MwWidget handle, void* user_data, void* call_data) { h = MwGetInteger(handle, MwNheight); MwVaApply(instructions, - MwNy, 50 + mh, + MwNy, 50, MwNwidth, w - 50 * 2, MwNheight, h - 125 - 50 * 3, NULL); MwVaApply(text, - MwNy, 200 + mh, + MwNy, 200, MwNwidth, w - 50 * 2, MwNheight, h - 125 - 50 * 3, NULL); @@ -30,7 +30,7 @@ void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)user_data; if(clipboard != NULL) { - MwVaApply(text, MwNtext, clipboard); + MwVaApply(text, MwNtext, clipboard, NULL); MwForceRender(text); } MwForceRender(window); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 0375ecebd..78916dcd9 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -186,6 +186,7 @@ struct _MwLLWayland { MwLL parent; MwBool force_render; + MwBool did_event_loop_early; struct _MwLLWaylandShmBuffer framebuffer; struct _MwLLWaylandShmBuffer cursor; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 7d8faeee1..46b3732a4 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,6 +5,8 @@ #include #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include #include @@ -432,6 +434,9 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { int i; + + p.point.x -= self->wayland.x; + p.point.y -= self->wayland.y; switch(button) { case BTN_LEFT: p.button = MwLLMouseLeft; @@ -1038,12 +1043,6 @@ static int event_loop(MwLL handle) { fd.fd = wl_display_get_fd(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 */ while(wl_display_flush(wayland->display) == -1) { if(errno != EAGAIN) { @@ -1060,19 +1059,17 @@ static int event_loop(MwLL handle) { } } + wl_display_prepare_read(handle->wayland.display); /* Condition where no events are being sent. */ if(!poll(&fd, 1, timeout)) { - wl_display_cancel_read(handle->wayland.display); + wl_display_cancel_read(wayland->display); /* In this case, we need to commit the surface for any animations, etc. */ - wl_surface_commit(handle->wayland.framebuffer.surface); + wl_surface_commit(wayland->framebuffer.surface); return 0; } - if(fd.revents & POLLIN) { - wl_display_read_events(wayland->display); - if(wl_display_dispatch_pending(wayland->display) > 0) { - } - } else { + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) < 0) { wl_display_cancel_read(handle->wayland.display); } @@ -1588,32 +1585,42 @@ static int MwLLPendingImpl(MwLL handle) { MwBool pending = MwFALSE; struct timespec timeout; int i; + timeout.tv_nsec = 1; + timeout.tv_sec = 0; + + pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); if(handle->wayland.always_render) { + event_loop(handle); + return 0; + } + // if(handle->wayland.force_render) { + // // event_loop(handle); + // // handle->wayland.force_render = 0; + // // update_buffer(&handle->wayland.framebuffer); + // return 1; + // } + if(handle->wayland.events_pending || handle->wayland.force_render) { + handle->wayland.did_event_loop_early = MwTRUE; return event_loop(handle); } - timeout.tv_nsec = 10; - timeout.tv_sec = 0; - - if(handle->wayland.force_render) { - return 1; - } - if(handle->wayland.events_pending) { - return 1; - } - - return wl_display_dispatch_timeout(handle->wayland.display, &timeout); + return pending; } static void MwLLNextEventImpl(MwLL handle) { if(!handle->wayland.always_render) { - event_loop(handle); + if(handle->wayland.did_event_loop_early) { + handle->wayland.did_event_loop_early = MwFALSE; + } else { + event_loop(handle); + } } if(handle->wayland.events_pending) { handle->wayland.events_pending = 0; } if(handle->wayland.force_render) { + update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } } @@ -1683,6 +1690,10 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_destroy(c); cairo_surface_destroy(cs); + + MwLLForceRender(handle); + // update_buffer(&handle->wayland.framebuffer); + // wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { From 1cb8fb6c534eccce5e1937e68d5f724c373b9d97 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 17 Mar 2026 20:28:58 -0700 Subject: [PATCH 187/409] wayland: SEVERAL fixes --- include/Mw/LowLevel/Wayland.h | 4 +- src/backend/wayland.c | 72 ++++++++++++++++++++++------------- src/widget/combobox.c | 2 +- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 78916dcd9..c09f81b14 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -178,7 +178,9 @@ struct _MwLLWayland { MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ - MwU32 x, y, ww, wh; /* Window position */ + MwI32 x, y; + MwI32 ox, oy; + MwU32 ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ MwU32 mw, mh; /* Monitor width and height as advertised by wl_output.mode */ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 46b3732a4..21cc561f7 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -7,6 +7,7 @@ #include "../../external/stb_ds.h" #include "Mw/BaseTypes.h" #include "Mw/LowLevel.h" +#include "Mw/LowLevel/Wayland/xdg-shell-client-protocol.h" #include #include @@ -405,12 +406,16 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time WAYLAND_EVENT_OP_START(self); - self->wayland.cur_mouse_pos.x = wl_fixed_to_double(surface_x); - self->wayland.cur_mouse_pos.y = wl_fixed_to_double(surface_y); - - p.point = self->wayland.cur_mouse_pos; + self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); + if(self->wayland.parent != NULL) { + if(!self->wayland.parent->wayland.currentlyHeldWidget) { + MwLLDispatch(self, down, &p); + } + } /* Only draw once every 50 milliseconds */ if((self->wayland.last_time + 50) <= time) { MwLLDispatch(self, draw, NULL); @@ -429,14 +434,16 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLL self = data; MwLLMouse p; + int x = self->wayland.x; + int y = self->wayland.y; + WAYLAND_EVENT_OP_START(self); p.point = self->wayland.cur_mouse_pos; - if(p.point.x > self->wayland.x && p.point.x < self->wayland.x + self->wayland.ww && p.point.y > self->wayland.y && p.point.y < self->wayland.y + self->wayland.wh) { + + if(p.point.x > x && p.point.x < x + self->wayland.ww && p.point.y > y && p.point.y < y + self->wayland.wh) { int i; - p.point.x -= self->wayland.x; - p.point.y -= self->wayland.y; switch(button) { case BTN_LEFT: p.button = MwLLMouseLeft; @@ -1006,13 +1013,18 @@ static void region_invalidate(MwLL handle) { if(!handle->wayland.configured) { return; } - wl_region_subtract(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + wl_region_subtract(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void region_setup(MwLL handle) { if(!handle->wayland.configured) { return; } - wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww, handle->wayland.wh); + + if(handle->wayland.type == MWLL_WAYLAND_POPUP) { + wl_region_add(handle->wayland.region, 0, 0, handle->wayland.ww + abs(handle->wayland.x), handle->wayland.wh + abs(handle->wayland.y)); + } else { + wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww + abs(handle->wayland.x), handle->wayland.wh + abs(handle->wayland.y)); + } wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } @@ -1116,6 +1128,8 @@ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); + r->wayland.x = x; + r->wayland.y = y; setup_callbacks(&r->wayland); @@ -1251,9 +1265,9 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { /* Sublevel setup function */ static void destroy_sublevel(MwLL r) { - wl_subsurface_destroy(r->wayland.sublevel->subsurface); + framebuffer_destroy(&r->wayland); - wl_surface_destroy(r->wayland.framebuffer.surface); + wl_subsurface_destroy(r->wayland.sublevel->subsurface); free(r->wayland.sublevel); } @@ -1315,10 +1329,11 @@ static void setup_popup(MwLL r, int x, int y) { r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); - xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_NONE); xdg_positioner_set_anchor_rect( - r->wayland.popup->xdg_positioner, 0, 0, 1, 1); - xdg_positioner_set_offset(r->wayland.popup->xdg_positioner, x, y); + r->wayland.popup->xdg_positioner, + x, y, r->wayland.ww, r->wayland.wh); + xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); + xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; @@ -1341,6 +1356,9 @@ static void setup_popup(MwLL r, int x, int y) { /* Perform the initial commit and wait for the first configure event */ wl_surface_commit(r->wayland.framebuffer.surface); event_loop(r); + + // framebuffer_destroy(&r->wayland); + framebuffer_setup(&r->wayland); } /* Popup destroy function */ @@ -1431,7 +1449,7 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&handle->wayland.eventsMutex); pthread_mutex_destroy(&handle->wayland.eventsMutex); - framebuffer_destroy(&handle->wayland); + // framebuffer_destroy(&handle->wayland); buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); @@ -1482,8 +1500,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); } if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - destroy_popup(handle); - setup_popup(handle, x, y); } region_setup(handle); @@ -1507,6 +1523,11 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } + if(handle->wayland.type == MWLL_WAYLAND_POPUP) { + destroy_popup(handle); + setup_popup(handle, handle->wayland.x, handle->wayland.y); + } + refresh: region_setup(handle); @@ -1594,12 +1615,12 @@ static int MwLLPendingImpl(MwLL handle) { event_loop(handle); return 0; } - // if(handle->wayland.force_render) { - // // event_loop(handle); - // // handle->wayland.force_render = 0; - // // update_buffer(&handle->wayland.framebuffer); - // return 1; - // } + if(handle->wayland.force_render) { + // event_loop(handle); + // handle->wayland.force_render = 0; + // update_buffer(&handle->wayland.framebuffer); + return 1; + } if(handle->wayland.events_pending || handle->wayland.force_render) { handle->wayland.did_event_loop_early = MwTRUE; return event_loop(handle); @@ -1812,7 +1833,7 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { switch(handle->wayland.type_to_be) { case MWLL_WAYLAND_POPUP: setup_popup(handle, point->x, point->y); - return; + break; default: setup_toplevel(handle, point->x, point->y); break; @@ -1842,9 +1863,6 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { 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"); } } } diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 6b5437335..591258f96 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -138,8 +138,8 @@ static void click(MwWidget handle) { p.x = 0; p.y = MwGetInteger(handle, MwNheight); MwLLBeginStateChange(cb->listbox->lowlevel); - MwLLDetach(cb->listbox->lowlevel, &p); MwLLMakeToolWindow(cb->listbox->lowlevel); + MwLLDetach(cb->listbox->lowlevel, &p); MwLLEndStateChange(cb->listbox->lowlevel); } else { MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); From eb0919333a78355a49f03bf1f8772288c00ebf47 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 17 Mar 2026 20:39:37 -0700 Subject: [PATCH 188/409] wayland: fix several examples --- src/backend/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 21cc561f7..d7d539115 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1616,7 +1616,7 @@ static int MwLLPendingImpl(MwLL handle) { return 0; } if(handle->wayland.force_render) { - // event_loop(handle); + MwLLDispatch(handle, draw, NULL); // handle->wayland.force_render = 0; // update_buffer(&handle->wayland.framebuffer); return 1; From fc7896b5ce1e018ead507f0033ec235273172847 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 17 Mar 2026 22:17:05 -0700 Subject: [PATCH 189/409] wayland: improve event loop --- src/backend/wayland.c | 29 +- src/widget/opengl.c | 627 +++++++++++++++++++++--------------------- 2 files changed, 326 insertions(+), 330 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d7d539115..7037a5d97 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1046,8 +1046,12 @@ static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* /* Standard Wayland event loop. */ static int event_loop(MwLL handle) { struct pollfd fd; - int timeout = 1; + struct timespec timeout; struct _MwLLWayland* wayland = &handle->wayland; + int res; + + timeout.tv_nsec = 1; + timeout.tv_sec = 0; if(wayland->display == NULL) { return 0; @@ -1072,19 +1076,15 @@ static int event_loop(MwLL handle) { } wl_display_prepare_read(handle->wayland.display); - /* 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_display_read_events(wayland->display); + if((res = wl_display_dispatch_timeout(wayland->display, &timeout)) <= 0) { + if(res < 0) { + wl_display_cancel_read(handle->wayland.display); + } + wl_surface_commit(wayland->framebuffer.surface); return 0; } - - wl_display_read_events(wayland->display); - if(wl_display_dispatch_pending(wayland->display) < 0) { - wl_display_cancel_read(handle->wayland.display); - } - return 1; } @@ -1605,20 +1605,17 @@ static void MwLLFreeColorImpl(MwLLColor color) { static int MwLLPendingImpl(MwLL handle) { MwBool pending = MwFALSE; struct timespec timeout; - int i; timeout.tv_nsec = 1; timeout.tv_sec = 0; + int i; pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); if(handle->wayland.always_render) { event_loop(handle); return 0; - } - if(handle->wayland.force_render) { + } else if(handle->wayland.force_render) { MwLLDispatch(handle, draw, NULL); - // handle->wayland.force_render = 0; - // update_buffer(&handle->wayland.framebuffer); return 1; } if(handle->wayland.events_pending || handle->wayland.force_render) { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 0f9c5c24f..b508ef6b5 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -4,46 +4,46 @@ #include #ifdef USE_GDI -typedef HGLRC(WINAPI *MWwglCreateContext)(HDC); -typedef BOOL(WINAPI *MWwglMakeCurrent)(HDC, HGLRC); -typedef PROC(WINAPI *MWwglGetProcAddress)(LPCSTR); -typedef BOOL(WINAPI *MWwglDeleteContext)(HGLRC); +typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); +typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); +typedef PROC(WINAPI* MWwglGetProcAddress)(LPCSTR); +typedef BOOL(WINAPI* MWwglDeleteContext)(HGLRC); typedef struct gdiopengl { - HDC dc; - HGLRC gl; + HDC dc; + HGLRC gl; - void *lib; + void* lib; - MWwglCreateContext wglCreateContext; - MWwglMakeCurrent wglMakeCurrent; - MWwglDeleteContext wglDeleteContext; - MWwglGetProcAddress wglGetProcAddress; + MWwglCreateContext wglCreateContext; + MWwglMakeCurrent wglMakeCurrent; + MWwglDeleteContext wglDeleteContext; + MWwglGetProcAddress wglGetProcAddress; } gdiopengl_t; #endif #ifdef USE_X11 -typedef XVisualInfo *(*MWglXChooseVisual)(Display *dpy, int screen, - int *attribList); -typedef GLXContext (*MWglXCreateContext)(Display *dpy, XVisualInfo *vis, - GLXContext shareList, Bool direct); -typedef void (*MWglXDestroyContext)(Display *dpy, GLXContext ctx); -typedef Bool (*MWglXMakeCurrent)(Display *dpy, GLXDrawable drawable, - GLXContext ctx); -typedef void (*MWglXSwapBuffers)(Display *dpy, GLXDrawable drawable); -typedef void *(*MWglXGetProcAddress)(const GLubyte *procname); +typedef XVisualInfo* (*MWglXChooseVisual)(Display* dpy, int screen, + int* attribList); +typedef GLXContext (*MWglXCreateContext)(Display* dpy, XVisualInfo* vis, + GLXContext shareList, Bool direct); +typedef void (*MWglXDestroyContext)(Display* dpy, GLXContext ctx); +typedef Bool (*MWglXMakeCurrent)(Display* dpy, GLXDrawable drawable, + GLXContext ctx); +typedef void (*MWglXSwapBuffers)(Display* dpy, GLXDrawable drawable); +typedef void* (*MWglXGetProcAddress)(const GLubyte* procname); typedef struct x11opengl { - XVisualInfo *visual; - GLXContext gl; + XVisualInfo* visual; + GLXContext gl; - void *lib; + void* lib; - MWglXChooseVisual glXChooseVisual; - MWglXCreateContext glXCreateContext; - MWglXDestroyContext glXDestroyContext; - MWglXMakeCurrent glXMakeCurrent; - MWglXSwapBuffers glXSwapBuffers; - MWglXGetProcAddress glXGetProcAddress; + MWglXChooseVisual glXChooseVisual; + MWglXCreateContext glXCreateContext; + MWglXDestroyContext glXDestroyContext; + MWglXMakeCurrent glXMakeCurrent; + MWglXSwapBuffers glXSwapBuffers; + MWglXGetProcAddress glXGetProcAddress; } x11opengl_t; #endif @@ -52,385 +52,384 @@ typedef struct x11opengl { #include typedef struct waylandopengl { - EGLNativeWindowType egl_window_native; - EGLDisplay egl_display; - EGLContext egl_context; - EGLSurface egl_surface; - EGLConfig egl_config; + EGLNativeWindowType egl_window_native; + EGLDisplay egl_display; + EGLContext egl_context; + EGLSurface egl_surface; + EGLConfig egl_config; } waylandopengl_t; #endif static int create(MwWidget handle) { - void *r = NULL; - MwWidget w = handle; + void* r = NULL; + MwWidget w = handle; #ifdef USE_GDI - if (handle->lowlevel->common.type == MwLLBackendGDI) { - PIXELFORMATDESCRIPTOR pfd; - int pf; - gdiopengl_t *o = r = malloc(sizeof(*o)); + if(handle->lowlevel->common.type == MwLLBackendGDI) { + PIXELFORMATDESCRIPTOR pfd; + int pf; + gdiopengl_t* o = r = malloc(sizeof(*o)); - memset(&pfd, 0, sizeof(pfd)); - pfd.nSize = sizeof(pfd); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; - pfd.cDepthBits = 32; - pfd.cColorBits = 32; + memset(&pfd, 0, sizeof(pfd)); + pfd.nSize = sizeof(pfd); + pfd.nVersion = 1; + pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; + pfd.cDepthBits = 32; + pfd.cColorBits = 32; - o->dc = GetDC(handle->lowlevel->gdi.hWnd); + o->dc = GetDC(handle->lowlevel->gdi.hWnd); - pf = ChoosePixelFormat(o->dc, &pfd); - SetPixelFormat(o->dc, pf, &pfd); + pf = ChoosePixelFormat(o->dc, &pfd); + SetPixelFormat(o->dc, pf, &pfd); - o->lib = MwDynamicOpen("opengl32.dll"); + o->lib = MwDynamicOpen("opengl32.dll"); - o->wglCreateContext = - (MWwglCreateContext)(void *)MwDynamicSymbol(o->lib, "wglCreateContext"); - o->wglMakeCurrent = - (MWwglMakeCurrent)(void *)MwDynamicSymbol(o->lib, "wglMakeCurrent"); - o->wglDeleteContext = - (MWwglDeleteContext)(void *)MwDynamicSymbol(o->lib, "wglDeleteContext"); - o->wglGetProcAddress = (MWwglGetProcAddress)(void *)MwDynamicSymbol( - o->lib, "wglGetProcAddress"); + o->wglCreateContext = + (MWwglCreateContext)(void*)MwDynamicSymbol(o->lib, "wglCreateContext"); + o->wglMakeCurrent = + (MWwglMakeCurrent)(void*)MwDynamicSymbol(o->lib, "wglMakeCurrent"); + o->wglDeleteContext = + (MWwglDeleteContext)(void*)MwDynamicSymbol(o->lib, "wglDeleteContext"); + o->wglGetProcAddress = (MWwglGetProcAddress)(void*)MwDynamicSymbol( + o->lib, "wglGetProcAddress"); - o->gl = o->wglCreateContext(o->dc); - } + o->gl = o->wglCreateContext(o->dc); + } #endif #ifdef USE_X11 - if (handle->lowlevel->common.type == MwLLBackendX11) { - int attribs[5]; - const char *glpath[] = {"libGL.so", "/usr/local/lib/libGL.so", - "/usr/X11R7/lib/libGL.so", "/usr/pkg/lib/libGL.so"}; - int glincr = 0; - x11opengl_t *o = r = malloc(sizeof(*o)); + if(handle->lowlevel->common.type == MwLLBackendX11) { + int attribs[5]; + const char* glpath[] = {"libGL.so", "/usr/local/lib/libGL.so", + "/usr/X11R7/lib/libGL.so", "/usr/pkg/lib/libGL.so"}; + int glincr = 0; + x11opengl_t* o = r = malloc(sizeof(*o)); - attribs[0] = GLX_RGBA; - attribs[1] = GLX_DOUBLEBUFFER; - attribs[2] = GLX_DEPTH_SIZE; - attribs[3] = 24; - attribs[4] = None; + attribs[0] = GLX_RGBA; + attribs[1] = GLX_DOUBLEBUFFER; + attribs[2] = GLX_DEPTH_SIZE; + attribs[3] = 24; + attribs[4] = None; - while (glpath[glincr] != NULL && - (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL) - ; + while(glpath[glincr] != NULL && + (o->lib = MwDynamicOpen(glpath[glincr++])) == NULL); - o->glXChooseVisual = - (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); - o->glXCreateContext = - (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); - o->glXDestroyContext = - (MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext"); - o->glXMakeCurrent = - (MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent"); - o->glXSwapBuffers = - (MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers"); - o->glXGetProcAddress = - (MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress"); + o->glXChooseVisual = + (MWglXChooseVisual)MwDynamicSymbol(o->lib, "glXChooseVisual"); + o->glXCreateContext = + (MWglXCreateContext)MwDynamicSymbol(o->lib, "glXCreateContext"); + o->glXDestroyContext = + (MWglXDestroyContext)MwDynamicSymbol(o->lib, "glXDestroyContext"); + o->glXMakeCurrent = + (MWglXMakeCurrent)MwDynamicSymbol(o->lib, "glXMakeCurrent"); + o->glXSwapBuffers = + (MWglXSwapBuffers)MwDynamicSymbol(o->lib, "glXSwapBuffers"); + o->glXGetProcAddress = + (MWglXGetProcAddress)MwDynamicSymbol(o->lib, "glXGetProcAddress"); - /* XXX: fix this */ - o->visual = o->glXChooseVisual(handle->lowlevel->x11.display, - DefaultScreen(handle->lowlevel->x11.display), - attribs); - o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL, - GL_TRUE); - } + /* XXX: fix this */ + o->visual = o->glXChooseVisual(handle->lowlevel->x11.display, + DefaultScreen(handle->lowlevel->x11.display), + attribs); + o->gl = o->glXCreateContext(handle->lowlevel->x11.display, o->visual, NULL, + GL_TRUE); + } #endif #ifdef USE_WAYLAND - if (handle->lowlevel->common.type == MwLLBackendWayland) { - int err; - EGLint numConfigs; - EGLint majorVersion; - EGLint minorVersion; - EGLContext context; - EGLSurface surface; - EGLint fbAttribs[] = {EGL_SURFACE_TYPE, - EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, - EGL_OPENGL_ES2_BIT, - EGL_RED_SIZE, - 8, - EGL_GREEN_SIZE, - 8, - EGL_BLUE_SIZE, - 8, - EGL_DEPTH_SIZE, - 24, - 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; - waylandopengl_t *o = r = malloc(sizeof(*o)); - MwLL topmost_parent = handle->lowlevel->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; + if(handle->lowlevel->common.type == MwLLBackendWayland) { + int err; + EGLint numConfigs; + EGLint majorVersion; + EGLint minorVersion; + EGLContext context; + EGLSurface surface; + EGLint fbAttribs[] = {EGL_SURFACE_TYPE, + EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, + EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, + 8, + EGL_GREEN_SIZE, + 8, + EGL_BLUE_SIZE, + 8, + EGL_DEPTH_SIZE, + 24, + 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; + waylandopengl_t* o = r = malloc(sizeof(*o)); + MwLL topmost_parent = handle->lowlevel->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; - while (topmost_parent->wayland.parent != NULL) { - topmost_parent = topmost_parent->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; - } + while(topmost_parent->wayland.parent != NULL) { + topmost_parent = topmost_parent->wayland.parent; + topmost_parent->wayland.always_render = MwTRUE; + } - display = - eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->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; - } + display = + eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->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; - } + /* 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, &o->egl_config, 1, &numConfigs) != - EGL_TRUE) || - (numConfigs != 1)) { - printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); - return MwFALSE; - } + /* Choose config */ + if((eglChooseConfig(display, fbAttribs, &o->egl_config, 1, &numConfigs) != + EGL_TRUE) || + (numConfigs != 1)) { + printf("ERROR: eglChooseConfig, %0X\n", eglGetError()); + return MwFALSE; + } - o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create( - handle->lowlevel->wayland.framebuffer.surface, - handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); - if (!o->egl_window_native) { - printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); - return MwFALSE; - } + o->egl_window_native = (EGLNativeWindowType)wl_egl_window_create( + handle->lowlevel->wayland.framebuffer.surface, + handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh); + if(!o->egl_window_native) { + printf("ERROR: wl_egl_window_create, EGL_NO_SURFACE\n"); + return MwFALSE; + } - /* Create a surface */ - surface = eglCreateWindowSurface(display, o->egl_config, - o->egl_window_native, NULL); - if (surface == EGL_NO_SURFACE) { - printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); - return MwFALSE; - } + /* Create a surface */ + surface = eglCreateWindowSurface(display, o->egl_config, + o->egl_window_native, NULL); + if(surface == EGL_NO_SURFACE) { + printf("ERROR: eglCreateWindowSurface, %0X\n", eglGetError()); + return MwFALSE; + } - eglBindAPI(EGL_OPENGL_API); + eglBindAPI(EGL_OPENGL_API); - /* Create a GL context */ - context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, - contextAttribs); - if (context == EGL_NO_CONTEXT) { - printf("ERROR: eglCreateContext, %0X\n", eglGetError()); - return MwFALSE; - } + /* Create a GL context */ + context = eglCreateContext(display, o->egl_config, EGL_NO_CONTEXT, + contextAttribs); + if(context == EGL_NO_CONTEXT) { + printf("ERROR: eglCreateContext, %0X\n", eglGetError()); + return MwFALSE; + } - if (!eglMakeCurrent(display, surface, surface, context)) { - printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); - } + if(!eglMakeCurrent(display, surface, surface, context)) { + printf("ERROR: eglMakeCurrent (setup): %0X\n", eglGetError()); + } - o->egl_display = display; - o->egl_surface = surface; - o->egl_context = context; - } + o->egl_display = display; + o->egl_surface = surface; + o->egl_context = context; + } #endif - handle->internal = r; - handle->lowlevel->common.copy_buffer = 0; + handle->internal = r; + handle->lowlevel->common.copy_buffer = 0; - MwSetDefault(handle); + MwSetDefault(handle); - while (w->parent != NULL) - w = w->parent; + while(w->parent != NULL) + w = w->parent; - w->berserk++; + w->berserk++; - return 0; + return 0; } static void destroy(MwWidget handle) { - MwWidget w = handle; + MwWidget w = handle; #ifdef USE_GDI - if (handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; - o->wglMakeCurrent(NULL, NULL); - DeleteDC(o->dc); - o->wglDeleteContext(o->gl); + o->wglMakeCurrent(NULL, NULL); + DeleteDC(o->dc); + o->wglDeleteContext(o->gl); - MwDynamicClose(o->lib); - } + MwDynamicClose(o->lib); + } #endif #ifdef USE_X11 - if (handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; - o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL); - o->glXDestroyContext(handle->lowlevel->x11.display, o->gl); + o->glXMakeCurrent(handle->lowlevel->x11.display, None, NULL); + o->glXDestroyContext(handle->lowlevel->x11.display, o->gl); - MwDynamicClose(o->lib); - } + MwDynamicClose(o->lib); + } #endif #ifdef USE_WAYLAND - if (handle->lowlevel->common.type == MwLLBackendWayland) { - /* todo */ - } + if(handle->lowlevel->common.type == MwLLBackendWayland) { + /* todo */ + } #endif - while (w->parent != NULL) - w = w->parent; + while(w->parent != NULL) + w = w->parent; - w->berserk--; + w->berserk--; - free(handle->internal); + free(handle->internal); } static void mwOpenGLMakeCurrentImpl(MwWidget handle) { - /* these swap interval functions belonging here actually stink! */ + /* these swap interval functions belonging here actually stink! */ #ifdef USE_GDI - if (handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t *o = handle->internal; - void (*swap_interval_ext)(int) = NULL; + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; + void (*swap_interval_ext)(int) = NULL; - o->wglMakeCurrent(o->dc, o->gl); + o->wglMakeCurrent(o->dc, o->gl); - if ((swap_interval_ext = - MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { - swap_interval_ext(1); - } - } + if((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "wglSwapIntervalEXT")) != NULL) { + swap_interval_ext(1); + } + } #endif #ifdef USE_X11 - if (handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t *o = handle->internal; - void (*swap_interval_ext)(Display *, GLXDrawable, int) = NULL; - void (*swap_interval_mesa)(unsigned int) = NULL; - void (*swap_interval_sgi)(int) = NULL; + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; + void (*swap_interval_ext)(Display*, GLXDrawable, int) = NULL; + void (*swap_interval_mesa)(unsigned int) = NULL; + void (*swap_interval_sgi)(int) = NULL; - o->glXMakeCurrent(handle->lowlevel->x11.display, - handle->lowlevel->x11.window, o->gl); + o->glXMakeCurrent(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, o->gl); - if ((swap_interval_ext = - MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { - swap_interval_ext(handle->lowlevel->x11.display, - handle->lowlevel->x11.window, 1); - } + if((swap_interval_ext = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalEXT")) != NULL) { + swap_interval_ext(handle->lowlevel->x11.display, + handle->lowlevel->x11.window, 1); + } - if ((swap_interval_mesa = - MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { - swap_interval_mesa(1); - } + if((swap_interval_mesa = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalMESA")) != NULL) { + swap_interval_mesa(1); + } - if ((swap_interval_sgi = - MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { - swap_interval_sgi(1); - } - } + if((swap_interval_sgi = + MwOpenGLGetProcAddress(handle, "glXSwapIntervalSGI")) != NULL) { + swap_interval_sgi(1); + } + } #endif #ifdef USE_WAYLAND - if (handle->lowlevel->common.type == MwLLBackendWayland) { - waylandopengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; - if (!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, - o->egl_context)) { - printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); - } + if(!eglMakeCurrent(o->egl_display, o->egl_surface, o->egl_surface, + o->egl_context)) { + printf("ERROR: eglMakeCurrent, %0X\n", eglGetError()); + } - eglSwapInterval(o->egl_display, 1); - } + eglSwapInterval(o->egl_display, 1); + } #endif } static void mwOpenGLSwapBufferImpl(MwWidget handle) { #ifdef USE_GDI - if (handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; - SwapBuffers(o->dc); - } + SwapBuffers(o->dc); + } #endif #ifdef USE_X11 - if (handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; - o->glXSwapBuffers(handle->lowlevel->x11.display, - handle->lowlevel->x11.window); - } + o->glXSwapBuffers(handle->lowlevel->x11.display, + handle->lowlevel->x11.window); + } #endif #ifdef USE_WAYLAND - if (handle->lowlevel->common.type == MwLLBackendWayland) { - waylandopengl_t *o = handle->internal; - eglSwapInterval(o->egl_display, 0); - if (!eglSwapBuffers(o->egl_display, o->egl_surface)) { - printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); - }; - wl_egl_window_resize((struct wl_egl_window *)o->egl_window_native, - handle->lowlevel->wayland.ww, - handle->lowlevel->wayland.wh, 0, 0); - MwLLForceRender(handle->lowlevel); - } + if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; + // eglSwapInterval(o->egl_display, 0); + if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { + printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); + }; + wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, + handle->lowlevel->wayland.ww, + handle->lowlevel->wayland.wh, 0, 0); + // MwLLForceRender(handle->lowlevel); + } #endif } -static void *mwOpenGLGetProcAddressImpl(MwWidget handle, const char *name) { +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #ifdef USE_GDI - if (handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendGDI) { + gdiopengl_t* o = handle->internal; - return o->wglGetProcAddress(name); - } + return o->wglGetProcAddress(name); + } #endif #ifdef USE_X11 - if (handle->lowlevel->common.type == MwLLBackendX11) { - x11opengl_t *o = handle->internal; + if(handle->lowlevel->common.type == MwLLBackendX11) { + x11opengl_t* o = handle->internal; - return o->glXGetProcAddress((const GLubyte *)name); - } + return o->glXGetProcAddress((const GLubyte*)name); + } #endif #ifdef USE_WAYLAND - if (handle->lowlevel->common.type == MwLLBackendWayland) { - return eglGetProcAddress(name); - } + if(handle->lowlevel->common.type == MwLLBackendWayland) { + return eglGetProcAddress(name); + } #endif - return NULL; + return NULL; } -static void func_handler(MwWidget handle, const char *name, void *out, - va_list va) { - if (strcmp(name, "mwOpenGLMakeCurrent") == 0) { - mwOpenGLMakeCurrentImpl(handle); - } - if (strcmp(name, "mwOpenGLSwapBuffer") == 0) { - mwOpenGLSwapBufferImpl(handle); - } - if (strcmp(name, "mwOpenGLGetProcAddress") == 0) { - const char *_name = va_arg(va, const char *); - *(void **)out = mwOpenGLGetProcAddressImpl(handle, _name); - } +static void func_handler(MwWidget handle, const char* name, void* out, + va_list va) { + if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if(strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if(strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char* _name = va_arg(va, const char*); + *(void**)out = mwOpenGLGetProcAddressImpl(handle, _name); + } } -MwClassRec MwOpenGLClassRec = {create, /* create */ - destroy, /* destroy */ - NULL, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - NULL, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - func_handler, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, NULL, NULL, NULL}; -MwClass MwOpenGLClass = &MwOpenGLClassRec; +MwClassRec MwOpenGLClassRec = {create, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; -#endif \ No newline at end of file +#endif From 9309b5fe83b2ac924824d24620bf44d2c19f4d8e Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 18 Mar 2026 19:24:51 -0700 Subject: [PATCH 190/409] remove old hacks from wayland code, including MwLLBeginDraw and MwLLEndDraw which was really only ever needed for wayland and not anymore --- include/Mw/LowLevel.h | 2 -- src/backend/call.c | 6 ++---- src/backend/cocoa.m | 26 ++++++++----------------- src/backend/gdi.c | 8 -------- src/backend/wayland.c | 45 ++----------------------------------------- src/backend/x11.c | 11 ++--------- src/core.c | 3 --- src/lowlevel.c | 3 --- src/widget/opengl.c | 2 -- 9 files changed, 14 insertions(+), 92 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 9766d052f..30d7f310a 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -190,8 +190,6 @@ 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 (*MwLLBeginDraw)(MwLL handle); -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 e2ce934c9..2ce5ed234 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -8,10 +8,8 @@ MwLLCreate = MwLLCreateImpl; \ MwLLDestroy = MwLLDestroyImpl; \ \ - MwLLPolygon = MwLLPolygonImpl; \ - MwLLLine = MwLLLineImpl; \ - MwLLBeginDraw = MwLLBeginDrawImpl; \ - MwLLEndDraw = MwLLEndDrawImpl; \ + MwLLPolygon = MwLLPolygonImpl; \ + MwLLLine = MwLLLineImpl; \ \ MwLLAllocColor = MwLLAllocColorImpl; \ MwLLColorUpdate = MwLLColorUpdateImpl; \ diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index c05fae59e..738ab1089 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -24,10 +24,10 @@ static NSPoint pointFlip(NSPoint point) { static NSRect localRectFlip(NSRect originFrame, NSView* view) { float viewHeight = [view bounds].size.height; NSRect destinationFrame = NSMakeRect( - originFrame.origin.x, - [view bounds].size.height - (originFrame.origin.y + originFrame.size.height), - originFrame.size.width, - originFrame.size.height); + originFrame.origin.x, + [view bounds].size.height - (originFrame.origin.y + originFrame.size.height), + originFrame.size.width, + originFrame.size.height); return destinationFrame; } @@ -151,8 +151,8 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { if(parent) { MilskoCocoa* topmost = p; - NSRect rect = localRectFlip(c->rect, p->view); - printf("%0.2f %0.2f %0.2f %0.2f\n",c->rect.origin.x, c->rect.origin.y, c->rect.size.width, c->rect.size.height); + NSRect rect = localRectFlip(c->rect, p->view); + printf("%0.2f %0.2f %0.2f %0.2f\n", c->rect.origin.x, c->rect.origin.y, c->rect.size.width, c->rect.size.height); c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; [c->view setBounds:c->rect]; } else { @@ -181,7 +181,6 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { c->pointerLocked = MwFALSE; - return c; } @@ -279,7 +278,7 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { } }; - (int)pending { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [NSApp runModalSession:self->modalSession]; [pool release]; return 1; @@ -327,7 +326,6 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { objectAtIndex:0]) pointer]; } - switch([ev type]) { case NSLeftMouseDragged: case NSRightMouseDragged: @@ -808,7 +806,7 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { - (void)drawRect:(NSRect)dirtyRect { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSSize sz = [self->rep size]; - MwLL ll = [((MilskoFakePointer *)[[[[self window] contentView] subviews] + MwLL ll = [((MilskoFakePointer*)[[[[self window] contentView] subviews] objectAtIndex:0]) pointer]; [super drawRect:dirtyRect]; @@ -1003,14 +1001,6 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; -} - static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { MilskoCocoa* h = handle->cocoa.real; diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 4601b79da..3c286a8e5 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -310,14 +310,6 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLEndDrawImpl(MwLL handle) { - (void)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 7037a5d97..c85ca6a29 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,16 +5,12 @@ #include #include "../../external/stb_ds.h" -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" -#include "Mw/LowLevel/Wayland/xdg-shell-client-protocol.h" #include #include #include /* TODO: - * - MwLLGrabPointerImpl * - MwLLMakePopupImpl * - MwLLShowImpl */ @@ -250,8 +246,6 @@ static void wl_data_source_listener_send(void* data, if(self->wayland.clipboard_buffer != NULL) { write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); close(fd); - - self->wayland.events_pending = 1; } WAYLAND_EVENT_OP_END(self); }; @@ -296,8 +290,6 @@ static void zwp_primary_selection_source_v1_send(void* data, if(self->wayland.clipboard_buffer != NULL) { write(fd, self->wayland.clipboard_buffer, strlen(self->wayland.clipboard_buffer)); close(fd); - - self->wayland.events_pending = 1; } WAYLAND_EVENT_OP_END(self); @@ -422,11 +414,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time self->wayland.last_time = time; } - self->wayland.events_pending += 1; - WAYLAND_EVENT_OP_END(self); - - /*timed_redraw(self, time, 50, &self->wayland.cooldown_timer);*/ }; /* `wl_pointer.button` callback */ @@ -481,7 +469,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; } WAYLAND_EVENT_OP_END(self); @@ -540,7 +527,6 @@ static void keyboard_enter(void* data, self->wayland.keyboard_serial = serial; MwLLDispatch(self, focus_in, NULL); - self->wayland.events_pending += 1; WAYLAND_EVENT_OP_END(self); }; @@ -555,7 +541,6 @@ static void keyboard_leave(void* data, WAYLAND_EVENT_OP_START(self); MwLLDispatch(self, focus_out, NULL); - self->wayland.events_pending += 1; WAYLAND_EVENT_OP_END(self); }; @@ -659,7 +644,6 @@ static void keyboard_key(void* data, if(!self->wayland.always_render) { MwLLDispatch(self, draw, NULL); - self->wayland.events_pending += 1; } WAYLAND_EVENT_OP_END(self); @@ -783,7 +767,6 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { free(data->listener); - // wl_seat_destroy(data->context); } /* wl_output setup function */ @@ -832,7 +815,6 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa } static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // xdg_wm_base_destroy(data->context); free(data->listener); } @@ -857,10 +839,6 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ } static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - zxdg_decoration_manager_v1_context_t* context = data->context; - - // zxdg_decoration_manager_v1_destroy(context->manager); - // zxdg_toplevel_decoration_v1_destroy(context->decoration); } /* `xdg_toplevel.close` callback */ @@ -1000,8 +978,6 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); update_buffer(&wayland->framebuffer); - - wayland->events_pending += 1; }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -1040,7 +1016,6 @@ static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { free(data->listener); - // xdg_toplevel_icon_manager_v1_destroy(data->context); } /* Standard Wayland event loop. */ @@ -1504,7 +1479,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { region_setup(handle); MwLLDispatch(handle, draw, NULL); - handle->wayland.events_pending += 1; } static void MwLLSetWHImpl(MwLL handle, int w, int h) { @@ -1551,7 +1525,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL cairo_close_path(handle->wayland.cairo); cairo_fill(handle->wayland.cairo); - handle->wayland.events_pending += 1; + handle->wayland.events_pending = 1; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { @@ -1570,16 +1544,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { cairo_close_path(handle->wayland.cairo); cairo_stroke(handle->wayland.cairo); - handle->wayland.events_pending += 1; -} - -static void MwLLBeginDrawImpl(MwLL handle) { -} - -static void MwLLEndDrawImpl(MwLL handle) { - update_buffer(&handle->wayland.framebuffer); - - handle->wayland.events_pending += 1; + handle->wayland.events_pending = 1; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -1756,12 +1721,6 @@ static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); handle->wayland.force_render = MwTRUE; - - /* - if(handle->wayland.egl_setup) { - timed_redraw_by_epoch(handle, 25); - } - */ } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { diff --git a/src/backend/x11.c b/src/backend/x11.c index f7c6fe4bd..6124ceeae 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -261,15 +261,8 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } -static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; -} - -static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { +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 9902a30e7..c3274a150 100644 --- a/src/core.c +++ b/src/core.c @@ -6,14 +6,11 @@ static void lldrawhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; (void)data; - MwLLBeginDraw(handle); h->bgcolor = NULL; MwDispatch(h, draw); if(h->draw_inject != NULL) h->draw_inject(h); MwDispatchUserHandler(h, MwNdrawHandler, NULL); - - MwLLEndDraw(handle); } static void lluphandler(MwLL handle, void* data) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 8f8a4d932..eeabaa339 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -6,9 +6,6 @@ void (*MwLLDestroy)(MwLL handle) = NULL; void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color) = NULL; void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color) = NULL; -void (*MwLLBeginDraw)(MwLL handle) = NULL; -void (*MwLLEndDraw)(MwLL handle) = NULL; - MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b) = NULL; void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b) = NULL; void (*MwLLFreeColor)(MwLLColor color) = NULL; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index b508ef6b5..779b17afa 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -364,14 +364,12 @@ static void mwOpenGLSwapBufferImpl(MwWidget handle) { #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { waylandopengl_t* o = handle->internal; - // eglSwapInterval(o->egl_display, 0); if(!eglSwapBuffers(o->egl_display, o->egl_surface)) { printf("ERROR: eglSwapBuffers, %0X\n", eglGetError()); }; wl_egl_window_resize((struct wl_egl_window*)o->egl_window_native, handle->lowlevel->wayland.ww, handle->lowlevel->wayland.wh, 0, 0); - // MwLLForceRender(handle->lowlevel); } #endif } From 0a62467760d794414516de1af6bdfd3d83f13f2a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 18 Mar 2026 23:01:39 -0700 Subject: [PATCH 191/409] correct mouse clicks --- include/Mw/LowLevel/Wayland.h | 2 ++ src/backend/wayland.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c09f81b14..024881388 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -204,6 +204,8 @@ struct _MwLLWayland { MwLL currentlyHeldWidget; + struct wl_surface* curSurface; + cairo_surface_t* cs; cairo_t* cairo; }; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index c85ca6a29..f15d3d7b9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -377,6 +377,7 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 seria MwLL self = data; WAYLAND_EVENT_OP_START(self); + self->wayland.curSurface = surface; self->wayland.pointer_serial = serial; @@ -429,7 +430,11 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; - if(p.point.x > x && p.point.x < x + self->wayland.ww && p.point.y > y && p.point.y < y + self->wayland.wh) { + if(self->wayland.parent == NULL) { + return; + } + + if(self->wayland.framebuffer.surface == self->wayland.curSurface) { int i; switch(button) { @@ -999,7 +1004,7 @@ static void region_setup(MwLL handle) { if(handle->wayland.type == MWLL_WAYLAND_POPUP) { wl_region_add(handle->wayland.region, 0, 0, handle->wayland.ww + abs(handle->wayland.x), handle->wayland.wh + abs(handle->wayland.y)); } else { - wl_region_add(handle->wayland.region, handle->wayland.x, handle->wayland.y, handle->wayland.ww + abs(handle->wayland.x), handle->wayland.wh + abs(handle->wayland.y)); + wl_region_add(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); } wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); @@ -1233,6 +1238,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(r->wayland.sublevel->subcompositor, r->wayland.framebuffer.surface, parent_surface); + wl_subsurface_set_desync(r->wayland.sublevel->subsurface); wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); r->wayland.configured = MwTRUE; From 59608238012c36ad7945969887b051653f30b4ff Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 18 Mar 2026 23:07:16 -0700 Subject: [PATCH 192/409] wayland: don't early return from pointer_button, it causes a deadlock --- src/backend/wayland.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f15d3d7b9..e45c367a9 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -430,10 +430,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; - if(self->wayland.parent == NULL) { - return; - } - if(self->wayland.framebuffer.surface == self->wayland.curSurface) { int i; @@ -878,7 +874,7 @@ static void xdg_toplevel_configure(void* data, region_setup(self); MwLLDispatch(self, resize, NULL); - MwLLDispatch(self, draw, NULL); + // MwLLDispatch(self, draw, NULL); MwLLForceRender(self); @@ -1407,7 +1403,7 @@ static void MwLLDestroyImpl(MwLL handle) { struct timeval tv; struct timespec t = { .tv_sec = 0, - .tv_nsec = 100, + .tv_nsec = 0, }; int select_ret; From 91c05b670d1171df71d8d9ea0e2f3fcc9b028019 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 15:57:20 -0700 Subject: [PATCH 193/409] wayland: working viewport, subsurface input region --- include/Mw/LowLevel.h | 2 ++ include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 31 +++++++++++++++++++++++++------ src/core.c | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 30d7f310a..b7e21afca 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -39,6 +39,8 @@ struct _MwLLCommon { int type; int coordinate_type; + MwBool place_above; + MwLLHandler handler; }; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 024881388..76a5801c0 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -147,6 +147,7 @@ struct _MwLLWayland { struct wl_registry* registry; struct wl_compositor* compositor; struct wl_registry_listener registry_listener; + struct wl_region* o_region; struct wl_region* region; struct wl_output* output; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index e45c367a9..f5880388b 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -996,14 +996,26 @@ static void region_setup(MwLL handle) { if(!handle->wayland.configured) { return; } + MwLL parent = handle->wayland.parent; + int width = handle->wayland.ww; + int height = handle->wayland.wh; + wl_region_add(handle->wayland.o_region, 0, 0, 1, 1); + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - wl_region_add(handle->wayland.region, 0, 0, handle->wayland.ww + abs(handle->wayland.x), handle->wayland.wh + abs(handle->wayland.y)); + wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); } else { - wl_region_add(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); + if(parent) { + if(width - handle->wayland.x > parent->wayland.ww) { + width = parent->wayland.ww - handle->wayland.x; + } + if(height - handle->wayland.y > parent->wayland.wh) { + height = parent->wayland.wh - handle->wayland.y; + } + } + wl_region_add(handle->wayland.region, 0, 0, width, height); } wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); - wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); } static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { @@ -1237,6 +1249,10 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { wl_subsurface_set_desync(r->wayland.sublevel->subsurface); wl_subsurface_set_position(r->wayland.sublevel->subsurface, x, y); + if(parent) { + wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); + } + r->wayland.configured = MwTRUE; } @@ -1387,7 +1403,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { framebuffer_setup(&r->wayland); - r->wayland.region = wl_compositor_create_region(r->wayland.compositor); + r->wayland.region = wl_compositor_create_region(r->wayland.compositor); + r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); region_setup(r); MwLLForceRender(r); @@ -1514,7 +1531,6 @@ refresh: static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); cairo_new_path(handle->wayland.cairo); for(i = 0; i < points_count; i++) { @@ -1525,6 +1541,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } } cairo_close_path(handle->wayland.cairo); + cairo_fill(handle->wayland.cairo); handle->wayland.events_pending = 1; @@ -1660,16 +1677,18 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; + MwLL parent = handle->wayland.parent; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); + cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + cairo_paint(c); - cairo_set_source_rgb(handle->wayland.cairo, 1, 1, 1); cairo_set_source_surface(handle->wayland.cairo, cs, rect->x, rect->y); cairo_paint(handle->wayland.cairo); diff --git a/src/core.c b/src/core.c index c3274a150..a8178c7dd 100644 --- a/src/core.c +++ b/src/core.c @@ -46,6 +46,7 @@ static void llresizehandler(MwLL handle, void* data) { MwDispatchUserHandler(h, MwNresizeHandler, NULL); for(i = 0; i < arrlen(h->children); i++) { MwDispatch(h->children[i], parent_resize); + MwDispatch(h->children[i], draw); } MwDispatch(h, resize); } From 5f53236c91e2abc2046845c2489bb29b2567a2a6 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 15:59:44 -0700 Subject: [PATCH 194/409] remove unused test parameter added to common lowLevel --- include/Mw/LowLevel.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index b7e21afca..30d7f310a 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -39,8 +39,6 @@ struct _MwLLCommon { int type; int coordinate_type; - MwBool place_above; - MwLLHandler handler; }; From 42db5889db2eae5c47031fed9f78e45d5140a32a Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 16:01:32 -0700 Subject: [PATCH 195/409] wayland c89 --- src/backend/wayland.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f5880388b..117a328cf 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -993,12 +993,14 @@ static void region_invalidate(MwLL handle) { wl_region_subtract(handle->wayland.region, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void region_setup(MwLL handle) { - if(!handle->wayland.configured) { - return; - } MwLL parent = handle->wayland.parent; int width = handle->wayland.ww; int height = handle->wayland.wh; + + if(!handle->wayland.configured) { + return; + } + wl_region_add(handle->wayland.o_region, 0, 0, 1, 1); wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); From 04eb28b6173fdcf52c996b8fd180d529cc92430b Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 16:05:44 -0700 Subject: [PATCH 196/409] revert the removal of MwLLBeginDraw/EndDraw, turns out the newer system still doesn't please weston and likely other compositors --- include/Mw/LowLevel.h | 2 ++ src/backend/call.c | 6 ++++-- src/backend/cocoa.m | 8 ++++++++ src/backend/gdi.c | 8 ++++++++ src/backend/wayland.c | 8 ++++++++ src/backend/x11.c | 11 +++++++++-- src/core.c | 3 +++ src/lowlevel.c | 3 +++ 8 files changed, 45 insertions(+), 4 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 30d7f310a..9766d052f 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -190,6 +190,8 @@ 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 (*MwLLBeginDraw)(MwLL handle); +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 2ce5ed234..e2ce934c9 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -8,8 +8,10 @@ MwLLCreate = MwLLCreateImpl; \ MwLLDestroy = MwLLDestroyImpl; \ \ - MwLLPolygon = MwLLPolygonImpl; \ - MwLLLine = MwLLLineImpl; \ + MwLLPolygon = MwLLPolygonImpl; \ + MwLLLine = MwLLLineImpl; \ + MwLLBeginDraw = MwLLBeginDrawImpl; \ + MwLLEndDraw = MwLLEndDrawImpl; \ \ MwLLAllocColor = MwLLAllocColorImpl; \ MwLLColorUpdate = MwLLColorUpdateImpl; \ diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 738ab1089..725642d35 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1001,6 +1001,14 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { MilskoCocoa* h = handle->cocoa.real; diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 3c286a8e5..4601b79da 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -310,6 +310,14 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)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 117a328cf..be4bc1489 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1531,6 +1531,14 @@ refresh: MwLLDispatch(handle, draw, NULL); } +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + update_buffer(&handle->wayland.framebuffer); +} + static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); diff --git a/src/backend/x11.c b/src/backend/x11.c index 6124ceeae..f7c6fe4bd 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -261,8 +261,15 @@ static void MwLLDestroyImpl(MwLL handle) { free(handle); } -static void -MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)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 a8178c7dd..f17fdbfa6 100644 --- a/src/core.c +++ b/src/core.c @@ -6,11 +6,14 @@ static void lldrawhandler(MwLL handle, void* data) { MwWidget h = (MwWidget)handle->common.user; (void)data; + MwLLBeginDraw(handle); h->bgcolor = NULL; MwDispatch(h, draw); if(h->draw_inject != NULL) h->draw_inject(h); MwDispatchUserHandler(h, MwNdrawHandler, NULL); + + MwLLEndDraw(handle); } static void lluphandler(MwLL handle, void* data) { diff --git a/src/lowlevel.c b/src/lowlevel.c index eeabaa339..8f8a4d932 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -6,6 +6,9 @@ void (*MwLLDestroy)(MwLL handle) = NULL; void (*MwLLPolygon)(MwLL handle, MwPoint* points, int points_count, MwLLColor color) = NULL; void (*MwLLLine)(MwLL handle, MwPoint* points, MwLLColor color) = NULL; +void (*MwLLBeginDraw)(MwLL handle) = NULL; +void (*MwLLEndDraw)(MwLL handle) = NULL; + MwLLColor (*MwLLAllocColor)(MwLL handle, int r, int g, int b) = NULL; void (*MwLLColorUpdate)(MwLL handle, MwLLColor c, int r, int g, int b) = NULL; void (*MwLLFreeColor)(MwLLColor color) = NULL; From f44f98b8aa8d0fd39ca3480d7594d7292189dcc7 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 16:35:56 -0700 Subject: [PATCH 197/409] wayland: don't update buffer if we haven't configured --- src/backend/wayland.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index be4bc1489..d42136533 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2,9 +2,12 @@ #include #include +#include +#include #include #include "../../external/stb_ds.h" +#include "Mw/BaseTypes.h" #include #include @@ -842,7 +845,7 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { } -/* `xdg_toplevel.close` callback */ +/* `xdg_toplevel.configure` callback */ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, @@ -867,6 +870,7 @@ static void xdg_toplevel_configure(void* data, region_invalidate(self); self->wayland.ww = width; self->wayland.wh = height; + xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); framebuffer_destroy(&self->wayland); @@ -874,7 +878,7 @@ static void xdg_toplevel_configure(void* data, region_setup(self); MwLLDispatch(self, resize, NULL); - // MwLLDispatch(self, draw, NULL); + MwLLDispatch(self, draw, NULL); MwLLForceRender(self); @@ -978,7 +982,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { wayland->cairo = cairo_create(wayland->cs); memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); - update_buffer(&wayland->framebuffer); + if(wayland->configured) update_buffer(&wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -1212,6 +1216,8 @@ static void destroy_toplevel(MwLL r) { wl_registry_destroy(r->wayland.registry); wl_display_disconnect(r->wayland.display); + + r->wayland.configured = MwFALSE; } /* Sublevel setup function */ @@ -1265,6 +1271,8 @@ static void destroy_sublevel(MwLL r) { wl_subsurface_destroy(r->wayland.sublevel->subsurface); free(r->wayland.sublevel); + + r->wayland.configured = MwFALSE; } static void popup_configure(void* data, @@ -1367,6 +1375,13 @@ static void destroy_popup(MwLL r) { wl_surface_destroy(r->wayland.framebuffer.surface); wl_registry_destroy(r->wayland.registry); + + r->wayland.configured = MwFALSE; +} + +static void wl_logger(const char* fmt, va_list args) { + vprintf(fmt, args); + raise(SIGTRAP); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -1375,6 +1390,8 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + wl_log_set_handler_client(wl_logger); + /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. */ r->common.coordinate_type = MwCoordinatesLocal; @@ -1519,8 +1536,9 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - destroy_popup(handle); - setup_popup(handle, handle->wayland.x, handle->wayland.y); + // destroy_popup(handle); + // wl_flush(handle); + // setup_popup(handle, handle->wayland.x, handle->wayland.y); } refresh: @@ -1536,7 +1554,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } static void MwLLEndDrawImpl(MwLL handle) { - update_buffer(&handle->wayland.framebuffer); + if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { @@ -1632,7 +1650,7 @@ static void MwLLNextEventImpl(MwLL handle) { handle->wayland.events_pending = 0; } if(handle->wayland.force_render) { - update_buffer(&handle->wayland.framebuffer); + if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } } @@ -1739,7 +1757,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { handle->wayland.icon->buf[i + 3] = 255; } - update_buffer(handle->wayland.icon); + if(handle->wayland.configured) update_buffer(handle->wayland.icon); xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); @@ -1817,6 +1835,8 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { return; } + wl_flush(handle); + switch(handle->wayland.type_to_be) { case MWLL_WAYLAND_POPUP: setup_popup(handle, point->x, point->y); From f78e5e620fe0929d45757844b59d0ed56692ca6e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 17:05:08 -0700 Subject: [PATCH 198/409] wayland: image clipping attempt --- src/backend/wayland.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d42136533..c22685faa 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,5 +1,6 @@ #include +#include #include #include #include @@ -877,12 +878,11 @@ static void xdg_toplevel_configure(void* data, framebuffer_setup(&self->wayland); region_setup(self); +finish: MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); MwLLForceRender(self); - - return; }; /* Empty function for satisfying zxdg_toplevel's requirements */ @@ -1710,6 +1710,11 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); + if(parent) { + cairo_rectangle(c, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y); + cairo_clip(c); + } + cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); @@ -1848,6 +1853,15 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { } static void MwLLShowImpl(MwLL handle, int show) { + switch(handle->wayland.type) { + case MWLL_WAYLAND_UNKNOWN: + case MWLL_WAYLAND_TOPLEVEL: + break; + case MWLL_WAYLAND_SUBLEVEL: + break; + case MWLL_WAYLAND_POPUP: + break; + } } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { From 3eeace0963b4e2551fa18459b58b5dddadd20301 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 17:32:36 -0700 Subject: [PATCH 199/409] don't use wl_dispatch_pending_timeout appearently debian still doesn't ship with it --- src/backend/wayland.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index c22685faa..8cc6000a2 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -1070,15 +1071,17 @@ static int event_loop(MwLL handle) { } wl_display_prepare_read(handle->wayland.display); - wl_display_read_events(wayland->display); - if((res = wl_display_dispatch_timeout(wayland->display, &timeout)) <= 0) { - if(res < 0) { - wl_display_cancel_read(handle->wayland.display); - } + /* Condition where no events are being sent. */ + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(wayland->display); wl_surface_commit(wayland->framebuffer.surface); return 0; } + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) < 0) { + wl_display_cancel_read(wayland->display); + } return 1; } @@ -1615,13 +1618,26 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - MwBool pending = MwFALSE; struct timespec timeout; - timeout.tv_nsec = 1; - timeout.tv_sec = 0; - int i; + struct pollfd fd; + int pending = 0; - pending = wl_display_dispatch_timeout(handle->wayland.display, &timeout); + timeout.tv_nsec = 100; + timeout.tv_sec = 0; + + fd.fd = wl_display_get_fd(handle->wayland.display); + fd.events = POLLOUT; + + wl_display_prepare_read(handle->wayland.display); + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(handle->wayland.display); + } else { + wl_display_read_events(handle->wayland.display); + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + } + wl_surface_commit(handle->wayland.framebuffer.surface); if(handle->wayland.always_render) { event_loop(handle); From 22fe52c4a3dd98134dba2f90d77f34c718ca689e Mon Sep 17 00:00:00 2001 From: Nishi Date: Fri, 20 Mar 2026 09:59:07 +0900 Subject: [PATCH 200/409] ugh --- src/backend/wayland.c | 19 ++++++++++++++----- src/core.c | 2 ++ 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8cc6000a2..9bf9f9002 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1382,6 +1382,16 @@ static void destroy_popup(MwLL r) { r->wayland.configured = MwFALSE; } +static void clip(MwLL handle){ + MwLL parent = handle->wayland.parent; + + if(parent && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + cairo_reset_clip(handle->wayland.cairo); + cairo_rectangle(handle->wayland.cairo, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y); + cairo_clip(handle->wayland.cairo); + } +} + static void wl_logger(const char* fmt, va_list args) { vprintf(fmt, args); raise(SIGTRAP); @@ -1562,6 +1572,9 @@ static void MwLLEndDrawImpl(MwLL handle) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; + + clip(handle); + cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); cairo_new_path(handle->wayland.cairo); for(i = 0; i < points_count; i++) { @@ -1721,15 +1734,11 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; - MwLL parent = handle->wayland.parent; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); - if(parent) { - cairo_rectangle(c, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y); - cairo_clip(c); - } + clip(handle); cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); diff --git a/src/core.c b/src/core.c index f17fdbfa6..39cae9244 100644 --- a/src/core.c +++ b/src/core.c @@ -815,6 +815,8 @@ void MwReparent(MwWidget handle, MwWidget new_parent) { arrput(new_parent->children, handle); MwDispatch(handle->parent, children_update); + + MwForceRender(handle); } MwClass MwGetClass(MwWidget handle) { From 3cf94f66513a5049f913032f0b927a3bc1b2ae31 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 19 Mar 2026 19:43:57 -0700 Subject: [PATCH 201/409] wayland: malicious compliance with gnome's CSD rule --- .clangd | 2 + include/Mw/LowLevel/Wayland.h | 26 ++++- pl/rules.pl | 1 + src/backend/wayland.c | 183 ++++++++++++++++++++++++---------- 4 files changed, 160 insertions(+), 52 deletions(-) create mode 100644 .clangd diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..c2520c5c5 --- /dev/null +++ b/.clangd @@ -0,0 +1,2 @@ +Completion: + HeaderInsertion: Never diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 76a5801c0..b2927494e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -24,12 +24,21 @@ MWDECL int MwLLWaylandCallInit(void); #ifndef WL_PROTOCOLS_DEFINED #define WL_PROTOCOLS_DEFINED #include "Wayland/xdg-shell-client-protocol.h" +#include "Wayland/viewporter-client-protocol.h" #include "Wayland/xdg-decoration-client-protocol.h" #include "Wayland/cursor-shape-client-protocol.h" #include "Wayland/primary-selection-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif +#define SSD_BORDER_FRAME_LEFT 5 +#define SSD_BORDER_FRAME_RIGHT 5 +#define SSD_BORDER_FRAME_TOP 24 +#define SSD_BORDER_FRAME_BOTTOM 5 + +#define SSD_LEFT_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_LEFT +#define SSD_TOP_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_TOP + struct _MwLLWayland; typedef struct wayland_protocol { @@ -58,6 +67,9 @@ struct _MwLLWaylandTopLevel { MwBool compositor_created; MwBool xdg_wm_base_created; MwBool xdg_surface_created; + + struct wl_subsurface* ssurface; + struct wl_subcompositor* scompositor; }; struct _MwLLWaylandSublevel { @@ -143,6 +155,9 @@ struct _MwLLWayland { MwBool always_render; + MwBool has_decorations; + char title[255]; + struct wl_display* display; struct wl_registry* registry; struct wl_compositor* compositor; @@ -151,6 +166,8 @@ struct _MwLLWayland { struct wl_region* region; struct wl_output* output; + struct wp_viewport* vp; + /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ @@ -192,6 +209,7 @@ struct _MwLLWayland { MwBool did_event_loop_early; struct _MwLLWaylandShmBuffer framebuffer; + struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; @@ -203,12 +221,16 @@ struct _MwLLWayland { uint32_t last_time; + MwBool moving; + MwLL currentlyHeldWidget; struct wl_surface* curSurface; - cairo_surface_t* cs; - cairo_t* cairo; + cairo_surface_t* front_cs; + cairo_surface_t* back_cs; + cairo_t* front_cairo; + cairo_t* back_cairo; }; struct _MwLLWaylandColor { diff --git a/pl/rules.pl b/pl/rules.pl index 45bb6daf3..a35a6c3e6 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -37,6 +37,7 @@ if (grep(/^wayland$/, @backends)) { } scan_wayland_protocol("stable", "xdg-shell", ""); + scan_wayland_protocol("stable", "viewporter", ""); scan_wayland_protocol("stable", "tablet", "-v2"); scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); scan_wayland_protocol("staging", "cursor-shape", "-v1"); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8cc6000a2..40dfbc7ce 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1,19 +1,9 @@ #include -#include -#include -#include -#include #include -#include -#include +#include #include "../../external/stb_ds.h" -#include "Mw/BaseTypes.h" - -#include -#include -#include /* TODO: * - MwLLMakePopupImpl @@ -49,6 +39,11 @@ static void framebuffer_setup(struct _MwLLWayland* wayland); /* Destroy the framebuffer */ static void framebuffer_destroy(struct _MwLLWayland* handle); +/* Setup the framebuffer with the saved width/height */ +static void backbuffer_setup(struct _MwLLWayland* wayland); +/* Destroy the backbuffer */ +static void backbuffer_destroy(struct _MwLLWayland* handle); + static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer); static void region_setup(MwLL handle); @@ -435,7 +430,7 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; - if(self->wayland.framebuffer.surface == self->wayland.curSurface) { + if(self->wayland.framebuffer.surface == self->wayland.curSurface || self->wayland.backbuffer.surface == self->wayland.curSurface) { int i; switch(button) { @@ -798,7 +793,11 @@ static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, waylan /* wl_subcompositor setup function */ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { + wayland->toplevel->scompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } else { + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); + } return NULL; } @@ -824,6 +823,18 @@ static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_ free(data->listener); } +/* xdg_wm_base setup function */ +static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); + proto->context = wl_registry_bind(wayland->registry, name, &wp_viewporter_interface, 1); + + return proto; +} + +static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + free(data->listener); +} + /* the two decoration manager constructs */ typedef struct zxdg_decoration_manager_v1_context { struct zxdg_decoration_manager_v1* manager; @@ -875,6 +886,9 @@ static void xdg_toplevel_configure(void* data, xdg_surface_set_window_geometry(self->wayland.toplevel->xdg_surface, 0, 0, self->wayland.ww, self->wayland.wh); + backbuffer_destroy(&self->wayland); + backbuffer_setup(&self->wayland); + framebuffer_destroy(&self->wayland); framebuffer_setup(&self->wayland); region_setup(self); @@ -910,6 +924,7 @@ static void xdg_surface_configure( if(self->wayland.configured) { wl_surface_commit(self->wayland.framebuffer.surface); + wl_surface_commit(self->wayland.backbuffer.surface); } self->wayland.configured = MwTRUE; @@ -917,8 +932,8 @@ static void xdg_surface_configure( /* wl_shm setup function */ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland) { - wayland->framebuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); + wayland->backbuffer.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); wayland->cursor.shm = wl_registry_bind(wayland->registry, name, &wl_shm_interface, 1); return NULL; @@ -979,16 +994,34 @@ static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { static void framebuffer_setup(struct _MwLLWayland* wayland) { buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh); - wayland->cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); - wayland->cairo = cairo_create(wayland->cs); + wayland->front_cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->front_cairo = cairo_create(wayland->front_cs); memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); if(wayland->configured) update_buffer(&wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); - cairo_destroy(wayland->cairo); - cairo_surface_destroy(wayland->cs); + cairo_destroy(wayland->front_cairo); + cairo_surface_destroy(wayland->front_cs); +}; + +static void backbuffer_setup(struct _MwLLWayland* wayland) { + if(wayland->type != MWLL_WAYLAND_TOPLEVEL) { + return; + } + buffer_setup(&wayland->backbuffer, wayland->ww, wayland->wh); + + wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->back_cairo = cairo_create(wayland->back_cs); + + memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size); + if(wayland->configured) update_buffer(&wayland->backbuffer); +}; +static void backbuffer_destroy(struct _MwLLWayland* wayland) { + buffer_destroy(&wayland->backbuffer); + cairo_destroy(wayland->back_cairo); + cairo_surface_destroy(wayland->back_cs); }; static void region_invalidate(MwLL handle) { @@ -1007,7 +1040,6 @@ static void region_setup(MwLL handle) { } wl_region_add(handle->wayland.o_region, 0, 0, 1, 1); - wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); if(handle->wayland.type == MWLL_WAYLAND_POPUP) { wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); @@ -1022,7 +1054,12 @@ static void region_setup(MwLL handle) { } wl_region_add(handle->wayland.region, 0, 0, width, height); } + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.region); + wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); + } } static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { @@ -1076,6 +1113,8 @@ static int event_loop(MwLL handle) { wl_display_cancel_read(wayland->display); wl_surface_commit(wayland->framebuffer.surface); + if(wayland->type == MWLL_WAYLAND_TOPLEVEL) + wl_surface_commit(wayland->backbuffer.surface); return 0; } wl_display_read_events(wayland->display); @@ -1109,8 +1148,10 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(zwp_primary_selection_device_manager_v1); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); + WL_INTERFACE(wp_viewporter); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(xdg_toplevel_icon_manager_v1); + WL_INTERFACE(wl_subcompositor); } else if(wayland->type == MWLL_WAYLAND_POPUP) { WL_INTERFACE(xdg_wm_base); } else { @@ -1138,8 +1179,6 @@ static void setup_toplevel(MwLL r, int x, int y) { return; } - r->wayland.framebuffer.surface = NULL; - /* Do a roundtrip to ensure all interfaces are setup. */ r->wayland.registry = wl_display_get_registry(r->wayland.display); wl_registry_add_listener(r->wayland.registry, &r->wayland.registry_listener, r); @@ -1153,9 +1192,11 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); + r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); r->wayland.toplevel->xdg_surface = - xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); r->wayland.toplevel->xdg_top_level = xdg_surface_get_toplevel(r->wayland.toplevel->xdg_surface); /* setup mandatory listeners */ @@ -1172,6 +1213,7 @@ static void setup_toplevel(MwLL r, int x, int y) { xdg_toplevel_set_app_id(r->wayland.toplevel->xdg_top_level, "MilskoWaylandApp"); /* Perform the initial commit and wait for the first configure event */ + wl_surface_commit(r->wayland.backbuffer.surface); wl_surface_commit(r->wayland.framebuffer.surface); while(!r->wayland.configured) { event_loop(r); @@ -1186,8 +1228,18 @@ static void setup_toplevel(MwLL r, int x, int y) { zxdg_toplevel_decoration_v1_set_mode( dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + + r->wayland.has_decorations = MwTRUE; } else { - printf("zxdg null\n"); + /* otherwise set up viewporter */ + struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; + r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); + wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT), r->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)); + r->wayland.has_decorations = MwFALSE; + + wl_subsurface_set_position(r->wayland.toplevel->ssurface, SSD_BORDER_FRAME_LEFT, SSD_BORDER_FRAME_TOP); + wl_subsurface_set_desync(r->wayland.toplevel->ssurface); } } @@ -1269,6 +1321,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { /* Sublevel setup function */ static void destroy_sublevel(MwLL r) { + backbuffer_destroy(&r->wayland); framebuffer_destroy(&r->wayland); wl_subsurface_destroy(r->wayland.sublevel->subsurface); @@ -1365,6 +1418,7 @@ static void setup_popup(MwLL r, int x, int y) { // framebuffer_destroy(&r->wayland); framebuffer_setup(&r->wayland); + backbuffer_setup(&r->wayland); } /* Popup destroy function */ @@ -1424,6 +1478,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } framebuffer_setup(&r->wayland); + backbuffer_setup(&r->wayland); r->wayland.region = wl_compositor_create_region(r->wayland.compositor); r->wayland.o_region = wl_compositor_create_region(r->wayland.compositor); @@ -1515,8 +1570,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { if(handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); } - if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - } region_setup(handle); MwLLDispatch(handle, draw, NULL); @@ -1531,17 +1584,29 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.wh = 10; goto refresh; } + if(handle->wayland.parent) { + if(handle->wayland.parent->wayland.type == MWLL_WAYLAND_TOPLEVEL && !handle->wayland.parent->wayland.has_decorations) { + if(w >= handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT)) + w = handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT); + if(h >= handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)) + h = handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM); + } + } handle->wayland.ww = w; handle->wayland.wh = h; + // if(handle->wayland.wh >= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)) { + // handle->wayland.wh -= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM); + // } + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } if(handle->wayland.type == MWLL_WAYLAND_POPUP) { - // destroy_popup(handle); - // wl_flush(handle); - // setup_popup(handle, handle->wayland.x, handle->wayland.y); + destroy_popup(handle); + wl_flush(handle); + setup_popup(handle, handle->wayland.x, handle->wayland.y); } refresh: @@ -1549,31 +1614,48 @@ refresh: framebuffer_destroy(&handle->wayland); framebuffer_setup(&handle->wayland); + backbuffer_destroy(&handle->wayland); + backbuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); } static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; + if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + return; + } + if(!handle->wayland.has_decorations) { + cairo_set_source_rgb(handle->wayland.back_cairo, 0, 0.25, 0.25); + cairo_rectangle(handle->wayland.back_cairo, 1, 1, handle->wayland.ww - 2, handle->wayland.wh - 2); + cairo_fill_preserve(handle->wayland.back_cairo); + cairo_set_source_rgb(handle->wayland.back_cairo, 1, 1, 1); + cairo_rectangle(handle->wayland.back_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); + cairo_stroke(handle->wayland.back_cairo); + } } static void MwLLEndDrawImpl(MwLL handle) { - if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); + if(handle->wayland.configured) { + update_buffer(&handle->wayland.framebuffer); + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + update_buffer(&handle->wayland.backbuffer); + } + } } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - cairo_new_path(handle->wayland.cairo); + cairo_set_source_rgb(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.front_cairo); for(i = 0; i < points_count; i++) { if(i == 0) { - cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y); } else { - cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y); } } - cairo_close_path(handle->wayland.cairo); + cairo_close_path(handle->wayland.front_cairo); - cairo_fill(handle->wayland.cairo); + cairo_fill(handle->wayland.front_cairo); handle->wayland.events_pending = 1; } @@ -1581,18 +1663,18 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { int i; - cairo_set_line_cap(handle->wayland.cairo, CAIRO_LINE_CAP_SQUARE); - cairo_set_source_rgb(handle->wayland.cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); - cairo_new_path(handle->wayland.cairo); + cairo_set_line_cap(handle->wayland.front_cairo, CAIRO_LINE_CAP_SQUARE); + cairo_set_source_rgb(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_new_path(handle->wayland.front_cairo); for(i = 0; i < 2; i++) { if(i == 0) { - cairo_move_to(handle->wayland.cairo, points[i].x, points[i].y); + cairo_move_to(handle->wayland.front_cairo, points[i].x, points[i].y); } else { - cairo_line_to(handle->wayland.cairo, points[i].x, points[i].y); + cairo_line_to(handle->wayland.front_cairo, points[i].x, points[i].y); } } - cairo_close_path(handle->wayland.cairo); - cairo_stroke(handle->wayland.cairo); + cairo_close_path(handle->wayland.front_cairo); + cairo_stroke(handle->wayland.front_cairo); handle->wayland.events_pending = 1; } @@ -1638,6 +1720,9 @@ static int MwLLPendingImpl(MwLL handle) { } } wl_surface_commit(handle->wayland.framebuffer.surface); + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + wl_surface_commit(handle->wayland.backbuffer.surface); + } if(handle->wayland.always_render) { event_loop(handle); @@ -1675,6 +1760,9 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { xdg_toplevel_set_title(handle->wayland.toplevel->xdg_top_level, title); } + if(!handle->wayland.has_decorations) { + strncpy(handle->wayland.title, title, 255); + } } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { @@ -1726,11 +1814,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); - if(parent) { - cairo_rectangle(c, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y); - cairo_clip(c); - } - cairo_scale(c, (double)rect->width / pixmap->common.width, (double)rect->height / pixmap->common.height); cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); @@ -1738,8 +1821,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_paint(c); - cairo_set_source_surface(handle->wayland.cairo, cs, rect->x, rect->y); - cairo_paint(handle->wayland.cairo); + cairo_set_source_surface(handle->wayland.front_cairo, cs, rect->x, rect->y); + cairo_paint(handle->wayland.front_cairo); cairo_destroy(c); cairo_surface_destroy(cs); From 52d676e54fc2ad56aa3370f7ca5ccee7a24134bf Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Fri, 20 Mar 2026 19:28:18 -0700 Subject: [PATCH 202/409] csd and clipping --- include/Mw/LowLevel/Wayland.h | 21 +++-- src/backend/wayland.c | 167 ++++++++++++++++++++++++++++------ 2 files changed, 153 insertions(+), 35 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index b2927494e..053d0ff91 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -31,13 +31,13 @@ MWDECL int MwLLWaylandCallInit(void); #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif -#define SSD_BORDER_FRAME_LEFT 5 -#define SSD_BORDER_FRAME_RIGHT 5 -#define SSD_BORDER_FRAME_TOP 24 -#define SSD_BORDER_FRAME_BOTTOM 5 +#define CSD_BORDER_FRAME_LEFT 5 +#define CSD_BORDER_FRAME_RIGHT 5 +#define CSD_BORDER_FRAME_TOP 24 +#define CSD_BORDER_FRAME_BOTTOM 5 -#define SSD_LEFT_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_LEFT -#define SSD_TOP_OFFSET(handle) handle->wayland.has_decorations ? 0 : SSD_BORDER_FRAME_TOP +#define CSD_LEFT_OFFSET(handle) handle->wayland.has_decorations ? 0 : CSD_BORDER_FRAME_LEFT +#define CSD_TOP_OFFSET(handle) handle->wayland.has_decorations ? 0 : CSD_BORDER_FRAME_TOP struct _MwLLWayland; @@ -185,8 +185,10 @@ struct _MwLLWayland { uint32_t clipboard_serial; wl_clipboard_device_context_t** clipboard_devices; - struct wl_pointer* pointer; - MwU32 pointer_serial; + struct wl_pointer* pointer; + MwU32 pointer_serial; + struct wl_seat* pointer_seat; + struct wl_keyboard* keyboard; MwU32 keyboard_serial; @@ -196,6 +198,8 @@ struct _MwLLWayland { MwBool configured; /* Whether or not xdg_toplevel_configure has run once */ + MwBool held_down; + MwI32 x, y; MwI32 ox, oy; MwU32 ww, wh; /* Window position */ @@ -231,6 +235,7 @@ struct _MwLLWayland { cairo_surface_t* back_cs; cairo_t* front_cairo; cairo_t* back_cairo; + cairo_t* selected_cairo; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index be8b45acc..d6eae3ccf 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -391,6 +391,30 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 seria struct wl_surface* surface) { }; +static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == self->wayland.curSurface) { + if(p.point.y >= self->wayland.wh - 5) { + if(p.point.x >= self->wayland.ww - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM); + } + } else if(p.point.y <= 5) { + if(p.point.x >= self->wayland.ww - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT); + } else { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP); + } + } else if(p.point.x >= self->wayland.ww - 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT); + } else if(p.point.x <= 5) { + xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT); + } else if(p.point.y <= CSD_BORDER_FRAME_TOP) { + xdg_toplevel_move(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial); + } + }; +} + /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { @@ -448,12 +472,15 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.button = MwLLMouseRight; break; } + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; + switch(state) { case WL_POINTER_BUTTON_STATE_PRESSED: MwLLDispatch(self, down, &p); if(self->wayland.parent != NULL) { self->wayland.parent->wayland.currentlyHeldWidget = self; } + break; case WL_POINTER_BUTTON_STATE_RELEASED: if(self->wayland.parent != NULL) { @@ -472,6 +499,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLLDispatch(self, draw, NULL); } + if(!self->wayland.has_decorations) { + xdg_borderless_step(self, p, serial); + } + WAYLAND_EVENT_OP_END(self); }; @@ -694,7 +725,8 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, wl_keyboard_add_listener(self->wayland.keyboard, &keyboard_listener, data); } if(capabilities & WL_SEAT_CAPABILITY_POINTER) { - self->wayland.pointer = wl_seat_get_pointer(wl_seat); + self->wayland.pointer_seat = wl_seat; + self->wayland.pointer = wl_seat_get_pointer(wl_seat); wl_pointer_add_listener(self->wayland.pointer, &pointer_listener, data); } @@ -893,7 +925,10 @@ static void xdg_toplevel_configure(void* data, framebuffer_setup(&self->wayland); region_setup(self); -finish: + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && !self->wayland.has_decorations) { + wp_viewport_set_destination(self->wayland.vp, self->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), self->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + } + MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); @@ -997,7 +1032,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { wayland->front_cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); wayland->front_cairo = cairo_create(wayland->front_cs); - memset(wayland->framebuffer.buf, 255, wayland->framebuffer.buf_size); + memset(wayland->framebuffer.buf, 0, wayland->framebuffer.buf_size); if(wayland->configured) update_buffer(&wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { @@ -1015,7 +1050,7 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); wayland->back_cairo = cairo_create(wayland->back_cs); - memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size); + memset(wayland->backbuffer.buf, 0, wayland->backbuffer.buf_size); if(wayland->configured) update_buffer(&wayland->backbuffer); }; static void backbuffer_destroy(struct _MwLLWayland* wayland) { @@ -1054,12 +1089,12 @@ static void region_setup(MwLL handle) { } wl_region_add(handle->wayland.region, 0, 0, width, height); } - wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); - wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.region); wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); } + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); + wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); } static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { @@ -1194,6 +1229,7 @@ static void setup_toplevel(MwLL r, int x, int y) { r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + wl_subsurface_set_desync(r->wayland.toplevel->ssurface); r->wayland.toplevel->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.backbuffer.surface); @@ -1235,11 +1271,10 @@ static void setup_toplevel(MwLL r, int x, int y) { struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); - wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT), r->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)); + wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); r->wayland.has_decorations = MwFALSE; - wl_subsurface_set_position(r->wayland.toplevel->ssurface, SSD_BORDER_FRAME_LEFT, SSD_BORDER_FRAME_TOP); - wl_subsurface_set_desync(r->wayland.toplevel->ssurface); + wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); } } @@ -1437,11 +1472,16 @@ static void destroy_popup(MwLL r) { } static void clip(MwLL handle) { - MwLL parent = handle->wayland.parent; - - if(parent && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + MwLL topmost = handle->wayland.parent; + if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { cairo_reset_clip(handle->wayland.front_cairo); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, parent->wayland.ww + handle->wayland.x, parent->wayland.wh + handle->wayland.y); + cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), (topmost->wayland.wh + handle->wayland.y) - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + cairo_clip(handle->wayland.front_cairo); + } + if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + while(topmost->wayland.parent) topmost = topmost->wayland.parent; + cairo_reset_clip(handle->wayland.front_cairo); + cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), (topmost->wayland.wh + handle->wayland.y) - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); cairo_clip(handle->wayland.front_cairo); } } @@ -1596,17 +1636,17 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { } if(handle->wayland.parent) { if(handle->wayland.parent->wayland.type == MWLL_WAYLAND_TOPLEVEL && !handle->wayland.parent->wayland.has_decorations) { - if(w >= handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT)) - w = handle->wayland.parent->wayland.ww - (SSD_BORDER_FRAME_LEFT + SSD_BORDER_FRAME_RIGHT); - if(h >= handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)) - h = handle->wayland.parent->wayland.wh - (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM); + if(w >= handle->wayland.parent->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT)) + w = handle->wayland.parent->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + if(h >= handle->wayland.parent->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)) + h = handle->wayland.parent->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); } } handle->wayland.ww = w; handle->wayland.wh = h; - // if(handle->wayland.wh >= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM)) { - // handle->wayland.wh -= (SSD_BORDER_FRAME_TOP + SSD_BORDER_FRAME_BOTTOM); + // if(handle->wayland.wh >= (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)) { + // handle->wayland.wh -= (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); // } if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { @@ -1631,23 +1671,96 @@ refresh: static void MwLLBeginDrawImpl(MwLL handle) { if(handle->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + handle->wayland.selected_cairo = handle->wayland.front_cairo; return; } if(!handle->wayland.has_decorations) { - cairo_set_source_rgb(handle->wayland.back_cairo, 0, 0.25, 0.25); - cairo_rectangle(handle->wayland.back_cairo, 1, 1, handle->wayland.ww - 2, handle->wayland.wh - 2); - cairo_fill_preserve(handle->wayland.back_cairo); - cairo_set_source_rgb(handle->wayland.back_cairo, 1, 1, 1); - cairo_rectangle(handle->wayland.back_cairo, 0, 0, handle->wayland.ww, handle->wayland.wh); + int x, y; + cairo_set_line_width(handle->wayland.back_cairo, 4.0); + for(x = 0; x < handle->wayland.ww; x++) { + float placeholder = (float)x / (float)handle->wayland.ww; + cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25); + + cairo_move_to(handle->wayland.back_cairo, handle->wayland.ww - x, 0); + cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww - x, CSD_BORDER_FRAME_TOP); + cairo_stroke(handle->wayland.back_cairo); + + cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP); + cairo_line_to(handle->wayland.back_cairo, x, handle->wayland.wh); + cairo_stroke(handle->wayland.back_cairo); + } + cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5); + cairo_move_to(handle->wayland.back_cairo, 0, 0); + cairo_line_to(handle->wayland.back_cairo, 0, handle->wayland.wh); cairo_stroke(handle->wayland.back_cairo); + cairo_move_to(handle->wayland.back_cairo, 0, 0); + cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, 0); + cairo_stroke(handle->wayland.back_cairo); + + cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5); + cairo_move_to(handle->wayland.back_cairo, 0, handle->wayland.wh); + cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, handle->wayland.wh); + cairo_stroke(handle->wayland.back_cairo); + cairo_move_to(handle->wayland.back_cairo, handle->wayland.ww, 0); + cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, handle->wayland.wh); + cairo_stroke(handle->wayland.back_cairo); + + if(strlen(handle->wayland.title) != 0) { + int y, x; + int i = 0, sx = 0, sy = 0; + int tw, th; + unsigned char* px; + MwRect r; + MwLLPixmap p; + tw = strlen(handle->wayland.title) * 7; + th = 14; + px = malloc(tw * th * 4); + assert(px); + + memset(px, 0, tw * th * 4); + + handle->wayland.selected_cairo = handle->wayland.back_cairo; + + while(handle->wayland.title[i]) { + int out; + i += MwUTF8ToUTF32(handle->wayland.title + i, &out); + + if(out > 0xff) { + out = 0; + } + + for(y = 0; y < 14; y++) { + for(x = 0; x < 7; x++) { + unsigned char* ppx = &px[((sy + y) * tw + sx + x) * 4]; + int col = MwFontData[out].data[y] & (1 << ((7 - 1) - x)) ? 255 : 0; + ppx[0] = col; + ppx[1] = col; + ppx[2] = col; + ppx[3] = col; + } + } + sx += 7; + } + + p = MwLLCreatePixmap(handle, px, tw, th); + r.x = 5; + r.y = 5; + r.width = tw; + r.height = th; + + MwLLDrawPixmap(handle, &r, p); + MwLLDestroyPixmap(p); + free(px); + } + update_buffer(&handle->wayland.backbuffer); } + handle->wayland.selected_cairo = handle->wayland.front_cairo; } static void MwLLEndDrawImpl(MwLL handle) { if(handle->wayland.configured) { update_buffer(&handle->wayland.framebuffer); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - update_buffer(&handle->wayland.backbuffer); } } } @@ -1835,8 +1948,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_paint(c); - cairo_set_source_surface(handle->wayland.front_cairo, cs, rect->x, rect->y); - cairo_paint(handle->wayland.front_cairo); + cairo_set_source_surface(handle->wayland.selected_cairo, cs, rect->x, rect->y); + cairo_paint(handle->wayland.selected_cairo); cairo_destroy(c); cairo_surface_destroy(cs); From dee940161e3c72fa2938e9e1182ed7ae5498266e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Fri, 20 Mar 2026 19:33:12 -0700 Subject: [PATCH 203/409] clip: only apply extra clipping when haves decorations --- src/backend/wayland.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d6eae3ccf..6f7a08ea7 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1472,16 +1472,22 @@ static void destroy_popup(MwLL r) { } static void clip(MwLL handle) { - MwLL topmost = handle->wayland.parent; - if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + MwLL parent = handle->wayland.parent; + MwLL topmost = parent; + int left_offset = 0; + int top_offset = 0; + + if(parent && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { cairo_reset_clip(handle->wayland.front_cairo); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), (topmost->wayland.wh + handle->wayland.y) - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + cairo_rectangle(handle->wayland.front_cairo, 0, 0, (parent->wayland.ww + handle->wayland.x), (parent->wayland.wh + handle->wayland.y)); cairo_clip(handle->wayland.front_cairo); } if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - while(topmost->wayland.parent) topmost = topmost->wayland.parent; cairo_reset_clip(handle->wayland.front_cairo); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), (topmost->wayland.wh + handle->wayland.y) - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + while(topmost->wayland.parent) topmost = topmost->wayland.parent; + left_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + top_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - left_offset, (topmost->wayland.wh + handle->wayland.y) - top_offset); cairo_clip(handle->wayland.front_cairo); } } From 69076f28930a25c31a579034f3f364be0e444f0f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Fri, 20 Mar 2026 19:42:30 -0700 Subject: [PATCH 204/409] fix menus on csd --- src/backend/wayland.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 6f7a08ea7..17872faaa 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1402,6 +1402,10 @@ static void setup_popup(MwLL r, int x, int y) { while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { topmost_parent = topmost_parent->wayland.parent; } + if(!topmost_parent->wayland.has_decorations) { + r->wayland.x += ceil((float)CSD_BORDER_FRAME_LEFT / 2.); + r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.); + } r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); memset(r->wayland.popup, 0, sizeof(struct _MwLLWaylandPopup)); @@ -1425,9 +1429,7 @@ static void setup_popup(MwLL r, int x, int y) { xdg_positioner_set_size(r->wayland.popup->xdg_positioner, r->wayland.ww, r->wayland.wh); xdg_positioner_set_anchor_rect( r->wayland.popup->xdg_positioner, - x, y, r->wayland.ww, r->wayland.wh); - xdg_positioner_set_anchor(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_TOP_LEFT); - xdg_positioner_set_gravity(r->wayland.popup->xdg_positioner, XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT); + r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); xdg_surface = topmost_parent->wayland.toplevel->xdg_surface; @@ -1759,6 +1761,8 @@ static void MwLLBeginDrawImpl(MwLL handle) { free(px); } update_buffer(&handle->wayland.backbuffer); + + wl_surface_commit(handle->wayland.backbuffer.surface); } handle->wayland.selected_cairo = handle->wayland.front_cairo; } @@ -1961,8 +1965,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_surface_destroy(cs); MwLLForceRender(handle); - // update_buffer(&handle->wayland.framebuffer); - // wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); + update_buffer(&handle->wayland.framebuffer); + wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { From 0527d376b7aa6fc344ecbcf9afa045bfaea3016f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Fri, 20 Mar 2026 20:23:02 -0700 Subject: [PATCH 205/409] add function for forcing the client to be configured before doing any xdg stuff (in a way Both all compositors like) --- src/backend/wayland.c | 117 ++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 51 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 17872faaa..3a5c461af 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -890,6 +890,68 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { } +/* Standard Wayland event loop. */ +static int event_loop(MwLL handle) { + struct pollfd fd; + struct timespec timeout; + struct _MwLLWayland* wayland = &handle->wayland; + int res; + + timeout.tv_nsec = 1; + timeout.tv_sec = 0; + + if(wayland->display == NULL) { + return 0; + } + fd.fd = wl_display_get_fd(wayland->display); + fd.events = POLLIN; + + /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ + while(wl_display_flush(wayland->display) == -1) { + if(errno != EAGAIN) { + return MwFALSE; + } + + while(poll(&fd, 1, -1) == -1) { + if(errno != EINTR && errno != EAGAIN) { + wl_display_cancel_read(wayland->display); + + MwLLDispatch(handle, close, NULL); + return 0; + } + } + } + + wl_display_prepare_read(handle->wayland.display); + /* Condition where no events are being sent. */ + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(wayland->display); + + wl_surface_commit(wayland->framebuffer.surface); + if(wayland->type == MWLL_WAYLAND_TOPLEVEL) + wl_surface_commit(wayland->backbuffer.surface); + return 0; + } + wl_display_read_events(wayland->display); + if(wl_display_dispatch_pending(wayland->display) < 0) { + wl_display_cancel_read(wayland->display); + } + return 1; +} + +/* make the fuck sure that we're configurd */ +static void hang_until_configured(MwLL handle) { + int i = 0; + while(!handle->wayland.configured) { + if(wl_display_roundtrip(handle->wayland.display) == -1) { + printf("roundtrip failed\n"); + raise(SIGTRAP); + return; + } + event_loop(handle); + } +} + /* `xdg_toplevel.configure` callback */ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, @@ -1033,7 +1095,8 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { wayland->front_cairo = cairo_create(wayland->front_cs); memset(wayland->framebuffer.buf, 0, wayland->framebuffer.buf_size); - if(wayland->configured) update_buffer(&wayland->framebuffer); + hang_until_configured((MwLL)wayland); + update_buffer(&wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -1051,7 +1114,8 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { wayland->back_cairo = cairo_create(wayland->back_cs); memset(wayland->backbuffer.buf, 0, wayland->backbuffer.buf_size); - if(wayland->configured) update_buffer(&wayland->backbuffer); + hang_until_configured((MwLL)wayland); + update_buffer(&wayland->backbuffer); }; static void backbuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->backbuffer); @@ -1110,55 +1174,6 @@ static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* free(data->listener); } -/* Standard Wayland event loop. */ -static int event_loop(MwLL handle) { - struct pollfd fd; - struct timespec timeout; - struct _MwLLWayland* wayland = &handle->wayland; - int res; - - timeout.tv_nsec = 1; - timeout.tv_sec = 0; - - if(wayland->display == NULL) { - return 0; - } - fd.fd = wl_display_get_fd(wayland->display); - fd.events = POLLIN; - - /* If an error other than EAGAIN happens, we have likely been disconnected from the Wayland session */ - while(wl_display_flush(wayland->display) == -1) { - if(errno != EAGAIN) { - return MwFALSE; - } - - while(poll(&fd, 1, -1) == -1) { - if(errno != EINTR && errno != EAGAIN) { - wl_display_cancel_read(wayland->display); - - MwLLDispatch(handle, close, NULL); - return 0; - } - } - } - - wl_display_prepare_read(handle->wayland.display); - /* Condition where no events are being sent. */ - if(!poll(&fd, 1, timeout.tv_nsec)) { - wl_display_cancel_read(wayland->display); - - wl_surface_commit(wayland->framebuffer.surface); - if(wayland->type == MWLL_WAYLAND_TOPLEVEL) - wl_surface_commit(wayland->backbuffer.surface); - return 0; - } - wl_display_read_events(wayland->display); - if(wl_display_dispatch_pending(wayland->display) < 0) { - wl_display_cancel_read(wayland->display); - } - return 1; -} - /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ static void setup_callbacks(struct _MwLLWayland* wayland) { /* Convience macro for adding the interface functions to the setup map */ From 2499f82933e35e8fddc521a6c55a7d6a43518595 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 22 Mar 2026 16:12:54 -0700 Subject: [PATCH 206/409] wayland: fix double free in wp_viewporter_interface_destroy --- src/backend/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 3a5c461af..06fdbb01c 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -864,7 +864,7 @@ static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* } static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - free(data->listener); + // free(data->listener); } /* the two decoration manager constructs */ From 09441380b5e07d2a990040c3dfd8c3ec435e3b23 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 22 Mar 2026 16:15:50 -0700 Subject: [PATCH 207/409] wayland: fallback if selected_cairo is null --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 053d0ff91..9659ac565 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -235,6 +235,7 @@ struct _MwLLWayland { cairo_surface_t* back_cs; cairo_t* front_cairo; cairo_t* back_cairo; + /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ cairo_t* selected_cairo; }; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 06fdbb01c..668892217 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1960,6 +1960,7 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; + cairo_t * selected_cairo = handle->wayland.selected_cairo ? handle->wayland.selected_cairo : handle->wayland.front_cairo; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); @@ -1973,8 +1974,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_paint(c); - cairo_set_source_surface(handle->wayland.selected_cairo, cs, rect->x, rect->y); - cairo_paint(handle->wayland.selected_cairo); + cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); + cairo_paint(selected_cairo); cairo_destroy(c); cairo_surface_destroy(cs); From c3d25e6b7d96c9b477aa1d248e3e0d721d63e8ca Mon Sep 17 00:00:00 2001 From: IoIxD Date: Sun, 22 Mar 2026 16:32:36 -0700 Subject: [PATCH 208/409] wayland: don't do draw dispatch on forceRender anymore, merely update the buffer --- src/backend/wayland.c | 29 ++++++++++++++++++----------- src/widget/opengl.c | 7 ++++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 668892217..0a21590d5 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1861,31 +1861,37 @@ static int MwLLPendingImpl(MwLL handle) { fd.fd = wl_display_get_fd(handle->wayland.display); fd.events = POLLOUT; - wl_display_prepare_read(handle->wayland.display); + if(!handle->wayland.always_render) wl_display_prepare_read(handle->wayland.display); if(!poll(&fd, 1, timeout.tv_nsec)) { wl_display_cancel_read(handle->wayland.display); } else { - wl_display_read_events(handle->wayland.display); + if(!handle->wayland.always_render) wl_display_read_events(handle->wayland.display); if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } } + + if(handle->wayland.always_render) { + // handle->wayland.did_event_loop_early = MwTRUE; + // event_loop(handle); + return pending; + } + wl_surface_commit(handle->wayland.framebuffer.surface); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { wl_surface_commit(handle->wayland.backbuffer.surface); } - if(handle->wayland.always_render) { + if(handle->wayland.events_pending) { + handle->wayland.did_event_loop_early = MwTRUE; event_loop(handle); - return 0; - } else if(handle->wayland.force_render) { - MwLLDispatch(handle, draw, NULL); return 1; } - if(handle->wayland.events_pending || handle->wayland.force_render) { - handle->wayland.did_event_loop_early = MwTRUE; - return event_loop(handle); - } + + // if(handle->wayland.force_render) { + + // return 1; + // } return pending; } @@ -1902,6 +1908,7 @@ static void MwLLNextEventImpl(MwLL handle) { handle->wayland.events_pending = 0; } if(handle->wayland.force_render) { + // MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } @@ -1960,7 +1967,7 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_t* c; cairo_surface_t* cs; - cairo_t * selected_cairo = handle->wayland.selected_cairo ? handle->wayland.selected_cairo : handle->wayland.front_cairo; + cairo_t* selected_cairo = handle->wayland.selected_cairo ? handle->wayland.selected_cairo : handle->wayland.front_cairo; cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, rect->width, rect->height); c = cairo_create(cs); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 779b17afa..6d67344ce 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -165,9 +165,10 @@ static int create(MwWidget handle) { 1, EGL_NONE}; EGLDisplay display; - waylandopengl_t* o = r = malloc(sizeof(*o)); - MwLL topmost_parent = handle->lowlevel->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; + waylandopengl_t* o = r = malloc(sizeof(*o)); + MwLL topmost_parent = handle->lowlevel->wayland.parent; + handle->lowlevel->wayland.always_render = MwTRUE; + topmost_parent->wayland.always_render = MwTRUE; while(topmost_parent->wayland.parent != NULL) { topmost_parent = topmost_parent->wayland.parent; From 9d65e9c6bf37a21c625a95a43410c030af4fc855 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 23 Mar 2026 12:05:32 -0700 Subject: [PATCH 209/409] Wayland improvements --- examples/basic/clipboard.c | 1 + examples/vkdemos/vulkan.c | 9 ++- include/Mw/LowLevel/Wayland.h | 7 +- src/backend/wayland.c | 143 ++++++++++++++++++---------------- src/widget/combobox.c | 2 +- src/widget/vulkan.c | 2 +- 6 files changed, 89 insertions(+), 75 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 384cbc6fe..57d579256 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -29,6 +29,7 @@ void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; + printf("got: %s\n", clipboard); if(clipboard != NULL) { MwVaApply(text, MwNtext, clipboard, NULL); MwForceRender(text); diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 0e1842d04..29547ce5e 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -27,6 +27,8 @@ MwWidget window, vulkan; int ow = 300; int oh = 250; +double timer = 0; + PFN_vkGetInstanceProcAddr _vkGetInstanceProcAddr; VkInstance instance; VkDevice device; @@ -75,9 +77,10 @@ void tick(MwWidget handle, void* user_data, void* call_data) { VkSubmitInfo submitInfo = {}; VkPresentInfoKHR presentInfo = {}; - VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; + VkClearValue clearColor = {{{sin(timer) / 10., cos(timer) / 10., atan(timer) / 10., 1.0f}}}; uint32_t vertexCount = 3; uint32_t instanceCount = 1; + timer += (float)(rand() % 1000) / 1000.; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT}; @@ -289,8 +292,8 @@ void vulkan_setup(MwWidget handle) { swapchainCreateInfo.imageExtent = (VkExtent2D){.width = ow, .height = oh}, swapchainCreateInfo.imageArrayLayers = 1, swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT; + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT; // th is how we specify no transformation. swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; swapchainCreateInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 9659ac565..00556dada 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -141,6 +141,9 @@ struct _MwLLWayland { enum _MwLLWaylandType type; enum _MwLLWaylandType type_to_be; + MwBool detatching; + MwPoint detach_point; + /* Map of Wayland interfaces to their relevant setup functions. */ struct { const char* key; @@ -227,8 +230,6 @@ struct _MwLLWayland { MwBool moving; - MwLL currentlyHeldWidget; - struct wl_surface* curSurface; cairo_surface_t* front_cs; @@ -236,7 +237,7 @@ struct _MwLLWayland { cairo_t* front_cairo; cairo_t* back_cairo; /* The cairo to actually use for draw operations. Typically is front_cairo, but MwLLBeginDraw can change this to the back_cairo so it can be used to draw window decorations. */ - cairo_t* selected_cairo; + cairo_t* selected_cairo; }; struct _MwLLWaylandColor { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 0a21590d5..2e32ceda6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -228,8 +228,12 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { arrpush(buf, 0); close(fds[0]); + printf("sending: %s\n", buf); + MwLLDispatch(ctx->ll, clipboard, buf); arrfree(buf); + + ctx->ll->wayland.events_pending = 1; } static void wl_data_source_listener_target(void* data, @@ -415,6 +419,8 @@ static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { }; } +static MwLL currentlyHeldWidget = NULL; + /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { @@ -428,15 +434,25 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); - if(self->wayland.parent != NULL) { - if(!self->wayland.parent->wayland.currentlyHeldWidget) { - MwLLDispatch(self, down, &p); - } + if(currentlyHeldWidget) { + MwLLDispatch(currentlyHeldWidget, down, &p); } - /* Only draw once every 50 milliseconds */ - if((self->wayland.last_time + 50) <= time) { - MwLLDispatch(self, draw, NULL); - self->wayland.last_time = time; + + /* We want to send a draw call whenever we move the cursor, BUT only if the topmost parent doesn't already have events pedngin. */ + if(self->wayland.parent) { + MwLL topmost = self->wayland.parent; + while(topmost->wayland.parent) topmost = topmost->wayland.parent; + /* also we only wanna do it every 50ms */ + if((self->wayland.last_time + 50) <= time && !topmost->wayland.events_pending) { + MwLLDispatch(self, draw, NULL); + self->wayland.last_time = time; + } + } else { + /* if there's no parent just impose the requirement on the widget itself */ + if((self->wayland.last_time + 50) <= time && !self->wayland.events_pending) { + MwLLDispatch(self, draw, NULL); + self->wayland.last_time = time; + } } WAYLAND_EVENT_OP_END(self); @@ -477,17 +493,13 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri switch(state) { case WL_POINTER_BUTTON_STATE_PRESSED: MwLLDispatch(self, down, &p); - if(self->wayland.parent != NULL) { - self->wayland.parent->wayland.currentlyHeldWidget = self; - } + currentlyHeldWidget = self; break; case WL_POINTER_BUTTON_STATE_RELEASED: - if(self->wayland.parent != NULL) { - if(self->wayland.parent->wayland.currentlyHeldWidget != NULL) { - MwLLDispatch(self->wayland.parent->wayland.currentlyHeldWidget, up, &p); - self->wayland.parent->wayland.currentlyHeldWidget = NULL; - } + if(currentlyHeldWidget != NULL) { + MwLLDispatch(currentlyHeldWidget, up, &p); + currentlyHeldWidget = NULL; } else { MwLLDispatch(self, up, &p); } @@ -993,8 +1005,6 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); - - MwLLForceRender(self); }; /* Empty function for satisfying zxdg_toplevel's requirements */ @@ -1851,15 +1861,15 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - struct timespec timeout; - struct pollfd fd; - int pending = 0; - - timeout.tv_nsec = 100; - timeout.tv_sec = 0; - - fd.fd = wl_display_get_fd(handle->wayland.display); - fd.events = POLLOUT; + struct timespec timeout = { + .tv_nsec = 100, + .tv_sec = 0, + }; + struct pollfd fd = { + .fd = wl_display_get_fd(handle->wayland.display), + .events = POLLOUT, + }; + int pending = 0; if(!handle->wayland.always_render) wl_display_prepare_read(handle->wayland.display); if(!poll(&fd, 1, timeout.tv_nsec)) { @@ -1872,8 +1882,8 @@ static int MwLLPendingImpl(MwLL handle) { } if(handle->wayland.always_render) { - // handle->wayland.did_event_loop_early = MwTRUE; - // event_loop(handle); + handle->wayland.did_event_loop_early = MwTRUE; + event_loop(handle); return pending; } @@ -1882,18 +1892,7 @@ static int MwLLPendingImpl(MwLL handle) { wl_surface_commit(handle->wayland.backbuffer.surface); } - if(handle->wayland.events_pending) { - handle->wayland.did_event_loop_early = MwTRUE; - event_loop(handle); - return 1; - } - - // if(handle->wayland.force_render) { - - // return 1; - // } - - return pending; + return handle->wayland.force_render || handle->wayland.events_pending || pending; } static void MwLLNextEventImpl(MwLL handle) { @@ -1904,14 +1903,15 @@ static void MwLLNextEventImpl(MwLL handle) { event_loop(handle); } } - if(handle->wayland.events_pending) { - handle->wayland.events_pending = 0; - } + if(handle->wayland.force_render) { - // MwLLDispatch(handle, draw, NULL); + if(!handle->wayland.events_pending) MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } + if(handle->wayland.events_pending) { + handle->wayland.events_pending = 0; + } } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -2034,6 +2034,9 @@ static void MwLLForceRenderImpl(MwLL handle) { wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); handle->wayland.force_render = MwTRUE; + if(handle->wayland.parent) { + handle->wayland.parent->wayland.force_render = MwTRUE; + } } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { @@ -2087,28 +2090,8 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - switch(handle->wayland.type) { - case MWLL_WAYLAND_UNKNOWN: - case MWLL_WAYLAND_TOPLEVEL: - destroy_toplevel(handle); - break; - case MWLL_WAYLAND_SUBLEVEL: - destroy_sublevel(handle); - break; - case MWLL_WAYLAND_POPUP: - return; - } - - wl_flush(handle); - - switch(handle->wayland.type_to_be) { - case MWLL_WAYLAND_POPUP: - setup_popup(handle, point->x, point->y); - break; - default: - setup_toplevel(handle, point->x, point->y); - break; - } + handle->wayland.detatching = MwTRUE; + handle->wayland.detach_point = *point; } static void MwLLShowImpl(MwLL handle, int show) { @@ -2201,6 +2184,32 @@ static void MwLLBeginStateChangeImpl(MwLL handle) { } static void MwLLEndStateChangeImpl(MwLL handle) { + if(handle->wayland.detatching) { + switch(handle->wayland.type) { + case MWLL_WAYLAND_UNKNOWN: + case MWLL_WAYLAND_TOPLEVEL: + destroy_toplevel(handle); + break; + case MWLL_WAYLAND_SUBLEVEL: + destroy_sublevel(handle); + break; + case MWLL_WAYLAND_POPUP: + return; + } + + wl_flush(handle); + + switch(handle->wayland.type_to_be) { + case MWLL_WAYLAND_POPUP: + setup_popup(handle, handle->wayland.detach_point.x, handle->wayland.detach_point.y); + break; + default: + setup_toplevel(handle, handle->wayland.detach_point.x, handle->wayland.detach_point.y); + break; + } + handle->wayland.detatching = MwFALSE; + } + MwLLShow(handle, 1); } diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 591258f96..6b5437335 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -138,8 +138,8 @@ static void click(MwWidget handle) { p.x = 0; p.y = MwGetInteger(handle, MwNheight); MwLLBeginStateChange(cb->listbox->lowlevel); - MwLLMakeToolWindow(cb->listbox->lowlevel); MwLLDetach(cb->listbox->lowlevel, &p); + MwLLMakeToolWindow(cb->listbox->lowlevel); MwLLEndStateChange(cb->listbox->lowlevel); } else { MwLLSetCursor(handle->lowlevel, &MwCursorDefault, &MwCursorDefaultMask); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index b78e7429b..e2dfa4c8b 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -231,7 +231,7 @@ static MwErrorEnum vulkan_instance_setup(MwWidget handle, vulkan_t* o) { arrput(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ - topmost_parent->wayland.always_render = MwTRUE; + handle->lowlevel->wayland.always_render = MwTRUE; while(topmost_parent->wayland.parent != NULL) { topmost_parent = topmost_parent->wayland.parent; From 6d7fe3271f0d12711639876ab049cd574cf2aeae Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 24 Mar 2026 04:26:26 +0900 Subject: [PATCH 210/409] fix cursor thing for x11/gdi, also format --- examples/gldemos/cube.c | 116 ++++++++++++++------------- include/Mw/LowLevel/Cocoa.h | 151 +++++++++++++++++------------------ include/Mw/Widget/OpenGL.h | 12 +-- pl/rules.pl | 4 +- src/backend/gdi.c | 2 +- src/backend/x11.c | 2 +- src/widget/opengl_cocoa.m | 155 ++++++++++++++++++------------------ tools/readme.pl | 3 +- 8 files changed, 224 insertions(+), 221 deletions(-) diff --git a/examples/gldemos/cube.c b/examples/gldemos/cube.c index 2d1954c5a..de0b84078 100644 --- a/examples/gldemos/cube.c +++ b/examples/gldemos/cube.c @@ -12,78 +12,82 @@ static double deg = 0; static void draw(void) { - int i; - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + int i; + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glPushMatrix(); - glRotatef(deg, 1, 0, 0); - glRotatef(deg, 0, 1, 0); - glRotatef(deg, 0, 0, 1); + glPushMatrix(); + glRotatef(deg, 1, 0, 0); + glRotatef(deg, 0, 1, 0); + glRotatef(deg, 0, 0, 1); - for (i = 0; i < 6; i++) { - if (i == 0) - glColor3f(1, 0, 0); - if (i == 1) - glColor3f(0, 1, 0); - if (i == 2) - glColor3f(1, 1, 0); - if (i == 3) - glColor3f(0, 0, 1); - if (i == 4) - glColor3f(1, 0, 1); - if (i == 5) - glColor3f(0, 1, 1); + for(i = 0; i < 6; i++) { + if(i == 0) + glColor3f(1, 0, 0); + if(i == 1) + glColor3f(0, 1, 0); + if(i == 2) + glColor3f(1, 1, 0); + if(i == 3) + glColor3f(0, 0, 1); + if(i == 4) + glColor3f(1, 0, 1); + if(i == 5) + glColor3f(0, 1, 1); - glBegin(GL_QUADS); - glNormal3f(0, 1, 0); - glVertex3f(-1, 1, -1); - glVertex3f(-1, 1, 1); - glVertex3f(1, 1, 1); - glVertex3f(1, 1, -1); - glEnd(); + glBegin(GL_QUADS); + glNormal3f(0, 1, 0); + glVertex3f(-1, 1, -1); + glVertex3f(-1, 1, 1); + glVertex3f(1, 1, 1); + glVertex3f(1, 1, -1); + glEnd(); - if (i < 3) - glRotatef(90, 0, 0, 1); - if (i == 3) - glRotatef(90, 1, 0, 0); - if (i == 4) - glRotatef(180, 0, 0, 1); - } - glPopMatrix(); + if(i < 3) + glRotatef(90, 0, 0, 1); + if(i == 3) + glRotatef(90, 1, 0, 0); + if(i == 4) + glRotatef(180, 0, 0, 1); + } + glPopMatrix(); } -static void idle(void) { deg += 1.0; } +static void idle(void) { + deg += 1.0; +} static void reshape(int width, int height) { - GLfloat lpos[4]; + GLfloat lpos[4]; - lpos[0] = 1; - lpos[1] = 1; - lpos[2] = 1; - lpos[3] = 0; + lpos[0] = 1; + lpos[1] = 1; + lpos[2] = 1; + lpos[3] = 0; - glViewport(0, 0, width, height); + glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60, (double)width / height, 1, 100); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60, (double)width / height, 1, 100); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt(2, 2, 2, 0, 0, 0, 0, 1, 0); - glLightfv(GL_LIGHT0, GL_POSITION, lpos); + glLightfv(GL_LIGHT0, GL_POSITION, lpos); } static void init(void) { - glEnable(GL_DEPTH_TEST); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_COLOR_MATERIAL); - glEnable(GL_CULL_FACE); - glEnable(GL_NORMALIZE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + glEnable(GL_LIGHT0); + glEnable(GL_COLOR_MATERIAL); + glEnable(GL_CULL_FACE); + glEnable(GL_NORMALIZE); - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); + glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); } -static void key(int k) { (void)k; } +static void key(int k) { + (void)k; +} diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 19e0bc3c1..7d1b217fe 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -23,9 +23,9 @@ // Note: implements NSApplicationDelegate @interface MilskoCocoaApplicationDelegate : NSObject { - NSApplication *appl; + NSApplication* appl; } -- (MilskoCocoaApplicationDelegate *)initWithAppl:(NSApplication *)appl; +- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)appl; @end @interface MilskoCocoaWindow : NSWindow { @@ -34,9 +34,9 @@ // Note: implements NSWindowDelegate @interface MilskoCocoaWindowDelegate : NSObject { - MilskoCocoaWindow *w; + MilskoCocoaWindow* w; } -- (MilskoCocoaWindowDelegate *)initWithWin:(MilskoCocoaWindow *)win; +- (MilskoCocoaWindowDelegate*)initWithWin:(MilskoCocoaWindow*)win; @end /* @@ -52,139 +52,138 @@ retrieved appropriately. */ @interface MilskoFakePointer : NSView { - void *ptr; + void* ptr; } -- (void)setPointer:(void *)ptr; -- (void *)pointer; +- (void)setPointer:(void*)ptr; +- (void*)pointer; @end @interface MilskoCocoaPixmap : NSObject { - MwBool valid; - int width; - int height; - unsigned char *buf; - NSImage *image; - NSBitmapImageRep *rep; + MwBool valid; + int width; + int height; + unsigned char* buf; + NSImage* image; + NSBitmapImageRep* rep; } -+ (MilskoCocoaPixmap *)newWithWidth:(int)width height:(int)height; -- (void)updateWithData:(unsigned char *)data; ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height; +- (void)updateWithData:(unsigned char*)data; - (void)destroy; /* using @property to create instance variables fucks up 10.4 gcc for some * reason? */ -- (NSImage *)image; +- (NSImage*)image; @end @interface MilskoCocoaView : NSView { - NSBitmapImageRep *rep; - NSGraphicsContext *context; - MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; - float width; - float height; + NSBitmapImageRep* rep; + NSGraphicsContext* context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + float width; + float height; } - (void)initRepAndContextWithWidth:(float)w Height:(float)h; -- (NSGraphicsContext *)context; +- (NSGraphicsContext*)context; - (void)destroy; -- (NSBitmapImageRep *)getRep; +- (NSBitmapImageRep*)getRep; @end @interface MilskoCocoa : NSObject { - NSApplication *application; - MwBool _forceRender; - MilskoCocoaWindow *window; - NSRect rect; - MilskoCocoaView *view; - MwLL parent; - MilskoFakePointer *handle; - unsigned int strHash; - NSEvent *lastEvent; + NSApplication* application; + MwBool _forceRender; + MilskoCocoaWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; - MilskoCocoaPixmap *cursorPixmap; - NSCursor *cursor; - NSModalSession modalSession; - - MwBool pointerLocked; - MwBool mouseMoved; + MilskoCocoaPixmap* cursorPixmap; + NSCursor* cursor; + NSModalSession modalSession; + MwBool pointerLocked; + MwBool mouseMoved; } -+ (MilskoCocoa *)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)handle; -- (void)polygonWithPoints:(MwPoint *)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint *)points color:(MwLLColor)color; -- (void)getX:(int *)x Y:(int *)y W:(unsigned int *)w H:(unsigned int *)h; ++ (MilskoCocoa*)newWithParent:(MwLL)parent + x:(int)x + y:(int)y + width:(int)width + height:(int)height + handle:(MwLL)handle; +- (void)polygonWithPoints:(MwPoint*)points + points_count:(int)points_count + color:(MwLLColor)color; +- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; +- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; -- (void)eventProcess:(NSEvent *)ev; -- (void)handleKeyEvent:(NSEvent *)ev ll:(MwLL)ll; -- (void)handleMouseEvent:(NSEvent *)ev ll:(MwLL)ll; +- (void)eventProcess:(NSEvent*)ev; +- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll; +- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll; - (void)getNextEvent; -- (void)setTitle:(const char *)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect *)rect; +- (void)setTitle:(const char*)title; +- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; - (void)setIcon:(MwLLPixmap)pixmap; - (void)forceRender; -- (void)setCursor:(MwCursor *)image mask:(MwCursor *)mask; -- (void)detachWithPoint:(MwPoint *)point; +- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; +- (void)detachWithPoint:(MwPoint*)point; - (void)show:(int)show; - (void)makePopupWithParent:(MwLL)parent; - (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; + MinY:(int)miny + MaxX:(int)maxx + MaxY:(int)maxy; - (void)makeBorderless:(int)toggle; - (void)focus; - (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char *)text; +- (void)setClipboard:(const char*)text; - (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint *)point; -- (void)getScreenSize:(MwRect *)rect; +- (void)getCursorCoord:(MwPoint*)point; +- (void)getScreenSize:(MwRect*)rect; - (void)destroy; - (void)sendClipboardEvent; - (MwLL)getParent; -- (NSView *)getView; -- (MilskoCocoaWindow *)getWindow; +- (NSView*)getView; +- (MilskoCocoaWindow*)getWindow; -- (MilskoFakePointer *)getHandle; -+ (void)eventCanceller:(MilskoCocoa *)this; +- (MilskoFakePointer*)getHandle; ++ (void)eventCanceller:(MilskoCocoa*)this; @end #define OBJC(x) x #else -#define OBJC(x) void * +#define OBJC(x) void* #endif MWDECL int MwLLCocoaCallInit(void); struct _MwLLCocoa { - struct _MwLLCommon common; - OBJC(MilskoCocoa *) - real; + struct _MwLLCommon common; + OBJC(MilskoCocoa*) + real; }; struct _MwLLCocoaColor { - struct _MwLLCommonColor common; + struct _MwLLCommonColor common; }; struct _MwLLCocoaPixmap { - struct _MwLLCommonPixmap common; - OBJC(MilskoCocoaPixmap *) - real; + struct _MwLLCommonPixmap common; + OBJC(MilskoCocoaPixmap*) + real; }; #endif diff --git a/include/Mw/Widget/OpenGL.h b/include/Mw/Widget/OpenGL.h index c3fab76ed..3f7a0c451 100644 --- a/include/Mw/Widget/OpenGL.h +++ b/include/Mw/Widget/OpenGL.h @@ -43,7 +43,7 @@ MWDECL MwClass MwOpenGLClass; * @param handle Widget */ MwInline void MwOpenGLMakeCurrent(MwWidget handle) { - MwVaWidgetExecute(handle, "mwOpenGLMakeCurrent", NULL); + MwVaWidgetExecute(handle, "mwOpenGLMakeCurrent", NULL); } /*! @@ -52,10 +52,10 @@ MwInline void MwOpenGLMakeCurrent(MwWidget handle) { * @param name Name * @return Procedure */ -MwInline void *MwOpenGLGetProcAddress(MwWidget handle, const char *name) { - void *out; - MwVaWidgetExecute(handle, "mwOpenGLGetProcAddress", &out, name); - return out; +MwInline void* MwOpenGLGetProcAddress(MwWidget handle, const char* name) { + void* out; + MwVaWidgetExecute(handle, "mwOpenGLGetProcAddress", &out, name); + return out; } /*! @@ -63,7 +63,7 @@ MwInline void *MwOpenGLGetProcAddress(MwWidget handle, const char *name) { * @param handle Widget */ MwInline void MwOpenGLSwapBuffer(MwWidget handle) { - MwVaWidgetExecute(handle, "mwOpenGLSwapBuffer", NULL); + MwVaWidgetExecute(handle, "mwOpenGLSwapBuffer", NULL); } #ifdef __cplusplus diff --git a/pl/rules.pl b/pl/rules.pl index a35a6c3e6..a4ba7bfc8 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -37,7 +37,7 @@ if (grep(/^wayland$/, @backends)) { } scan_wayland_protocol("stable", "xdg-shell", ""); - scan_wayland_protocol("stable", "viewporter", ""); + scan_wayland_protocol("stable", "viewporter", ""); scan_wayland_protocol("stable", "tablet", "-v2"); scan_wayland_protocol("staging", "xdg-toplevel-icon", "-v1"); scan_wayland_protocol("staging", "cursor-shape", "-v1"); @@ -55,7 +55,7 @@ if (grep(/^cocoa$/, @backends)) { new_object("src/widget/opengl_cocoa.m"); } - # tim cook my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this +# tim cook my man literally everybody and their mother who knows what opengl is knows its deprecated on macos and i'm not having you spam the console with this add_cflags("-DGL_SILENCE_DEPRECATION"); $gl_libs = "-framework OpenGL"; diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 4601b79da..d6ad07a53 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -621,7 +621,7 @@ HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) { } } - cursor = CreateCursor(GetModuleHandle(NULL), xs, ys, MwCursorDataHeight, MwCursorDataHeight, dmask, dimage); + cursor = CreateCursor(GetModuleHandle(NULL), xs - image->x, ys + (MwCursorDataHeight + image->y), MwCursorDataHeight, MwCursorDataHeight, dmask, dimage); free(dimage); free(dmask); diff --git a/src/backend/x11.c b/src/backend/x11.c index f7c6fe4bd..cd9e8825f 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -849,7 +849,7 @@ Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask) { XPutImage(display, pimage, imagegc, cimage, 0, 0, 0, 0, MwCursorDataHeight, MwCursorDataHeight); XPutImage(display, pmask, maskgc, cmask, 0, 0, 0, 0, MwCursorDataHeight, MwCursorDataHeight); - cur = XCreatePixmapCursor(display, pimage, pmask, &cfg, &cbg, xs, ys); + cur = XCreatePixmapCursor(display, pimage, pmask, &cfg, &cbg, xs - image->x, ys + (MwCursorDataHeight + image->y)); XFreePixmap(display, pimage); XFreePixmap(display, pmask); diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index 503fe5e7b..2397a8473 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -7,124 +7,125 @@ #import @interface MacOpenGLWidget : NSObject { - NSOpenGLPixelFormat *pixelFormat; - NSOpenGLContext *glc; - MilskoCocoa *_win; + NSOpenGLPixelFormat* pixelFormat; + NSOpenGLContext* glc; + MilskoCocoa* _win; } -- (MacOpenGLWidget *)initWithWindow:(MilskoCocoa *)w; +- (MacOpenGLWidget*)initWithWindow:(MilskoCocoa*)w; - (void)destroy; - (void)makeCurrent; - (void)swapBuffer; -- (void *)getProcAddressWithName:(const char *)name; +- (void*)getProcAddressWithName:(const char*)name; @end static int create(MwWidget handle) { - void *r = NULL; - MwWidget w = handle; + void* r = NULL; + MwWidget w = handle; - int x = MwGetInteger(w, MwNx); - int y = MwGetInteger(w, MwNy); - int width = MwGetInteger(w, MwNwidth); - int height = MwGetInteger(w, MwNheight); + int x = MwGetInteger(w, MwNx); + int y = MwGetInteger(w, MwNy); + int width = MwGetInteger(w, MwNwidth); + int height = MwGetInteger(w, MwNheight); - printf("%d %d\n", width, height); + printf("%d %d\n", width, height); - handle->internal = - [[MacOpenGLWidget alloc] initWithWindow:handle->lowlevel->cocoa.real]; - handle->lowlevel->common.copy_buffer = 0; + handle->internal = + [[MacOpenGLWidget alloc] initWithWindow:handle->lowlevel->cocoa.real]; + handle->lowlevel->common.copy_buffer = 0; - MwSetDefault(handle); + MwSetDefault(handle); - while (w->parent != NULL) - w = w->parent; + while(w->parent != NULL) + w = w->parent; - w->berserk++; + w->berserk++; - return 0; + return 0; } static void destroy(MwWidget handle) { - [(MacOpenGLWidget *)handle->internal destroy]; + [(MacOpenGLWidget*)handle->internal destroy]; } static void mwOpenGLMakeCurrentImpl(MwWidget handle) { - [(MacOpenGLWidget *)handle->internal makeCurrent]; + [(MacOpenGLWidget*)handle->internal makeCurrent]; } static void mwOpenGLSwapBufferImpl(MwWidget handle) { - [(MacOpenGLWidget *)handle->internal swapBuffer]; + [(MacOpenGLWidget*)handle->internal swapBuffer]; } -static void *mwOpenGLGetProcAddressImpl(MwWidget handle, const char *name) { - return [(MacOpenGLWidget *)handle->internal getProcAddressWithName:name]; +static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { + return [(MacOpenGLWidget*)handle->internal getProcAddressWithName:name]; } -static void func_handler(MwWidget handle, const char *name, void *out, - va_list va) { - if (strcmp(name, "mwOpenGLMakeCurrent") == 0) { - mwOpenGLMakeCurrentImpl(handle); - } - if (strcmp(name, "mwOpenGLSwapBuffer") == 0) { - mwOpenGLSwapBufferImpl(handle); - } - if (strcmp(name, "mwOpenGLGetProcAddress") == 0) { - const char *_name = va_arg(va, const char *); - *(void **)out = mwOpenGLGetProcAddressImpl(handle, _name); - } +static void func_handler(MwWidget handle, const char* name, void* out, + va_list va) { + if(strcmp(name, "mwOpenGLMakeCurrent") == 0) { + mwOpenGLMakeCurrentImpl(handle); + } + if(strcmp(name, "mwOpenGLSwapBuffer") == 0) { + mwOpenGLSwapBufferImpl(handle); + } + if(strcmp(name, "mwOpenGLGetProcAddress") == 0) { + const char* _name = va_arg(va, const char*); + *(void**)out = mwOpenGLGetProcAddressImpl(handle, _name); + } } @implementation MacOpenGLWidget -- (MacOpenGLWidget *)initWithWindow:(MilskoCocoa *)w { - NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { - NSOpenGLPFAColorSize, 24, - NSOpenGLPFAStencilSize, 8, - NSOpenGLPFAAlphaSize, 8, - NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, - NSOpenGLPFANoRecovery, 0}; - self->pixelFormat = - [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; - self->glc = - [[NSOpenGLContext alloc] initWithFormat:pixelFormat shareContext:nil]; - [self->glc setView:[w getView]]; - self->_win = w; - return self; +- (MacOpenGLWidget*)initWithWindow:(MilskoCocoa*)w { + NSOpenGLPixelFormatAttribute pixelFormatAttributes[] = { + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAStencilSize, 8, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, + NSOpenGLPFANoRecovery, 0}; + self->pixelFormat = + [[NSOpenGLPixelFormat alloc] initWithAttributes:pixelFormatAttributes]; + self->glc = + [[NSOpenGLContext alloc] initWithFormat:pixelFormat + shareContext:nil]; + [self->glc setView:[w getView]]; + self->_win = w; + return self; }; - (void)destroy { }; - (void)makeCurrent { - [self->glc makeCurrentContext]; + [self->glc makeCurrentContext]; }; - (void)swapBuffer { - [self->glc flushBuffer]; + [self->glc flushBuffer]; }; -- (void *)getProcAddressWithName:(const char *)name { - if (NSIsSymbolNameDefined(name)) { - return NSAddressOfSymbol(NSLookupAndBindSymbol(name)); - } else { - return NULL; - } +- (void*)getProcAddressWithName:(const char*)name { + if(NSIsSymbolNameDefined(name)) { + return NSAddressOfSymbol(NSLookupAndBindSymbol(name)); + } else { + return NULL; + } }; @end -MwClassRec MwOpenGLClassRec = {create, /* create */ - destroy, /* destroy */ - NULL, /* draw */ - NULL, /* click */ - NULL, /* parent_resize */ - NULL, /* prop_change */ - NULL, /* mouse_move */ - NULL, /* mouse_up */ - NULL, /* mouse_down */ - NULL, /* key */ - func_handler, /* execute */ - NULL, /* tick */ - NULL, /* resize */ - NULL, /* children_update */ - NULL, /* children_prop_change */ - NULL, /* clipboard */ - NULL, NULL, NULL, NULL}; -MwClass MwOpenGLClass = &MwOpenGLClassRec; \ No newline at end of file +MwClassRec MwOpenGLClassRec = {create, /* create */ + destroy, /* destroy */ + NULL, /* draw */ + NULL, /* click */ + NULL, /* parent_resize */ + NULL, /* prop_change */ + NULL, /* mouse_move */ + NULL, /* mouse_up */ + NULL, /* mouse_down */ + NULL, /* key */ + func_handler, /* execute */ + NULL, /* tick */ + NULL, /* resize */ + NULL, /* children_update */ + NULL, /* children_prop_change */ + NULL, /* clipboard */ + NULL, NULL, NULL, NULL}; +MwClass MwOpenGLClass = &MwOpenGLClassRec; \ No newline at end of file diff --git a/tools/readme.pl b/tools/readme.pl index 7070312dd..653184c1b 100755 --- a/tools/readme.pl +++ b/tools/readme.pl @@ -58,8 +58,7 @@ l( l(""); c("Requirements"); l(""); -l( -" Milsko requires either"); +l(" Milsko requires either"); l(" * A Windows environment with GDI (so anything NT or 9x)"); l(" * A MacOS environment with Cocoa (10.4 or above supported)"); l(" * A Unix-like environment with X11 for runtime."); From 6c65e58e372c8a1512910ec5e2a74606077f0d6e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Tue, 24 Mar 2026 04:27:57 +0900 Subject: [PATCH 211/409] fix --- src/text/text.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text/text.c b/src/text/text.c index 8d19de838..98849156c 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -70,8 +70,7 @@ void* MwFontLoad(unsigned char* data, unsigned int size) { } void MwFontFree(void* handle) { - if(MwFLFontFree) - return MwFLFontFree(handle); + if(MwFLFontFree) MwFLFontFree(handle); } static void bitmap_MwDrawText(MwWidget handle, MwPoint* point, const char* text, int bold, int align, MwLLColor color) { From efa6804f46573edcb09689e83f6a09ee41830eab Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 24 Mar 2026 04:34:10 +0900 Subject: [PATCH 212/409] fix math --- src/backend/gdi.c | 4 ++-- src/backend/x11.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index d6ad07a53..5d89419d0 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -589,8 +589,8 @@ HCURSOR MwLLGDICreateCursor(MwCursor* image, MwCursor* mask) { int y, x, ys, xs; xs = -mask->x + image->x; - ys = MwCursorDataHeight + mask->y; - ys = MwCursorDataHeight + image->y - ys; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; memset(dmask, 0xff, (MwCursorDataHeight / 8) * MwCursorDataHeight); memset(dimage, 0, (MwCursorDataHeight / 8) * MwCursorDataHeight); diff --git a/src/backend/x11.c b/src/backend/x11.c index cd9e8825f..de69fffb9 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -811,8 +811,8 @@ Cursor MwLLX11CreateCursor(Display* display, MwCursor* image, MwCursor* mask) { XColor cfg, cbg; xs = -mask->x + image->x; - ys = MwCursorDataHeight + mask->y; - ys = MwCursorDataHeight + image->y - ys; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; memset(cimage->data, 0, cimage->bytes_per_line * cimage->height); memset(cmask->data, 0, cmask->bytes_per_line * cmask->height); From 3d83e0ca64b1092350833bbe5c1d8d6be4024795 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 23 Mar 2026 12:35:29 -0700 Subject: [PATCH 213/409] wayland: fix cursor --- src/backend/wayland.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 2e32ceda6..611a82c1b 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2040,7 +2040,7 @@ static void MwLLForceRenderImpl(MwLL handle) { } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - int x, y; + int x, y, xs, ys; if(handle->wayland.cursor.setup) { buffer_destroy(&handle->wayland.cursor); @@ -2049,11 +2049,15 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { buffer_setup(&handle->wayland.cursor, image->width, image->height); memset(handle->wayland.cursor.buf, 0, handle->wayland.cursor.buf_size); + xs = -mask->x + image->x; + ys = MwCursorDataHeight + mask->y; + ys = MwCursorDataHeight + image->y - ys; + for(y = 0; y < mask->height; y++) { unsigned int d = mask->data[y]; for(x = mask->width - 1; x >= 0; x--) { int px = 0; - int idx = ((y * mask->width) + x) * 4; + int idx = (((y + ys) * mask->width) + (x + xs)) * 4; if(d & 1) { handle->wayland.cursor.buf[idx + 3] = 255; @@ -2065,7 +2069,7 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { unsigned int d = image->data[y]; for(x = image->width - 1; x >= 0; x--) { int px = 0; - int idx = ((y * image->width) + x) * 4; + int idx = (((y + ys) * image->width) + (x + xs)) * 4; if(d & 1) { px = 255; From 56cb0d4841dc44c6916587404244b6f0db25a59e Mon Sep 17 00:00:00 2001 From: Nishi Date: Tue, 24 Mar 2026 04:56:08 +0900 Subject: [PATCH 214/409] wayland: fix cursor --- src/backend/wayland.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 611a82c1b..cb35c2068 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2050,14 +2050,14 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { memset(handle->wayland.cursor.buf, 0, handle->wayland.cursor.buf_size); xs = -mask->x + image->x; - ys = MwCursorDataHeight + mask->y; - ys = MwCursorDataHeight + image->y - ys; + ys = mask->height + mask->y; + ys = image->height + image->y - ys; for(y = 0; y < mask->height; y++) { unsigned int d = mask->data[y]; for(x = mask->width - 1; x >= 0; x--) { int px = 0; - int idx = (((y + ys) * mask->width) + (x + xs)) * 4; + int idx = ((y * image->width) + x) * 4; if(d & 1) { handle->wayland.cursor.buf[idx + 3] = 255; @@ -2084,7 +2084,7 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); - wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, 0, 0); + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, xs + image->x, ys + image->height + image->y); wl_surface_commit(handle->wayland.cursor.surface); /* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */ From f4072bcb3f83f29583405650c51c867dfb85d0f6 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 13:38:26 -0700 Subject: [PATCH 215/409] fix clipboard --- examples/basic/clipboard.c | 3 ++- src/backend/wayland.c | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 57d579256..c792db8ca 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -29,7 +29,6 @@ void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)handle; (void)user_data; - printf("got: %s\n", clipboard); if(clipboard != NULL) { MwVaApply(text, MwNtext, clipboard, NULL); MwForceRender(text); @@ -52,6 +51,8 @@ int main() { MwAddUserHandler(window, MwNresizeHandler, resize, NULL); MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(instructions, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(text, MwNclipboardHandler, clipboard, NULL); resize(window, NULL, NULL); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index cb35c2068..2f01c478e 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -228,8 +228,6 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { arrpush(buf, 0); close(fds[0]); - printf("sending: %s\n", buf); - MwLLDispatch(ctx->ll, clipboard, buf); arrfree(buf); @@ -470,7 +468,10 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri p.point = self->wayland.cur_mouse_pos; - if(self->wayland.framebuffer.surface == self->wayland.curSurface || self->wayland.backbuffer.surface == self->wayland.curSurface) { + // p.point.x > x && p.point.x < x + self->wayland.ww && p.point.y > y && p.point.y < y + self->wayland.wh + if( + self->wayland.framebuffer.surface == self->wayland.curSurface || + self->wayland.backbuffer.surface == self->wayland.curSurface) { int i; switch(button) { From ea2d62f2e104b76816ef1b916e02ab368a526a83 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 14:28:49 -0700 Subject: [PATCH 216/409] more wayland fixes --- examples/basic/rotate.c | 1 + include/Mw/LowLevel/Wayland.h | 2 ++ src/backend/wayland.c | 36 +++++++++++++++++++++-------------- 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/examples/basic/rotate.c b/examples/basic/rotate.c index 574eb2d6f..68c9133bf 100644 --- a/examples/basic/rotate.c +++ b/examples/basic/rotate.c @@ -49,6 +49,7 @@ void resize(MwWidget w, void* user, void* client) { (void)user; (void)client; + printf("H\n"); ww = MwGetInteger(w, MwNwidth); wh = MwGetInteger(w, MwNheight); } diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 00556dada..2a16f50ff 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -144,6 +144,8 @@ struct _MwLLWayland { MwBool detatching; MwPoint detach_point; + MwBool did_initial_resize; + /* Map of Wayland interfaces to their relevant setup functions. */ struct { const char* key; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 2f01c478e..1588cdf7b 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1165,10 +1165,10 @@ static void region_setup(MwLL handle) { wl_region_add(handle->wayland.region, 0, 0, width, height); } if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.region); + wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region); wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); } - wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.region); + wl_surface_set_opaque_region(handle->wayland.framebuffer.surface, handle->wayland.o_region); wl_surface_set_input_region(handle->wayland.framebuffer.surface, handle->wayland.region); } @@ -1249,6 +1249,11 @@ static void setup_toplevel(MwLL r, int x, int y) { return; } + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } + r->wayland.toplevel->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); /* Create a wl_surface, a xdg_surface and a xdg_toplevel */ @@ -1282,7 +1287,7 @@ static void setup_toplevel(MwLL r, int x, int y) { } /* setup decorations if we can */ - if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + if(r->wayland.has_decorations) { 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( @@ -1290,15 +1295,12 @@ static void setup_toplevel(MwLL r, int x, int y) { zxdg_toplevel_decoration_v1_set_mode( dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); - - r->wayland.has_decorations = MwTRUE; } else { /* otherwise set up viewporter */ struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); - r->wayland.has_decorations = MwFALSE; wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); } @@ -1510,14 +1512,14 @@ static void clip(MwLL handle) { cairo_rectangle(handle->wayland.front_cairo, 0, 0, (parent->wayland.ww + handle->wayland.x), (parent->wayland.wh + handle->wayland.y)); cairo_clip(handle->wayland.front_cairo); } - if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - cairo_reset_clip(handle->wayland.front_cairo); - while(topmost->wayland.parent) topmost = topmost->wayland.parent; - left_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - top_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); - cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - left_offset, (topmost->wayland.wh + handle->wayland.y) - top_offset); - cairo_clip(handle->wayland.front_cairo); - } + // if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + // cairo_reset_clip(handle->wayland.front_cairo); + // while(topmost->wayland.parent) topmost = topmost->wayland.parent; + // left_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + // top_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + // cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - left_offset, (topmost->wayland.wh + handle->wayland.y) - top_offset); + // cairo_clip(handle->wayland.front_cairo); + // } } static void wl_logger(const char* fmt, va_list args) { @@ -1872,6 +1874,12 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; + if(!handle->wayland.did_initial_resize) { + MwLLDispatch(handle, resize, NULL); + handle->wayland.did_initial_resize = 1; + return 1; + } + if(!handle->wayland.always_render) wl_display_prepare_read(handle->wayland.display); if(!poll(&fd, 1, timeout.tv_nsec)) { wl_display_cancel_read(handle->wayland.display); From 682d84879bea449d76c113831a12ce6b403e1196 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 14:54:36 -0700 Subject: [PATCH 217/409] wayland: cap x/y for viewporter to 0,0 --- src/backend/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1588cdf7b..ec82081cf 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1299,7 +1299,7 @@ static void setup_toplevel(MwLL r, int x, int y) { /* otherwise set up viewporter */ struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); - wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + wp_viewport_set_source(r->wayland.vp, (r->wayland.x >= 0) ? r->wayland.x : 0, (r->wayland.y >= 0) ? r->wayland.y : 0, r->wayland.ww, r->wayland.wh); wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); From 8ccf819b572b2591259e83a68c89e650711d6c8c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 14:56:27 -0700 Subject: [PATCH 218/409] wayland: positive width/height --- src/backend/wayland.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index ec82081cf..f1ad80db3 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1001,7 +1001,11 @@ static void xdg_toplevel_configure(void* data, region_setup(self); if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && !self->wayland.has_decorations) { - wp_viewport_set_destination(self->wayland.vp, self->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), self->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + MwU32 vwidth = self->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + MwU32 vheight = self->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + if(vwidth < 0) vwidth = 0; + if(vheight < 0) vheight = 0; + wp_viewport_set_destination(self->wayland.vp, vwidth, vheight); } MwLLDispatch(self, resize, NULL); @@ -1299,8 +1303,12 @@ static void setup_toplevel(MwLL r, int x, int y) { /* otherwise set up viewporter */ struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); - wp_viewport_set_source(r->wayland.vp, (r->wayland.x >= 0) ? r->wayland.x : 0, (r->wayland.y >= 0) ? r->wayland.y : 0, r->wayland.ww, r->wayland.wh); - wp_viewport_set_destination(r->wayland.vp, r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT), r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)); + MwU32 vwidth = r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + MwU32 vheight = r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + if(vwidth < 0) vwidth = 0; + if(vheight < 0) vheight = 0; + wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + wp_viewport_set_destination(r->wayland.vp, vwidth, vheight); wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); } From 24ae1c4e11f610d95215939b5d8cd7e77c78be5a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 15:32:28 -0700 Subject: [PATCH 219/409] wayland: have backbuffer be larger then framebuffer instead of other way around --- src/backend/wayland.c | 63 +++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f1ad80db3..05b7b927b 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1001,8 +1001,8 @@ static void xdg_toplevel_configure(void* data, region_setup(self); if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && !self->wayland.has_decorations) { - MwU32 vwidth = self->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - MwU32 vheight = self->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + MwU32 vwidth = self->wayland.ww; + MwU32 vheight = self->wayland.wh; if(vwidth < 0) vwidth = 0; if(vheight < 0) vheight = 0; wp_viewport_set_destination(self->wayland.vp, vwidth, vheight); @@ -1123,9 +1123,15 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { if(wayland->type != MWLL_WAYLAND_TOPLEVEL) { return; } - buffer_setup(&wayland->backbuffer, wayland->ww, wayland->wh); + MwU32 w = wayland->ww; + MwU32 h = wayland->wh; + if(!wayland->has_decorations) { + w += (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); + h += (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + } + buffer_setup(&wayland->backbuffer, w, h); - wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, w, h, 4 * w); wayland->back_cairo = cairo_create(wayland->back_cs); memset(wayland->backbuffer.buf, 0, wayland->backbuffer.buf_size); @@ -1301,13 +1307,17 @@ static void setup_toplevel(MwLL r, int x, int y) { dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { /* otherwise set up viewporter */ - struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; - r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); - MwU32 vwidth = r->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - MwU32 vheight = r->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); + struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; + MwI32 x = r->wayland.x; + MwI32 y = r->wayland.y; + MwU32 vwidth = r->wayland.ww; + MwU32 vheight = r->wayland.wh; + r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); + if(x < 0) x = 0; + if(y < 0) y = 0; if(vwidth < 0) vwidth = 0; if(vheight < 0) vheight = 0; - wp_viewport_set_source(r->wayland.vp, r->wayland.x, r->wayland.y, r->wayland.ww, r->wayland.wh); + wp_viewport_set_source(r->wayland.vp, wl_fixed_from_int(x), wl_fixed_from_int(y), wl_fixed_from_int(r->wayland.ww), wl_fixed_from_int(r->wayland.wh)); wp_viewport_set_destination(r->wayland.vp, vwidth, vheight); wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); @@ -1678,14 +1688,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.wh = 10; goto refresh; } - if(handle->wayland.parent) { - if(handle->wayland.parent->wayland.type == MWLL_WAYLAND_TOPLEVEL && !handle->wayland.parent->wayland.has_decorations) { - if(w >= handle->wayland.parent->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT)) - w = handle->wayland.parent->wayland.ww - (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - if(h >= handle->wayland.parent->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)) - h = handle->wayland.parent->wayland.wh - (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); - } - } + handle->wayland.ww = w; handle->wayland.wh = h; @@ -1719,34 +1722,36 @@ static void MwLLBeginDrawImpl(MwLL handle) { return; } if(!handle->wayland.has_decorations) { - int x, y; + int x, y; + MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; cairo_set_line_width(handle->wayland.back_cairo, 4.0); - for(x = 0; x < handle->wayland.ww; x++) { - float placeholder = (float)x / (float)handle->wayland.ww; + for(x = 0; x < w; x++) { + float placeholder = (float)x / (float)w; cairo_set_source_rgb(handle->wayland.back_cairo, placeholder, 0.25, 0.25); - cairo_move_to(handle->wayland.back_cairo, handle->wayland.ww - x, 0); - cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww - x, CSD_BORDER_FRAME_TOP); + cairo_move_to(handle->wayland.back_cairo, w - x, 0); + cairo_line_to(handle->wayland.back_cairo, w - x, CSD_BORDER_FRAME_TOP); cairo_stroke(handle->wayland.back_cairo); cairo_move_to(handle->wayland.back_cairo, x, CSD_BORDER_FRAME_TOP); - cairo_line_to(handle->wayland.back_cairo, x, handle->wayland.wh); + cairo_line_to(handle->wayland.back_cairo, x, h); cairo_stroke(handle->wayland.back_cairo); } cairo_set_source_rgba(handle->wayland.back_cairo, 1, 1, 1, 0.5); cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, 0, handle->wayland.wh); + cairo_line_to(handle->wayland.back_cairo, 0, h); cairo_stroke(handle->wayland.back_cairo); cairo_move_to(handle->wayland.back_cairo, 0, 0); - cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, 0); + cairo_line_to(handle->wayland.back_cairo, w, 0); cairo_stroke(handle->wayland.back_cairo); cairo_set_source_rgba(handle->wayland.back_cairo, 0, 0, 0, 0.5); - cairo_move_to(handle->wayland.back_cairo, 0, handle->wayland.wh); - cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, handle->wayland.wh); + cairo_move_to(handle->wayland.back_cairo, 0, h); + cairo_line_to(handle->wayland.back_cairo, w, h); cairo_stroke(handle->wayland.back_cairo); - cairo_move_to(handle->wayland.back_cairo, handle->wayland.ww, 0); - cairo_line_to(handle->wayland.back_cairo, handle->wayland.ww, handle->wayland.wh); + cairo_move_to(handle->wayland.back_cairo, w, 0); + cairo_line_to(handle->wayland.back_cairo, w, h); cairo_stroke(handle->wayland.back_cairo); if(strlen(handle->wayland.title) != 0) { From d4913576358f14d6431e603a78d27377d2940212 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 15:45:48 -0700 Subject: [PATCH 220/409] wayland: csd fixes --- src/backend/wayland.c | 45 ++++++++++++++----------------------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 05b7b927b..9a2ca75a7 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -203,7 +203,7 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { if(ctx->ll->wayland.supports_zwp) { zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); - } else { + } else if(ctx->offer.wl) { wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); } close(fds[1]); @@ -395,19 +395,19 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 seria static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == self->wayland.curSurface) { - if(p.point.y >= self->wayland.wh - 5) { - if(p.point.x >= self->wayland.ww - 5) { + if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); } else { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM); } } else if(p.point.y <= 5) { - if(p.point.x >= self->wayland.ww - 5) { + if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT); } else { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_TOP); } - } else if(p.point.x >= self->wayland.ww - 5) { + } else if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_RIGHT); } else if(p.point.x <= 5) { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_LEFT); @@ -1000,14 +1000,6 @@ static void xdg_toplevel_configure(void* data, framebuffer_setup(&self->wayland); region_setup(self); - if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && !self->wayland.has_decorations) { - MwU32 vwidth = self->wayland.ww; - MwU32 vheight = self->wayland.wh; - if(vwidth < 0) vwidth = 0; - if(vheight < 0) vheight = 0; - wp_viewport_set_destination(self->wayland.vp, vwidth, vheight); - } - MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); }; @@ -1171,9 +1163,15 @@ static void region_setup(MwLL handle) { if(height - handle->wayland.y > parent->wayland.wh) { height = parent->wayland.wh - handle->wayland.y; } + } else { + if(!handle->wayland.has_decorations) { + width += CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; + height += CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; + } } wl_region_add(handle->wayland.region, 0, 0, width, height); } + if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { wl_surface_set_opaque_region(handle->wayland.backbuffer.surface, handle->wayland.o_region); wl_surface_set_input_region(handle->wayland.backbuffer.surface, handle->wayland.region); @@ -1306,20 +1304,6 @@ static void setup_toplevel(MwLL r, int x, int y) { zxdg_toplevel_decoration_v1_set_mode( dec->decoration, ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { - /* otherwise set up viewporter */ - struct wp_viewporter* wp = WAYLAND_GET_INTERFACE(r->wayland, wp_viewporter)->context; - MwI32 x = r->wayland.x; - MwI32 y = r->wayland.y; - MwU32 vwidth = r->wayland.ww; - MwU32 vheight = r->wayland.wh; - r->wayland.vp = wp_viewporter_get_viewport(wp, r->wayland.framebuffer.surface); - if(x < 0) x = 0; - if(y < 0) y = 0; - if(vwidth < 0) vwidth = 0; - if(vheight < 0) vheight = 0; - wp_viewport_set_source(r->wayland.vp, wl_fixed_from_int(x), wl_fixed_from_int(y), wl_fixed_from_int(r->wayland.ww), wl_fixed_from_int(r->wayland.wh)); - wp_viewport_set_destination(r->wayland.vp, vwidth, vheight); - wl_subsurface_set_position(r->wayland.toplevel->ssurface, CSD_BORDER_FRAME_LEFT, CSD_BORDER_FRAME_TOP); } } @@ -1692,10 +1676,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { handle->wayland.ww = w; handle->wayland.wh = h; - // if(handle->wayland.wh >= (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM)) { - // handle->wayland.wh -= (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); - // } - if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL && handle->wayland.configured) { xdg_surface_set_window_geometry(handle->wayland.toplevel->xdg_surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } @@ -1714,6 +1694,8 @@ refresh: backbuffer_destroy(&handle->wayland); backbuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); + + handle->wayland.events_pending = 1; } static void MwLLBeginDrawImpl(MwLL handle) { @@ -1721,6 +1703,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { handle->wayland.selected_cairo = handle->wayland.front_cairo; return; } + if(!handle->wayland.has_decorations) { int x, y; MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; From b9933b70e254eacc0de932112950b50293f35a3d Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 23 Mar 2026 15:56:01 -0700 Subject: [PATCH 221/409] wayland: on resize, fire draw before resize --- src/backend/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 9a2ca75a7..dbb2bd28d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1000,8 +1000,8 @@ static void xdg_toplevel_configure(void* data, framebuffer_setup(&self->wayland); region_setup(self); - MwLLDispatch(self, resize, NULL); MwLLDispatch(self, draw, NULL); + MwLLDispatch(self, resize, NULL); }; /* Empty function for satisfying zxdg_toplevel's requirements */ From 5e823b5a25782b0dfe151e77e2e4cee373e10e48 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 23 Mar 2026 19:30:21 -0700 Subject: [PATCH 222/409] wayland: gl improvements --- src/backend/wayland.c | 4 ++-- src/widget/opengl.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index dbb2bd28d..dab1a1b0a 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -441,13 +441,13 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL topmost = self->wayland.parent; while(topmost->wayland.parent) topmost = topmost->wayland.parent; /* also we only wanna do it every 50ms */ - if((self->wayland.last_time + 50) <= time && !topmost->wayland.events_pending) { + if((self->wayland.last_time + 50) <= time && !topmost->wayland.events_pending && !topmost->wayland.always_render) { MwLLDispatch(self, draw, NULL); self->wayland.last_time = time; } } else { /* if there's no parent just impose the requirement on the widget itself */ - if((self->wayland.last_time + 50) <= time && !self->wayland.events_pending) { + if((self->wayland.last_time + 50) <= time && !self->wayland.events_pending && !self->wayland.always_render) { MwLLDispatch(self, draw, NULL); self->wayland.last_time = time; } diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 6d67344ce..7d685ada6 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -168,11 +168,10 @@ static int create(MwWidget handle) { waylandopengl_t* o = r = malloc(sizeof(*o)); MwLL topmost_parent = handle->lowlevel->wayland.parent; handle->lowlevel->wayland.always_render = MwTRUE; - topmost_parent->wayland.always_render = MwTRUE; while(topmost_parent->wayland.parent != NULL) { - topmost_parent = topmost_parent->wayland.parent; topmost_parent->wayland.always_render = MwTRUE; + topmost_parent = topmost_parent->wayland.parent; } display = From 57609f182388abc17f8d218c1e020ecbf90336c7 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 13:31:49 -0700 Subject: [PATCH 223/409] fire a draw/resize event manually to children when resizing --- examples/basic/rotate.c | 1 - src/backend/wayland.c | 72 +++++++++++++++++++++++++++++++++++------ 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/examples/basic/rotate.c b/examples/basic/rotate.c index 68c9133bf..574eb2d6f 100644 --- a/examples/basic/rotate.c +++ b/examples/basic/rotate.c @@ -49,7 +49,6 @@ void resize(MwWidget w, void* user, void* client) { (void)user; (void)client; - printf("H\n"); ww = MwGetInteger(w, MwNwidth); wh = MwGetInteger(w, MwNheight); } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index dab1a1b0a..b2bbe8f94 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -98,6 +98,51 @@ static void wl_flush(MwLL handle) { } } +/* Recursively dispatch a draw event to a widget and its children */ +static void recursive_dispatch_draw_n_resize(MwLL handle) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, draw, NULL); + MwLLDispatch(handle, resize, NULL); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwDispatch(h->children[i], draw); + MwDispatch(h->children[i], resize); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_draw_n_resize(h->children[i]->lowlevel); + } + } + } +}; + +/* Recursively dispatch a key event to a widget and its children */ +static void recursive_dispatch_key(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key(h->children[i]->lowlevel, k); + } + } + } +}; +/* Recursively dispatch a key released event to a widget and its children */ +static void recursive_dispatch_key_released(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key_released, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key_released, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key_released(h->children[i]->lowlevel, k); + } + } + } +}; static void wl_offer(void* data, struct wl_data_offer* wl_data_offer, const char* mime_type) { @@ -424,6 +469,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time wl_fixed_t surface_x, wl_fixed_t surface_y) { MwLL self = data; MwLLMouse p; + int i = 0; + MwWidget h = (MwWidget)self->common.user; WAYLAND_EVENT_OP_START(self); @@ -680,9 +727,9 @@ static void keyboard_key(void* data, } if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { - MwLLDispatch(self, key, &key); + recursive_dispatch_key(self, &key); } else { - MwLLDispatch(self, key_released, &key); + recursive_dispatch_key_released(self, &key); } } } @@ -970,8 +1017,9 @@ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, struct wl_array* states) { - MwLL self = data; - int i; + MwLL self = data; + int i; + MwWidget h = ((MwWidget)self->common.user); /* Yes, somehow this can get called before */ if(!self->wayland.configured) { @@ -1000,8 +1048,7 @@ static void xdg_toplevel_configure(void* data, framebuffer_setup(&self->wayland); region_setup(self); - MwLLDispatch(self, draw, NULL); - MwLLDispatch(self, resize, NULL); + recursive_dispatch_draw_n_resize(self); }; /* Empty function for satisfying zxdg_toplevel's requirements */ @@ -1652,6 +1699,9 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { + int i = 0; + MwWidget h = (MwWidget)handle->common.user; + region_invalidate(handle); handle->wayland.x = x; handle->wayland.y = y; @@ -1664,6 +1714,8 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { + int i = 0; + MwWidget widget = (MwWidget)handle->common.user; region_invalidate(handle); /* Prevent an integer underflow when the w/h is too low */ @@ -1694,7 +1746,6 @@ refresh: backbuffer_destroy(&handle->wayland); backbuffer_setup(&handle->wayland); MwLLDispatch(handle, draw, NULL); - handle->wayland.events_pending = 1; } @@ -1871,7 +1922,7 @@ static int MwLLPendingImpl(MwLL handle) { int pending = 0; if(!handle->wayland.did_initial_resize) { - MwLLDispatch(handle, resize, NULL); + recursive_dispatch_draw_n_resize(handle); handle->wayland.did_initial_resize = 1; return 1; } @@ -1901,6 +1952,7 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { + int i = 0; if(!handle->wayland.always_render) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; @@ -1910,7 +1962,9 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.force_render) { - if(!handle->wayland.events_pending) MwLLDispatch(handle, draw, NULL); + if(!handle->wayland.events_pending) { + MwLLDispatch(handle, draw, NULL); + } if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } From 1ad75eca90e76ba44c73fd691f84e00d031f1859 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 14:41:20 -0700 Subject: [PATCH 224/409] only draw on the parent and resize on the child in draw_n_resize --- src/backend/wayland.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index b2bbe8f94..8d39d6b97 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -102,11 +102,9 @@ static void wl_flush(MwLL handle) { static void recursive_dispatch_draw_n_resize(MwLL handle) { MwWidget h = (MwWidget)handle->common.user; MwLLDispatch(handle, draw, NULL); - MwLLDispatch(handle, resize, NULL); if(h) { int i; for(i = 0; i < arrlen(h->children); i++) { - MwDispatch(h->children[i], draw); MwDispatch(h->children[i], resize); if(arrlen(h->children[i]->children) > 0) { recursive_dispatch_draw_n_resize(h->children[i]->lowlevel); @@ -483,23 +481,6 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLLDispatch(currentlyHeldWidget, down, &p); } - /* We want to send a draw call whenever we move the cursor, BUT only if the topmost parent doesn't already have events pedngin. */ - if(self->wayland.parent) { - MwLL topmost = self->wayland.parent; - while(topmost->wayland.parent) topmost = topmost->wayland.parent; - /* also we only wanna do it every 50ms */ - if((self->wayland.last_time + 50) <= time && !topmost->wayland.events_pending && !topmost->wayland.always_render) { - MwLLDispatch(self, draw, NULL); - self->wayland.last_time = time; - } - } else { - /* if there's no parent just impose the requirement on the widget itself */ - if((self->wayland.last_time + 50) <= time && !self->wayland.events_pending && !self->wayland.always_render) { - MwLLDispatch(self, draw, NULL); - self->wayland.last_time = time; - } - } - WAYLAND_EVENT_OP_END(self); }; From 9a23045c30b40e21ea621fce93612ec43d2ffdb2 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 14:43:38 -0700 Subject: [PATCH 225/409] change draw_n_resize to just resize --- src/backend/wayland.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8d39d6b97..37a1f29e1 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -99,15 +99,14 @@ static void wl_flush(MwLL handle) { } /* Recursively dispatch a draw event to a widget and its children */ -static void recursive_dispatch_draw_n_resize(MwLL handle) { +static void recursive_dispatch_resize(MwLL handle) { MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, draw, NULL); if(h) { int i; for(i = 0; i < arrlen(h->children); i++) { MwDispatch(h->children[i], resize); if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_draw_n_resize(h->children[i]->lowlevel); + recursive_dispatch_resize(h->children[i]->lowlevel); } } } @@ -1028,8 +1027,10 @@ static void xdg_toplevel_configure(void* data, framebuffer_destroy(&self->wayland); framebuffer_setup(&self->wayland); region_setup(self); + MwLLDispatch(self, resize, NULL); - recursive_dispatch_draw_n_resize(self); + MwLLDispatch(self, draw, NULL); + recursive_dispatch_resize(self); }; /* Empty function for satisfying zxdg_toplevel's requirements */ @@ -1903,7 +1904,7 @@ static int MwLLPendingImpl(MwLL handle) { int pending = 0; if(!handle->wayland.did_initial_resize) { - recursive_dispatch_draw_n_resize(handle); + recursive_dispatch_resize(handle); handle->wayland.did_initial_resize = 1; return 1; } From e86d6acdf37037c5f9445f884c0c5c9286d2713e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 14:52:53 -0700 Subject: [PATCH 226/409] we can just draw even if events are pending --- src/backend/wayland.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 37a1f29e1..2b581c693 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -535,10 +535,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri } } - if(!self->wayland.always_render) { - MwLLDispatch(self, draw, NULL); - } - if(!self->wayland.has_decorations) { xdg_borderless_step(self, p, serial); } @@ -1894,7 +1890,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { static int MwLLPendingImpl(MwLL handle) { struct timespec timeout = { - .tv_nsec = 100, + .tv_nsec = 1, .tv_sec = 0, }; struct pollfd fd = { @@ -1906,7 +1902,6 @@ static int MwLLPendingImpl(MwLL handle) { if(!handle->wayland.did_initial_resize) { recursive_dispatch_resize(handle); handle->wayland.did_initial_resize = 1; - return 1; } if(!handle->wayland.always_render) wl_display_prepare_read(handle->wayland.display); @@ -1925,9 +1920,9 @@ static int MwLLPendingImpl(MwLL handle) { return pending; } - wl_surface_commit(handle->wayland.framebuffer.surface); + update_buffer(&handle->wayland.framebuffer); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - wl_surface_commit(handle->wayland.backbuffer.surface); + update_buffer(&handle->wayland.backbuffer); } return handle->wayland.force_render || handle->wayland.events_pending || pending; @@ -1944,9 +1939,9 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.force_render) { - if(!handle->wayland.events_pending) { - MwLLDispatch(handle, draw, NULL); - } + // if(!handle->wayland.events_pending) { + MwLLDispatch(handle, draw, NULL); + // } if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); handle->wayland.force_render = 0; } From 47746ff30e6fa5ef41cd6dbe1bb7caa0731b048d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 17:38:21 -0700 Subject: [PATCH 227/409] dynamically load wayland and its dependencies, fix warnings --- include/Mw/LowLevel/Wayland.h | 275 ++++++++++++++++++++++++++++++++-- pl/rules.pl | 5 +- pl/utils.pl | 29 ++++ src/backend/wayland.c | 192 +++++++++++++++++------- src/widget/opengl.c | 95 +++++++++++- 5 files changed, 522 insertions(+), 74 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 2a16f50ff..a6f225437 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -7,22 +7,279 @@ #ifndef __MW_LOWLEVEL_WAYLAND_H__ #define __MW_LOWLEVEL_WAYLAND_H__ -#include "Mw/BaseTypes.h" #include #include #include +#include -#include - -#include #include #include #include MWDECL int MwLLWaylandCallInit(void); +#define CSD_BORDER_FRAME_LEFT 5 +#define CSD_BORDER_FRAME_RIGHT 5 +#define CSD_BORDER_FRAME_TOP 24 +#define CSD_BORDER_FRAME_BOTTOM 5 + +struct _MwLLWayland; + +#include + +#if WAYLAND_LOAD_OPENGL +#include +#include +#endif + +typedef struct wayland_call_table { + void* lib; + void* xkb_lib; + void* cairo_lib; +#if WAYLAND_LOAD_OPENGL +#endif + + int (*wl_display_dispatch_pending)(struct wl_display* display); + void (*wl_display_disconnect)(struct wl_display* display); + void (*wl_display_cancel_read)(struct wl_display* display); + int (*wl_display_prepare_read)(struct wl_display* display); + int (*wl_display_read_events)(struct wl_display* display); + int (*wl_display_flush)(struct wl_display* display); + int (*wl_display_get_fd)(struct wl_display* display); + int (*wl_display_roundtrip)(struct wl_display* display); + int (*wl_proxy_add_listener)(struct wl_proxy* proxy, void (**implementation)(void), void* data); + void (*wl_proxy_destroy)(struct wl_proxy* proxy); + void (*wl_log_set_handler_client)(wl_log_func_t handler); + struct wl_proxy* (*wl_proxy_marshal_flags)(struct wl_proxy* proxy, uint32_t opcode, + const struct wl_interface* interface, + uint32_t version, + uint32_t flags, ...); + struct wl_display* (*wl_display_connect)(const char* name); + uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); + + struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); + void (*xkb_context_unref)(struct xkb_context* context); + struct xkb_state* (*xkb_state_new)(struct xkb_keymap* keymap); + void (*xkb_state_unref)(struct xkb_state* state); + struct xkb_keymap* (*xkb_keymap_new_from_string)(struct xkb_context* context, const char* string, enum xkb_keymap_format format, enum xkb_keymap_compile_flags flags); + xkb_level_index_t (*xkb_keymap_num_levels_for_key)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout); + int (*xkb_keymap_key_get_syms_by_level)(struct xkb_keymap* keymap, xkb_keycode_t key, xkb_layout_index_t layout, xkb_level_index_t level, const xkb_keysym_t** syms_out); + xkb_layout_index_t (*xkb_state_key_get_layout)(struct xkb_state* state, xkb_keycode_t key); + void (*xkb_keymap_unref)(struct xkb_keymap* keymap); + + void (*cairo_set_line_width)(cairo_t* cr, + double width); + void (*cairo_scale)(cairo_t* cr, + double sx, + double sy); + cairo_t* (*cairo_create)(cairo_surface_t* target); + void (*cairo_move_to)(cairo_t* cr, + double x, + double y); + + void (*cairo_rectangle)(cairo_t* cr, + double x, + double y, + double width, + double height); + void (*cairo_new_path)(cairo_t* cr); + void (*cairo_set_line_cap)(cairo_t* cr, + cairo_line_cap_t line_cap); + void (*cairo_set_source_rgba)(cairo_t* cr, + double red, + double green, + double blue, + double alpha); + void (*cairo_set_source_rgb)(cairo_t* cr, + double red, + double green, + double blue); + void (*cairo_reset_clip)(cairo_t* cr); + unsigned char* (*cairo_image_surface_get_data)(cairo_surface_t* surface); + void (*cairo_line_to)(cairo_t* cr, + double x, + double y); + void (*cairo_surface_destroy)(cairo_surface_t* surface); + cairo_surface_t* (*cairo_image_surface_create_for_data)(unsigned char* data, + cairo_format_t format, + int width, + int height, + int stride); + cairo_surface_t* (*cairo_image_surface_create)(cairo_format_t format, + int width, + int height); + void (*cairo_destroy)(cairo_t* cr); + cairo_pattern_t* (*cairo_get_source)(cairo_t* cr); + void (*cairo_close_path)(cairo_t* cr); + void (*cairo_paint)(cairo_t* cr); + void (*cairo_surface_flush)(cairo_surface_t* surface); + void (*cairo_clip)(cairo_t* cr); + void (*cairo_surface_mark_dirty)(cairo_surface_t* surface); + void (*cairo_stroke)(cairo_t* cr); + void (*cairo_set_source_surface)(cairo_t* cr, + cairo_surface_t* surface, + double x, + double y); + void (*cairo_fill)(cairo_t* cr); + void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, + cairo_filter_t filter); + +} wayland_call_table_t; + +extern wayland_call_table_t wl_call_tbl; + +/* defined inline right here so that it doesn't conflict with the other macros */ +MwInline int wayland_load_funcs() { + wl_call_tbl.lib = MwDynamicOpen("libwayland-client.so"); + if(!wl_call_tbl.lib) { + printf("(libwayland-client.so not found, falling back to X11)\n"); + return 1; + } + wl_call_tbl.xkb_lib = MwDynamicOpen("libxkbcommon.so"); + if(!wl_call_tbl.xkb_lib) { + printf("(libxkbcommon.so not found, cannot use Wayland backend.)\n"); + return 1; + } + wl_call_tbl.cairo_lib = MwDynamicOpen("libcairo.so"); + if(!wl_call_tbl.cairo_lib) { + printf("(libcairo.so not found, cannot use Wayland backend.)\n"); + return 1; + } +#define WAYLAND_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Could use Wayland backend if " #x " was found.\n"); \ + return 1; \ + }; + + WAYLAND_FUNC(wl_display_dispatch_pending) + WAYLAND_FUNC(wl_display_disconnect) + WAYLAND_FUNC(wl_display_cancel_read) + WAYLAND_FUNC(wl_display_prepare_read) + WAYLAND_FUNC(wl_display_read_events) + WAYLAND_FUNC(wl_display_flush) + WAYLAND_FUNC(wl_display_get_fd) + WAYLAND_FUNC(wl_display_roundtrip) + WAYLAND_FUNC(wl_proxy_add_listener) + WAYLAND_FUNC(wl_proxy_destroy) + WAYLAND_FUNC(wl_log_set_handler_client) + WAYLAND_FUNC(wl_proxy_marshal_flags) + WAYLAND_FUNC(wl_display_connect) + WAYLAND_FUNC(wl_proxy_get_version) + +#undef WAYLAND_FUNC + +#define XKB_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.xkb_lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libxkbcommon?\n"); \ + return 1; \ + }; + + XKB_FUNC(xkb_state_unref) + XKB_FUNC(xkb_context_new) + XKB_FUNC(xkb_context_unref) + XKB_FUNC(xkb_state_new) + XKB_FUNC(xkb_keymap_new_from_string) + XKB_FUNC(xkb_keymap_unref) + XKB_FUNC(xkb_keymap_num_levels_for_key) + XKB_FUNC(xkb_keymap_key_get_syms_by_level) + XKB_FUNC(xkb_state_key_get_layout) +#undef XKB_FUNC + +#define CAIRO_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.cairo_lib, #x); \ + if(!wl_call_tbl.x) { \ + printf("WARNING: Could use Wayland backend if " #x " was found. Do you have libcairo?\n"); \ + return 1; \ + }; + + CAIRO_FUNC(cairo_set_line_width); + CAIRO_FUNC(cairo_scale); + CAIRO_FUNC(cairo_create); + CAIRO_FUNC(cairo_move_to); + CAIRO_FUNC(cairo_rectangle); + CAIRO_FUNC(cairo_new_path); + CAIRO_FUNC(cairo_set_line_cap); + CAIRO_FUNC(cairo_set_source_rgba); + CAIRO_FUNC(cairo_set_source_rgb); + CAIRO_FUNC(cairo_reset_clip); + CAIRO_FUNC(cairo_image_surface_get_data); + CAIRO_FUNC(cairo_line_to); + CAIRO_FUNC(cairo_surface_destroy); + CAIRO_FUNC(cairo_image_surface_create_for_data); + CAIRO_FUNC(cairo_image_surface_create); + CAIRO_FUNC(cairo_destroy); + CAIRO_FUNC(cairo_get_source); + CAIRO_FUNC(cairo_close_path); + CAIRO_FUNC(cairo_paint); + CAIRO_FUNC(cairo_surface_flush); + CAIRO_FUNC(cairo_clip); + CAIRO_FUNC(cairo_surface_mark_dirty); + CAIRO_FUNC(cairo_stroke); + CAIRO_FUNC(cairo_set_source_surface); + CAIRO_FUNC(cairo_fill); + CAIRO_FUNC(cairo_pattern_set_filter); +#undef CAIRO_FUNC + + return 0; +} + +#define wl_display_dispatch_pending wl_call_tbl.wl_display_dispatch_pending +#define wl_display_disconnect wl_call_tbl.wl_display_disconnect +#define wl_display_cancel_read wl_call_tbl.wl_display_cancel_read +#define wl_display_prepare_read wl_call_tbl.wl_display_prepare_read +#define wl_display_read_events wl_call_tbl.wl_display_read_events +#define wl_display_flush wl_call_tbl.wl_display_flush +#define wl_display_get_fd wl_call_tbl.wl_display_get_fd +#define wl_display_roundtrip wl_call_tbl.wl_display_roundtrip +#define wl_proxy_add_listener wl_call_tbl.wl_proxy_add_listener +#define wl_proxy_destroy wl_call_tbl.wl_proxy_destroy +#define wl_log_set_handler_client wl_call_tbl.wl_log_set_handler_client +#define wl_proxy_marshal_flags wl_call_tbl.wl_proxy_marshal_flags +#define wl_display_connect wl_call_tbl.wl_display_connect +#define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version + +#define xkb_state_unref wl_call_tbl.xkb_state_unref +#define xkb_context_new wl_call_tbl.xkb_context_new +#define xkb_context_unref wl_call_tbl.xkb_context_unref +#define xkb_state_new wl_call_tbl.xkb_state_new +#define xkb_keymap_new_from_string wl_call_tbl.xkb_keymap_new_from_string +#define xkb_keymap_unref wl_call_tbl.xkb_keymap_unref +#define xkb_keymap_num_levels_for_key wl_call_tbl.xkb_keymap_num_levels_for_key +#define xkb_keymap_key_get_syms_by_level wl_call_tbl.xkb_keymap_key_get_syms_by_level +#define xkb_state_key_get_layout wl_call_tbl.xkb_state_key_get_layout + +#define cairo_set_line_width wl_call_tbl.cairo_set_line_width +#define cairo_scale wl_call_tbl.cairo_scale +#define cairo_create wl_call_tbl.cairo_create +#define cairo_move_to wl_call_tbl.cairo_move_to +#define cairo_rectangle wl_call_tbl.cairo_rectangle +#define cairo_new_path wl_call_tbl.cairo_new_path +#define cairo_set_line_cap wl_call_tbl.cairo_set_line_cap +#define cairo_set_source_rgba wl_call_tbl.cairo_set_source_rgba +#define cairo_set_source_rgb wl_call_tbl.cairo_set_source_rgb +#define cairo_reset_clip wl_call_tbl.cairo_reset_clip +#define cairo_image_surface_get_data wl_call_tbl.cairo_image_surface_get_data +#define cairo_line_to wl_call_tbl.cairo_line_to +#define cairo_surface_destroy wl_call_tbl.cairo_surface_destroy +#define cairo_image_surface_create_for_data wl_call_tbl.cairo_image_surface_create_for_data +#define cairo_image_surface_create wl_call_tbl.cairo_image_surface_create +#define cairo_destroy wl_call_tbl.cairo_destroy +#define cairo_get_source wl_call_tbl.cairo_get_source +#define cairo_close_path wl_call_tbl.cairo_close_path +#define cairo_paint wl_call_tbl.cairo_paint +#define cairo_surface_flush wl_call_tbl.cairo_surface_flush +#define cairo_clip wl_call_tbl.cairo_clip +#define cairo_surface_mark_dirty wl_call_tbl.cairo_surface_mark_dirty +#define cairo_stroke wl_call_tbl.cairo_stroke +#define cairo_set_source_surface wl_call_tbl.cairo_set_source_surface +#define cairo_fill wl_call_tbl.cairo_fill +#define cairo_pattern_set_filter wl_call_tbl.cairo_pattern_set_filter + #ifndef WL_PROTOCOLS_DEFINED #define WL_PROTOCOLS_DEFINED +#include "Wayland/wayland-core-protocol.h" #include "Wayland/xdg-shell-client-protocol.h" #include "Wayland/viewporter-client-protocol.h" #include "Wayland/xdg-decoration-client-protocol.h" @@ -31,16 +288,6 @@ MWDECL int MwLLWaylandCallInit(void); #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif -#define CSD_BORDER_FRAME_LEFT 5 -#define CSD_BORDER_FRAME_RIGHT 5 -#define CSD_BORDER_FRAME_TOP 24 -#define CSD_BORDER_FRAME_BOTTOM 5 - -#define CSD_LEFT_OFFSET(handle) handle->wayland.has_decorations ? 0 : CSD_BORDER_FRAME_LEFT -#define CSD_TOP_OFFSET(handle) handle->wayland.has_decorations ? 0 : CSD_BORDER_FRAME_TOP - -struct _MwLLWayland; - typedef struct wayland_protocol { void* listener; void* context; diff --git a/pl/rules.pl b/pl/rules.pl index a4ba7bfc8..81a1ecec7 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -29,13 +29,12 @@ if (grep(/^gdi$/, @backends)) { if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); - add_cflags(`pkg-config --cflags cairo wayland-client xkbcommon`); - add_libs(`pkg-config --libs cairo wayland-client xkbcommon`); if (param_get("opengl")) { - add_libs(`pkg-config --libs egl wayland-egl`); + add_cflags("-DWAYLAND_LOAD_OPENGL"); } + scan_wayland_protocol_core(); scan_wayland_protocol("stable", "xdg-shell", ""); scan_wayland_protocol("stable", "viewporter", ""); scan_wayland_protocol("stable", "tablet", "-v2"); diff --git a/pl/utils.pl b/pl/utils.pl index f2f722b05..77131a007 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -58,6 +58,35 @@ sub use_backend { } } + +sub scan_wayland_protocol_core { + my $proto_c = "src/backend/wayland-core-protocol.c"; + + if ( + system( +"wayland-scanner private-code /usr/share/wayland/wayland.xml ${proto_c}" + ) != 0 + ) + { + print( +"^ Error on getting private code for /usr/share/wayland/wayland.xml\n" + ); + } + else { + new_object($proto_c); + } + if ( + system( +"wayland-scanner client-header /usr/share/wayland/wayland.xml include/Mw/LowLevel/Wayland/wayland-core-protocol.h" + ) + ) + { + print( +"^ Error on getting client header for /usr/share/wayland/wayland.xml\n" + ); + } +} + sub scan_wayland_protocol { my $tier = $_[0]; my $proto = $_[1]; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 2b581c693..34c87cf22 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -19,6 +19,8 @@ #include #endif +wayland_call_table_t wl_call_tbl; + /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ do { \ @@ -57,6 +59,8 @@ static void new_protocol(void* data, struct wl_registry* registry, MwU32 name, const char* interface, MwU32 version) { MwLL self = data; + (void)version; + (void)registry; WAYLAND_EVENT_OP_START(self); @@ -76,6 +80,9 @@ static void new_protocol(void* data, struct wl_registry* registry, static void protocol_removed(void* data, struct wl_registry* registry, MwU32 name) { + (void)data; + (void)registry; + (void)name; printf("%d destroyed\n", name); }; @@ -155,6 +162,7 @@ static void wl_data_device_data_offer(void* data, struct wl_data_device* wl_data_device, struct wl_data_offer* offer) { wl_clipboard_device_context_t* self = data; + (void)wl_data_device; wl_data_offer_add_listener(offer, &offer_listener, data); @@ -169,6 +177,11 @@ static void wl_data_device_enter(void* data, wl_fixed_t y, struct wl_data_offer* id) { MwLL self = data; + (void)wl_data_device; + (void)surface; + (void)x; + (void)y; + (void)id; WAYLAND_EVENT_OP_START(self); @@ -189,14 +202,24 @@ static void wl_data_device_motion(void* data, uint32_t time, wl_fixed_t x, wl_fixed_t y) { + (void)data; + (void)wl_data_device; + (void)time; + (void)x; + (void)y; }; static void wl_data_device_drop(void* data, struct wl_data_device* wl_data_device) { + (void)data; + (void)wl_data_device; }; static void wl_data_device_selection(void* data, struct wl_data_device* wl_data_device, struct wl_data_offer* id) { + (void)data; + (void)wl_data_device; + (void)id; }; struct wl_data_device_listener wl_data_device_listener = { @@ -212,6 +235,7 @@ static void zwp_primary_selection_device_v1_data_offer(void* data, struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1* offer) { wl_clipboard_device_context_t* self = data; + (void)zwp_primary_selection_device_v1; self->offer.zwp = offer; }; @@ -219,6 +243,9 @@ static void zwp_primary_selection_device_v1_data_offer(void* data, static void zwp_primary_selection_device_v1_selection(void* data, struct zwp_primary_selection_device_v1* zwp_primary_selection_device_v1, struct zwp_primary_selection_offer_v1* id) { + (void)data; + (void)zwp_primary_selection_device_v1; + (void)id; }; struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_listener = { @@ -232,7 +259,6 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { char* buf = NULL; struct timeval timeout; int rc = 0; - int n; if(pipe(fds) != 0) { return; @@ -254,7 +280,6 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { wl_display_roundtrip(ctx->ll->wayland.display); while(MwTRUE) { - char ch; rc = select(fds[0] + 1, &set, NULL, NULL, &timeout); if(rc <= 0) { break; @@ -279,12 +304,17 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { static void wl_data_source_listener_target(void* data, struct wl_data_source* wl_data_source, const char* mime_type) { + (void)data; + (void)wl_data_source; + (void)mime_type; }; static void wl_data_source_listener_send(void* data, struct wl_data_source* wl_data_source, const char* mime_type, int32_t fd) { MwLL self = data; + (void)wl_data_source; + (void)mime_type; WAYLAND_EVENT_OP_START(self); if(self->wayland.clipboard_buffer != NULL) { @@ -328,6 +358,8 @@ static void zwp_primary_selection_source_v1_send(void* data, const char* mime_type, int32_t fd) { MwLL self = data; + (void)wl_data_source; + (void)mime_type; WAYLAND_EVENT_OP_START(self); @@ -341,6 +373,7 @@ static void zwp_primary_selection_source_v1_send(void* data, static void zwp_primary_selection_source_v1_cancelled(void* data, struct zwp_primary_selection_source_v1* wl_data_source) { MwLL self = data; + (void)wl_data_source; WAYLAND_EVENT_OP_START(self); @@ -380,6 +413,7 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL } static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; if(wayland->clipboard_manager.wl != NULL && !wayland->supports_zwp) { wl_data_device_manager_destroy(wayland->clipboard_manager.wl); wl_data_source_destroy(wayland->clipboard_source.wl); @@ -411,7 +445,8 @@ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 n } static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // zwp_primary_selection_device_manager_v1_destroy(wayland->clipboard_manager.zwp); + (void)wayland; + (void)data; } /* `wl_pointer.enter` callback */ @@ -419,6 +454,8 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 seria struct wl_surface* surface, wl_fixed_t surface_x, wl_fixed_t surface_y) { MwLL self = data; + (void)surface_x; + (void)surface_y; WAYLAND_EVENT_OP_START(self); self->wayland.curSurface = surface; @@ -433,6 +470,10 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 seria /* `wl_pointer.leave` callback */ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface) { + (void)data; + (void)wl_pointer; + (void)serial; + (void)surface; }; static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { @@ -466,8 +507,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time wl_fixed_t surface_x, wl_fixed_t surface_y) { MwLL self = data; MwLLMouse p; - int i = 0; - MwWidget h = (MwWidget)self->common.user; + (void)time; + (void)wl_pointer; WAYLAND_EVENT_OP_START(self); @@ -488,8 +529,9 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri MwLL self = data; MwLLMouse p; - int x = self->wayland.x; - int y = self->wayland.y; + (void)wl_pointer; + (void)serial; + (void)time; WAYLAND_EVENT_OP_START(self); @@ -544,7 +586,13 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri /* `wl_pointer.axis` callback */ static void pointer_axis(void* data, struct wl_pointer* wl_pointer, MwU32 time, - MwU32 axis, wl_fixed_t value) {}; + MwU32 axis, wl_fixed_t value) { + (void)data; + (void)wl_pointer; + (void)time; + (void)axis; + (void)value; +}; struct wl_pointer_listener pointer_listener = { .enter = pointer_enter, @@ -561,6 +609,7 @@ static void keyboard_keymap(void* data, int32_t fd, MwU32 size) { MwLL self = data; + (void)wl_keyboard; if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { struct _MwLLWaylandTopLevel* wayland = self->wayland.toplevel; @@ -589,6 +638,9 @@ static void keyboard_enter(void* data, struct wl_surface* surface, struct wl_array* keys) { MwLL self = data; + (void)wl_keyboard; + (void)surface; + (void)keys; WAYLAND_EVENT_OP_START(self); @@ -605,6 +657,9 @@ static void keyboard_leave(void* data, MwU32 serial, struct wl_surface* surface) { MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)surface; WAYLAND_EVENT_OP_START(self); @@ -621,6 +676,9 @@ static void keyboard_key(void* data, MwU32 key, MwU32 state) { MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)time; WAYLAND_EVENT_OP_START(self); @@ -726,6 +784,10 @@ static void keyboard_modifiers(void* data, MwU32 mods_locked, MwU32 group) { MwLL self = data; + (void)wl_keyboard; + (void)serial; + (void)group; + (void)mods_latched; WAYLAND_EVENT_OP_START(self); @@ -746,7 +808,11 @@ struct wl_keyboard_listener keyboard_listener = { /* `wl_seat.name` callback */ static void -wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) {}; +wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { + (void)data; + (void)wl_seat; + (void)name; +}; /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, @@ -797,14 +863,28 @@ static void output_geometry(void* data, int32_t subpixel, const char* make, const char* model, - int32_t transform) {}; + int32_t transform) { + (void)data; + (void)wl_output; + (void)x; + (void)y; + (void)physical_width; + (void)physical_height; + (void)subpixel; + (void)make; + (void)model; + (void)transform; +}; static void output_mode(void* data, struct wl_output* wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh) { - MwLL self = data; + MwLL self = data; + (void)wl_output; + (void)flags; + (void)refresh; self->wayland.mw = width; self->wayland.mh = height; }; @@ -818,6 +898,7 @@ struct wl_output_listener output_listener = { void xdg_wm_base_ping(void* data, struct xdg_wm_base* xdg_wm_base, MwU32 serial) { + (void)data; xdg_wm_base_pong(xdg_wm_base, serial); }; @@ -835,6 +916,7 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { } static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; free(data->listener); } @@ -847,6 +929,8 @@ static wayland_protocol_t* wl_output_setup(MwU32 name, MwLL ll) { } static void wl_output_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; } /* wl_compositor setup function */ @@ -857,6 +941,8 @@ static wayland_protocol_t* wl_compositor_setup(MwU32 name, struct _MwLLWayland* } static void wl_compositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; } /* wl_subcompositor setup function */ @@ -871,6 +957,7 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan } static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)data; wl_subcompositor_destroy(wayland->sublevel->subcompositor); } @@ -888,6 +975,7 @@ static wayland_protocol_t* xdg_wm_base_setup(MwU32 name, struct _MwLLWayland* wa } static void xdg_wm_base_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; free(data->listener); } @@ -900,7 +988,8 @@ static wayland_protocol_t* wp_viewporter_setup(MwU32 name, struct _MwLLWayland* } static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - // free(data->listener); + (void)wayland; + (void)data; } /* the two decoration manager constructs */ @@ -924,6 +1013,8 @@ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _ } static void zxdg_decoration_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; } /* Standard Wayland event loop. */ @@ -931,7 +1022,6 @@ static int event_loop(MwLL handle) { struct pollfd fd; struct timespec timeout; struct _MwLLWayland* wayland = &handle->wayland; - int res; timeout.tv_nsec = 1; timeout.tv_sec = 0; @@ -977,7 +1067,6 @@ static int event_loop(MwLL handle) { /* make the fuck sure that we're configurd */ static void hang_until_configured(MwLL handle) { - int i = 0; while(!handle->wayland.configured) { if(wl_display_roundtrip(handle->wayland.display) == -1) { printf("roundtrip failed\n"); @@ -993,9 +1082,9 @@ static void xdg_toplevel_configure(void* data, struct xdg_toplevel* xdg_toplevel, MwI32 width, MwI32 height, struct wl_array* states) { - MwLL self = data; - int i; - MwWidget h = ((MwWidget)self->common.user); + MwLL self = data; + (void)states; + (void)xdg_toplevel; /* Yes, somehow this can get called before */ if(!self->wayland.configured) { @@ -1029,16 +1118,11 @@ static void xdg_toplevel_configure(void* data, recursive_dispatch_resize(self); }; -/* Empty function for satisfying zxdg_toplevel's requirements */ -static void decoration_configure( - void* data, struct zxdg_toplevel_decoration_v1* zxdg_toplevel_decoration_v1, - MwU32 mode) { -} - /* `xdg_surface.close` callback */ static void xdg_toplevel_close( void* data, struct xdg_toplevel* xdg_toplevel) { MwLL self = data; + (void)xdg_toplevel; WAYLAND_EVENT_OP_START(self); MwLLDispatch(self, close, NULL); WAYLAND_EVENT_OP_END(self); @@ -1069,6 +1153,8 @@ static wayland_protocol_t* wl_shm_setup(MwU32 name, struct _MwLLWayland* wayland } static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; } static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { @@ -1077,7 +1163,6 @@ static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { - int x, y; int stride = width * 4; char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; @@ -1215,6 +1300,7 @@ static wayland_protocol_t* xdg_toplevel_icon_manager_v1_setup(MwU32 name, struct } static void xdg_toplevel_icon_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; free(data->listener); } @@ -1256,8 +1342,6 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { /* Toplevel setup function */ static void setup_toplevel(MwLL r, int x, int y) { - int i; - r->wayland.type = MWLL_WAYLAND_TOPLEVEL; r->wayland.toplevel = malloc(sizeof(struct _MwLLWaylandTopLevel)); r->wayland.x = x; @@ -1335,8 +1419,6 @@ static void setup_toplevel(MwLL r, int x, int y) { /* Toplevel destroy function */ static void destroy_toplevel(MwLL r) { - int i; - 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; zxdg_decoration_manager_v1_destroy(dec->manager); @@ -1428,6 +1510,7 @@ static void popup_configure(void* data, int32_t width, int32_t height) { MwLL self = data; + (void)xdg_popup; self->wayland.x = x; self->wayland.y = y; @@ -1437,6 +1520,8 @@ static void popup_configure(void* data, static void popup_done(void* data, struct xdg_popup* xdg_popup) { + (void)data; + (void)xdg_popup; }; struct xdg_popup_listener popup_listener = { @@ -1446,7 +1531,6 @@ struct xdg_popup_listener popup_listener = { /* Popup setup function */ static void setup_popup(MwLL r, int x, int y) { - int i; struct xdg_surface* xdg_surface; MwLL topmost_parent = r->wayland.parent; @@ -1529,24 +1613,12 @@ static void destroy_popup(MwLL r) { } static void clip(MwLL handle) { - MwLL parent = handle->wayland.parent; - MwLL topmost = parent; - int left_offset = 0; - int top_offset = 0; - + MwLL parent = handle->wayland.parent; if(parent && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { cairo_reset_clip(handle->wayland.front_cairo); cairo_rectangle(handle->wayland.front_cairo, 0, 0, (parent->wayland.ww + handle->wayland.x), (parent->wayland.wh + handle->wayland.y)); cairo_clip(handle->wayland.front_cairo); } - // if(topmost && handle->wayland.type == MWLL_WAYLAND_SUBLEVEL) { - // cairo_reset_clip(handle->wayland.front_cairo); - // while(topmost->wayland.parent) topmost = topmost->wayland.parent; - // left_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT); - // top_offset = topmost->wayland.has_decorations ? 0 : (CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM); - // cairo_rectangle(handle->wayland.front_cairo, 0, 0, (topmost->wayland.ww + handle->wayland.x) - left_offset, (topmost->wayland.wh + handle->wayland.y) - top_offset); - // cairo_clip(handle->wayland.front_cairo); - // } } static void wl_logger(const char* fmt, va_list args) { @@ -1560,8 +1632,6 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); - wl_log_set_handler_client(wl_logger); - /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. */ r->common.coordinate_type = MwCoordinatesLocal; @@ -1677,9 +1747,6 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - int i = 0; - MwWidget h = (MwWidget)handle->common.user; - region_invalidate(handle); handle->wayland.x = x; handle->wayland.y = y; @@ -1692,8 +1759,6 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { } static void MwLLSetWHImpl(MwLL handle, int w, int h) { - int i = 0; - MwWidget widget = (MwWidget)handle->common.user; region_invalidate(handle); /* Prevent an integer underflow when the w/h is too low */ @@ -1734,7 +1799,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { } if(!handle->wayland.has_decorations) { - int x, y; + int x; MwU32 w = handle->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT; MwU32 h = handle->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM; cairo_set_line_width(handle->wayland.back_cairo, 4.0); @@ -1870,6 +1935,7 @@ 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)); + (void)handle; c->common.red = r; c->common.blue = b; @@ -1879,6 +1945,7 @@ static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { } static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + (void)handle; c->common.red = r; c->common.blue = b; c->common.green = g; @@ -1929,7 +1996,6 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - int i = 0; if(!handle->wayland.always_render) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; @@ -1961,6 +2027,7 @@ 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)); + (void)handle; r->common.width = width; r->common.height = height; @@ -2030,7 +2097,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { if(WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1) != NULL) { - void* map; struct xdg_toplevel_icon_manager_v1* icon_manager = WAYLAND_GET_INTERFACE(handle->wayland, xdg_toplevel_icon_manager_v1)->context; struct xdg_toplevel_icon_v1* icon = xdg_toplevel_icon_manager_v1_create_icon(icon_manager); MwU64 size = pixmap->common.width * pixmap->common.height * 4; @@ -2092,7 +2158,6 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { for(y = 0; y < mask->height; y++) { unsigned int d = mask->data[y]; for(x = mask->width - 1; x >= 0; x--) { - int px = 0; int idx = ((y * image->width) + x) * 4; if(d & 1) { @@ -2135,6 +2200,7 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { } static void MwLLShowImpl(MwLL handle, int show) { + (void)show; switch(handle->wayland.type) { case MWLL_WAYLAND_UNKNOWN: case MWLL_WAYLAND_TOPLEVEL: @@ -2147,6 +2213,9 @@ static void MwLLShowImpl(MwLL handle, int show) { } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { + (void)handle; + (void)parent; + /* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { @@ -2157,6 +2226,7 @@ static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { + (void)toggle; if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { if(WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1) != NULL) { zxdg_decoration_manager_v1_context_t* dec = WAYLAND_GET_INTERFACE(handle->wayland, zxdg_decoration_manager_v1)->context; @@ -2171,10 +2241,14 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { } static void MwLLFocusImpl(MwLL handle) { + (void)handle; printf("[WARNING] MwLLFocus not supported on Wayland\n"); } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; + printf("[WARNING] MwLLGrabPointer not supported on Wayland\n"); } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { @@ -2200,6 +2274,7 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { } static void MwLLGetClipboardImpl(MwLL handle) { + (void)handle; /* no-op */ return; } @@ -2255,11 +2330,16 @@ static void MwLLEndStateChangeImpl(MwLL handle) { static int MwLLWaylandCallInitImpl(void) { #ifdef __linux__ - if(strcmp(getenv("XDG_SESSION_TYPE"), "wayland")) { - return 1; + if(strcmp(getenv("XDG_SESSION_TYPE"), "wayland") == 0) { + if(wayland_load_funcs()) { + return 1; + } + wl_log_set_handler_client(wl_logger); + + return 0; } #endif - return 0; + return 1; } #include "call.c" diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 7d685ada6..59e3a4052 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -57,6 +57,47 @@ typedef struct waylandopengl { EGLContext egl_context; EGLSurface egl_surface; EGLConfig egl_config; + + void* gllib; + void* wlgllib; + EGLBoolean (*eglGetConfigs)(EGLDisplay display, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + EGLBoolean (*eglInitialize)(EGLDisplay display, + EGLint* major, + EGLint* minor); + EGLContext (*eglCreateContext)(EGLDisplay display, + EGLConfig config, + EGLContext share_context, + EGLint const* attrib_list); + EGLBoolean (*eglMakeCurrent)(EGLDisplay display, + EGLSurface draw, + EGLSurface read, + EGLContext context); + void* (*eglGetProcAddress)(char const* procname); + EGLBoolean (*eglSwapBuffers)(EGLDisplay display, + EGLSurface surface); + EGLBoolean (*eglSwapInterval)(EGLDisplay display, + EGLint interval); + EGLint (*eglGetError)(void); + EGLBoolean (*eglBindAPI)(EGLenum api); + EGLDisplay (*eglGetDisplay)(NativeDisplayType native_display); + EGLSurface (*eglCreateWindowSurface)(EGLDisplay display, + EGLConfig config, + NativeWindowType native_window, + EGLint const* attrib_list); + EGLBoolean (*eglChooseConfig)(EGLDisplay display, + EGLint const* attrib_list, + EGLConfig* configs, + EGLint config_size, + EGLint* num_config); + + struct wl_egl_window* (*wl_egl_window_create)(struct wl_surface* surface, + int width, int height); + void (*wl_egl_window_resize)(struct wl_egl_window* egl_window, + int width, int height, + int dx, int dy); } waylandopengl_t; #endif @@ -136,7 +177,6 @@ static int create(MwWidget handle) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - int err; EGLint numConfigs; EGLint majorVersion; EGLint minorVersion; @@ -174,6 +214,58 @@ static int create(MwWidget handle) { topmost_parent = topmost_parent->wayland.parent; } + o->gllib = MwDynamicOpen("libEGL.so"); + if(!o->gllib) { + printf("Could not load OpenGL widget under Wayland! libEGL.so missing.\n"); + return 1; + } + o->wlgllib = MwDynamicOpen("libwayland-egl.so"); + if(!o->gllib) { + printf("Could not load OpenGL widget under Wayland! libwayland-egl.so missing.\n"); + return 1; + } +#define EGL_FUNC(x) \ + o->x = MwDynamicSymbol(o->gllib, #x); \ + if(!o->x) { \ + printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ + return 1; \ + }; +#define WAYLAND_EGL_FUNC(x) \ + o->x = MwDynamicSymbol(o->wlgllib, #x); \ + if(!o->x) { \ + printf("Could not load OpenGL widget under Wayland! " #x " missing.\n"); \ + return 1; \ + }; + EGL_FUNC(eglGetConfigs) + EGL_FUNC(eglInitialize) + EGL_FUNC(eglCreateContext) + EGL_FUNC(eglMakeCurrent) + EGL_FUNC(eglGetProcAddress) + EGL_FUNC(eglSwapBuffers) + EGL_FUNC(eglSwapInterval) + EGL_FUNC(eglGetError) + EGL_FUNC(eglBindAPI) + EGL_FUNC(eglGetDisplay) + EGL_FUNC(eglCreateWindowSurface) + EGL_FUNC(eglChooseConfig) + WAYLAND_EGL_FUNC(wl_egl_window_create) + WAYLAND_EGL_FUNC(wl_egl_window_resize) + +#define eglGetConfigs o->eglGetConfigs +#define eglInitialize o->eglInitialize +#define eglCreateContext o->eglCreateContext +#define eglMakeCurrent o->eglMakeCurrent +#define eglGetProcAddress o->eglGetProcAddress +#define eglSwapBuffers o->eglSwapBuffers +#define eglSwapInterval o->eglSwapInterval +#define eglGetError o->eglGetError +#define wl_egl_window_create o->wl_egl_window_create +#define eglBindAPI o->eglBindAPI +#define eglGetDisplay o->eglGetDisplay +#define wl_egl_window_resize o->wl_egl_window_resize +#define eglCreateWindowSurface o->eglCreateWindowSurface +#define eglChooseConfig o->eglChooseConfig + display = eglGetDisplay((EGLNativeDisplayType)handle->lowlevel->wayland.display); if(display == EGL_NO_DISPLAY) { @@ -391,6 +483,7 @@ static void* mwOpenGLGetProcAddressImpl(MwWidget handle, const char* name) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { + waylandopengl_t* o = handle->internal; return eglGetProcAddress(name); } #endif From 7162350e248b08190c3331526ac9530ab5350108 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 17:39:25 -0700 Subject: [PATCH 228/409] use-experimental-wayland => use-wayland --- configure | 4 ++-- pl/ostype/Linux.pl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 5ffbe544d..1c06c0d65 100755 --- a/configure +++ b/configure @@ -58,7 +58,7 @@ my %features = ( "vulkan-string-helper" => "use Vulkan string helper", "shared" => "build shared library", "static" => "build static library", - "experimental-wayland" => "enable WIP wayland backend", + "wayland" => "enable ayland backend", ); my @features_keys = ( "1classic-theme", "1stb-image", @@ -66,7 +66,7 @@ my @features_keys = ( "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", "1shared", "1static", - "1experimental-wayland" + "1wayland" ); foreach my $l (@ARGV) { diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 155cd4aaf..88adcf838 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -1,4 +1,4 @@ -if (param_get("experimental-wayland")) { +if (param_get("wayland")) { use_backend("wayland", "x11"); } else { From aad8d1b536d92a43ffc772547d9af283271d8219 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 18:01:55 -0700 Subject: [PATCH 229/409] wayland: combo box consistently shows up now --- src/backend/wayland.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 34c87cf22..40a24739c 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2322,6 +2322,21 @@ static void MwLLEndStateChangeImpl(MwLL handle) { setup_toplevel(handle, handle->wayland.detach_point.x, handle->wayland.detach_point.y); break; } + + // framebuffer_setup(&handle->wayland); + // backbuffer_setup(&handle->wayland); + + handle->wayland.region = wl_compositor_create_region(handle->wayland.compositor); + handle->wayland.o_region = wl_compositor_create_region(handle->wayland.compositor); + region_setup(handle); + + MwLLForceRender(handle); + if(handle->wayland.parent != NULL) { + MwLLForceRender(handle->wayland.parent); + } + + handle->wayland.events_pending = 1; + handle->wayland.detatching = MwFALSE; } From 2a7327f27a40e1b4031b45d61a597ba2101a084f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 19:42:34 -0700 Subject: [PATCH 230/409] wayland: update backbuffer on enddraw --- src/backend/wayland.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 40a24739c..b83c799e8 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1889,6 +1889,7 @@ static void MwLLEndDrawImpl(MwLL handle) { if(handle->wayland.configured) { update_buffer(&handle->wayland.framebuffer); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + update_buffer(&handle->wayland.backbuffer); } } } From 195cccd65a6417a6cf235a7eaba5b31ad4ff637e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 22:40:36 -0700 Subject: [PATCH 231/409] perfect MwLLDetach --- include/Mw/LowLevel/Wayland.h | 2 - src/backend/wayland.c | 69 +++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index a6f225437..778826140 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -479,8 +479,6 @@ struct _MwLLWayland { MwBool moving; - struct wl_surface* curSurface; - cairo_surface_t* front_cs; cairo_surface_t* back_cs; cairo_t* front_cairo; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index b83c799e8..f400b3086 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -449,6 +449,8 @@ static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _Mw (void)data; } +static struct wl_surface* curSurface; + /* `wl_pointer.enter` callback */ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 serial, struct wl_surface* surface, wl_fixed_t surface_x, @@ -458,7 +460,7 @@ static void pointer_enter(void* data, struct wl_pointer* wl_pointer, MwU32 seria (void)surface_y; WAYLAND_EVENT_OP_START(self); - self->wayland.curSurface = surface; + curSurface = surface; self->wayland.pointer_serial = serial; @@ -477,7 +479,7 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 seria }; static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { - if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == self->wayland.curSurface) { + if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { xdg_toplevel_resize(self->wayland.toplevel->xdg_top_level, self->wayland.pointer_seat, serial, XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT); @@ -539,8 +541,8 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri // p.point.x > x && p.point.x < x + self->wayland.ww && p.point.y > y && p.point.y < y + self->wayland.wh if( - self->wayland.framebuffer.surface == self->wayland.curSurface || - self->wayland.backbuffer.surface == self->wayland.curSurface) { + self->wayland.framebuffer.surface == curSurface || + self->wayland.backbuffer.surface == curSurface) { int i; switch(button) { @@ -1108,9 +1110,9 @@ static void xdg_toplevel_configure(void* data, backbuffer_destroy(&self->wayland); backbuffer_setup(&self->wayland); - framebuffer_destroy(&self->wayland); framebuffer_setup(&self->wayland); + region_setup(self); MwLLDispatch(self, resize, NULL); @@ -1261,7 +1263,7 @@ static void region_setup(MwLL handle) { return; } - wl_region_add(handle->wayland.o_region, 0, 0, 1, 1); + wl_region_add(handle->wayland.o_region, 0, 0, width, height); if(handle->wayland.type == MWLL_WAYLAND_POPUP) { wl_region_add(handle->wayland.region, 0, 0, width + abs(handle->wayland.x), height + abs(handle->wayland.y)); @@ -1626,12 +1628,7 @@ static void wl_logger(const char* fmt, va_list args) { raise(SIGTRAP); } -static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - r = malloc(sizeof(*r)); - memset(r, 0, sizeof(*r)); - MwLLCreateCommon(r); - +static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int height, enum _MwLLWaylandType ty) { /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. */ r->common.coordinate_type = MwCoordinatesLocal; @@ -1654,10 +1651,26 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->wayland.y = y; r->wayland.parent = parent; - if(parent == NULL) { - setup_toplevel(r, x, y); + if(ty == MWLL_WAYLAND_UNKNOWN) { + if(parent == NULL) { + setup_toplevel(r, x, y); + } else { + setup_sublevel(parent, r, x, y); + } } else { - setup_sublevel(parent, r, x, y); + switch(ty) { + case MWLL_WAYLAND_UNKNOWN: + break; + case MWLL_WAYLAND_TOPLEVEL: + setup_toplevel(r, x, y); + break; + case MWLL_WAYLAND_SUBLEVEL: + setup_sublevel(parent, r, x, y); + break; + case MWLL_WAYLAND_POPUP: + setup_popup(r, x, y); + break; + } } framebuffer_setup(&r->wayland); @@ -1671,6 +1684,14 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(parent != NULL) { MwLLForceRender(parent); } +} +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); + MwLLCreateCommon(r); + + widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); return r; } @@ -1887,10 +1908,10 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { if(handle->wayland.configured) { - update_buffer(&handle->wayland.framebuffer); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { update_buffer(&handle->wayland.backbuffer); } + update_buffer(&handle->wayland.framebuffer); } } @@ -2303,6 +2324,7 @@ static void MwLLEndStateChangeImpl(MwLL handle) { if(handle->wayland.detatching) { switch(handle->wayland.type) { case MWLL_WAYLAND_UNKNOWN: + break; case MWLL_WAYLAND_TOPLEVEL: destroy_toplevel(handle); break; @@ -2310,22 +2332,13 @@ static void MwLLEndStateChangeImpl(MwLL handle) { destroy_sublevel(handle); break; case MWLL_WAYLAND_POPUP: - return; + destroy_popup(handle); + break; } wl_flush(handle); - switch(handle->wayland.type_to_be) { - case MWLL_WAYLAND_POPUP: - setup_popup(handle, handle->wayland.detach_point.x, handle->wayland.detach_point.y); - break; - default: - setup_toplevel(handle, handle->wayland.detach_point.x, handle->wayland.detach_point.y); - break; - } - - // framebuffer_setup(&handle->wayland); - // backbuffer_setup(&handle->wayland); + widget_setup(handle, handle->wayland.parent, handle->wayland.detach_point.x, handle->wayland.detach_point.y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); handle->wayland.region = wl_compositor_create_region(handle->wayland.compositor); handle->wayland.o_region = wl_compositor_create_region(handle->wayland.compositor); From a826ce5e12ad22949d4861c2b3c2aab2de9ae74d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 23:08:43 -0700 Subject: [PATCH 232/409] GOD IS GOOD --- src/backend/wayland.c | 76 ++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f400b3086..26b359110 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1238,7 +1238,7 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, w, h, 4 * w); wayland->back_cairo = cairo_create(wayland->back_cs); - memset(wayland->backbuffer.buf, 0, wayland->backbuffer.buf_size); + memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size); hang_until_configured((MwLL)wayland); update_buffer(&wayland->backbuffer); }; @@ -1532,13 +1532,14 @@ struct xdg_popup_listener popup_listener = { }; /* Popup setup function */ -static void setup_popup(MwLL r, int x, int y) { +static void setup_popup(MwLL r, int x, int y, MwLL parent) { struct xdg_surface* xdg_surface; MwLL topmost_parent = r->wayland.parent; - r->wayland.type = MWLL_WAYLAND_POPUP; - r->wayland.x = x; - r->wayland.y = y; + r->wayland.type = MWLL_WAYLAND_POPUP; + r->wayland.x = x; + r->wayland.y = y; + r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { topmost_parent = topmost_parent->wayland.parent; @@ -1548,12 +1549,11 @@ static void setup_popup(MwLL r, int x, int y) { r->wayland.y += ceil((float)CSD_BORDER_FRAME_TOP / 2.); } - r->wayland.popup = malloc(sizeof(struct _MwLLWaylandPopup)); - memset(r->wayland.popup, 0, sizeof(struct _MwLLWaylandPopup)); - r->wayland.popup->topmost_parent = topmost_parent; - setup_callbacks(&r->wayland); + /* Connect to the Wayland compositor */ + r->wayland.display = parent->wayland.display; + /* 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); @@ -1563,7 +1563,12 @@ static void setup_popup(MwLL r, int x, int y) { return; } - r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(topmost_parent->wayland, xdg_wm_base)->context; + /* check now if we have decorations so that everything else can act accordingly */ + if(shget(r->wayland.wl_protocol_map, zxdg_decoration_manager_v1_interface.name) != NULL) { + r->wayland.has_decorations = MwTRUE; + } + + r->wayland.popup->xdg_wm_base = WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context; r->wayland.popup->xdg_positioner = xdg_wm_base_create_positioner(r->wayland.popup->xdg_wm_base); @@ -1577,7 +1582,7 @@ static void setup_popup(MwLL r, int x, int y) { r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); r->wayland.popup->xdg_surface = - xdg_wm_base_get_xdg_surface(r->wayland.popup->xdg_wm_base, r->wayland.framebuffer.surface); + xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); r->wayland.popup->xdg_popup = xdg_surface_get_popup( r->wayland.popup->xdg_surface, @@ -1587,16 +1592,13 @@ static void setup_popup(MwLL r, int x, int y) { xdg_popup_add_listener(r->wayland.popup->xdg_popup, &popup_listener, r); r->wayland.popup->xdg_surface_listener.configure = xdg_surface_configure; - xdg_surface_add_listener(r->wayland.popup->xdg_surface, &r->wayland.popup->xdg_surface_listener, r); /* Perform the initial commit and wait for the first configure event */ wl_surface_commit(r->wayland.framebuffer.surface); - event_loop(r); - - // framebuffer_destroy(&r->wayland); - framebuffer_setup(&r->wayland); - backbuffer_setup(&r->wayland); + while(!r->wayland.configured) { + event_loop(r); + } } /* Popup destroy function */ @@ -1668,7 +1670,7 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh setup_sublevel(parent, r, x, y); break; case MWLL_WAYLAND_POPUP: - setup_popup(r, x, y); + setup_popup(r, x, y, parent); break; } } @@ -1758,6 +1760,10 @@ static void MwLLDestroyImpl(MwLL handle) { shfree(handle->wayland.wl_protocol_setup_map); free(handle); + + if(currentlyHeldWidget == handle) { + currentlyHeldWidget = NULL; + } } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { @@ -1799,7 +1805,7 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { if(handle->wayland.type == MWLL_WAYLAND_POPUP) { destroy_popup(handle); wl_flush(handle); - setup_popup(handle, handle->wayland.x, handle->wayland.y); + setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); } refresh: @@ -2322,6 +2328,11 @@ static void MwLLBeginStateChangeImpl(MwLL handle) { static void MwLLEndStateChangeImpl(MwLL handle) { if(handle->wayland.detatching) { + MwLL topmost_parent = handle->wayland.parent; + + while(topmost_parent->wayland.type != MWLL_WAYLAND_TOPLEVEL) { + topmost_parent = topmost_parent->wayland.parent; + } switch(handle->wayland.type) { case MWLL_WAYLAND_UNKNOWN: break; @@ -2338,11 +2349,32 @@ static void MwLLEndStateChangeImpl(MwLL handle) { wl_flush(handle); + handle->wayland.detach_point.x += 4; + handle->wayland.detach_point.y += 4; + widget_setup(handle, handle->wayland.parent, handle->wayland.detach_point.x, handle->wayland.detach_point.y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); - handle->wayland.region = wl_compositor_create_region(handle->wayland.compositor); - handle->wayland.o_region = wl_compositor_create_region(handle->wayland.compositor); - region_setup(handle); + if(handle->common.user) { + MwWidget w = handle->common.user; + int i; + for(i = 0; i < arrlen(w->children); i++) { + if(w->children[i]->lowlevel->wayland.type == MWLL_WAYLAND_SUBLEVEL) { + MwLL child = w->children[i]->lowlevel; + child->wayland.sublevel->parent_xdg_surface = handle->wayland.popup->xdg_surface; + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + wl_flush(handle); + + child->wayland.sublevel->subsurface = wl_subcompositor_get_subsurface(child->wayland.sublevel->subcompositor, child->wayland.framebuffer.surface, handle->wayland.framebuffer.surface); + wl_subsurface_set_desync(child->wayland.sublevel->subsurface); + wl_subsurface_set_position(child->wayland.sublevel->subsurface, child->wayland.x, child->wayland.y); + + wl_subsurface_place_above(child->wayland.sublevel->subsurface, handle->wayland.framebuffer.surface); + MwLLEndStateChangeImpl(w->children[i]->lowlevel); + + currentlyHeldWidget = NULL; + } + } + } MwLLForceRender(handle); if(handle->wayland.parent != NULL) { From 9757623d3c28996363f630008e20699981b670f4 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 23:24:20 -0700 Subject: [PATCH 233/409] make always_render a global variable, MwWaylandAlwaysRender --- include/Mw/LowLevel/Wayland.h | 4 +--- src/backend/wayland.c | 11 ++++++----- src/widget/opengl.c | 11 +++-------- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 778826140..95e84eb94 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -127,7 +127,7 @@ typedef struct wayland_call_table { } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; - +extern MwBool MwWaylandAlwaysRender; /* defined inline right here so that it doesn't conflict with the other macros */ MwInline int wayland_load_funcs() { wl_call_tbl.lib = MwDynamicOpen("libwayland-client.so"); @@ -405,8 +405,6 @@ struct _MwLLWayland { wayland_protocol_t* value; }* wl_protocol_map; - MwBool always_render; - MwBool has_decorations; char title[255]; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 26b359110..5e4e76792 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -20,6 +20,7 @@ #endif wayland_call_table_t wl_call_tbl; +MwBool MwWaylandAlwaysRender = MwFALSE; /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ @@ -770,7 +771,7 @@ static void keyboard_key(void* data, } } - if(!self->wayland.always_render) { + if(!MwWaylandAlwaysRender) { MwLLDispatch(self, draw, NULL); } @@ -1999,17 +2000,17 @@ static int MwLLPendingImpl(MwLL handle) { handle->wayland.did_initial_resize = 1; } - if(!handle->wayland.always_render) wl_display_prepare_read(handle->wayland.display); + if(!MwWaylandAlwaysRender) wl_display_prepare_read(handle->wayland.display); if(!poll(&fd, 1, timeout.tv_nsec)) { wl_display_cancel_read(handle->wayland.display); } else { - if(!handle->wayland.always_render) wl_display_read_events(handle->wayland.display); + if(!MwWaylandAlwaysRender) wl_display_read_events(handle->wayland.display); if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } } - if(handle->wayland.always_render) { + if(MwWaylandAlwaysRender) { handle->wayland.did_event_loop_early = MwTRUE; event_loop(handle); return pending; @@ -2024,7 +2025,7 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - if(!handle->wayland.always_render) { + if(!MwWaylandAlwaysRender) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; } else { diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 59e3a4052..0afbe9ac7 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -205,14 +205,9 @@ static int create(MwWidget handle) { 1, EGL_NONE}; EGLDisplay display; - waylandopengl_t* o = r = malloc(sizeof(*o)); - MwLL topmost_parent = handle->lowlevel->wayland.parent; - handle->lowlevel->wayland.always_render = MwTRUE; - - while(topmost_parent->wayland.parent != NULL) { - topmost_parent->wayland.always_render = MwTRUE; - topmost_parent = topmost_parent->wayland.parent; - } + waylandopengl_t* o = r = malloc(sizeof(*o)); + MwLL topmost_parent = handle->lowlevel->wayland.parent; + MwWaylandAlwaysRender = MwTRUE; o->gllib = MwDynamicOpen("libEGL.so"); if(!o->gllib) { From f4e2ec8fa93b0f7f8f8fe326aacafb9c2d0d8a72 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 24 Mar 2026 23:44:30 -0700 Subject: [PATCH 234/409] h --- include/Mw/LowLevel/Wayland.h | 4 ++++ pl/rules.pl | 1 + src/backend/wayland.c | 25 +++++++++++++++++-------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 95e84eb94..bc8ce1ff2 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -285,6 +285,7 @@ MwInline int wayland_load_funcs() { #include "Wayland/xdg-decoration-client-protocol.h" #include "Wayland/cursor-shape-client-protocol.h" #include "Wayland/primary-selection-client-protocol.h" +#include "Wayland/pointer-constraints-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #endif @@ -418,6 +419,9 @@ struct _MwLLWayland { struct wp_viewport* vp; + struct zwp_pointer_constraints_v1* pointer_constraints; + struct zwp_locked_pointer_v1* locked_pointer; + /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/pl/rules.pl b/pl/rules.pl index 81a1ecec7..5433a1764 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -42,6 +42,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("staging", "cursor-shape", "-v1"); scan_wayland_protocol("unstable", "xdg-decoration", "-unstable-v1"); scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); + scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); $gl_libs = "-lGL -lGLU"; } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5e4e76792..4d7f72aca 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -5,11 +5,6 @@ #include "../../external/stb_ds.h" -/* TODO: - * - MwLLMakePopupImpl - * - MwLLShowImpl - */ - /* TODO: find out what FreeBSD and such wants us to include */ #ifdef __FreeBSD__ /* XXX: Untested (nishi) */ @@ -450,6 +445,17 @@ static void zwp_primary_selection_device_manager_v1_interface_destroy(struct _Mw (void)data; } +/* zwp_primary_selection_device_manager_v1 setup function */ +static wayland_protocol_t* zwp_pointer_constraints_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { + wayland->pointer_constraints = wl_registry_bind(wayland->registry, name, &zwp_pointer_constraints_v1_interface, 1); + return NULL; +} + +static void zwp_pointer_constraints_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { + (void)wayland; + (void)data; +} + static struct wl_surface* curSurface; /* `wl_pointer.enter` callback */ @@ -1329,6 +1335,7 @@ static void setup_callbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_output); WL_INTERFACE(wl_data_device_manager); WL_INTERFACE(zwp_primary_selection_device_manager_v1); + WL_INTERFACE(zwp_pointer_constraints_v1); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(xdg_wm_base); WL_INTERFACE(wp_viewporter); @@ -2275,9 +2282,11 @@ static void MwLLFocusImpl(MwLL handle) { } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - (void)handle; - (void)toggle; - printf("[WARNING] MwLLGrabPointer not supported on Wayland\n"); + if(handle->wayland.pointer_constraints) { + handle->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(handle->wayland.pointer_constraints, handle->wayland.framebuffer.surface, handle->wayland.pointer, handle->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + } else { + printf("[WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 required.\n"); + } } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { From 4b2bf63889e9a2bc05cc153ec7660497b1ae0024 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 00:31:23 -0700 Subject: [PATCH 235/409] wayland: support pointer locking --- include/Mw/LowLevel/Wayland.h | 2 ++ src/backend/wayland.c | 47 ++++++++++++++++++++++++----------- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index bc8ce1ff2..c24ce3cec 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -419,8 +419,10 @@ struct _MwLLWayland { struct wp_viewport* vp; + MwBool do_lock_pointer; struct zwp_pointer_constraints_v1* pointer_constraints; struct zwp_locked_pointer_v1* locked_pointer; + MwBool pointer_constrained; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 4d7f72aca..1d1d2b8ac 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -514,22 +514,35 @@ static MwLL currentlyHeldWidget = NULL; /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - MwLL self = data; + MwLL self = data; + MwLL topmost_parent = self; MwLLMouse p; (void)time; (void)wl_pointer; WAYLAND_EVENT_OP_START(self); + while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); - p.point = self->wayland.cur_mouse_pos; + if(self->wayland.do_lock_pointer) { + self->wayland.cur_mouse_pos.x -= topmost_parent->wayland.ww / 2.; + self->wayland.cur_mouse_pos.y -= topmost_parent->wayland.wh / 2.; + } + p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); if(currentlyHeldWidget) { MwLLDispatch(currentlyHeldWidget, down, &p); } + if(self->wayland.do_lock_pointer) { + topmost_parent->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(topmost_parent->wayland.pointer_constraints, topmost_parent->wayland.backbuffer.surface, topmost_parent->wayland.pointer, topmost_parent->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + zwp_locked_pointer_v1_set_cursor_position_hint(topmost_parent->wayland.locked_pointer, wl_fixed_from_double(topmost_parent->wayland.ww / 2.), wl_fixed_from_double(topmost_parent->wayland.wh / 2.)); + wl_surface_commit(topmost_parent->wayland.backbuffer.surface); + zwp_locked_pointer_v1_destroy(topmost_parent->wayland.locked_pointer); + } + WAYLAND_EVENT_OP_END(self); }; @@ -1125,6 +1138,11 @@ static void xdg_toplevel_configure(void* data, MwLLDispatch(self, draw, NULL); recursive_dispatch_resize(self); + + if(self->wayland.pointer_constrained) { + zwp_locked_pointer_v1_set_cursor_position_hint(self->wayland.locked_pointer, wl_fixed_from_double(self->wayland.ww / 2.), wl_fixed_from_double(self->wayland.wh / 2.)); + wl_surface_commit(self->wayland.framebuffer.surface); + } }; /* `xdg_surface.close` callback */ @@ -1166,7 +1184,8 @@ static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_proto (void)data; } -static void update_buffer(struct _MwLLWaylandShmBuffer* buffer) { +static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { + (void)self; // for later, just in case. wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); wl_surface_commit(buffer->surface); } @@ -1222,7 +1241,7 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->framebuffer.buf, 0, wayland->framebuffer.buf_size); hang_until_configured((MwLL)wayland); - update_buffer(&wayland->framebuffer); + update_buffer((MwLL)wayland, &wayland->framebuffer); }; static void framebuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->framebuffer); @@ -1247,7 +1266,7 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size); hang_until_configured((MwLL)wayland); - update_buffer(&wayland->backbuffer); + update_buffer((MwLL)wayland, &wayland->backbuffer); }; static void backbuffer_destroy(struct _MwLLWayland* wayland) { buffer_destroy(&wayland->backbuffer); @@ -1913,7 +1932,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { MwLLDestroyPixmap(p); free(px); } - update_buffer(&handle->wayland.backbuffer); + update_buffer(handle, &handle->wayland.backbuffer); wl_surface_commit(handle->wayland.backbuffer.surface); } @@ -1923,9 +1942,9 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { if(handle->wayland.configured) { if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - update_buffer(&handle->wayland.backbuffer); + update_buffer(handle, &handle->wayland.backbuffer); } - update_buffer(&handle->wayland.framebuffer); + update_buffer(handle, &handle->wayland.framebuffer); } } @@ -2023,9 +2042,9 @@ static int MwLLPendingImpl(MwLL handle) { return pending; } - update_buffer(&handle->wayland.framebuffer); + update_buffer(handle, &handle->wayland.framebuffer); if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { - update_buffer(&handle->wayland.backbuffer); + update_buffer(handle, &handle->wayland.backbuffer); } return handle->wayland.force_render || handle->wayland.events_pending || pending; @@ -2044,7 +2063,7 @@ static void MwLLNextEventImpl(MwLL handle) { // if(!handle->wayland.events_pending) { MwLLDispatch(handle, draw, NULL); // } - if(handle->wayland.configured) update_buffer(&handle->wayland.framebuffer); + if(handle->wayland.configured) update_buffer(handle, &handle->wayland.framebuffer); handle->wayland.force_render = 0; } if(handle->wayland.events_pending) { @@ -2127,7 +2146,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_surface_destroy(cs); MwLLForceRender(handle); - update_buffer(&handle->wayland.framebuffer); + update_buffer(handle, &handle->wayland.framebuffer); wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { @@ -2159,7 +2178,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { handle->wayland.icon->buf[i + 3] = 255; } - if(handle->wayland.configured) update_buffer(handle->wayland.icon); + if(handle->wayland.configured) update_buffer(handle, handle->wayland.icon); xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); @@ -2283,7 +2302,7 @@ static void MwLLFocusImpl(MwLL handle) { static void MwLLGrabPointerImpl(MwLL handle, int toggle) { if(handle->wayland.pointer_constraints) { - handle->wayland.locked_pointer = zwp_pointer_constraints_v1_lock_pointer(handle->wayland.pointer_constraints, handle->wayland.framebuffer.surface, handle->wayland.pointer, handle->wayland.region, ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT); + handle->wayland.do_lock_pointer = toggle; } else { printf("[WARNING] MwLLGrabPointer not supported in Wayland session, zwp_pointer_constraints_v1 required.\n"); } From fa9ad8b9848d60ed2ccae17c8a890edc18c799bf Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 00:43:35 -0700 Subject: [PATCH 236/409] enable wayland by default on linux builds --- configure | 6 +++++- src/backend/wayland.c | 14 ++++++++++---- src/widget/opengl.c | 5 ++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/configure b/configure index 1c06c0d65..3cfe05055 100755 --- a/configure +++ b/configure @@ -46,6 +46,10 @@ param_set("vulkan-string-helper", 1); param_set("shared", 1); param_set("static", 1); param_set("examples", 1); +print($target); +if($target eq "Linux") { + param_set("wayland", 1); +} my %features = ( "classic-theme" => "use classic theme", @@ -58,7 +62,7 @@ my %features = ( "vulkan-string-helper" => "use Vulkan string helper", "shared" => "build shared library", "static" => "build static library", - "wayland" => "enable ayland backend", + "wayland" => "enable wayland backend", ); my @features_keys = ( "1classic-theme", "1stb-image", diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1d1d2b8ac..5ba779b1c 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2026,11 +2026,17 @@ static int MwLLPendingImpl(MwLL handle) { handle->wayland.did_initial_resize = 1; } - if(!MwWaylandAlwaysRender) wl_display_prepare_read(handle->wayland.display); - if(!poll(&fd, 1, timeout.tv_nsec)) { - wl_display_cancel_read(handle->wayland.display); + if(!MwWaylandAlwaysRender) { + wl_display_prepare_read(handle->wayland.display); + if(!poll(&fd, 1, timeout.tv_nsec)) { + wl_display_cancel_read(handle->wayland.display); + } else { + wl_display_read_events(handle->wayland.display); + if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { + wl_display_cancel_read(handle->wayland.display); + } + } } else { - if(!MwWaylandAlwaysRender) wl_display_read_events(handle->wayland.display); if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 0afbe9ac7..bf06981b9 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -205,9 +205,8 @@ static int create(MwWidget handle) { 1, EGL_NONE}; EGLDisplay display; - waylandopengl_t* o = r = malloc(sizeof(*o)); - MwLL topmost_parent = handle->lowlevel->wayland.parent; - MwWaylandAlwaysRender = MwTRUE; + waylandopengl_t* o = r = malloc(sizeof(*o)); + MwWaylandAlwaysRender = MwTRUE; o->gllib = MwDynamicOpen("libEGL.so"); if(!o->gllib) { From aa6d1f43d3e37d16b6c0ee676118542dccf8eeb0 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 25 Mar 2026 17:06:44 +0900 Subject: [PATCH 237/409] fix --- src/widget/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index e2dfa4c8b..92f319265 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -231,7 +231,7 @@ static MwErrorEnum vulkan_instance_setup(MwWidget handle, vulkan_t* o) { arrput(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ - handle->lowlevel->wayland.always_render = MwTRUE; + MwWaylandAlwaysRender = MwTRUE; while(topmost_parent->wayland.parent != NULL) { topmost_parent = topmost_parent->wayland.parent; From c05843a04b99e755b5c2abb1927432b16efcb76b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Wed, 25 Mar 2026 17:09:36 +0900 Subject: [PATCH 238/409] ugh --- src/widget/vulkan.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 92f319265..a67c47440 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -227,16 +227,9 @@ static MwErrorEnum vulkan_instance_setup(MwWidget handle, vulkan_t* o) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - MwLL topmost_parent = handle->lowlevel->wayland.parent; - arrput(enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ MwWaylandAlwaysRender = MwTRUE; - - while(topmost_parent->wayland.parent != NULL) { - topmost_parent = topmost_parent->wayland.parent; - topmost_parent->wayland.always_render = MwTRUE; - } } #endif From 6bb72c224b6ccad718d689901e2c4d1656ed1fa7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 25 Mar 2026 14:06:50 -0700 Subject: [PATCH 239/409] support wayland backend on cmake --- CMakeLists.txt | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 09a5bd90c..743824f91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,10 @@ option(MW_BUILD_SHARED "Build a shared library" ON) option(MW_BUILD_STATIC "Build a static library" OFF) option(MW_INSTALL_HEADERS "Install headers" ON) +if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) +option(MW_USE_WAYLAND "Enable Wayland backend" ON) +endif() + file( GLOB SOURCES @@ -127,6 +131,97 @@ if(MW_USE_FREETYPE2) list(APPEND LIBRARIES ${FT2_LIBRARIES}) endif() +if(MW_USE_WAYLAND) + function(scan_wayland_protocol_core) + execute_process( + COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c + ) + execute_process( + COMMAND wayland-scanner client-header /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/wayland-core-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + + function(scan_wayland_protocol tier proto ver) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-${proto}-protocol.c) + execute_process( + COMMAND wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + target_sources( + Mw + PRIVATE + ${proto_c} + ) + execute_process( + COMMAND wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT + ERROR_VARIABLE WAYLAND_SCANNER_ERROR + ECHO_OUTPUT_VARIABLE + ECHO_ERROR_VARIABLE + COMMAND_ECHO STDOUT + ) + endfunction() + + check_include_files(wayland-client.h HAVE_WL_H) + check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H) + check_include_files(cairo/cairo.h HAVE_CAIRO_H) + if(HAVE_WL_H) + if(HAVE_XKBCOMMON_H) + if(HAVE_CAIRO_H) + scan_wayland_protocol_core() + scan_wayland_protocol("stable" "xdg-shell" "") + scan_wayland_protocol("stable" "viewporter" "") + scan_wayland_protocol("stable" "tablet" "-v2") + scan_wayland_protocol("staging" "xdg-toplevel-icon" "-v1") + scan_wayland_protocol("staging" "cursor-shape" "-v1") + scan_wayland_protocol("unstable" "xdg-decoration" "-unstable-v1") + scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") + scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") + + target_sources( + Mw + PRIVATE + src/backend/wayland.c + ) + target_compile_definitions( + Mw + PRIVATE + USE_WAYLAND + ) + message(STATUS "Wayland backend has been enabled") + else() + message(WARNING "Wayland backend has been disabled") + endif() + else() + message(WARNING "Wayland backend has been disabled") + endif() + else() + message(WARNING "Wayland backend has been disabled") + endif() +endif() + target_include_directories( Mw PUBLIC From 82999d716a435ab770355ae0fe9ae02370cc5435 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 17:49:28 -0700 Subject: [PATCH 240/409] apple: move all event stuff into callback system, fix cmake support for apple, add gl/vk examples to cmake --- .clangd | 1 + .gitignore | 1 + CMakeLists.txt | 24 +- configure | 7 +- examples/CMakeLists.txt | 6 + examples/basic/CMakeLists.txt | 2 +- examples/gldemos/CMakeLists.txt | 27 ++ examples/vkdemos/CMakeLists.txt | 22 ++ include/Mw/LowLevel/Cocoa.h | 56 +-- src/backend/cocoa.m | 630 +++++++++++++++++--------------- 10 files changed, 457 insertions(+), 319 deletions(-) create mode 100644 examples/gldemos/CMakeLists.txt create mode 100644 examples/vkdemos/CMakeLists.txt diff --git a/.clangd b/.clangd index c2520c5c5..1058f6f19 100644 --- a/.clangd +++ b/.clangd @@ -1,2 +1,3 @@ Completion: HeaderInsertion: Never +ClangFormat: Tab diff --git a/.gitignore b/.gitignore index 153abcca4..22460554b 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ examples/*/*.exe /build compile_flags.txt .cache +.DS_Store diff --git a/CMakeLists.txt b/CMakeLists.txt index 743824f91..7bf75294a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,11 +15,16 @@ option(MW_CLASSIC_THEME "Use classic theme" OFF) option(MW_BUILD_EXAMPLES "Build examples" OFF) option(MW_USE_STB_IMAGE "Use stb_image" ON) option(MW_USE_STB_TRUETYPE "Use stb_truetype" OFF) -option(MW_USE_FREETYPE2 "Use FreeType 2" ON) option(MW_BUILD_SHARED "Build a shared library" ON) option(MW_BUILD_STATIC "Build a static library" OFF) option(MW_INSTALL_HEADERS "Install headers" ON) +if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) +option(MW_USE_FREETYPE2 "Use FreeType 2" OFF) +else() +option(MW_USE_FREETYPE2 "Use FreeType 2" ON) +endif() + if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) option(MW_USE_WAYLAND "Enable Wayland backend" ON) endif() @@ -47,10 +52,13 @@ if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") endif() if(MW_TRY_OPENGL) - check_include_files(GL/gl.h HAVE_GL_GL_H) - if(HAVE_GL_GL_H) + find_package(OpenGL) + if(OpenGL_FOUND) set(MW_BUILD_OPENGL ON) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") + list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") + if(APPLE) + list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") + endif() message(STATUS "OpenGL widget has been enabled") else() message(WARNING "OpenGL widget has been disabled") @@ -222,6 +230,14 @@ if(MW_USE_WAYLAND) endif() endif() +if(APPLE AND MW_BUILD_OPENGL) + target_compile_definitions( + Mw + PRIVATE + GL_SILENCE_DEPRECATION + ) +endif() + target_include_directories( Mw PUBLIC diff --git a/configure b/configure index 3cfe05055..cb465378b 100755 --- a/configure +++ b/configure @@ -38,7 +38,6 @@ require("./pl/utils.pl"); param_set("classic-theme", 0); param_set("stb-image", 1); param_set("stb-truetype", 0); -param_set("freetype2", 1); param_set("xrender", 1); param_set("opengl", 0); param_set("vulkan", 0); @@ -46,11 +45,15 @@ param_set("vulkan-string-helper", 1); param_set("shared", 1); param_set("static", 1); param_set("examples", 1); -print($target); if($target eq "Linux") { param_set("wayland", 1); } +if($target ne "Darwin") { + param_set("freetype2", 1); +} + + my %features = ( "classic-theme" => "use classic theme", "stb-image" => "use stb_image, instead use libjpeg/libpng", diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6f4cd2f5a..5baed4a88 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1 +1,7 @@ add_subdirectory(basic) +if(${MW_TRY_OPENGL}) +add_subdirectory(gldemos) +endif() +if(${MW_TRY_VULKAN}) +add_subdirectory(vkdemos) +endif() diff --git a/examples/basic/CMakeLists.txt b/examples/basic/CMakeLists.txt index b4eb0a1cd..acda320d2 100644 --- a/examples/basic/CMakeLists.txt +++ b/examples/basic/CMakeLists.txt @@ -6,7 +6,7 @@ file( foreach(PATH IN LISTS EXAMPLES_BASIC_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) - add_executable(${TARGET} ${PATH}) + add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) target_link_libraries( ${TARGET} PRIVATE diff --git a/examples/gldemos/CMakeLists.txt b/examples/gldemos/CMakeLists.txt new file mode 100644 index 000000000..9afda19fb --- /dev/null +++ b/examples/gldemos/CMakeLists.txt @@ -0,0 +1,27 @@ +file( + GLOB + EXAMPLES_GL_SOURCES + *.c +) +find_package(OpenGL) + +foreach(PATH IN LISTS EXAMPLES_GL_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + if(${TARGET} STREQUAL "glutlayer") + continue() + endif() + add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + target_link_libraries( + ${TARGET} + PRIVATE + Mw + OpenGL::GL + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() +endforeach() diff --git a/examples/vkdemos/CMakeLists.txt b/examples/vkdemos/CMakeLists.txt new file mode 100644 index 000000000..354bf3634 --- /dev/null +++ b/examples/vkdemos/CMakeLists.txt @@ -0,0 +1,22 @@ +file( + GLOB + EXAMPLES_VULKAN_SOURCES + *.c +) + +foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) + get_filename_component(TARGET ${PATH} NAME_WE) + add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + target_link_libraries( + ${TARGET} + PRIVATE + Mw + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() +endforeach() diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 7d1b217fe..da104f018 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -21,11 +21,17 @@ #import #endif +@interface MilskoCocoaApplication : NSApplication { + MwBool doPending; +} +- (MwBool)pending; +@end + // Note: implements NSApplicationDelegate @interface MilskoCocoaApplicationDelegate : NSObject { - NSApplication* appl; + MilskoCocoaApplication* appl; } -- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)appl; +- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)appl; @end @interface MilskoCocoaWindow : NSWindow { @@ -80,32 +86,39 @@ @end @interface MilskoCocoaView : NSView { - NSBitmapImageRep* rep; - NSGraphicsContext* context; - MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; - float width; - float height; + NSBitmapImageRep* rep; + NSGraphicsContext* context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + NSRect givenRect; + float x; + float y; + float width; + float height; + MwBool _child; + IBOutlet NSViewController* viewController; } - (void)initRepAndContextWithWidth:(float)w Height:(float)h; - (NSGraphicsContext*)context; - (void)destroy; - (NSBitmapImageRep*)getRep; +- (void)setChild; @end @interface MilskoCocoa : NSObject { - NSApplication* application; - MwBool _forceRender; - MilskoCocoaWindow* window; - NSRect rect; - MilskoCocoaView* view; - MwLL parent; - MilskoFakePointer* handle; - unsigned int strHash; - NSEvent* lastEvent; + MilskoCocoaApplication* application; + MwBool _forceRender; + MwBool _eventsPending; + MilskoCocoaWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; MilskoCocoaPixmap* cursorPixmap; NSCursor* cursor; @@ -129,9 +142,6 @@ - (void)setX:(int)x Y:(int)y; - (void)setW:(int)w H:(int)h; - (int)pending; -- (void)eventProcess:(NSEvent*)ev; -- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll; -- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll; - (void)getNextEvent; - (void)setTitle:(const char*)title; - (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; @@ -158,6 +168,10 @@ - (MwLL)getParent; - (NSView*)getView; - (MilskoCocoaWindow*)getWindow; +- (void)nudge; + +- (void)pushCursor; +- (void)popCursor; - (MilskoFakePointer*)getHandle; + (void)eventCanceller:(MilskoCocoa*)this; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 725642d35..d3fec7ebb 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,5 +1,9 @@ #include "Mw/BaseTypes.h" +#include "Mw/LowLevel.h" #include +#include +#include "../../external/stb_ds.h" +#include "Mw/TypeDefs.h" #ifdef __clang__ #pragma clang push @@ -22,15 +26,44 @@ static NSPoint pointFlip(NSPoint point) { } static NSRect localRectFlip(NSRect originFrame, NSView* view) { - float viewHeight = [view bounds].size.height; - NSRect destinationFrame = NSMakeRect( - originFrame.origin.x, - [view bounds].size.height - (originFrame.origin.y + originFrame.size.height), - originFrame.size.width, - originFrame.size.height); + float viewHeight = [view bounds].size.height; + NSRect destinationFrame = + NSMakeRect(originFrame.origin.x, + [view bounds].size.height - + (originFrame.origin.y + originFrame.size.height), + originFrame.size.width, originFrame.size.height); return destinationFrame; } +/* Recursively dispatch a key event to a widget and its children */ +static void recursive_dispatch_key(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key(h->children[i]->lowlevel, k); + } + } + } +}; +/* Recursively dispatch a key released event to a widget and its children */ +static void recursive_dispatch_key_released(MwLL handle, int* k) { + MwWidget h = (MwWidget)handle->common.user; + MwLLDispatch(handle, key_released, k); + if(h) { + int i; + for(i = 0; i < arrlen(h->children); i++) { + MwLLDispatch(h->children[i]->lowlevel, key_released, k); + if(arrlen(h->children[i]->children) > 0) { + recursive_dispatch_key_released(h->children[i]->lowlevel, k); + } + } + } +}; + @implementation MilskoCocoaPixmap + (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { @@ -85,6 +118,8 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [self->image removeRepresentation:self->rep]; [self->image dealloc]; [self->rep dealloc]; + self->image = NULL; + self->rep = NULL; } - (NSImage*)image { return self->image; @@ -103,16 +138,18 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [c retain]; /* - * MacOS doesn't really have a "default" window position, you're actually meant to center the window yourself, - * so if the user passes MwDEFAULT respond appropriately. Also for child windows just have it be 0. + * MacOS doesn't really have a "default" window position, you're actually + * meant to center the window yourself, so if the user passes MwDEFAULT + * respond appropriately. Also for child windows just have it be 0. */ if(x == MwDEFAULT) { x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; } if(y == MwDEFAULT) { - y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) : 0; + y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) + : 0; } - c->application = [NSApplication sharedApplication]; + c->application = [MilskoCocoaApplication sharedApplication]; c->rect = NSMakeRect(x, y, width, height); if(parent == NULL) { @@ -130,7 +167,6 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [c->window makeKeyAndOrderFront:c->application]; [c->window makeFirstResponder:c->view]; - [c->window setAcceptsMouseMovedEvents:MwTRUE]; c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; [c->view retain]; @@ -140,29 +176,31 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; } - [c->application activateIgnoringOtherApps:true]; + [c->application activateIgnoringOtherApps:MwTRUE]; [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; [c->application retain]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; } else { MilskoCocoa* p = parent->cocoa.real; c->window = p->window; - if(parent) { - MilskoCocoa* topmost = p; - NSRect rect = localRectFlip(c->rect, p->view); - printf("%0.2f %0.2f %0.2f %0.2f\n", c->rect.origin.x, c->rect.origin.y, c->rect.size.width, c->rect.size.height); - c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; - [c->view setBounds:c->rect]; - } else { - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - } + NSRect rect = localRectFlip(c->rect, p->view); + c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; + [c->view setBounds:c->rect]; + [c->view retain]; [c->view setNeedsDisplay:TRUE]; + [c->view setChild]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + [p->view addSubview:c->view]; [p->window setContentView:p->view]; } + [c->window setAcceptsMouseMovedEvents:MwTRUE]; c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; [c->handle retain]; @@ -208,11 +246,11 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { NSRectFill(self->view.bounds); for(i = 0; i < points_count; i++) { if(i == 0) { - [path moveToPoint:NSMakePoint(points[i].x, _rect.size.height - - points[i].y)]; + [path moveToPoint:NSMakePoint(points[i].x, + _rect.size.height - points[i].y)]; } else { - [path lineToPoint:NSMakePoint(points[i].x, _rect.size.height - - points[i].y)]; + [path lineToPoint:NSMakePoint(points[i].x, + _rect.size.height - points[i].y)]; } } @@ -262,6 +300,7 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { frame = localRectFlip(frame, parent->cocoa.real->view); [self->view setBounds:frame]; } + self->_eventsPending = MwTRUE; }; - (void)setW:(int)w H:(int)h { NSRect frame = [self->window frame]; @@ -276,23 +315,28 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { } else { [self->window setFrame:frame display:YES animate:false]; } + self->_eventsPending = MwTRUE; }; - (int)pending { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = [self->application pending]; [NSApp runModalSession:self->modalSession]; [pool release]; - return 1; + return _forceRender || _eventsPending || isPending; }; - (void)getNextEvent { - [self eventProcess:self->lastEvent]; - + MwLL h = [self->handle pointer]; if(_forceRender) { - MwLL h = [self->handle pointer]; MwLLDispatch(h, draw, NULL); [self->view setNeedsDisplay:true]; _forceRender = MwFALSE; } + if(_eventsPending) { + MwLLDispatch(h, draw, NULL); + [self->view setNeedsDisplay:true]; + _eventsPending = MwFALSE; + } [self sendClipboardEvent]; if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { @@ -306,258 +350,6 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [self->application updateWindows]; }; -- (void)eventProcess:(NSEvent*)ev { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSWindow* win = [ev window]; - MwLL h; - MwBool doSendEvent = MwTRUE; - - if(!win) { - [pool release]; - return; - } - - if([[[win contentView] subviews] count] == 0) { - printf("no subviews on %p\n", win); - [pool release]; - return; - } else { - h = [((MilskoFakePointer*)[[[win contentView] subviews] - objectAtIndex:0]) pointer]; - } - - switch([ev type]) { - case NSLeftMouseDragged: - case NSRightMouseDragged: - case NSOtherMouseDragged: - case NSMouseMoved: { - MwPoint pos; - NSPoint pos_translated = pointFlip([ev locationInWindow]); - pos.x = pos_translated.x; - pos.y = pos_translated.y; - MwLLDispatch(h, move, &pos); - break; - } - case NSLeftMouseDown: - case NSRightMouseDown: - case NSOtherMouseDown: - case NSLeftMouseUp: - case NSRightMouseUp: - case NSOtherMouseUp: { - [self handleMouseEvent:ev ll:h]; - break; - } - - case NSMouseEntered: - MwLLDispatch(h, focus_in, NULL); - [self->cursor push]; - break; - case NSMouseExited: - MwLLDispatch(h, focus_out, NULL); - [self->cursor pop]; - break; - case NSKeyDown: - case NSKeyUp: { - [self handleKeyEvent:ev ll:h]; - break; - } - case NSCursorUpdate: - [self->cursor set]; - break; - case NSScrollWheel: - break; - default: - /* mute bizarre "unknown subtype" errors that flood the console */ - break; - }; - if(doSendEvent) { - [win sendEvent:ev]; - } - [pool release]; -} - -- (void)handleMouseEvent:(NSEvent*)ev ll:(MwLL)ll { - MwLLMouse mouse; - MwBool isDown = MwTRUE; - NSPoint mousePoint = [ev locationInWindow]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - MwLL this = [self->handle pointer]; - - switch([ev type]) { - case NSLeftMouseUp: - isDown = MwFALSE; - case NSEventTypeLeftMouseDragged: - case NSLeftMouseDown: - mouse.button = MwLLMouseLeft; - break; - case NSRightMouseUp: - isDown = MwFALSE; - case NSRightMouseDown: - case NSEventTypeRightMouseDragged: - mouse.button = MwLLMouseRight; - break; - case NSOtherMouseUp: - isDown = MwFALSE; - case NSOtherMouseDown: - case NSEventTypeOtherMouseDragged: - mouse.button = MwLLMouseMiddle; - break; - default: - break; - } - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; - - printf("%s at %d %d\n", isDown ? "down" : "up", mouse.point.x, mouse.point.y); - - if(isDown) { - MwLLDispatch(ll, down, &mouse); - } else { - MwLLDispatch(ll, up, &mouse); - } -} - -- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll { - int ch; - MwLL this = [self->handle pointer]; - enum { - kVK_ANSI_A = 0x00, - kVK_ANSI_S = 0x01, - kVK_ANSI_D = 0x02, - kVK_ANSI_F = 0x03, - kVK_ANSI_H = 0x04, - kVK_ANSI_G = 0x05, - kVK_ANSI_Z = 0x06, - kVK_ANSI_X = 0x07, - kVK_ANSI_C = 0x08, - kVK_ANSI_V = 0x09, - kVK_ANSI_B = 0x0B, - kVK_ANSI_Q = 0x0C, - kVK_ANSI_W = 0x0D, - kVK_ANSI_E = 0x0E, - kVK_ANSI_R = 0x0F, - kVK_ANSI_Y = 0x10, - kVK_ANSI_T = 0x11, - kVK_ANSI_1 = 0x12, - kVK_ANSI_2 = 0x13, - kVK_ANSI_3 = 0x14, - kVK_ANSI_4 = 0x15, - kVK_ANSI_6 = 0x16, - kVK_ANSI_5 = 0x17, - kVK_ANSI_Equal = 0x18, - kVK_ANSI_9 = 0x19, - kVK_ANSI_7 = 0x1A, - kVK_ANSI_Minus = 0x1B, - kVK_ANSI_8 = 0x1C, - kVK_ANSI_0 = 0x1D, - kVK_ANSI_RightBracket = 0x1E, - kVK_ANSI_O = 0x1F, - kVK_ANSI_U = 0x20, - kVK_ANSI_LeftBracket = 0x21, - kVK_ANSI_I = 0x22, - kVK_ANSI_P = 0x23, - kVK_ANSI_L = 0x25, - kVK_ANSI_J = 0x26, - kVK_ANSI_Quote = 0x27, - kVK_ANSI_K = 0x28, - kVK_ANSI_Semicolon = 0x29, - kVK_ANSI_Backslash = 0x2A, - kVK_ANSI_Comma = 0x2B, - kVK_ANSI_Slash = 0x2C, - kVK_ANSI_N = 0x2D, - kVK_ANSI_M = 0x2E, - kVK_ANSI_Period = 0x2F, - kVK_ANSI_Grave = 0x32, - kVK_Return = 0x24, - kVK_Space = 0x31, - kVK_Escape = 0x35, - kVK_Shift = 0x38, - kVK_Control = 0x3B, - kVK_RightShift = 0x3C, - kVK_RightControl = 0x3E, - kVK_LeftArrow = 0x7B, - kVK_RightArrow = 0x7C, - kVK_DownArrow = 0x7D, - kVK_UpArrow = 0x7E - }; -#define KEY_CASE(x, y) \ - case x: \ - ch = y; \ - break; - switch([ev keyCode]) { - KEY_CASE(kVK_ANSI_A, 'a') - KEY_CASE(kVK_ANSI_B, 'b') - KEY_CASE(kVK_ANSI_C, 'c') - KEY_CASE(kVK_ANSI_D, 'd') - KEY_CASE(kVK_ANSI_E, 'e') - KEY_CASE(kVK_ANSI_F, 'f') - KEY_CASE(kVK_ANSI_G, 'g') - KEY_CASE(kVK_ANSI_H, 'h') - KEY_CASE(kVK_ANSI_I, 'i') - KEY_CASE(kVK_ANSI_J, 'j') - KEY_CASE(kVK_ANSI_K, 'k') - KEY_CASE(kVK_ANSI_L, 'l') - KEY_CASE(kVK_ANSI_M, 'm') - KEY_CASE(kVK_ANSI_N, 'n') - KEY_CASE(kVK_ANSI_O, 'o') - KEY_CASE(kVK_ANSI_P, 'p') - KEY_CASE(kVK_ANSI_Q, 'q') - KEY_CASE(kVK_ANSI_R, 'r') - KEY_CASE(kVK_ANSI_S, 's') - KEY_CASE(kVK_ANSI_T, 't') - KEY_CASE(kVK_ANSI_U, 'u') - KEY_CASE(kVK_ANSI_V, 'v') - KEY_CASE(kVK_ANSI_W, 'w') - KEY_CASE(kVK_ANSI_X, 'x') - KEY_CASE(kVK_ANSI_Y, 'y') - KEY_CASE(kVK_ANSI_Z, 'z') - KEY_CASE(kVK_ANSI_0, '0') - KEY_CASE(kVK_ANSI_1, '1') - KEY_CASE(kVK_ANSI_2, '2') - KEY_CASE(kVK_ANSI_3, '3') - KEY_CASE(kVK_ANSI_4, '4') - KEY_CASE(kVK_ANSI_5, '5') - KEY_CASE(kVK_ANSI_6, '6') - KEY_CASE(kVK_ANSI_7, '7') - KEY_CASE(kVK_ANSI_8, '8') - KEY_CASE(kVK_ANSI_9, '9') - KEY_CASE(kVK_ANSI_Quote, '\"') - KEY_CASE(kVK_ANSI_Grave, '`') - KEY_CASE(kVK_ANSI_Backslash, '/') - KEY_CASE(kVK_ANSI_Comma, ',') - KEY_CASE(kVK_ANSI_Equal, '=') - KEY_CASE(kVK_Escape, MwLLKeyEscape) - KEY_CASE(kVK_ANSI_LeftBracket, '[') - KEY_CASE(kVK_ANSI_Minus, '-') - KEY_CASE(kVK_ANSI_Period, '.') - KEY_CASE(kVK_Return, MwLLKeyEnter) - KEY_CASE(kVK_ANSI_RightBracket, ']') - KEY_CASE(kVK_ANSI_Semicolon, ';') - KEY_CASE(kVK_ANSI_Slash, '\\') - KEY_CASE(kVK_Space, ' ') - KEY_CASE(kVK_Control, MwLLKeyControl) - KEY_CASE(kVK_RightControl, MwLLKeyControl) - KEY_CASE(kVK_Shift, MwLLKeyLeftShift) - KEY_CASE(kVK_RightShift, MwLLKeyRightShift) - KEY_CASE(kVK_DownArrow, MwLLKeyDown) - KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) - KEY_CASE(kVK_RightArrow, MwLLKeyRight) - KEY_CASE(kVK_UpArrow, MwLLKeyUp) - } - switch([ev type]) { - case NSKeyDown: - MwLLDispatch(this, key, &ch); - MwLLDispatch(ll, key, &ch); - break; - case NSKeyUp: - MwLLDispatch(this, key_released, &ch); - MwLLDispatch(ll, key_released, &ch); - break; - default: - break; - } -} - - (void)sendClipboardEvent { /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; @@ -772,14 +564,42 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { return window; } +- (void)nudge { + self->_eventsPending = MwTRUE; +} + +- (void)pushCursor { + [self->cursor push]; +} +- (void)popCursor { + [self->cursor pop]; +} + - (MilskoFakePointer*)getHandle { return handle; } @end +@implementation MilskoCocoaApplication +- (void)sendEvent:(NSEvent*)event { + self->doPending = MwTRUE; + [super sendEvent:event]; +} +- (MwBool)pending { + if(self->doPending) { + self->doPending = MwFALSE; + return MwTRUE; + } + return MwFALSE; +} +@end + @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { + givenRect = frame; + x = frame.origin.x; + y = frame.origin.y; width = frame.size.width; height = frame.size.height; self = [super initWithFrame:frame]; @@ -792,9 +612,15 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { [self initRepAndContextWithWidth:width Height:height]; } + self->_child = MwFALSE; + return self; } +- (void)setChild { + self->_child = MwTRUE; +} + - (NSGraphicsContext*)context { return self->context; } @@ -871,16 +697,238 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { self->height = newSize.height; } -- (void)displayRect:(NSRect)rect { - (void)rect; -}; - -- (BOOL)acceptsFirstResponder { - return MwTRUE; +- (BOOL)canBecomeKeyView { + return YES; } -- (BOOL)performKeyEquivalent:(NSEvent*)event { - (void)event; - return MwTRUE; +- (BOOL)acceptsFirstResponder { + return YES; +} + +- (NSView*)hitTest:(NSPoint)aPoint { + if(self->_child) { + return NSPointInRect(aPoint, givenRect) ? self : nil; + } else { + return [super hitTest:aPoint]; + } +} + +- (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll down:(MwBool)isDown { + int ch; + enum { + kVK_ANSI_A = 0x00, + kVK_ANSI_S = 0x01, + kVK_ANSI_D = 0x02, + kVK_ANSI_F = 0x03, + kVK_ANSI_H = 0x04, + kVK_ANSI_G = 0x05, + kVK_ANSI_Z = 0x06, + kVK_ANSI_X = 0x07, + kVK_ANSI_C = 0x08, + kVK_ANSI_V = 0x09, + kVK_ANSI_B = 0x0B, + kVK_ANSI_Q = 0x0C, + kVK_ANSI_W = 0x0D, + kVK_ANSI_E = 0x0E, + kVK_ANSI_R = 0x0F, + kVK_ANSI_Y = 0x10, + kVK_ANSI_T = 0x11, + kVK_ANSI_1 = 0x12, + kVK_ANSI_2 = 0x13, + kVK_ANSI_3 = 0x14, + kVK_ANSI_4 = 0x15, + kVK_ANSI_6 = 0x16, + kVK_ANSI_5 = 0x17, + kVK_ANSI_Equal = 0x18, + kVK_ANSI_9 = 0x19, + kVK_ANSI_7 = 0x1A, + kVK_ANSI_Minus = 0x1B, + kVK_ANSI_8 = 0x1C, + kVK_ANSI_0 = 0x1D, + kVK_ANSI_RightBracket = 0x1E, + kVK_ANSI_O = 0x1F, + kVK_ANSI_U = 0x20, + kVK_ANSI_LeftBracket = 0x21, + kVK_ANSI_I = 0x22, + kVK_ANSI_P = 0x23, + kVK_ANSI_L = 0x25, + kVK_ANSI_J = 0x26, + kVK_ANSI_Quote = 0x27, + kVK_ANSI_K = 0x28, + kVK_ANSI_Semicolon = 0x29, + kVK_ANSI_Backslash = 0x2A, + kVK_ANSI_Comma = 0x2B, + kVK_ANSI_Slash = 0x2C, + kVK_ANSI_N = 0x2D, + kVK_ANSI_M = 0x2E, + kVK_ANSI_Period = 0x2F, + kVK_ANSI_Grave = 0x32, + kVK_Return = 0x24, + kVK_Space = 0x31, + kVK_Escape = 0x35, + kVK_Shift = 0x38, + kVK_Control = 0x3B, + kVK_RightShift = 0x3C, + kVK_RightControl = 0x3E, + kVK_LeftArrow = 0x7B, + kVK_RightArrow = 0x7C, + kVK_DownArrow = 0x7D, + kVK_UpArrow = 0x7E + }; +#define KEY_CASE(x, y) \ + case x: \ + ch = y; \ + break; + switch([ev keyCode]) { + KEY_CASE(kVK_ANSI_A, 'a') + KEY_CASE(kVK_ANSI_B, 'b') + KEY_CASE(kVK_ANSI_C, 'c') + KEY_CASE(kVK_ANSI_D, 'd') + KEY_CASE(kVK_ANSI_E, 'e') + KEY_CASE(kVK_ANSI_F, 'f') + KEY_CASE(kVK_ANSI_G, 'g') + KEY_CASE(kVK_ANSI_H, 'h') + KEY_CASE(kVK_ANSI_I, 'i') + KEY_CASE(kVK_ANSI_J, 'j') + KEY_CASE(kVK_ANSI_K, 'k') + KEY_CASE(kVK_ANSI_L, 'l') + KEY_CASE(kVK_ANSI_M, 'm') + KEY_CASE(kVK_ANSI_N, 'n') + KEY_CASE(kVK_ANSI_O, 'o') + KEY_CASE(kVK_ANSI_P, 'p') + KEY_CASE(kVK_ANSI_Q, 'q') + KEY_CASE(kVK_ANSI_R, 'r') + KEY_CASE(kVK_ANSI_S, 's') + KEY_CASE(kVK_ANSI_T, 't') + KEY_CASE(kVK_ANSI_U, 'u') + KEY_CASE(kVK_ANSI_V, 'v') + KEY_CASE(kVK_ANSI_W, 'w') + KEY_CASE(kVK_ANSI_X, 'x') + KEY_CASE(kVK_ANSI_Y, 'y') + KEY_CASE(kVK_ANSI_Z, 'z') + KEY_CASE(kVK_ANSI_0, '0') + KEY_CASE(kVK_ANSI_1, '1') + KEY_CASE(kVK_ANSI_2, '2') + KEY_CASE(kVK_ANSI_3, '3') + KEY_CASE(kVK_ANSI_4, '4') + KEY_CASE(kVK_ANSI_5, '5') + KEY_CASE(kVK_ANSI_6, '6') + KEY_CASE(kVK_ANSI_7, '7') + KEY_CASE(kVK_ANSI_8, '8') + KEY_CASE(kVK_ANSI_9, '9') + KEY_CASE(kVK_ANSI_Quote, '\"') + KEY_CASE(kVK_ANSI_Grave, '`') + KEY_CASE(kVK_ANSI_Backslash, '/') + KEY_CASE(kVK_ANSI_Comma, ',') + KEY_CASE(kVK_ANSI_Equal, '=') + KEY_CASE(kVK_Escape, MwLLKeyEscape) + KEY_CASE(kVK_ANSI_LeftBracket, '[') + KEY_CASE(kVK_ANSI_Minus, '-') + KEY_CASE(kVK_ANSI_Period, '.') + KEY_CASE(kVK_Return, MwLLKeyEnter) + KEY_CASE(kVK_ANSI_RightBracket, ']') + KEY_CASE(kVK_ANSI_Semicolon, ';') + KEY_CASE(kVK_ANSI_Slash, '\\') + KEY_CASE(kVK_Space, ' ') + KEY_CASE(kVK_Control, MwLLKeyControl) + KEY_CASE(kVK_RightControl, MwLLKeyControl) + KEY_CASE(kVK_Shift, MwLLKeyLeftShift) + KEY_CASE(kVK_RightShift, MwLLKeyRightShift) + KEY_CASE(kVK_DownArrow, MwLLKeyDown) + KEY_CASE(kVK_LeftArrow, MwLLKeyLeft) + KEY_CASE(kVK_RightArrow, MwLLKeyRight) + KEY_CASE(kVK_UpArrow, MwLLKeyUp) + } + if(isDown) { + recursive_dispatch_key(ll, &ch); + } else { + recursive_dispatch_key_released(ll, &ch); + } + [ll->cocoa.real nudge]; +} +- (void)mouseEntered:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_in, NULL); + [h->cocoa.real pushCursor]; + [super mouseEntered:ev]; +} +- (void)mouseExited:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + MwLLDispatch(h, focus_out, NULL); + [h->cocoa.real popCursor]; + [super mouseExited:ev]; +} +- (void)keyDown:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + [self handleKeyEvent:ev ll:h down:MwTRUE]; + [super keyDown:ev]; +} +- (void)keyUp:(NSEvent*)ev { + MwLL h = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + [self handleKeyEvent:ev ll:h down:MwFALSE]; + [super keyUp:ev]; +} + +- (void)mouseMoved:(NSEvent*)ev { + MwLLMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwLLMouseLeft; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, move, &mouse); + [this->cocoa.real nudge]; + [super mouseMoved:ev]; +} +- (void)mouseDown:(NSEvent*)ev { + MwLLMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwLLMouseLeft; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, down, &mouse); + [this->cocoa.real nudge]; + [super mouseDown:ev]; +} + +- (void)mouseUp:(NSEvent*)ev { + MwLLMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwLLMouseLeft; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, up, &mouse); + [this->cocoa.real nudge]; + [super mouseUp:ev]; +} +- (void)rightMouseDown:(NSEvent*)ev { + MwLLMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwLLMouseRight; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, down, &mouse); + [this->cocoa.real nudge]; + [super rightMouseDown:ev]; +} + +- (void)rightMouseUp:(NSEvent*)ev { + MwLLMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwLLMouseRight; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; + MwLLDispatch(this, up, &mouse); + [this->cocoa.real nudge]; + [super rightMouseUp:ev]; } @end From 74779c8f4233192f9fa47771a11de395ead0f734 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 18:21:27 -0700 Subject: [PATCH 241/409] apple: better polygons, revealing a bigger issue maybe --- src/backend/cocoa.m | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index d3fec7ebb..114cb3a5e 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -243,14 +243,16 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [NSGraphicsContext setCurrentContext:ctx]; [nscolor setFill]; - NSRectFill(self->view.bounds); for(i = 0; i < points_count; i++) { - if(i == 0) { - [path moveToPoint:NSMakePoint(points[i].x, - _rect.size.height - points[i].y)]; + NSPoint p = NSMakePoint(points[i].x, [self->view frame].size.height - points[i].y); + if((i % 3) == 0) { + if(i != 0) { + [path lineToPoint:p]; + [path fill]; + } + [path moveToPoint:p]; } else { - [path lineToPoint:NSMakePoint(points[i].x, - _rect.size.height - points[i].y)]; + [path lineToPoint:p]; } } From bcb108ae5f52a5c3b6a3cbee4c6b8f96f1f5cb8f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 18:47:58 -0700 Subject: [PATCH 242/409] apple: 'more correct' polygons weren't correct at all --- src/backend/cocoa.m | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 114cb3a5e..57dea3be2 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -245,11 +245,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [nscolor setFill]; for(i = 0; i < points_count; i++) { NSPoint p = NSMakePoint(points[i].x, [self->view frame].size.height - points[i].y); - if((i % 3) == 0) { - if(i != 0) { - [path lineToPoint:p]; - [path fill]; - } + if(i == 0) { [path moveToPoint:p]; } else { [path lineToPoint:p]; From 0bbbc51bb9f9418cbcd7c531125efc5dcb5f9557 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 18:53:13 -0700 Subject: [PATCH 243/409] apple: fix polygon/pixmap coordinates, add line function --- src/backend/cocoa.m | 44 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 57dea3be2..1632271e5 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -34,6 +34,9 @@ static NSRect localRectFlip(NSRect originFrame, NSView* view) { originFrame.size.width, originFrame.size.height); return destinationFrame; } +static NSPoint localPointFlip(NSPoint point, NSView* view) { + return localRectFlip(NSMakeRect(point.x, point.y, 0, 0), view).origin; +} /* Recursively dispatch a key event to a widget and its children */ static void recursive_dispatch_key(MwLL handle, int* k) { @@ -244,7 +247,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [nscolor setFill]; for(i = 0; i < points_count; i++) { - NSPoint p = NSMakePoint(points[i].x, [self->view frame].size.height - points[i].y); + NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); if(i == 0) { [path moveToPoint:p]; } else { @@ -262,8 +265,41 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [pool release]; }; - (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { - (void)points; - (void)color; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + /* whatever rect we use for coordinate flipping */ + NSRect _rect = parent ? [self->view bounds] : [self->window frame]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; + + [nscolor setFill]; + for(i = 0; i < 2; i++) { + NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); + if(i == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path stroke]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } + [pool release]; }; - (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { NSRect frame; @@ -394,7 +430,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [NSGraphicsContext setCurrentContext:ctx]; [[p image] - drawInRect:NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height) + drawInRect:localRectFlip(NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height), self->view) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; From 90706b184f0c9e936c1481933fa2c584e91ae95a Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 19:09:01 -0700 Subject: [PATCH 244/409] apple: assorted fixes --- src/backend/cocoa.m | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1632271e5..7a138af40 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1,9 +1,6 @@ -#include "Mw/BaseTypes.h" -#include "Mw/LowLevel.h" #include -#include #include "../../external/stb_ds.h" -#include "Mw/TypeDefs.h" +#include "Mw/LowLevel/Cocoa.h" #ifdef __clang__ #pragma clang push @@ -904,9 +901,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (void)mouseMoved:(NSEvent*)ev { MwLLMouse mouse; - NSPoint mousePoint = [ev locationInWindow]; + NSPoint mousePoint = pointFlip([ev locationInWindow]); MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; mouse.button = MwLLMouseLeft; mouse.point.x = mousePoint.x; mouse.point.y = mousePoint.y; @@ -914,6 +910,10 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [this->cocoa.real nudge]; [super mouseMoved:ev]; } +- (BOOL)mouseDownCanMoveWindow { + return NO; +} + - (void)mouseDown:(NSEvent*)ev { MwLLMouse mouse; NSPoint mousePoint = [ev locationInWindow]; @@ -990,11 +990,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (NSSize)windowWillResize:(NSWindow*)win toSize:(NSSize)frameSize; { if([[[win contentView] subviews] count] >= 1) { - MilskoFakePointer* ptr = [[[win contentView] subviews] objectAtIndex:0]; - MwLL h = [ptr pointer]; - - MwLLDispatch(h, resize, NULL); - MwLLDispatch(h, draw, NULL); + NSView* ptr = [[[win contentView] subviews] objectAtIndex:0]; + if([ptr isKindOfClass:[MilskoFakePointer class]]) { + MwLL h = [(MilskoFakePointer*)ptr pointer]; + MwLLDispatch(h, resize, NULL); + // MwLLDispatch(h, draw, NULL); + } } return frameSize; } @@ -1159,6 +1160,7 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, (void)handle; MwLLPixmap r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); r->common.raw = malloc(4 * width * height); memcpy(r->common.raw, data, 4 * width * height); @@ -1169,7 +1171,6 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, r->cocoa.real = [MilskoCocoaPixmap newWithWidth:width height:height]; MwLLPixmapUpdate(r); - free(r->common.raw); return r; } From 6ba77904d62df440f79c4b349b4afb3c1eb3db83 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 25 Mar 2026 21:06:32 -0700 Subject: [PATCH 245/409] fix hitTest --- src/backend/cocoa.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 7a138af40..04ce17edf 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -737,7 +737,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (NSView*)hitTest:(NSPoint)aPoint { if(self->_child) { - return NSPointInRect(aPoint, givenRect) ? self : nil; + return NSPointInRect(aPoint, [self bounds]) ? self : nil; } else { return [super hitTest:aPoint]; } From 70f7f8f0842f33e4c28c091ee9f812cd6e22ebd7 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 27 Mar 2026 11:05:15 +0900 Subject: [PATCH 246/409] fix box bug --- src/widget/box.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widget/box.c b/src/widget/box.c index 99f3e0772..4c4ae687c 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -53,6 +53,7 @@ static void layout(MwWidget handle) { sz -= s + Margin; } else { sum += n; + sz -= Margin; } } From 8d7016367e8f2f40b9d91899250e1999fa1a5304 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 14:40:21 -0700 Subject: [PATCH 247/409] experimental rounded corners idea --- include/Mw/Draw.h | 6 +- include/Mw/LowLevel.h | 9 +- include/Mw/LowLevel/Wayland.h | 3 + src/backend/wayland.c | 3 + src/draw.c | 232 ++++++++++++++++++++++++++++------ src/widget/box.c | 2 +- src/widget/combobox.c | 2 +- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/listbox.c | 6 +- src/widget/menu.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 8 +- src/widget/window.c | 2 +- 16 files changed, 223 insertions(+), 62 deletions(-) diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index b90d4e423..4fb74c201 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -53,7 +53,7 @@ MWDECL void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); * @param rect Rectangle area * @param color Color */ -MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); +MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounded); /*! * @brief Draws a frame @@ -63,7 +63,7 @@ MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); * @param invert Invert the 3D border color or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert); +MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int rounded); /*! * @brief Does the DrawFrame/DrawRect combo used for drawing widget. @@ -95,7 +95,7 @@ MWDECL void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int i * @param same Same as dark color * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); +MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded); /*! * @brief Creates a pixmap from image diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 9766d052f..d7ddb4b45 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -34,10 +34,11 @@ enum MwLLBackends { }; struct _MwLLCommon { - void* user; - int copy_buffer; - int type; - int coordinate_type; + void* user; + int copy_buffer; + int type; + int coordinate_type; + MwBool supports_transparency; MwLLHandler handler; }; diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index c24ce3cec..de7828ad5 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -123,6 +123,7 @@ typedef struct wayland_call_table { void (*cairo_fill)(cairo_t* cr); void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, cairo_filter_t filter); + void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); } wayland_call_table_t; @@ -201,6 +202,7 @@ MwInline int wayland_load_funcs() { CAIRO_FUNC(cairo_rectangle); CAIRO_FUNC(cairo_new_path); CAIRO_FUNC(cairo_set_line_cap); + CAIRO_FUNC(cairo_set_antialias); CAIRO_FUNC(cairo_set_source_rgba); CAIRO_FUNC(cairo_set_source_rgb); CAIRO_FUNC(cairo_reset_clip); @@ -257,6 +259,7 @@ MwInline int wayland_load_funcs() { #define cairo_rectangle wl_call_tbl.cairo_rectangle #define cairo_new_path wl_call_tbl.cairo_new_path #define cairo_set_line_cap wl_call_tbl.cairo_set_line_cap +#define cairo_set_antialias wl_call_tbl.cairo_set_antialias #define cairo_set_source_rgba wl_call_tbl.cairo_set_source_rgba #define cairo_set_source_rgb wl_call_tbl.cairo_set_source_rgb #define cairo_reset_clip wl_call_tbl.cairo_reset_clip diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 5ba779b1c..f747955e2 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1972,6 +1972,9 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { int i; + clip(handle); + + cairo_set_antialias(handle->wayland.front_cairo, CAIRO_ANTIALIAS_NONE); cairo_set_line_cap(handle->wayland.front_cairo, CAIRO_LINE_CAP_SQUARE); cairo_set_source_rgb(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); cairo_new_path(handle->wayland.front_cairo); diff --git a/src/draw.c b/src/draw.c index 4286d6696..274623772 100644 --- a/src/draw.c +++ b/src/draw.c @@ -11,9 +11,12 @@ #include "../external/stb_ds.h" +#define BORDER_ROUNDNESS 10 +#define BORDER_SMOOTHNESS 50 + static int get_color_diff(MwWidget handle) { if(MwGetInteger(handle, MwNmodernLook)) { - return 46; + return 23; } else { return 80; } @@ -29,7 +32,7 @@ static int hex(const char* txt, int len) { n = c - 'a' + 10; } else if('A' <= c && c <= 'F') { n = c - 'A' + 10; - } else if('0' <= c && c <= '9') { + } else if('0' <= c && c <= 'g') { n = c - '0'; } r = r << 4; @@ -102,14 +105,15 @@ void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPolygon(handle->lowlevel, p, 4, color); } -void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { +void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounded) { MwLLPixmap pixmap; - int y; + int y, i; double darken = 0.; int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 4.) / rect->height; unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz); + MwRect r = *rect; memset(data, 0, sz); for(y = 0; y < rect->height; y++) { @@ -124,18 +128,64 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { } pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - MwLLDrawPixmap(handle->lowlevel, rect, pixmap); + if(rounded && rect->height >= (BORDER_ROUNDNESS * 2) && rect->width >= (BORDER_ROUNDNESS * 2)) { + int xt; + int x = rect->x + (BORDER_ROUNDNESS + 1); + int y = rect->y + (BORDER_ROUNDNESS + 1); + for(i = 0; i < BORDER_ROUNDNESS; i++) { + double point = ((i + (M_PI * 4)) / 7.); + double point2 = (((i + 1) + (M_PI * 4)) / 7.); + int x2 = x - (sin(point2) * BORDER_ROUNDNESS); + r.x = x - (sin(point) * BORDER_ROUNDNESS); + r.y = y + (cos(point) * BORDER_ROUNDNESS); + r.width = (x - (sin(point + 1) * BORDER_ROUNDNESS)) - r.x; + r.height = (rect->height - ((r.y - rect->y) * 2) - 1); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + for(xt = x; xt < x2; xt++) { + r.x = xt; + r.y = y + (cos(point2) * BORDER_ROUNDNESS); + r.height = (rect->height - ((r.y - rect->y)) - 1); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + } + } + r = *rect; + r.x += BORDER_ROUNDNESS; + r.width -= (BORDER_ROUNDNESS * 2); + r.height -= 1; + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + r = *rect; + x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); + y = rect->y + (BORDER_ROUNDNESS + 1); + for(i = 0; i < BORDER_ROUNDNESS; i++) { + double point = ((i + (M_PI * 4)) / 7.); + double point2 = (((i + 1) + (M_PI * 4)) / 7.); + int x2 = x + (sin(point2) * BORDER_ROUNDNESS); + r.x = x + (sin(point) * BORDER_ROUNDNESS); + r.y = y + (cos(point) * BORDER_ROUNDNESS); + r.width = 1; + r.height = (rect->height - ((r.y - rect->y) * 2) - 1); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + for(xt = x; xt < x2; xt++) { + r.x = xt; + r.y = y + (cos(point2) * BORDER_ROUNDNESS); + r.height = (rect->height - ((r.y - rect->y) * 2) - 2); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + } + } + } else { + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + } MwLLDestroyPixmap(pixmap); free(data); } -void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { +void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int rounded) { int inv; if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0); + MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0, rounded); } else { int diff = get_color_diff(handle) / 3 * 2; @@ -143,11 +193,11 @@ void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { int i; int st = invert ? 1 : 0; for(i = st; i < st + 2; i++) { - if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0); - if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0); + if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0, 0); + if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0, 0); } } else { - MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0); + MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0, 0); } } } @@ -156,11 +206,11 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert MwLLColor col; if(border) { - MwDrawFrame(handle, rect, color, invert); + MwDrawFrame(handle, rect, color, invert, handle->lowlevel->common.supports_transparency); } col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawRectFading(handle, rect, col); + MwDrawRectFading(handle, rect, col, handle->lowlevel->common.supports_transparency); } else { MwDrawRect(handle, rect, col); } @@ -234,54 +284,158 @@ void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwLLFreeColor(darker); } -void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { - MwPoint p[6]; +void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded) { + MwPoint p[7]; int ColorDiff = get_color_diff(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); + int i; + MwLLColor middle = MwLLAllocColor(handle->lowlevel, + (lighter->common.red * darker->common.red) / 255, + (lighter->common.green * darker->common.green) / 255, + (lighter->common.blue * darker->common.blue) / 255); - p[0].x = rect->x; - p[0].y = rect->y; + if(rounded) { + /* top left edge */ + for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { + MwPoint line[2]; + double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); + int x = rect->x + (BORDER_ROUNDNESS + 2); + int y = rect->y + (BORDER_ROUNDNESS + 2); - p[1].x = rect->x + rect->width; - p[1].y = rect->y; + line[0].x = x - (sin(point) * BORDER_ROUNDNESS); + line[0].y = y + (cos(point) * BORDER_ROUNDNESS); + line[1].x = x - (sin(point + 1) * BORDER_ROUNDNESS); + line[1].y = y + (cos(point + 1) * BORDER_ROUNDNESS); + MwLLLine(handle->lowlevel, line, invert ? darker : lighter); + } - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + border; + p[0].x = rect->x + BORDER_ROUNDNESS; + p[0].y = rect->y; - p[3].x = rect->x + border; - p[3].y = rect->y + border; + p[1].x = rect->x + rect->width - BORDER_ROUNDNESS; + p[1].y = rect->y; - p[4].x = rect->x + border; - p[4].y = rect->y + rect->height - border; + p[2].x = rect->x + rect->width - border - BORDER_ROUNDNESS; + p[2].y = rect->y + border; - p[5].x = rect->x; - p[5].y = rect->y + rect->height; + p[3].x = rect->x + border - BORDER_ROUNDNESS; + p[3].y = rect->y + border + BORDER_ROUNDNESS; + p[4].x = rect->x + border - BORDER_ROUNDNESS; + p[4].y = rect->y + rect->height - border - BORDER_ROUNDNESS; + + p[5].x = rect->x + BORDER_ROUNDNESS; + p[5].y = rect->y + rect->height - BORDER_ROUNDNESS; + MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); + + /* top right edge */ + for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { + MwPoint line[2]; + double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); + int x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); + int y = rect->y + (BORDER_ROUNDNESS + 2); + double placeholder = (sin(point) * BORDER_ROUNDNESS); + line[0].x = x + placeholder; + line[0].y = y + (cos(point) * BORDER_ROUNDNESS); + line[1].x = x + (sin(point + 1) * BORDER_ROUNDNESS); + line[1].y = y + (cos(point + 1) * BORDER_ROUNDNESS); + MwLLLine(handle->lowlevel, line, middle); + } + } else { + p[0].x = rect->x; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width; + p[1].y = rect->y; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; + + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; + + p[5].x = rect->x; + p[5].y = rect->y + rect->height; + } MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); - p[0].x = rect->x + rect->width; - p[0].y = rect->y; + if(rounded && rect->height >= (BORDER_ROUNDNESS * 2) && rect->width >= (BORDER_ROUNDNESS * 2)) { + /* bottom left edge */ + for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { + MwPoint line[2]; + double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); + int x = rect->x + (BORDER_ROUNDNESS + 2); + int y = (rect->y + rect->height) - (BORDER_ROUNDNESS + 2); - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border; + line[0].x = x - (sin(point) * BORDER_ROUNDNESS); + line[0].y = y - (cos(point) * BORDER_ROUNDNESS); + line[1].x = x - (sin(point + 1) * BORDER_ROUNDNESS); + line[1].y = y - (cos(point + 1) * BORDER_ROUNDNESS); + MwLLLine(handle->lowlevel, line, middle); + } + p[0].x = rect->x + BORDER_ROUNDNESS; + p[0].y = rect->y + 1; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border; + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border + BORDER_ROUNDNESS; - p[3].x = rect->x + border; - p[3].y = rect->y + rect->height - border; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border - BORDER_ROUNDNESS; - p[4].x = rect->x; - p[4].y = rect->y + rect->height; + p[3].x = rect->x + rect->width - border - BORDER_ROUNDNESS; + p[3].y = rect->y + rect->height - border; - p[5].x = rect->x + rect->width; - p[5].y = rect->y + rect->height; + p[4].x = rect->x + border + BORDER_ROUNDNESS; + p[4].y = rect->y + rect->height - border; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[5].x = rect->x + BORDER_ROUNDNESS; + p[5].y = rect->y + rect->height - BORDER_ROUNDNESS; + + p[6].x = rect->x + rect->width - BORDER_ROUNDNESS; + p[6].y = rect->y + rect->height - BORDER_ROUNDNESS; + + MwLLPolygon(handle->lowlevel, p, 7, invert ? lighter : darker); + + /* bottom right edge */ + for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { + MwPoint line[2]; + double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); + int x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); + int y = (rect->y + rect->height) - (BORDER_ROUNDNESS + 2); + + line[0].x = x + (sin(point) * BORDER_ROUNDNESS); + line[0].y = y - (cos(point) * BORDER_ROUNDNESS); + line[1].x = x + (sin(point + 1) * BORDER_ROUNDNESS); + line[1].y = y - (cos(point + 1) * BORDER_ROUNDNESS); + MwLLLine(handle->lowlevel, line, middle); + } + } else { + p[0].x = rect->x + rect->width; + p[0].y = rect->y; + + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; + + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; + + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; + + p[4].x = rect->x; + p[4].y = rect->y + rect->height; + + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + } MwLLFreeColor(lighter); MwLLFreeColor(darker); + MwLLFreeColor(middle); rect->x += border; rect->y += border; diff --git a/src/widget/box.c b/src/widget/box.c index 4c4ae687c..d8d474519 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -24,7 +24,7 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); if(MwGetInteger(handle, MwNhasBorder)) { - MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); + MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted), 0); } MwDrawRect(handle, &r, base); diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 6b5437335..0672ff3ad 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -72,7 +72,7 @@ static void draw(MwWidget handle) { r.y += r.height; r.height = MwDefaultBorderWidth(handle) * 2; - MwDrawFrame(handle, &r, base, 0); + MwDrawFrame(handle, &r, base, 0, 0); MwLLFreeColor(text); MwLLFreeColor(base); diff --git a/src/widget/frame.c b/src/widget/frame.c index 117b0f8b9..3c2ffe99f 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -22,7 +22,7 @@ static void draw(MwWidget handle) { fr.y = 0; fr.width = MwGetInteger(handle, MwNwidth); fr.height = MwGetInteger(handle, MwNheight); - MwDrawFrame(handle, &fr, base, inverted); + MwDrawFrame(handle, &fr, base, inverted, 0); rr.x = MwDefaultBorderWidth(handle); rr.y = MwDefaultBorderWidth(handle); diff --git a/src/widget/image.c b/src/widget/image.c index 74ee0bfd6..cadddb323 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -20,7 +20,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted), 0); MwDrawRect(handle, &r, base); if(px != NULL) { diff --git a/src/widget/listbox.c b/src/widget/listbox.c index cb84e44c4..be467084a 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -208,7 +208,7 @@ static void frame_draw(MwWidget handle) { p.x = MwDefaultBorderWidth(handle); p.y = MwDefaultBorderWidth(handle); - MwDrawFrame(handle, &r, base, 1); + MwDrawFrame(handle, &r, base, 1, 0); MwDrawRect(handle, &r, base2); r = r2; @@ -282,7 +282,7 @@ static void frame_draw(MwWidget handle) { handle->bgcolor = NULL; } - MwDrawFrame(handle, &r, base, 1); + MwDrawFrame(handle, &r, base, 1, 0); MwLLFreeColor(text2); MwLLFreeColor(text); @@ -401,7 +401,7 @@ static void draw(MwWidget handle) { r.y = 0; r.width = get_col_width(lb, i); r.height = MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, "M"); - MwDrawFrame(handle, &r, base, 0); + MwDrawFrame(handle, &r, base, 0, 0); x += MwDefaultBorderWidth(handle); diff --git a/src/widget/menu.c b/src/widget/menu.c index 44fc2fe57..e360f3d91 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -100,7 +100,7 @@ static void draw(MwWidget handle) { BEGIN_MENU_LOOP; if(m->sub[i]->wsub != NULL || (in_area && handle->pressed)) { - MwDrawFrame(handle, &r, base, MwFALSE); + MwDrawFrame(handle, &r, base, MwFALSE, 0); MwDrawWidgetBack(handle, &r, base, 0, MwFALSE); } diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index d85a8ddaf..7be7bffd7 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -23,7 +23,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawFrame(handle, &r, base, 1); + MwDrawFrame(handle, &r, base, 1, 0); MwDrawRect(handle, &r, base); w = MwGetInteger(handle, MwNvalue) - MwGetInteger(handle, MwNminValue); w = w / (MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue)); diff --git a/src/widget/separator.c b/src/widget/separator.c index 8fcfc5b71..571c5dfa9 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -25,7 +25,7 @@ static void draw(MwWidget handle) { r.y = (r.height - 2) / 2; r.height = 2; } - MwDrawFrameEx(handle, &r, base, 1, 1, 0, 0); + MwDrawFrameEx(handle, &r, base, 1, 1, 0, 0, MwGetInteger(handle, MwNmodernLook)); MwLLFreeColor(base); } diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 828155014..88607ffc0 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -59,7 +59,7 @@ static void draw(MwWidget handle) { rc.x += MwGetInteger(handle, MwNleftPadding); - MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0); + MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0, 0); p.y += 2 + 1; } else { diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 76e1e0139..3a335be32 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -64,7 +64,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** const int len = 4; MwDrawRect(handle, &r, col); - MwDrawFrame(handle, &r, base, tree->opened); + MwDrawFrame(handle, &r, base, tree->opened, 0); if(tree->opened) { l[0].x = r.x + (r.width - len) / 2; l[0].y = r.y + r.height / 2; @@ -91,7 +91,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** MwLLLine(handle->lowlevel, &l[0], text); } r = r2; - MwDrawFrame(handle, &r, base, tree->opened); + MwDrawFrame(handle, &r, base, tree->opened, 0); if(col != base) MwLLFreeColor(col); } else { @@ -183,7 +183,7 @@ static void frame_draw(MwWidget handle) { p.x = MwDefaultBorderWidth(handle); p.y = MwDefaultBorderWidth(handle); - MwDrawFrame(handle, &r, base, 1); + MwDrawFrame(handle, &r, base, 1, 0); MwDrawRect(handle, &r, base2); r = r2; @@ -193,7 +193,7 @@ static void frame_draw(MwWidget handle) { recursion(handle, tv->tree[i], tv->tree, base, text, base2, text2, &p, 0, LineSpace, &skip, &shared, 1, NULL); } - MwDrawFrame(handle, &r, base, 1); + MwDrawFrame(handle, &r, base, 1, 0); MwLLFreeColor(text2); MwLLFreeColor(text); diff --git a/src/widget/window.c b/src/widget/window.c index 979e073c8..74a96e61e 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -18,7 +18,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, c, MwGetInteger(handle, MwNinverted)); + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, c, MwGetInteger(handle, MwNinverted), 0); MwDrawRect(handle, &r, c); From 548d6c46fd2d7b9df2f75b7c9ab8c8df4169f17e Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 15:17:01 -0700 Subject: [PATCH 248/409] r --- include/Mw/StringDefs.h | 1 + src/backend/wayland.c | 1 + src/draw.c | 152 +++++++++++++++++++++------------------- 3 files changed, 82 insertions(+), 72 deletions(-) diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index db597889f..832096338 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -39,6 +39,7 @@ #define MwNsevenSegment "IsevenSegment" #define MwNlength "Ilength" #define MwNforceInverted "IforceInverted" +#define MwNroundness "Iroundness" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/src/backend/wayland.c b/src/backend/wayland.c index f747955e2..d43a2c595 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1719,6 +1719,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r = malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + r->common.supports_transparency = MwTRUE; widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); diff --git a/src/draw.c b/src/draw.c index 274623772..e367c2f78 100644 --- a/src/draw.c +++ b/src/draw.c @@ -11,7 +11,8 @@ #include "../external/stb_ds.h" -#define BORDER_ROUNDNESS 10 +#define DEFAULT_ROUNDNESS 10 +#define MAX_ROUNDNESS 30 #define BORDER_SMOOTHNESS 50 static int get_color_diff(MwWidget handle) { @@ -114,6 +115,11 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz); MwRect r = *rect; + int roundness = MwGetInteger(handle, MwNroundness); + double h; + if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; + if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; + h = (roundness <= 10) ? 7. : 10.; memset(data, 0, sz); for(y = 0; y < rect->height; y++) { @@ -128,46 +134,46 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde } pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - if(rounded && rect->height >= (BORDER_ROUNDNESS * 2) && rect->width >= (BORDER_ROUNDNESS * 2)) { + if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { int xt; - int x = rect->x + (BORDER_ROUNDNESS + 1); - int y = rect->y + (BORDER_ROUNDNESS + 1); - for(i = 0; i < BORDER_ROUNDNESS; i++) { - double point = ((i + (M_PI * 4)) / 7.); - double point2 = (((i + 1) + (M_PI * 4)) / 7.); - int x2 = x - (sin(point2) * BORDER_ROUNDNESS); - r.x = x - (sin(point) * BORDER_ROUNDNESS); - r.y = y + (cos(point) * BORDER_ROUNDNESS); - r.width = (x - (sin(point + 1) * BORDER_ROUNDNESS)) - r.x; + int x = rect->x + (roundness + 1); + int y = rect->y + (roundness + 1); + for(i = 0; i < roundness; i++) { + double point = ((i + (M_PI * 4)) / h); + double point2 = (((i + 1) + (M_PI * 4)) / h); + int x2 = x - (sin(point2) * roundness); + r.x = x - (sin(point) * roundness); + r.y = y + (cos(point) * roundness); + r.width = (x - (sin(point + 1) * roundness)) - r.x; r.height = (rect->height - ((r.y - rect->y) * 2) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); for(xt = x; xt < x2; xt++) { r.x = xt; - r.y = y + (cos(point2) * BORDER_ROUNDNESS); + r.y = y + (cos(point2) * roundness); r.height = (rect->height - ((r.y - rect->y)) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); } } r = *rect; - r.x += BORDER_ROUNDNESS; - r.width -= (BORDER_ROUNDNESS * 2); + r.x += roundness; + r.width -= (roundness * 2); r.height -= 1; MwLLDrawPixmap(handle->lowlevel, &r, pixmap); r = *rect; - x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); - y = rect->y + (BORDER_ROUNDNESS + 1); - for(i = 0; i < BORDER_ROUNDNESS; i++) { - double point = ((i + (M_PI * 4)) / 7.); - double point2 = (((i + 1) + (M_PI * 4)) / 7.); - int x2 = x + (sin(point2) * BORDER_ROUNDNESS); - r.x = x + (sin(point) * BORDER_ROUNDNESS); - r.y = y + (cos(point) * BORDER_ROUNDNESS); + x = (rect->x + rect->width) - (roundness + 2); + y = rect->y + (roundness + 1); + for(i = 0; i < roundness; i++) { + double point = ((i + (M_PI * 4)) / h); + double point2 = (((i + 1) + (M_PI * 4)) / h); + int x2 = x + (sin(point2) * roundness); + r.x = x + (sin(point) * roundness); + r.y = y + (cos(point) * roundness); r.width = 1; r.height = (rect->height - ((r.y - rect->y) * 2) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); for(xt = x; xt < x2; xt++) { r.x = xt; - r.y = y + (cos(point2) * BORDER_ROUNDNESS); + r.y = y + (cos(point2) * roundness); r.height = (rect->height - ((r.y - rect->y) * 2) - 2); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); } @@ -290,56 +296,58 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); int i; - MwLLColor middle = MwLLAllocColor(handle->lowlevel, - (lighter->common.red * darker->common.red) / 255, - (lighter->common.green * darker->common.green) / 255, - (lighter->common.blue * darker->common.blue) / 255); - - if(rounded) { + MwLLColor middle = MwLLAllocColor(handle->lowlevel, + (lighter->common.red * darker->common.red) / 255, + (lighter->common.green * darker->common.green) / 255, + (lighter->common.blue * darker->common.blue) / 255); + int roundness = MwGetInteger(handle, MwNroundness); + if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; + if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; + if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { /* top left edge */ for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { MwPoint line[2]; double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = rect->x + (BORDER_ROUNDNESS + 2); - int y = rect->y + (BORDER_ROUNDNESS + 2); + int x = rect->x + (roundness + 2); + int y = rect->y + (roundness + 2); - line[0].x = x - (sin(point) * BORDER_ROUNDNESS); - line[0].y = y + (cos(point) * BORDER_ROUNDNESS); - line[1].x = x - (sin(point + 1) * BORDER_ROUNDNESS); - line[1].y = y + (cos(point + 1) * BORDER_ROUNDNESS); + line[0].x = x - (sin(point) * roundness); + line[0].y = y + (cos(point) * roundness); + line[1].x = x - (sin(point + 1) * roundness); + line[1].y = y + (cos(point + 1) * roundness); MwLLLine(handle->lowlevel, line, invert ? darker : lighter); } - p[0].x = rect->x + BORDER_ROUNDNESS; + p[0].x = rect->x + roundness; p[0].y = rect->y; - p[1].x = rect->x + rect->width - BORDER_ROUNDNESS; + p[1].x = rect->x + rect->width - roundness; p[1].y = rect->y; - p[2].x = rect->x + rect->width - border - BORDER_ROUNDNESS; + p[2].x = rect->x + rect->width - border - roundness; p[2].y = rect->y + border; - p[3].x = rect->x + border - BORDER_ROUNDNESS; - p[3].y = rect->y + border + BORDER_ROUNDNESS; + p[3].x = rect->x + border - roundness; + p[3].y = rect->y + border + roundness; - p[4].x = rect->x + border - BORDER_ROUNDNESS; - p[4].y = rect->y + rect->height - border - BORDER_ROUNDNESS; + p[4].x = rect->x + border - roundness; + p[4].y = rect->y + rect->height - border - roundness; - p[5].x = rect->x + BORDER_ROUNDNESS; - p[5].y = rect->y + rect->height - BORDER_ROUNDNESS; + p[5].x = rect->x + roundness; + p[5].y = rect->y + rect->height - roundness; MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); /* top right edge */ for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { MwPoint line[2]; double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); - int y = rect->y + (BORDER_ROUNDNESS + 2); - double placeholder = (sin(point) * BORDER_ROUNDNESS); + int x = (rect->x + rect->width) - (roundness + 2); + int y = rect->y + (roundness + 2); + double placeholder = (sin(point) * roundness); line[0].x = x + placeholder; - line[0].y = y + (cos(point) * BORDER_ROUNDNESS); - line[1].x = x + (sin(point + 1) * BORDER_ROUNDNESS); - line[1].y = y + (cos(point + 1) * BORDER_ROUNDNESS); + line[0].y = y + (cos(point) * roundness); + line[1].x = x + (sin(point + 1) * roundness); + line[1].y = y + (cos(point + 1) * roundness); MwLLLine(handle->lowlevel, line, middle); } } else { @@ -362,40 +370,40 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i } MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); - if(rounded && rect->height >= (BORDER_ROUNDNESS * 2) && rect->width >= (BORDER_ROUNDNESS * 2)) { + if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { /* bottom left edge */ for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { MwPoint line[2]; double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = rect->x + (BORDER_ROUNDNESS + 2); - int y = (rect->y + rect->height) - (BORDER_ROUNDNESS + 2); + int x = rect->x + (roundness + 2); + int y = (rect->y + rect->height) - (roundness + 2); - line[0].x = x - (sin(point) * BORDER_ROUNDNESS); - line[0].y = y - (cos(point) * BORDER_ROUNDNESS); - line[1].x = x - (sin(point + 1) * BORDER_ROUNDNESS); - line[1].y = y - (cos(point + 1) * BORDER_ROUNDNESS); + line[0].x = x - (sin(point) * roundness); + line[0].y = y - (cos(point) * roundness); + line[1].x = x - (sin(point + 1) * roundness); + line[1].y = y - (cos(point + 1) * roundness); MwLLLine(handle->lowlevel, line, middle); } - p[0].x = rect->x + BORDER_ROUNDNESS; + p[0].x = rect->x + roundness; p[0].y = rect->y + 1; p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border + BORDER_ROUNDNESS; + p[1].y = rect->y + border + roundness; p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border - BORDER_ROUNDNESS; + p[2].y = rect->y + rect->height - border - roundness; - p[3].x = rect->x + rect->width - border - BORDER_ROUNDNESS; + p[3].x = rect->x + rect->width - border - roundness; p[3].y = rect->y + rect->height - border; - p[4].x = rect->x + border + BORDER_ROUNDNESS; + p[4].x = rect->x + border + roundness; p[4].y = rect->y + rect->height - border; - p[5].x = rect->x + BORDER_ROUNDNESS; - p[5].y = rect->y + rect->height - BORDER_ROUNDNESS; + p[5].x = rect->x + roundness; + p[5].y = rect->y + rect->height - roundness; - p[6].x = rect->x + rect->width - BORDER_ROUNDNESS; - p[6].y = rect->y + rect->height - BORDER_ROUNDNESS; + p[6].x = rect->x + rect->width - roundness; + p[6].y = rect->y + rect->height - roundness; MwLLPolygon(handle->lowlevel, p, 7, invert ? lighter : darker); @@ -403,13 +411,13 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { MwPoint line[2]; double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = (rect->x + rect->width) - (BORDER_ROUNDNESS + 2); - int y = (rect->y + rect->height) - (BORDER_ROUNDNESS + 2); + int x = (rect->x + rect->width) - (roundness + 2); + int y = (rect->y + rect->height) - (roundness + 2); - line[0].x = x + (sin(point) * BORDER_ROUNDNESS); - line[0].y = y - (cos(point) * BORDER_ROUNDNESS); - line[1].x = x + (sin(point + 1) * BORDER_ROUNDNESS); - line[1].y = y - (cos(point + 1) * BORDER_ROUNDNESS); + line[0].x = x + (sin(point) * roundness); + line[0].y = y - (cos(point) * roundness); + line[1].x = x + (sin(point + 1) * roundness); + line[1].y = y - (cos(point + 1) * roundness); MwLLLine(handle->lowlevel, line, middle); } } else { From 19cd6dc242f7a44ca6d480401d22dec0ef64acae Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 15:56:27 -0700 Subject: [PATCH 249/409] increase smoothness --- src/draw.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/draw.c b/src/draw.c index e367c2f78..d5d466c68 100644 --- a/src/draw.c +++ b/src/draw.c @@ -13,7 +13,7 @@ #define DEFAULT_ROUNDNESS 10 #define MAX_ROUNDNESS 30 -#define BORDER_SMOOTHNESS 50 +#define BORDER_SMOOTHNESS 250 static int get_color_diff(MwWidget handle) { if(MwGetInteger(handle, MwNmodernLook)) { @@ -135,7 +135,6 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { - int xt; int x = rect->x + (roundness + 1); int y = rect->y + (roundness + 1); for(i = 0; i < roundness; i++) { @@ -147,9 +146,8 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde r.width = (x - (sin(point + 1) * roundness)) - r.x; r.height = (rect->height - ((r.y - rect->y) * 2) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - for(xt = x; xt < x2; xt++) { - r.x = xt; - r.y = y + (cos(point2) * roundness); + r.y = y + (cos(point2) * roundness); + for(r.x = x; r.x < x2; r.x++) { r.height = (rect->height - ((r.y - rect->y)) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); } @@ -171,9 +169,8 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde r.width = 1; r.height = (rect->height - ((r.y - rect->y) * 2) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - for(xt = x; xt < x2; xt++) { - r.x = xt; - r.y = y + (cos(point2) * roundness); + r.y = y + (cos(point2) * roundness); + for(r.x = x; r.x < x2; r.x++) { r.height = (rect->height - ((r.y - rect->y) * 2) - 2); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); } @@ -321,7 +318,7 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i p[0].x = rect->x + roundness; p[0].y = rect->y; - p[1].x = rect->x + rect->width - roundness; + p[1].x = rect->x + rect->width - border - roundness; p[1].y = rect->y; p[2].x = rect->x + rect->width - border - roundness; @@ -402,7 +399,7 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i p[5].x = rect->x + roundness; p[5].y = rect->y + rect->height - roundness; - p[6].x = rect->x + rect->width - roundness; + p[6].x = rect->x + rect->width - border - roundness; p[6].y = rect->y + rect->height - roundness; MwLLPolygon(handle->lowlevel, p, 7, invert ? lighter : darker); From 2a2fdf55bcbbb51730aa81f3cb11108869685f5f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 16:54:40 -0700 Subject: [PATCH 250/409] wayland: double buffering --- include/Mw/LowLevel/Wayland.h | 4 ++ src/backend/wayland.c | 70 +++++++++++++++++++++++------------ src/draw.c | 6 +-- 3 files changed, 53 insertions(+), 27 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index de7828ad5..8d47b5103 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -346,12 +346,16 @@ struct _MwLLWaylandShmBuffer { struct wl_shm* shm; struct wl_shm_pool* shm_pool; struct wl_buffer* shm_buffer; + struct wl_shm_pool* shm_pool_back; + struct wl_buffer* shm_buffer_back; struct wl_surface* surface; struct wl_output* output; MwU8* buf; + MwU8* buf_back; MwU64 buf_size; int fd; + int fd_back; MwBool setup; }; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index d43a2c595..1f27ed7f6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1186,41 +1186,60 @@ static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_proto static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { (void)self; // for later, just in case. + memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); wl_surface_commit(buffer->surface); } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { - int stride = width * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + int stride = width * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; + char temp_name_back[] = "/tmp/milsko-wl-shm-back-XXXXXX"; buffer->buf_size = width * height * 4; - buffer->fd = mkstemp(temp_name); + buffer->fd = mkstemp(temp_name); + buffer->fd_back = mkstemp(temp_name_back); unlink(temp_name); + unlink(temp_name_back); if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); close(buffer->fd); return; } + if(posix_fallocate(buffer->fd_back, 0, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } if(ftruncate(buffer->fd, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); close(buffer->fd); return; } + if(ftruncate(buffer->fd_back, buffer->buf_size) != 0) { + printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); + close(buffer->fd_back); + return; + } - buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); + buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); + buffer->buf_back = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd_back, 0); fsync(buffer->fd); + fsync(buffer->fd_back); if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { printf("failure setting up wl_shm: could not create pool.\n"); } - - buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->setup = MwTRUE; + if(!(buffer->shm_pool_back = wl_shm_create_pool(buffer->shm, buffer->fd_back, buffer->buf_size))) { + printf("failure setting up wl_shm: could not create pool.\n"); + } + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->shm_buffer_back = wl_shm_pool_create_buffer(buffer->shm_pool_back, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; } static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { @@ -1228,18 +1247,21 @@ static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { return; } wl_buffer_destroy(buffer->shm_buffer); + wl_buffer_destroy(buffer->shm_buffer_back); wl_shm_pool_destroy(buffer->shm_pool); + wl_shm_pool_destroy(buffer->shm_pool_back); close(buffer->fd); + close(buffer->fd_back); buffer->setup = MwFALSE; } static void framebuffer_setup(struct _MwLLWayland* wayland) { buffer_setup(&wayland->framebuffer, wayland->ww, wayland->wh); - wayland->front_cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); + wayland->front_cs = cairo_image_surface_create_for_data(wayland->framebuffer.buf_back, CAIRO_FORMAT_ARGB32, wayland->ww, wayland->wh, 4 * wayland->ww); wayland->front_cairo = cairo_create(wayland->front_cs); - memset(wayland->framebuffer.buf, 0, wayland->framebuffer.buf_size); + memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); hang_until_configured((MwLL)wayland); update_buffer((MwLL)wayland, &wayland->framebuffer); }; @@ -1261,10 +1283,10 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { } buffer_setup(&wayland->backbuffer, w, h); - wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf, CAIRO_FORMAT_ARGB32, w, h, 4 * w); + wayland->back_cs = cairo_image_surface_create_for_data(wayland->backbuffer.buf_back, CAIRO_FORMAT_ARGB32, w, h, 4 * w); wayland->back_cairo = cairo_create(wayland->back_cs); - memset(wayland->backbuffer.buf, 255, wayland->backbuffer.buf_size); + memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); hang_until_configured((MwLL)wayland); update_buffer((MwLL)wayland, &wayland->backbuffer); }; @@ -2156,7 +2178,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_surface_destroy(cs); MwLLForceRender(handle); - update_buffer(handle, &handle->wayland.framebuffer); + // update_buffer(handle, &handle->wayland.framebuffer); wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { @@ -2182,15 +2204,15 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { buffer_setup(handle->wayland.icon, pixmap->common.width, pixmap->common.height); for(; i < size; i += 2) { - handle->wayland.icon->buf[i] = pixmap->common.raw[i + 2]; - handle->wayland.icon->buf[i + 1] = pixmap->common.raw[i + 1]; - handle->wayland.icon->buf[i + 2] = pixmap->common.raw[i + 0]; - handle->wayland.icon->buf[i + 3] = 255; + handle->wayland.icon->buf_back[i] = pixmap->common.raw[i + 2]; + handle->wayland.icon->buf_back[i + 1] = pixmap->common.raw[i + 1]; + handle->wayland.icon->buf_back[i + 2] = pixmap->common.raw[i + 0]; + handle->wayland.icon->buf_back[i + 3] = 255; } if(handle->wayland.configured) update_buffer(handle, handle->wayland.icon); - xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer_back, 1); xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); } @@ -2214,7 +2236,7 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { wl_surface_destroy(handle->wayland.cursor.surface); } buffer_setup(&handle->wayland.cursor, image->width, image->height); - memset(handle->wayland.cursor.buf, 0, handle->wayland.cursor.buf_size); + memset(handle->wayland.cursor.buf_back, 0, handle->wayland.cursor.buf_size); xs = -mask->x + image->x; ys = mask->height + mask->y; @@ -2226,7 +2248,7 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { int idx = ((y * image->width) + x) * 4; if(d & 1) { - handle->wayland.cursor.buf[idx + 3] = 255; + handle->wayland.cursor.buf_back[idx + 3] = 255; }; d = d >> 1; } @@ -2241,16 +2263,16 @@ static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { px = 255; }; - handle->wayland.cursor.buf[idx] = px; - handle->wayland.cursor.buf[idx + 1] = px; - handle->wayland.cursor.buf[idx + 2] = px; - d = d >> 1; + handle->wayland.cursor.buf_back[idx] = px; + handle->wayland.cursor.buf_back[idx + 1] = px; + handle->wayland.cursor.buf_back[idx + 2] = px; + d = d >> 1; } } handle->wayland.cursor.surface = wl_compositor_create_surface(handle->wayland.compositor); - wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer, xs + image->x, ys + image->height + image->y); + wl_surface_attach(handle->wayland.cursor.surface, handle->wayland.cursor.shm_buffer_back, xs + image->x, ys + image->height + image->y); wl_surface_commit(handle->wayland.cursor.surface); /* If there's currently a pointer, set it up. (Otherwise, it'll be setup during the pointer enter event) */ diff --git a/src/draw.c b/src/draw.c index d5d466c68..7bf413e34 100644 --- a/src/draw.c +++ b/src/draw.c @@ -11,9 +11,9 @@ #include "../external/stb_ds.h" -#define DEFAULT_ROUNDNESS 10 +#define DEFAULT_ROUNDNESS 5 #define MAX_ROUNDNESS 30 -#define BORDER_SMOOTHNESS 250 +#define BORDER_SMOOTHNESS 50 static int get_color_diff(MwWidget handle) { if(MwGetInteger(handle, MwNmodernLook)) { @@ -171,7 +171,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde MwLLDrawPixmap(handle->lowlevel, &r, pixmap); r.y = y + (cos(point2) * roundness); for(r.x = x; r.x < x2; r.x++) { - r.height = (rect->height - ((r.y - rect->y) * 2) - 2); + r.height = (rect->height - ((r.y - rect->y) * 2) - 1); MwLLDrawPixmap(handle->lowlevel, &r, pixmap); } } From 6538f8e836cbd79c1c9cebf00542381d5a6fd3c6 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 17:48:22 -0700 Subject: [PATCH 251/409] fix wayland csd, more doublebuffering fixes --- src/backend/wayland.c | 30 ++++++++++++++++++------------ src/draw.c | 28 ++++++++++++++-------------- src/widget/button.c | 1 + src/widget/checkbox.c | 1 + src/widget/combobox.c | 1 + src/widget/entry.c | 1 + 6 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1f27ed7f6..d3e8e0241 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -46,7 +46,7 @@ static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer); static void region_setup(MwLL handle); static void region_invalidate(MwLL handle); - +static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer); /* Get the registered interface from r, or NULL if it doesn't currently have it. */ #define WAYLAND_GET_INTERFACE(handle, inter) shget(handle.wl_protocol_map, inter##_interface.name) @@ -65,8 +65,11 @@ static void new_protocol(void* data, struct wl_registry* registry, char* inter = malloc(strlen(interface) + 1); strcpy(inter, interface); shput(self->wayland.wl_protocol_map, inter, cb->setup(name, data)); + /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ + } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { + self->common.supports_transparency = MwTRUE; } else { - /* printf("unknown interface %s\n", interface); */ + // printf("unknown interface %s\n", interface); } WAYLAND_EVENT_OP_END(self); @@ -1075,9 +1078,9 @@ static int event_loop(MwLL handle) { if(!poll(&fd, 1, timeout.tv_nsec)) { wl_display_cancel_read(wayland->display); - wl_surface_commit(wayland->framebuffer.surface); + update_buffer(handle, &wayland->framebuffer); if(wayland->type == MWLL_WAYLAND_TOPLEVEL) - wl_surface_commit(wayland->backbuffer.surface); + update_buffer(handle, &wayland->backbuffer); return 0; } wl_display_read_events(wayland->display); @@ -1163,8 +1166,8 @@ static void xdg_surface_configure( xdg_surface_ack_configure(xdg_surface, serial); if(self->wayland.configured) { - wl_surface_commit(self->wayland.framebuffer.surface); - wl_surface_commit(self->wayland.backbuffer.surface); + update_buffer(self, &self->wayland.framebuffer); + update_buffer(self, &self->wayland.backbuffer); } self->wayland.configured = MwTRUE; @@ -1735,13 +1738,17 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh if(parent != NULL) { MwLLForceRender(parent); } + + if(!r->wayland.has_decorations) { + MwLLBeginDraw(r); + MwLLEndDraw(r); + } } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); - r->common.supports_transparency = MwTRUE; widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); @@ -1956,8 +1963,6 @@ static void MwLLBeginDrawImpl(MwLL handle) { free(px); } update_buffer(handle, &handle->wayland.backbuffer); - - wl_surface_commit(handle->wayland.backbuffer.surface); } handle->wayland.selected_cairo = handle->wayland.front_cairo; } @@ -1976,7 +1981,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL clip(handle); - cairo_set_source_rgb(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_set_source_rgba(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); cairo_new_path(handle->wayland.front_cairo); for(i = 0; i < points_count; i++) { if(i == 0) { @@ -1999,7 +2004,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { cairo_set_antialias(handle->wayland.front_cairo, CAIRO_ANTIALIAS_NONE); cairo_set_line_cap(handle->wayland.front_cairo, CAIRO_LINE_CAP_SQUARE); - cairo_set_source_rgb(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0); + cairo_set_source_rgba(handle->wayland.front_cairo, color->common.red / 255.0, color->common.green / 255.0, color->common.blue / 255.0, 1.0); cairo_new_path(handle->wayland.front_cairo); for(i = 0; i < 2; i++) { if(i == 0) { @@ -2109,6 +2114,8 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { } if(!handle->wayland.has_decorations) { strncpy(handle->wayland.title, title, 255); + MwLLBeginDraw(handle); + MwLLEndDraw(handle); } } @@ -2178,7 +2185,6 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_surface_destroy(cs); MwLLForceRender(handle); - // update_buffer(handle, &handle->wayland.framebuffer); wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { diff --git a/src/draw.c b/src/draw.c index 7bf413e34..ee9475e3c 100644 --- a/src/draw.c +++ b/src/draw.c @@ -116,10 +116,10 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde unsigned char* data = malloc(sz); MwRect r = *rect; int roundness = MwGetInteger(handle, MwNroundness); - double h; + double div; if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; - h = (roundness <= 10) ? 7. : 10.; + div = (roundness <= 10) ? 7. : 10.; memset(data, 0, sz); for(y = 0; y < rect->height; y++) { @@ -138,8 +138,8 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde int x = rect->x + (roundness + 1); int y = rect->y + (roundness + 1); for(i = 0; i < roundness; i++) { - double point = ((i + (M_PI * 4)) / h); - double point2 = (((i + 1) + (M_PI * 4)) / h); + double point = ((i + (M_PI * 4)) / div); + double point2 = (((i + 1) + (M_PI * 4)) / div); int x2 = x - (sin(point2) * roundness); r.x = x - (sin(point) * roundness); r.y = y + (cos(point) * roundness); @@ -153,16 +153,16 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde } } r = *rect; - r.x += roundness; - r.width -= (roundness * 2); - r.height -= 1; + r.x += roundness - 1; + r.width -= (roundness * 2) + 1; + r.height -= 2; MwLLDrawPixmap(handle->lowlevel, &r, pixmap); r = *rect; x = (rect->x + rect->width) - (roundness + 2); y = rect->y + (roundness + 1); for(i = 0; i < roundness; i++) { - double point = ((i + (M_PI * 4)) / h); - double point2 = (((i + 1) + (M_PI * 4)) / h); + double point = ((i + (M_PI * 4)) / div); + double point2 = (((i + 1) + (M_PI * 4)) / div); int x2 = x + (sin(point2) * roundness); r.x = x + (sin(point) * roundness); r.y = y + (cos(point) * roundness); @@ -207,13 +207,14 @@ void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { MwLLColor col; + MwBool rounded = handle->lowlevel->common.supports_transparency && MwGetInteger(handle, MwNroundness) != MwDEFAULT; if(border) { - MwDrawFrame(handle, rect, color, invert, handle->lowlevel->common.supports_transparency); + MwDrawFrame(handle, rect, color, invert, rounded); } col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawRectFading(handle, rect, col, handle->lowlevel->common.supports_transparency); + MwDrawRectFading(handle, rect, col, rounded); } else { MwDrawRect(handle, rect, col); } @@ -318,10 +319,10 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i p[0].x = rect->x + roundness; p[0].y = rect->y; - p[1].x = rect->x + rect->width - border - roundness; + p[1].x = rect->x + rect->width - border - roundness - 2; p[1].y = rect->y; - p[2].x = rect->x + rect->width - border - roundness; + p[2].x = rect->x + rect->width - border - roundness - 2; p[2].y = rect->y + border; p[3].x = rect->x + border - roundness; @@ -332,7 +333,6 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i p[5].x = rect->x + roundness; p[5].y = rect->y + rect->height - roundness; - MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); /* top right edge */ for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { diff --git a/src/widget/button.c b/src/widget/button.c index dac7739c6..f3240b0a4 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -8,6 +8,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNflat, 0); MwSetInteger(handle, MwNpadding, 0); MwSetInteger(handle, MwNfillArea, 1); + MwSetInteger(handle, MwNroundness, 5); return 0; } diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 1ccccd416..224cfec1d 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -4,6 +4,7 @@ static int create(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNchecked, 0); + MwSetInteger(handle, MwNroundness, 5); return 0; } diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 0672ff3ad..998237263 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -14,6 +14,7 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNareaShown, 6); MwSetInteger(handle, MwNvalue, 0); + MwSetInteger(handle, MwNroundness, 5); return 0; } diff --git a/src/widget/entry.c b/src/widget/entry.c index 34a90a36b..998935b80 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -11,6 +11,7 @@ static int create(MwWidget handle) { MwSetDefault(handle); MwLLSetCursor(handle->lowlevel, &MwCursorText, &MwCursorTextMask); + MwSetInteger(handle, MwNroundness, 5); return 0; } From 00e44bec324a00011c55089a775eb0775a0733bc Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 18:02:48 -0700 Subject: [PATCH 252/409] MwNisRounded --- include/Mw/StringDefs.h | 1 + src/core.c | 1 + src/draw.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index 832096338..f30a21b31 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -40,6 +40,7 @@ #define MwNlength "Ilength" #define MwNforceInverted "IforceInverted" #define MwNroundness "Iroundness" +#define MwNisRounded "IisRounded" #define MwNtitle "Stitle" #define MwNtext "Stext" diff --git a/src/core.c b/src/core.c index 39cae9244..88cd84285 100644 --- a/src/core.c +++ b/src/core.c @@ -516,6 +516,7 @@ int MwGetInteger(MwWidget handle, const char* key) { #else if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 1); #endif + if(strcmp(key, MwNisRounded) == 0) return inherit_integer(handle, key, 1); } return shget(handle->integer, key); } diff --git a/src/draw.c b/src/draw.c index ee9475e3c..944600f78 100644 --- a/src/draw.c +++ b/src/draw.c @@ -207,7 +207,7 @@ void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { MwLLColor col; - MwBool rounded = handle->lowlevel->common.supports_transparency && MwGetInteger(handle, MwNroundness) != MwDEFAULT; + MwBool rounded = handle->lowlevel->common.supports_transparency && MwGetInteger(handle, MwNroundness) != MwDEFAULT && MwGetInteger(handle, MwNisRounded) != 0; if(border) { MwDrawFrame(handle, rect, color, invert, rounded); @@ -333,6 +333,7 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i p[5].x = rect->x + roundness; p[5].y = rect->y + rect->height - roundness; + MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); /* top right edge */ for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { From 60e1f36a4125472040ee1b61b1dfc19fd943a73c Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 18:12:45 -0700 Subject: [PATCH 253/409] slightly stronger gradient on modern theme --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index 944600f78..4926fe085 100644 --- a/src/draw.c +++ b/src/draw.c @@ -111,7 +111,7 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde int y, i; double darken = 0.; int ColorDiff = get_color_diff(handle); - double darkenStep = (ColorDiff / 4.) / rect->height; + double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz); MwRect r = *rect; From 17e437075e7763d5c8a3872683a0034ec15957ea Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 27 Mar 2026 10:28:21 +0900 Subject: [PATCH 254/409] let ioixd do the job --- src/draw.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/draw.c b/src/draw.c index 4926fe085..2983e5635 100644 --- a/src/draw.c +++ b/src/draw.c @@ -299,6 +299,13 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i (lighter->common.green * darker->common.green) / 255, (lighter->common.blue * darker->common.blue) / 255); int roundness = MwGetInteger(handle, MwNroundness); + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL){ + MwDrawRect(handle, rect, c); + MwLLFreeColor(c); + } + if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { From 8dfa34e55553ffbe1642baa0d4500e710d22ed65 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 18:34:08 -0700 Subject: [PATCH 255/409] only do backing box draw if backend doesn't do transparency --- src/draw.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/draw.c b/src/draw.c index 2983e5635..51e79ff9d 100644 --- a/src/draw.c +++ b/src/draw.c @@ -207,7 +207,7 @@ void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { MwLLColor col; - MwBool rounded = handle->lowlevel->common.supports_transparency && MwGetInteger(handle, MwNroundness) != MwDEFAULT && MwGetInteger(handle, MwNisRounded) != 0; + MwBool rounded = MwGetInteger(handle, MwNroundness) != MwDEFAULT && MwGetInteger(handle, MwNisRounded) != 0; if(border) { MwDrawFrame(handle, rect, color, invert, rounded); @@ -299,11 +299,14 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i (lighter->common.green * darker->common.green) / 255, (lighter->common.blue * darker->common.blue) / 255); int roundness = MwGetInteger(handle, MwNroundness); - MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); - if(c != NULL){ - MwDrawRect(handle, rect, c); - MwLLFreeColor(c); + if(!handle->lowlevel->common.supports_transparency) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + MwDrawRect(handle, rect, c); + MwLLFreeColor(c); + } } if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; From e5acf07b38e494c03ad0870b1f941677c6122783 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 18:36:35 -0700 Subject: [PATCH 256/409] disable rounding on combobox --- src/widget/combobox.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 998237263..0672ff3ad 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -14,7 +14,6 @@ static int create(MwWidget handle) { MwSetInteger(handle, MwNareaShown, 6); MwSetInteger(handle, MwNvalue, 0); - MwSetInteger(handle, MwNroundness, 5); return 0; } From fc18c86201386dfdff0421bd0fe3c93863017494 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 26 Mar 2026 18:37:47 -0700 Subject: [PATCH 257/409] disable rounding on checkbox --- src/widget/checkbox.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 224cfec1d..1ccccd416 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -4,7 +4,6 @@ static int create(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNchecked, 0); - MwSetInteger(handle, MwNroundness, 5); return 0; } From 8f7df275fba511c3f78e3523707e8895b2f0e6a2 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 27 Mar 2026 10:40:35 +0900 Subject: [PATCH 258/409] better --- src/draw.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/draw.c b/src/draw.c index 51e79ff9d..dfaf90c6e 100644 --- a/src/draw.c +++ b/src/draw.c @@ -210,6 +210,15 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert MwBool rounded = MwGetInteger(handle, MwNroundness) != MwDEFAULT && MwGetInteger(handle, MwNisRounded) != 0; if(border) { + if(!handle->lowlevel->common.supports_transparency) { + MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); + + if(c != NULL) { + MwDrawRect(handle, rect, c); + MwLLFreeColor(c); + } + } + MwDrawFrame(handle, rect, color, invert, rounded); } col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; @@ -300,15 +309,6 @@ void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, i (lighter->common.blue * darker->common.blue) / 255); int roundness = MwGetInteger(handle, MwNroundness); - if(!handle->lowlevel->common.supports_transparency) { - MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); - - if(c != NULL) { - MwDrawRect(handle, rect, c); - MwLLFreeColor(c); - } - } - if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { From a42482a4e44ddd346f393d29b69270cd8b7932d8 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 27 Mar 2026 10:46:27 +0900 Subject: [PATCH 259/409] epic --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index dfaf90c6e..84587b44f 100644 --- a/src/draw.c +++ b/src/draw.c @@ -233,7 +233,7 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwPoint p[6]; int border = MwDefaultBorderWidth(handle); - int ColorDiff = get_color_diff(handle); + int ColorDiff = get_color_diff(handle) + (MwGetInteger(handle, MwNmodernLook) ? 48 : 0); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff, -ColorDiff, -ColorDiff); MwLLColor lighter = MwLightenColor(handle, color, ColorDiff, ColorDiff, ColorDiff); MwLLColor col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; From 258d0d2cb21b71be73cbeaec31445165ee58bc5d Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 27 Mar 2026 10:58:17 +0900 Subject: [PATCH 260/409] update xml --- milsko.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/milsko.xml b/milsko.xml index bc73f0e2b..bc7f1531d 100644 --- a/milsko.xml +++ b/milsko.xml @@ -42,7 +42,9 @@ - - - - + + + + @@ -80,38 +66,39 @@ - - + + - - - + + + - + - + - - + + + - - - - + + + + - + diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 0bd23a649..801c03f68 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1264,7 +1264,7 @@ static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); // Yes this is needed every time, it's how we fix weston. wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - wl_surface_commit(buffer->surface); + wl_surface_commit(buffer->surface); } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { From 3852646ce30caf47b74a7be2ed388d2fd6d17ea1 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 12 Apr 2026 07:12:59 +0900 Subject: [PATCH 324/409] fix warning --- src/text/text.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/text/text.c b/src/text/text.c index f550195c4..fec0bb449 100644 --- a/src/text/text.c +++ b/src/text/text.c @@ -26,6 +26,7 @@ static int is_bold(MwWidget handle, MwFLFont ttf) { return s; } +#ifdef TTF static int is_monospace(MwWidget handle, MwFLFont ttf) { size_t u = (size_t)ttf; int s; @@ -36,6 +37,7 @@ static int is_monospace(MwWidget handle, MwFLFont ttf) { if(s == MwDEFAULT) return 0; return s; } +#endif #ifdef TTF From d1f351a7efb8a3b278e5684b801b07b11a92811f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Sun, 12 Apr 2026 07:27:07 +0900 Subject: [PATCH 325/409] fix cmake --- examples/gldemos/CMakeLists.txt | 2 +- examples/vkdemos/CMakeLists.txt | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/gldemos/CMakeLists.txt b/examples/gldemos/CMakeLists.txt index 9afda19fb..122f62c59 100644 --- a/examples/gldemos/CMakeLists.txt +++ b/examples/gldemos/CMakeLists.txt @@ -15,7 +15,7 @@ foreach(PATH IN LISTS EXAMPLES_GL_SOURCES) ${TARGET} PRIVATE Mw - OpenGL::GL + OpenGL::GL OpenGL::GLU ) if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") target_link_libraries( diff --git a/examples/vkdemos/CMakeLists.txt b/examples/vkdemos/CMakeLists.txt index 354bf3634..a315bf91b 100644 --- a/examples/vkdemos/CMakeLists.txt +++ b/examples/vkdemos/CMakeLists.txt @@ -3,10 +3,16 @@ file( EXAMPLES_VULKAN_SOURCES *.c ) +find_package(Vulkan) foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + target_include_directories( + ${TARGET} + PRIVATE + ${Vulkan_INCLUDE_DIR} + ) target_link_libraries( ${TARGET} PRIVATE From 2a7cf2de83d1fb5051013ccc988ec367564a932f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sat, 11 Apr 2026 18:26:15 -0500 Subject: [PATCH 326/409] x11: allow apple. --- src/backend/x11.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/x11.c b/src/backend/x11.c index 72e54f336..755da7127 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1292,7 +1292,11 @@ static int MwLLX11CallInitImpl(void) { return 1; } +#ifdef __APPLE__ + xsymtbl.lib_xlib = MwDynamicOpen("libX11.dylib"); +#else xsymtbl.lib_xlib = MwDynamicOpen("libX11.so"); +#endif if(!xsymtbl.lib_xlib) { return 1; } From c4f6d1eb14c94721fc4e18b76b4557c7def4b3e4 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Sat, 11 Apr 2026 18:30:00 -0500 Subject: [PATCH 327/409] Update src/core.c --- src/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core.c b/src/core.c index c8a5c12d0..b4b6743ce 100644 --- a/src/core.c +++ b/src/core.c @@ -856,15 +856,16 @@ MwWidget MwGetParent(MwWidget handle) { typedef int (*call_t)(void); int MwLibraryInit(void) { call_t calls[] = { +/* x11 has higher priority then cocoa until it works */ +#ifdef USE_X11 + MwLLX11CallInit, +#endif #ifdef USE_COCOA MwLLCocoaCallInit, #endif #ifdef USE_WAYLAND MwLLWaylandCallInit, #endif -#ifdef USE_X11 - MwLLX11CallInit, -#endif #ifdef USE_GDI MwLLGDICallInit, #endif From 0ab497ca8869bcc968d3e48ff5e3ea4c15c3c766 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 11:28:54 -0700 Subject: [PATCH 328/409] oops prioritize wayland --- src/backend/wayland.c | 7 +------ src/backend/x11.c | 3 --- src/core.c | 8 ++++---- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 801c03f68..148ca4420 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2575,7 +2575,6 @@ static int MwLLWaylandCallInitImpl(void) { /* * Order of precedence: * - MILSKO_BACKEND - * - XDG_SESSION_TYPE * - manually checking environment variables */ #ifdef __linux__ @@ -2583,11 +2582,7 @@ static int MwLLWaylandCallInitImpl(void) { if(getenv("MILSKO_BACKEND")) { loadWayland |= (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); - } - if(getenv("XDG_SESSION_TYPE")) { - loadWayland |= (strcmp(getenv("XDG_SESSION_TYPE"), "wayland") == 0); - } - if(getenv("WAYLAND_DISPLAY")) { + } else if(getenv("WAYLAND_DISPLAY")) { loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); } diff --git a/src/backend/x11.c b/src/backend/x11.c index 755da7127..4068186d4 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1281,9 +1281,6 @@ static int MwLLX11CallInitImpl(void) { loadX11 |= (strcmp(getenv("MILSKO_BACKEND"), "x11") == 0); } - if(getenv("XDG_SESSION_TYPE")) { - loadX11 |= (strcmp(getenv("XDG_SESSION_TYPE"), "x11") == 0); - } if(getenv("DISPLAY")) { loadX11 |= (getenv("DISPLAY") != NULL); } diff --git a/src/core.c b/src/core.c index b4b6743ce..cdd0723b9 100644 --- a/src/core.c +++ b/src/core.c @@ -856,16 +856,16 @@ MwWidget MwGetParent(MwWidget handle) { typedef int (*call_t)(void); int MwLibraryInit(void) { call_t calls[] = { -/* x11 has higher priority then cocoa until it works */ +#ifdef USE_WAYLAND + MwLLWaylandCallInit, +#endif +/* x11 has higher priority then cocoa until it works */ #ifdef USE_X11 MwLLX11CallInit, #endif #ifdef USE_COCOA MwLLCocoaCallInit, #endif -#ifdef USE_WAYLAND - MwLLWaylandCallInit, -#endif #ifdef USE_GDI MwLLGDICallInit, #endif From 728983b92ccd4a79925b36f035b0cbdce003221c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 13:46:25 -0700 Subject: [PATCH 329/409] fix builds on osx 10.4 --- configure | 4 +++- include/Mw/LowLevel/Cocoa.h | 23 +++++++++++------------ include/Mw/MachDep.h | 9 +++++++++ pl/utils.pl | 1 + src/backend/cocoa.m | 8 ++++++-- 5 files changed, 30 insertions(+), 15 deletions(-) diff --git a/configure b/configure index 0371bcd05..0c1766315 100755 --- a/configure +++ b/configure @@ -38,7 +38,6 @@ require("./pl/utils.pl"); param_set("classic-theme", 0); param_set("stb-image", 1); -param_set("stb-truetype", 0); param_set("xrender", 1); param_set("opengl", 0); param_set("vulkan", 0); @@ -50,6 +49,9 @@ param_set("examples", 1); if($target ne "Darwin") { param_set("freetype2", 1); + param_set("stb-truetype", 0); +} else { + param_set("stb-truetype", 1); } my %features = ( diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index da104f018..6e51c3051 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -86,18 +86,17 @@ @end @interface MilskoCocoaView : NSView { - NSBitmapImageRep* rep; - NSGraphicsContext* context; - MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; - NSRect givenRect; - float x; - float y; - float width; - float height; - MwBool _child; - IBOutlet NSViewController* viewController; + NSBitmapImageRep* rep; + NSGraphicsContext* context; + MwBool valid; + CGColorSpaceRef space; + CGDataProviderRef provider; + NSRect givenRect; + float x; + float y; + float width; + float height; + MwBool _child; } - (void)initRepAndContextWithWidth:(float)w Height:(float)h; diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 61a6f909b..50898f676 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -57,17 +57,26 @@ #define M_PI 3.14159265 #endif +/* Windows */ #if defined(_MILSKO) && defined(_WIN32) #define MWDECL extern __declspec(dllexport) #elif defined(_WIN32) #define MWDECL extern __declspec(dllimport) +/* GCC/Clang */ +/* First check if we have __has_attribute and can check for the existence of visibility */ #elif defined(__has_attribute) #if __has_attribute(visibility) #define MWDECL extern __attribute__((visibility("default"))) #else #define MWDECL extern #endif +/* It might be that we're on an old version of GCC (like the one Apple ships with older versions of Mac OS). + * If we're on gcc 3 or above, assume it's there + */ +#elif __GNUC__ >= 3 +#define MWDECL extern __attribute__((visibility("default"))) #else +/* all else fails */ #define MWDECL extern #endif diff --git a/pl/utils.pl b/pl/utils.pl index 70c0b517c..947212328 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -55,6 +55,7 @@ sub new_object { my @l = glob($_[0]); foreach my $e (@l) { $e =~ s/\.(c|m)$/$object_suffix/; + print($e."\n"); push(@library_targets, $e); } } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 04ce17edf..195e33948 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -665,6 +665,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSSize sz = [self->rep size]; MwLL ll = [((MilskoFakePointer*)[[[[self window] contentView] subviews] objectAtIndex:0]) pointer]; + NSRect bounds; + NSArray* subviews = [self subviews]; + int i; [super drawRect:dirtyRect]; if(!self->rep) { @@ -683,8 +686,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [self->rep drawInRect:dirtyRect]; - for(NSView* subview in [self subviews]) { - NSRect bounds = [subview bounds]; + for(i = 0; i < [subviews count]; i++) { + NSView* subview = [subviews objectAtIndex:i]; + bounds = [subview bounds]; [subview drawRect:bounds]; } From 14e908488c3f5ffa7e450e6380a318be97cb4d65 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 16:09:28 -0700 Subject: [PATCH 330/409] mac --- include/Mw/LowLevel/Cocoa.h | 6 +++ src/backend/cocoa.m | 86 ++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 6e51c3051..fc39b07e4 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -104,7 +104,11 @@ - (void)destroy; - (NSBitmapImageRep*)getRep; - (void)setChild; +- (void)drawRectSub:(NSRect)dirtyRect; +@end +@interface MilskoCocoaSubView : MilskoCocoaView { +} @end @interface MilskoCocoa : NSObject { @@ -125,6 +129,8 @@ MwBool pointerLocked; MwBool mouseMoved; + + MwBool rejectFirstTest; } + (MilskoCocoa*)newWithParent:(MwLL)parent diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 195e33948..dc3028738 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -116,8 +116,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (void)destroy { free(self->buf); [self->image removeRepresentation:self->rep]; - [self->image dealloc]; - [self->rep dealloc]; + [self->image release]; + [self->rep release]; self->image = NULL; self->rep = NULL; } @@ -134,7 +134,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { width:(int)width height:(int)height handle:(MwLL)r { - MilskoCocoa* c = [MilskoCocoa alloc]; + MilskoCocoa* c = [MilskoCocoa alloc]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [c retain]; /* @@ -156,7 +158,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { c->window = [[MilskoCocoaWindow alloc] initWithContentRect:rectFlip(c->rect) styleMask:(NSTitledWindowMask | - NSTexturedBackgroundWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) backing:NSBackingStoreBuffered @@ -190,15 +191,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSRect rect = localRectFlip(c->rect, p->view); c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; [c->view setBounds:c->rect]; - [c->view retain]; - [c->view setNeedsDisplay:TRUE]; [c->view setChild]; [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; [p->view addSubview:c->view]; - [p->window setContentView:p->view]; } [c->window setAcceptsMouseMovedEvents:MwTRUE]; @@ -219,6 +217,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { c->pointerLocked = MwFALSE; + [pool release]; return c; } @@ -331,7 +330,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { frame = localRectFlip(frame, parent->cocoa.real->view); [self->view setBounds:frame]; } - self->_eventsPending = MwTRUE; + // [self->view setNeedsDisplay:true]; + [self nudge]; }; - (void)setW:(int)w H:(int)h { NSRect frame = [self->window frame]; @@ -346,7 +346,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } else { [self->window setFrame:frame display:YES animate:false]; } - self->_eventsPending = MwTRUE; + [self nudge]; }; - (int)pending { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -360,12 +360,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { MwLL h = [self->handle pointer]; if(_forceRender) { MwLLDispatch(h, draw, NULL); - [self->view setNeedsDisplay:true]; + // [self->view setNeedsDisplay:true]; _forceRender = MwFALSE; } if(_eventsPending) { MwLLDispatch(h, draw, NULL); - [self->view setNeedsDisplay:true]; + // [self->view setNeedsDisplay:true]; _eventsPending = MwFALSE; } [self sendClipboardEvent]; @@ -579,9 +579,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { }; - (void)destroy { [self->handle release]; - [self->handle dealloc]; [self->window release]; - [self->window dealloc]; } - (MwLL)getParent { @@ -596,7 +594,13 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)nudge { + MwLL p = self->parent; self->_eventsPending = MwTRUE; + + if(p) { + [p->cocoa.real->view setNeedsDisplay:true]; + p = p->cocoa.real->parent; + } } - (void)pushCursor { @@ -661,15 +665,10 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)drawRect:(NSRect)dirtyRect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSSize sz = [self->rep size]; - MwLL ll = [((MilskoFakePointer*)[[[[self window] contentView] subviews] - objectAtIndex:0]) pointer]; - NSRect bounds; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* subviews = [self subviews]; int i; - [super drawRect:dirtyRect]; if(!self->rep) { if(dirtyRect.size.width && dirtyRect.size.height) { [self initRepAndContextWithWidth:dirtyRect.size.width @@ -682,22 +681,41 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } } - // MwLLDispatch(ll, draw, NULL); - - [self->rep drawInRect:dirtyRect]; + if(!_child) + [self->rep drawInRect:[self bounds]]; for(i = 0; i < [subviews count]; i++) { - NSView* subview = [subviews objectAtIndex:i]; - bounds = [subview bounds]; - [subview drawRect:bounds]; + MilskoCocoaView* subview = [subviews objectAtIndex:i]; + NSRect bounds = [subview bounds]; + if([subview respondsToSelector:@selector(drawRectSub:)]) { + [subview drawRectSub:bounds]; + } } - - [self->rep bitmapData]; - [pool release]; } +- (void)drawRectSub:(NSRect)dirtyRect { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + + if(!self->rep) { + if(dirtyRect.size.width && dirtyRect.size.height) { + [self initRepAndContextWithWidth:dirtyRect.size.width + Height:dirtyRect.size.height]; + self->width = dirtyRect.size.width; + self->height = dirtyRect.size.height; + } else { + [pool release]; + return; + } + } + + [self->rep drawInRect:dirtyRect]; + + [pool release]; +}; + - (void)initRepAndContextWithWidth:(float)w Height:(float)h { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; self->rep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:w @@ -712,10 +730,14 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { assert(self->rep); [self->rep retain]; + [self->rep setOpaque:MwFALSE]; + [self->rep setAlpha:MwTRUE]; + self->context = [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; assert(self->context); [self->context retain]; + [pool release]; } - (void)destroy { @@ -1142,11 +1164,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - int p = [handle->cocoa.real pending]; - if(p) { - MwLLDispatch(handle, draw, NULL); - } - return p; + return [handle->cocoa.real pending]; } static void MwLLNextEventImpl(MwLL handle) { @@ -1186,7 +1204,7 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { MilskoCocoaPixmap* p = pixmap->cocoa.real; [p destroy]; - [p dealloc]; + [p release]; free(pixmap); } From f44a70d4ecc621897eb723eb30c848cb6235fd9d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 16:21:30 -0700 Subject: [PATCH 331/409] mac: untested code but i'll fall asleep at night with this in the codebase compared to the other thing --- include/Mw/LowLevel/Cocoa.h | 1 - src/backend/cocoa.m | 51 +++++++++---------------------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index fc39b07e4..89e5f5887 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -104,7 +104,6 @@ - (void)destroy; - (NSBitmapImageRep*)getRep; - (void)setChild; -- (void)drawRectSub:(NSRect)dirtyRect; @end @interface MilskoCocoaSubView : MilskoCocoaView { diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index dc3028738..0f979b9dc 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -669,51 +669,24 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSArray* subviews = [self subviews]; int i; - if(!self->rep) { - if(dirtyRect.size.width && dirtyRect.size.height) { - [self initRepAndContextWithWidth:dirtyRect.size.width - Height:dirtyRect.size.height]; - self->width = dirtyRect.size.width; - self->height = dirtyRect.size.height; - } else { - [pool release]; - return; - } + if(self->rep) { + [self->rep release]; + } + if(dirtyRect.size.width && dirtyRect.size.height) { + [self initRepAndContextWithWidth:dirtyRect.size.width + Height:dirtyRect.size.height]; + self->width = dirtyRect.size.width; + self->height = dirtyRect.size.height; + } else { + [pool release]; + return; } - if(!_child) - [self->rep drawInRect:[self bounds]]; + [self->rep drawInRect:[self bounds]]; - for(i = 0; i < [subviews count]; i++) { - MilskoCocoaView* subview = [subviews objectAtIndex:i]; - NSRect bounds = [subview bounds]; - if([subview respondsToSelector:@selector(drawRectSub:)]) { - [subview drawRectSub:bounds]; - } - } [pool release]; } -- (void)drawRectSub:(NSRect)dirtyRect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - - if(!self->rep) { - if(dirtyRect.size.width && dirtyRect.size.height) { - [self initRepAndContextWithWidth:dirtyRect.size.width - Height:dirtyRect.size.height]; - self->width = dirtyRect.size.width; - self->height = dirtyRect.size.height; - } else { - [pool release]; - return; - } - } - - [self->rep drawInRect:dirtyRect]; - - [pool release]; -}; - - (void)initRepAndContextWithWidth:(float)w Height:(float)h { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; self->rep = From b661face2647645499a5d475ce1e99e0561d3138 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 16:43:31 -0700 Subject: [PATCH 332/409] mac: more untested changes but its just removing dead comments so i know this won't break anything --- src/backend/cocoa.m | 89 +++++++++++++-------------------------------- 1 file changed, 25 insertions(+), 64 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 0f979b9dc..a66b31c36 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -330,7 +330,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { frame = localRectFlip(frame, parent->cocoa.real->view); [self->view setBounds:frame]; } - // [self->view setNeedsDisplay:true]; [self nudge]; }; - (void)setW:(int)w H:(int)h { @@ -360,12 +359,10 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { MwLL h = [self->handle pointer]; if(_forceRender) { MwLLDispatch(h, draw, NULL); - // [self->view setNeedsDisplay:true]; _forceRender = MwFALSE; } if(_eventsPending) { MwLLDispatch(h, draw, NULL); - // [self->view setNeedsDisplay:true]; _eventsPending = MwFALSE; } [self sendClipboardEvent]; @@ -443,18 +440,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { }; - (void)forceRender { self->_forceRender = MwTRUE; - // NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - // NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined - // location:NSMakePoint(0, 0) - // modifierFlags:0 - // timestamp:0 - // windowNumber:0 - // context:nil - // subtype:0 - // data1:0 - // data2:0]; - // [NSApp postEvent:event atStart:YES]; - // [pool release]; }; - (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { int y, x, ys, xs; @@ -670,8 +655,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { int i; if(self->rep) { - [self->rep release]; - } + [self->rep release]; + } if(dirtyRect.size.width && dirtyRect.size.height) { [self initRepAndContextWithWidth:dirtyRect.size.width Height:dirtyRect.size.height]; @@ -993,7 +978,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { if([ptr isKindOfClass:[MilskoFakePointer class]]) { MwLL h = [(MilskoFakePointer*)ptr pointer]; MwLLDispatch(h, resize, NULL); - // MwLLDispatch(h, draw, NULL); } } return frameSize; @@ -1118,18 +1102,15 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* height) { - MilskoCocoa* h = handle->cocoa.real; - [h getX:x Y:y W:w H:height]; + [handle->cocoa.real getX:x Y:y W:w H:height]; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - MilskoCocoa* h = handle->cocoa.real; - [h setX:x Y:y]; + [handle->cocoa.real setX:x Y:y]; } static void MwLLSetWHImpl(MwLL handle, int w, int height) { - MilskoCocoa* h = handle->cocoa.real; - [h setW:w H:height]; + [handle->cocoa.real setW:w H:height]; } static void MwLLFreeColorImpl(MwLLColor color) { @@ -1141,13 +1122,11 @@ static int MwLLPendingImpl(MwLL handle) { } static void MwLLNextEventImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h getNextEvent]; + [handle->cocoa.real getNextEvent]; } static void MwLLSetTitleImpl(MwLL handle, const char* title) { - MilskoCocoa* h = handle->cocoa.real; - [h setTitle:title]; + [handle->cocoa.real setTitle:title]; } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, @@ -1170,77 +1149,63 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p updateWithData:pixmap->common.raw]; + [pixmap->cocoa.real updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { - MilskoCocoaPixmap* p = pixmap->cocoa.real; - [p destroy]; - [p release]; + [pixmap->cocoa.real destroy]; + [pixmap->cocoa.real release]; free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h drawPixmap:pixmap rect:rect]; + [handle->cocoa.real drawPixmap:pixmap rect:rect]; MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - MilskoCocoa* h = handle->cocoa.real; - [h setIcon:pixmap]; + [handle->cocoa.real setIcon:pixmap]; } static void MwLLForceRenderImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h forceRender]; + [handle->cocoa.real forceRender]; } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - MilskoCocoa* h = handle->cocoa.real; - [h setCursor:image mask:mask]; + [handle->cocoa.real setCursor:image mask:mask]; } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h detachWithPoint:point]; + [handle->cocoa.real detachWithPoint:point]; } static void MwLLShowImpl(MwLL handle, int show) { - MilskoCocoa* h = handle->cocoa.real; - [h show:show]; + [handle->cocoa.real show:show]; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - MilskoCocoa* h = handle->cocoa.real; - [h makePopupWithParent:parent]; + [handle->cocoa.real makePopupWithParent:parent]; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - MilskoCocoa* h = handle->cocoa.real; - [h setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + [handle->cocoa.real setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h makeBorderless:toggle]; + [handle->cocoa.real makeBorderless:toggle]; } static void MwLLFocusImpl(MwLL handle) { - MilskoCocoa* h = handle->cocoa.real; - [h focus]; + [handle->cocoa.real focus]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - MilskoCocoa* h = handle->cocoa.real; - [h grabPointer:toggle]; + [handle->cocoa.real grabPointer:toggle]; } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { - MilskoCocoa* h = handle->cocoa.real; - [h setClipboard:text]; + [handle->cocoa.real setClipboard:text]; } static void MwLLGetClipboardImpl(MwLL handle) { @@ -1248,19 +1213,15 @@ static void MwLLGetClipboardImpl(MwLL handle) { } static void MwLLMakeToolWindowImpl(MwLL handle) { - - MilskoCocoa* h = handle->cocoa.real; - [h makeToolWindow]; + [handle->cocoa.real makeToolWindow]; } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - MilskoCocoa* h = handle->cocoa.real; - [h getCursorCoord:point]; + [handle->cocoa.real getCursorCoord:point]; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - MilskoCocoa* h = handle->cocoa.real; - [h getScreenSize:rect]; + [handle->cocoa.real getScreenSize:rect]; } static void MwLLBeginStateChangeImpl(MwLL handle) { From bb876b96201a93c1fe6a55583ebcd79a9842b27f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 16:45:20 -0700 Subject: [PATCH 333/409] mac: only recreate rep if width/height is different. also untested but i'm confident in this --- src/backend/cocoa.m | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index a66b31c36..6961a9630 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -654,17 +654,19 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSArray* subviews = [self subviews]; int i; - if(self->rep) { - [self->rep release]; - } - if(dirtyRect.size.width && dirtyRect.size.height) { - [self initRepAndContextWithWidth:dirtyRect.size.width - Height:dirtyRect.size.height]; - self->width = dirtyRect.size.width; - self->height = dirtyRect.size.height; - } else { - [pool release]; - return; + if(self->width != dirtyRect.size.width || self->height != dirtyRect.size.height) { + if(self->rep) { + [self->rep release]; + } + if(dirtyRect.size.width && dirtyRect.size.height) { + [self initRepAndContextWithWidth:dirtyRect.size.width + Height:dirtyRect.size.height]; + self->width = dirtyRect.size.width; + self->height = dirtyRect.size.height; + } else { + [pool release]; + return; + } } [self->rep drawInRect:[self bounds]]; From a4c61b0e38c9737978e28014e38d5fc48fe02f06 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 17:44:27 -0700 Subject: [PATCH 334/409] gnustep support? --- configure | 17 ++++++++++------- include/Mw/LowLevel/Cocoa.h | 34 +++++++++++++--------------------- pl/rules.pl | 6 +++++- pl/utils.pl | 1 - src/backend/cocoa.m | 18 +++++++++--------- src/backend/x11.c | 3 +-- 6 files changed, 38 insertions(+), 41 deletions(-) diff --git a/configure b/configure index 0c1766315..5551d4ced 100755 --- a/configure +++ b/configure @@ -66,6 +66,7 @@ my %features = ( "shared" => "build shared library", "static" => "build static library", "wayland" => "enable wayland backend", + "gnustep" => "use gnustep", ); my @features_keys = ( "1classic-theme", "1stb-image", @@ -73,9 +74,16 @@ my @features_keys = ( "1opengl", "2xrender", "1vulkan", "2vulkan-string-helper", "1shared", "1static", - "1wayland", + "1wayland", "1gnustep", ); +if($target eq "Linux") { + param_set("x11", 1); + if(!param_get("tiny")){ + param_set("wayland", 1); + } +} + foreach my $l (@ARGV) { if ($l =~ /^--with-([^=]+)=(.+)$/) { param_set($1, $2); @@ -138,12 +146,7 @@ foreach my $l (@ARGV) { } } -if($target eq "Linux") { - param_set("x11", 1); - if(!param_get("tiny")){ - param_set("wayland", 1); - } -} + if (-f "./pl/ostype/${target}.pl") { require("./pl/ostype/${target}.pl"); diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 89e5f5887..d31e590b6 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -15,12 +15,6 @@ #import #import -#ifdef __APPLE__ -#import -#else -#import -#endif - @interface MilskoCocoaApplication : NSApplication { MwBool doPending; } @@ -29,9 +23,9 @@ // Note: implements NSApplicationDelegate @interface MilskoCocoaApplicationDelegate : NSObject { - MilskoCocoaApplication* appl; + NSApplication* appl; } -- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)appl; +- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)appl; @end @interface MilskoCocoaWindow : NSWindow { @@ -40,7 +34,7 @@ // Note: implements NSWindowDelegate @interface MilskoCocoaWindowDelegate : NSObject { - MilskoCocoaWindow* w; + NSWindow* w; } - (MilskoCocoaWindowDelegate*)initWithWin:(MilskoCocoaWindow*)win; @end @@ -89,8 +83,6 @@ NSBitmapImageRep* rep; NSGraphicsContext* context; MwBool valid; - CGColorSpaceRef space; - CGDataProviderRef provider; NSRect givenRect; float x; float y; @@ -111,16 +103,16 @@ @end @interface MilskoCocoa : NSObject { - MilskoCocoaApplication* application; - MwBool _forceRender; - MwBool _eventsPending; - MilskoCocoaWindow* window; - NSRect rect; - MilskoCocoaView* view; - MwLL parent; - MilskoFakePointer* handle; - unsigned int strHash; - NSEvent* lastEvent; + NSApplication* application; + MwBool _forceRender; + MwBool _eventsPending; + MilskoCocoaWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; MilskoCocoaPixmap* cursorPixmap; NSCursor* cursor; diff --git a/pl/rules.pl b/pl/rules.pl index bf1857576..000a6fec0 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -52,10 +52,14 @@ if (grep(/^wayland$/, @backends)) { $gl_libs = "-lGL -lGLU"; } -if (grep(/^cocoa$/, @backends)) { +if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { add_cflags("-DUSE_COCOA"); new_object("src/backend/cocoa.m"); + if(param_get("gnustep")){ + add_ldflags("-lobjc -lgnustep-base -lm -lgnustep-gui"); + } + if (param_get("opengl")) { new_object("src/widget/opengl_cocoa.m"); } diff --git a/pl/utils.pl b/pl/utils.pl index 947212328..70c0b517c 100644 --- a/pl/utils.pl +++ b/pl/utils.pl @@ -55,7 +55,6 @@ sub new_object { my @l = glob($_[0]); foreach my $e (@l) { $e =~ s/\.(c|m)$/$object_suffix/; - print($e."\n"); push(@library_targets, $e); } } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 6961a9630..7b281722e 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -325,7 +325,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { if(!parent) { frame = rectFlip(frame); - [self->window setFrame:frame display:TRUE animate:TRUE]; + [self->window setFrame:frame display:MwTRUE animate:MwTRUE]; } else { frame = localRectFlip(frame, parent->cocoa.real->view); [self->view setBounds:frame]; @@ -367,6 +367,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } [self sendClipboardEvent]; +#ifdef __APPLE__ if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { struct CGPoint pos; pos.x = [window frame].origin.x + [window frame].size.width / 2; @@ -374,6 +375,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { CGWarpMouseCursorPosition(pos); } +#endif [self->application updateWindows]; }; @@ -617,13 +619,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - givenRect = frame; - x = frame.origin.x; - y = frame.origin.y; - width = frame.size.width; - height = frame.size.height; - self = [super initWithFrame:frame]; - self->space = CGColorSpaceCreateDeviceRGB(); + givenRect = frame; + x = frame.origin.x; + y = frame.origin.y; + width = frame.size.width; + height = frame.size.height; + self = [super initWithFrame:frame]; if(width == 0 || height == 0) { self->rep = NULL; @@ -701,7 +702,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)destroy { - CGColorSpaceRelease(self->space); [self->rep release]; [self->context release]; } diff --git a/src/backend/x11.c b/src/backend/x11.c index 4068186d4..ad97d6885 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1280,8 +1280,7 @@ static int MwLLX11CallInitImpl(void) { if(getenv("MILSKO_BACKEND")) { loadX11 |= (strcmp(getenv("MILSKO_BACKEND"), "x11") == 0); - } - if(getenv("DISPLAY")) { + } else if(getenv("DISPLAY")) { loadX11 |= (getenv("DISPLAY") != NULL); } From 7d85a784f589a79d14bd3158a3a258d6175cefff Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 18:39:21 -0700 Subject: [PATCH 335/409] i think we're now linking to gnustep properly --- pl/rules.pl | 4 +++- src/backend/cocoa.m | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pl/rules.pl b/pl/rules.pl index 000a6fec0..3d1f2c0fc 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -57,7 +57,9 @@ if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { new_object("src/backend/cocoa.m"); if(param_get("gnustep")){ - add_ldflags("-lobjc -lgnustep-base -lm -lgnustep-gui"); + add_incdir2("-I/usr/GNUstep/System/Library/Headers"); + add_libdir("-L/usr/GNUstep/System/Library/Libraries"); + add_ldflags("-fblocks -lobjc -lgnustep-base -lm -lgnustep-gui"); } if (param_get("opengl")) { diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 7b281722e..1048f82bf 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -151,7 +151,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) : 0; } - c->application = [MilskoCocoaApplication sharedApplication]; + c->application = NSApp; c->rect = NSMakeRect(x, y, width, height); if(parent == NULL) { @@ -1235,6 +1235,8 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static int MwLLCocoaCallInitImpl(void) { + [NSApplication sharedApplication]; + return 0; } From 9283455cb971857e14e62f0aa594b4b4091ace0b Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 13 Apr 2026 20:07:00 -0700 Subject: [PATCH 336/409] links to gnustep but doesn't run --- configure | 2 -- include/Mw/LowLevel/Cocoa.h | 29 ++++++++++++++--------------- pl/rules.pl | 7 ++++--- src/backend/cocoa.m | 29 ++++++++++++++++------------- 4 files changed, 34 insertions(+), 33 deletions(-) diff --git a/configure b/configure index 5551d4ced..5d9810863 100755 --- a/configure +++ b/configure @@ -146,8 +146,6 @@ foreach my $l (@ARGV) { } } - - if (-f "./pl/ostype/${target}.pl") { require("./pl/ostype/${target}.pl"); } diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index d31e590b6..ff7029580 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -23,9 +23,9 @@ // Note: implements NSApplicationDelegate @interface MilskoCocoaApplicationDelegate : NSObject { - NSApplication* appl; + MilskoCocoaApplication* appl; } -- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)appl; +- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)appl; @end @interface MilskoCocoaWindow : NSWindow { @@ -36,7 +36,7 @@ @interface MilskoCocoaWindowDelegate : NSObject { NSWindow* w; } -- (MilskoCocoaWindowDelegate*)initWithWin:(MilskoCocoaWindow*)win; +- (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win; @end /* @@ -103,16 +103,16 @@ @end @interface MilskoCocoa : NSObject { - NSApplication* application; - MwBool _forceRender; - MwBool _eventsPending; - MilskoCocoaWindow* window; - NSRect rect; - MilskoCocoaView* view; - MwLL parent; - MilskoFakePointer* handle; - unsigned int strHash; - NSEvent* lastEvent; + MilskoCocoaApplication* application; + MwBool _forceRender; + MwBool _eventsPending; + NSWindow* window; + NSRect rect; + MilskoCocoaView* view; + MwLL parent; + MilskoFakePointer* handle; + unsigned int strHash; + NSEvent* lastEvent; MilskoCocoaPixmap* cursorPixmap; NSCursor* cursor; @@ -163,14 +163,13 @@ - (MwLL)getParent; - (NSView*)getView; -- (MilskoCocoaWindow*)getWindow; +- (NSWindow*)getWindow; - (void)nudge; - (void)pushCursor; - (void)popCursor; - (MilskoFakePointer*)getHandle; -+ (void)eventCanceller:(MilskoCocoa*)this; @end #define OBJC(x) x diff --git a/pl/rules.pl b/pl/rules.pl index 3d1f2c0fc..6c23006bd 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -57,9 +57,10 @@ if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { new_object("src/backend/cocoa.m"); if(param_get("gnustep")){ - add_incdir2("-I/usr/GNUstep/System/Library/Headers"); - add_libdir("-L/usr/GNUstep/System/Library/Libraries"); - add_ldflags("-fblocks -lobjc -lgnustep-base -lm -lgnustep-gui"); + add_incdir("-I".`gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`); + add_libdir("-L".`gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`); + add_cflags("-fobjc-runtime=gnustep-2.0 -fblocks"); + add_ldflags("-lobjc -lgnustep-base -lm -lgnustep-gui"); } if (param_get("opengl")) { diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 1048f82bf..adf8f740f 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -136,8 +136,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { handle:(MwLL)r { MilskoCocoa* c = [MilskoCocoa alloc]; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [c retain]; + c->application = (MilskoCocoaApplication*)[MilskoCocoaApplication sharedApplication]; + [c->application retain]; /* * MacOS doesn't really have a "default" window position, you're actually @@ -151,11 +152,10 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) : 0; } - c->application = NSApp; - c->rect = NSMakeRect(x, y, width, height); + c->rect = NSMakeRect(x, y, width, height); if(parent == NULL) { - c->window = [[MilskoCocoaWindow alloc] + c->window = [[NSWindow alloc] initWithContentRect:rectFlip(c->rect) styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | @@ -183,6 +183,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [c->application retain]; [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + c->modalSession = [c->application beginModalSessionForWindow:c->window]; } else { MilskoCocoa* p = parent->cocoa.real; @@ -197,6 +198,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; [p->view addSubview:c->view]; + + c->modalSession = p->modalSession; } [c->window setAcceptsMouseMovedEvents:MwTRUE]; @@ -205,8 +208,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [c->handle setPointer:r]; [c->view addSubview:c->handle]; - c->modalSession = [c->application beginModalSessionForWindow:c->window]; - c->parent = parent; + c->parent = parent; c->_forceRender = MwTRUE; c->strHash = 0; @@ -350,7 +352,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (int)pending { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; MwBool isPending = [self->application pending]; - [NSApp runModalSession:self->modalSession]; + [self->application runModalSession:self->modalSession]; [pool release]; return _forceRender || _eventsPending || isPending; }; @@ -954,7 +956,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @end @implementation MilskoCocoaApplicationDelegate -- (MilskoCocoaApplicationDelegate*)initWithAppl:(NSApplication*)_appl { +- (MilskoCocoaApplicationDelegate*)initWithAppl:(MilskoCocoaApplication*)_appl { self->appl = _appl; return self; } @@ -1001,10 +1003,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { // This will close/terminate the application when the main window is closed. - (void)windowWillClose:(NSNotification*)notification { (void)notification; - // MilskoCocoa *window = notification.object; - // MwLL handle = [window getHandle].pointer; - // MwLLDispatch(handle, close, NULL); - [NSApp terminate:nil]; + MilskoCocoa* window = notification.object; + MwLL handle = [window getHandle].pointer; + MwLLDispatch(handle, close, NULL); } - (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { @@ -1235,7 +1236,9 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static int MwLLCocoaCallInitImpl(void) { - [NSApplication sharedApplication]; + printf("Using GNUStep Backend\n"); + + [MilskoCocoaApplication sharedApplication]; return 0; } From 522f32cfcdd1f0edc85ab429c447482058a201ec Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 21:19:09 -0700 Subject: [PATCH 337/409] mac: revert back to what i had before with drawing, i still don't know how to fix this but it's better then nothing --- src/backend/cocoa.m | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index adf8f740f..c8fa2a9ca 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -657,10 +657,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSArray* subviews = [self subviews]; int i; - if(self->width != dirtyRect.size.width || self->height != dirtyRect.size.height) { - if(self->rep) { - [self->rep release]; - } + if(!self->rep) { if(dirtyRect.size.width && dirtyRect.size.height) { [self initRepAndContextWithWidth:dirtyRect.size.width Height:dirtyRect.size.height]; @@ -672,8 +669,13 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } } - [self->rep drawInRect:[self bounds]]; + [self->rep drawInRect:NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, [self->rep pixelsWide], [self->rep pixelsHigh])]; + for(i = 0; i < [subviews count]; i++) { + MilskoCocoaView* subview = [subviews objectAtIndex:i]; + NSRect bounds = [subview bounds]; + [subview drawRect:bounds]; + } [pool release]; } @@ -1003,9 +1005,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { // This will close/terminate the application when the main window is closed. - (void)windowWillClose:(NSNotification*)notification { (void)notification; - MilskoCocoa* window = notification.object; - MwLL handle = [window getHandle].pointer; - MwLLDispatch(handle, close, NULL); + // MilskoCocoa* window = notification.object; + // MwLL handle = [window getHandle].pointer; + // MwLLDispatch(handle, close, NULL); } - (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { @@ -1236,7 +1238,9 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static int MwLLCocoaCallInitImpl(void) { +#ifndef __APPLE__ printf("Using GNUStep Backend\n"); +#endif [MilskoCocoaApplication sharedApplication]; From 554e5cd5ddf711ebb8d69f06768de73eeb6d3afc Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 21:36:17 -0700 Subject: [PATCH 338/409] mac: merge all the MilskoCocoa* functions into the C Milsko functions that call them, cleaning up the codebase --- include/Mw/LowLevel/Cocoa.h | 37 +- src/backend/cocoa.m | 820 +++++++++++++++++------------------- 2 files changed, 377 insertions(+), 480 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index ff7029580..3577ad03e 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -61,6 +61,7 @@ @end @interface MilskoCocoaPixmap : NSObject { + @public MwBool valid; int width; int height; @@ -103,6 +104,7 @@ @end @interface MilskoCocoa : NSObject { + @public MilskoCocoaApplication* application; MwBool _forceRender; MwBool _eventsPending; @@ -123,41 +125,6 @@ MwBool rejectFirstTest; } - -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)handle; -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h; -- (void)setX:(int)x Y:(int)y; -- (void)setW:(int)w H:(int)h; -- (int)pending; -- (void)getNextEvent; -- (void)setTitle:(const char*)title; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)rect; -- (void)setIcon:(MwLLPixmap)pixmap; -- (void)forceRender; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask; -- (void)detachWithPoint:(MwPoint*)point; -- (void)show:(int)show; -- (void)makePopupWithParent:(MwLL)parent; -- (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy; -- (void)makeBorderless:(int)toggle; -- (void)focus; -- (void)grabPointer:(int)toggle; -- (void)setClipboard:(const char*)text; -- (void)makeToolWindow; -- (void)getCursorCoord:(MwPoint*)point; -- (void)getScreenSize:(MwRect*)rect; - (void)destroy; - (void)sendClipboardEvent; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index c8fa2a9ca..b43aef2b7 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -127,261 +127,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @end @implementation MilskoCocoa - -+ (MilskoCocoa*)newWithParent:(MwLL)parent - x:(int)x - y:(int)y - width:(int)width - height:(int)height - handle:(MwLL)r { - MilskoCocoa* c = [MilskoCocoa alloc]; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [c retain]; - c->application = (MilskoCocoaApplication*)[MilskoCocoaApplication sharedApplication]; - [c->application retain]; - - /* - * MacOS doesn't really have a "default" window position, you're actually - * meant to center the window yourself, so if the user passes MwDEFAULT - * respond appropriately. Also for child windows just have it be 0. - */ - if(x == MwDEFAULT) { - x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; - } - if(y == MwDEFAULT) { - y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) - : 0; - } - c->rect = NSMakeRect(x, y, width, height); - - if(parent == NULL) { - c->window = [[NSWindow alloc] - initWithContentRect:rectFlip(c->rect) - styleMask:(NSTitledWindowMask | - NSClosableWindowMask | NSMiniaturizableWindowMask | - NSResizableWindowMask) - backing:NSBackingStoreBuffered - defer:NO]; - [c->window - setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; - [c->window retain]; - - [c->window makeKeyAndOrderFront:c->application]; - [c->window makeFirstResponder:c->view]; - - c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; - [c->view retain]; - [c->window setContentView:c->view]; - - if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { - [c->application - setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; - } - [c->application activateIgnoringOtherApps:MwTRUE]; - [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] - initWithAppl:c->application]]; - [c->application retain]; - - [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; - c->modalSession = [c->application beginModalSessionForWindow:c->window]; - } else { - MilskoCocoa* p = parent->cocoa.real; - - c->window = p->window; - - NSRect rect = localRectFlip(c->rect, p->view); - c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; - [c->view setBounds:c->rect]; - [c->view retain]; - [c->view setChild]; - - [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; - - [p->view addSubview:c->view]; - - c->modalSession = p->modalSession; - } - [c->window setAcceptsMouseMovedEvents:MwTRUE]; - - c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; - [c->handle retain]; - [c->handle setPointer:r]; - [c->view addSubview:c->handle]; - - c->parent = parent; - - c->_forceRender = MwTRUE; - c->strHash = 0; - - c->cursorPixmap = NULL; - - [c->application finishLaunching]; - - c->pointerLocked = MwFALSE; - - [pool release]; - return c; -} - -- (void)polygonWithPoints:(MwPoint*)points - points_count:(int)points_count - color:(MwLLColor)color { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - int i; - NSBezierPath* path = [NSBezierPath bezierPath]; - /* whatever rect we use for coordinate flipping */ - NSRect _rect = parent ? [self->view bounds] : [self->window frame]; - - NSColor* nscolor = - [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; - - [nscolor setFill]; - for(i = 0; i < points_count; i++) { - NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); - if(i == 0) { - [path moveToPoint:p]; - } else { - [path lineToPoint:p]; - } - } - - [path closePath]; - [path fill]; - - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; -}; -- (void)lineWithPoints:(MwPoint*)points color:(MwLLColor)color { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - int i; - NSBezierPath* path = [NSBezierPath bezierPath]; - /* whatever rect we use for coordinate flipping */ - NSRect _rect = parent ? [self->view bounds] : [self->window frame]; - - NSColor* nscolor = - [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; - - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; - - [nscolor setFill]; - for(i = 0; i < 2; i++) { - NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); - if(i == 0) { - [path moveToPoint:p]; - } else { - [path lineToPoint:p]; - } - } - - [path closePath]; - [path stroke]; - - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; -}; -- (void)getX:(int*)x Y:(int*)y W:(unsigned int*)w H:(unsigned int*)h { - NSRect frame; - if(parent) { - frame = [self->view frame]; - } else { - frame = [self->window frame]; - } - frame = rectFlip(frame); - - *x = frame.origin.x; - *y = frame.origin.y; - - *w = frame.size.width; - *h = frame.size.height; -}; -- (void)setX:(int)x Y:(int)y { - NSRect frame; - if(parent) { - frame = [self->view frame]; - } else { - frame = [self->window frame]; - } - - frame.origin.x = x; - frame.origin.y = y; - - if(!parent) { - frame = rectFlip(frame); - [self->window setFrame:frame display:MwTRUE animate:MwTRUE]; - } else { - frame = localRectFlip(frame, parent->cocoa.real->view); - [self->view setBounds:frame]; - } - [self nudge]; -}; -- (void)setW:(int)w H:(int)h { - NSRect frame = [self->window frame]; - frame.size.width = w; - frame.size.height = h; - - self->rect = frame; - - [self->view setFrameSize:frame.size]; - if(self->parent) { - [self->view setFrame:frame]; - } else { - [self->window setFrame:frame display:YES animate:false]; - } - [self nudge]; -}; -- (int)pending { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MwBool isPending = [self->application pending]; - [self->application runModalSession:self->modalSession]; - [pool release]; - return _forceRender || _eventsPending || isPending; -}; - -- (void)getNextEvent { - MwLL h = [self->handle pointer]; - if(_forceRender) { - MwLLDispatch(h, draw, NULL); - _forceRender = MwFALSE; - } - if(_eventsPending) { - MwLLDispatch(h, draw, NULL); - _eventsPending = MwFALSE; - } - [self sendClipboardEvent]; - -#ifdef __APPLE__ - if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { - struct CGPoint pos; - pos.x = [window frame].origin.x + [window frame].size.width / 2; - pos.y = [window frame].origin.y + [window frame].size.height / 2; - - CGWarpMouseCursorPosition(pos); - } -#endif - - [self->application updateWindows]; -}; - - (void)sendClipboardEvent { /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; @@ -413,159 +158,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [pool release];*/ } -- (void)setTitle:(const char*)title { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [self->window - setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; - [pool release]; -}; -- (void)drawPixmap:(MwLLPixmap)pixmap rect:(MwRect*)_rect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MilskoCocoaPixmap* p = pixmap->cocoa.real; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; - - [[p image] - drawInRect:localRectFlip(NSMakeRect(_rect->x, _rect->y, _rect->width, _rect->height), self->view) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0]; - - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; -}; -- (void)setIcon:(MwLLPixmap)pixmap { - [self->application setApplicationIconImage:[pixmap->cocoa.real image]]; -}; -- (void)forceRender { - self->_forceRender = MwTRUE; -}; -- (void)setCursor:(MwCursor*)image mask:(MwCursor*)mask { - int y, x, ys, xs; - unsigned char* di = malloc(image->width * image->height * 4); - memset(di, 0, image->width * image->height * 4); - - if(self->cursorPixmap) { - [self->cursorPixmap destroy]; - } - self->cursorPixmap = - [MilskoCocoaPixmap newWithWidth:image->width - height:image->height]; - - xs = -mask->x + image->x; - ys = MwCursorDataHeight + mask->y; - ys = MwCursorDataHeight + image->y - ys; - - for(y = 0; y < mask->height; y++) { - unsigned int d = mask->data[y]; - for(x = mask->width - 1; x >= 0; x--) { - int px = 0; - int idx = ((y * mask->width) + x) * 4; - - if(d & 1) { - di[idx + 3] = 255; - }; - d = d >> 1; - } - } - for(y = 0; y < image->height; y++) { - unsigned int d = image->data[y]; - for(x = image->width - 1; x >= 0; x--) { - int px = 0; - int idx = ((y * image->width) + x) * 4; - - if(d & 1) { - px = 255; - }; - - di[idx] = px; - di[idx + 1] = px; - di[idx + 2] = px; - d = d >> 1; - } - } - - [self->cursorPixmap updateWithData:di]; - - self->cursor = [[NSCursor alloc] - initWithImage:[self->cursorPixmap image] - hotSpot:NSMakePoint(image->x, image->y + image->height)]; - [self->cursor retain]; - - [self->cursor pop]; - [self->cursor push]; - - free(di); -}; -- (void)detachWithPoint:(MwPoint*)point { - [self->window setParentWindow:NULL]; -}; -- (void)show:(int)show { - (void)show; -}; -- (void)makePopupWithParent:(MwLL)_parent { - (void)_parent; -}; -- (void)setSizeHintsWithMinX:(int)minx - MinY:(int)miny - MaxX:(int)maxx - MaxY:(int)maxy { - [self->window setMinSize:NSMakeSize(minx, miny)]; - [self->window setMaxSize:NSMakeSize(maxx, maxy)]; -}; -- (void)makeBorderless:(int)toggle { - MwU32 mask = [self->window styleMask]; - if(toggle) { - mask ^= NSBorderlessWindowMask; - mask |= NSTitledWindowMask; - } else { - mask |= NSBorderlessWindowMask; - mask ^= NSTitledWindowMask; - } - [self->window initWithContentRect:self->rect - styleMask:mask - backing:NSBackingStoreBuffered - defer:NO]; -}; -- (void)focus { - [self->window makeMainWindow]; -}; -- (void)grabPointer:(int)toggle { - self->pointerLocked = toggle; -}; -- (void)setClipboard:(const char*)text { - (void)text; - // TODO: find out how to do this while supporting 10.4 - // NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - // NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - // [pasteboard declareTypes:[NSArray arrayWithObjects:NSPasteboardTypeString] - // owner:nil]; [pasteboard setString:[NSString stringWithUTF8String:text] - // forType:NSPasteboardTypeString]; [pool release]; -}; -- (void)makeToolWindow { - /* If my understand of what a "tool window" usually is is correct then I - * highly doubt the Mac OS has this and if they did they probably outright - * removed it along time ago is this kind of conflicts with modern UX. So - * we'll just make it borderless idgaf */ - [self makeBorderless:MwTRUE]; -}; -- (void)getCursorCoord:(MwPoint*)point { - NSPoint p = [NSEvent mouseLocation]; - point->x = p.x; - point->y = p.y; -}; -- (void)getScreenSize:(MwRect*)_rect { - NSScreen* screen = [self->window screen]; - _rect->x = [screen frame].origin.x; - _rect->y = [screen frame].origin.y; - _rect->width = [screen frame].size.width; - _rect->height = [screen frame].size.height; -}; - (void)destroy { [self->handle release]; [self->window release]; @@ -1046,18 +638,98 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @end static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { - MwLL r; - r = malloc(sizeof(*r)); + MwLL r; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoa* c = [MilskoCocoa alloc]; + r = malloc(sizeof(*r)); MwLLCreateCommon(r); - MilskoCocoa* o = [MilskoCocoa newWithParent:parent - x:x - y:y - width:width - height:height - handle:r]; - r->cocoa.real = o; + [c retain]; + c->application = (MilskoCocoaApplication*)[MilskoCocoaApplication sharedApplication]; + [c->application retain]; + + /* + * MacOS doesn't really have a "default" window position, you're actually + * meant to center the window yourself, so if the user passes MwDEFAULT + * respond appropriately. Also for child windows just have it be 0. + */ + if(x == MwDEFAULT) { + x = r ? ([[NSScreen mainScreen] frame].size.width / 2.) - (width / 2.) : 0; + } + if(y == MwDEFAULT) { + y = r ? ([[NSScreen mainScreen] frame].size.height / 2.) - (height / 2.) + : 0; + } + c->rect = NSMakeRect(x, y, width, height); + + if(parent == NULL) { + c->window = [[NSWindow alloc] + initWithContentRect:rectFlip(c->rect) + styleMask:(NSTitledWindowMask | + NSClosableWindowMask | NSMiniaturizableWindowMask | + NSResizableWindowMask) + backing:NSBackingStoreBuffered + defer:NO]; + [c->window + setDelegate:[[MilskoCocoaWindowDelegate alloc] initWithWin:c->window]]; + [c->window retain]; + + [c->window makeKeyAndOrderFront:c->application]; + [c->window makeFirstResponder:c->view]; + + c->view = [[MilskoCocoaView alloc] initWithFrame:c->rect]; + [c->view retain]; + [c->window setContentView:c->view]; + + if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { + [c->application + setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; + } + [c->application activateIgnoringOtherApps:MwTRUE]; + [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] + initWithAppl:c->application]]; + [c->application retain]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + c->modalSession = [c->application beginModalSessionForWindow:c->window]; + } else { + MilskoCocoa* p = parent->cocoa.real; + + c->window = p->window; + + NSRect rect = localRectFlip(c->rect, p->view); + c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; + [c->view setBounds:c->rect]; + [c->view retain]; + [c->view setChild]; + + [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; + + [p->view addSubview:c->view]; + + c->modalSession = p->modalSession; + } + [c->window setAcceptsMouseMovedEvents:MwTRUE]; + + c->handle = [[MilskoFakePointer alloc] initWithFrame:NSMakeRect(0, 0, 1, 1)]; + [c->handle retain]; + [c->handle setPointer:r]; + [c->view addSubview:c->handle]; + + c->parent = parent; + + c->_forceRender = MwTRUE; + c->strHash = 0; + + c->cursorPixmap = NULL; + + [c->application finishLaunching]; + + c->pointerLocked = MwFALSE; + + [pool release]; + r->cocoa.real = c; return r; } @@ -1082,13 +754,81 @@ static void MwLLEndDrawImpl(MwLL handle) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h polygonWithPoints:points points_count:points_count color:color]; + MilskoCocoa* self = handle->cocoa.real; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + /* whatever rect we use for coordinate flipping */ + NSRect _rect = self->parent ? [self->view bounds] : [self->window frame]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; + + [nscolor setFill]; + for(i = 0; i < points_count; i++) { + NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); + if(i == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path fill]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } + [pool release]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MilskoCocoa* h = handle->cocoa.real; - [h lineWithPoints:points color:color]; + MilskoCocoa* self = handle->cocoa.real; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + /* whatever rect we use for coordinate flipping */ + NSRect _rect = self->parent ? [self->view bounds] : [self->window frame]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:color->common.red / 255. + green:color->common.green / 255. + blue:color->common.blue / 255. + alpha:1.0]; + + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; + + [nscolor setFill]; + for(i = 0; i < 2; i++) { + NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); + if(i == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path stroke]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } + [pool release]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -1106,16 +846,60 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, - unsigned int* height) { - [handle->cocoa.real getX:x Y:y W:w H:height]; + unsigned int* h) { + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + frame = rectFlip(frame); + + *x = frame.origin.x; + *y = frame.origin.y; + + *w = frame.size.width; + *h = frame.size.height; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { - [handle->cocoa.real setX:x Y:y]; + MilskoCocoa* self = handle->cocoa.real; + NSRect frame; + if(self->parent) { + frame = [self->view frame]; + } else { + frame = [self->window frame]; + } + + frame.origin.x = x; + frame.origin.y = y; + + if(!self->parent) { + frame = rectFlip(frame); + [self->window setFrame:frame display:MwTRUE animate:MwTRUE]; + } else { + frame = localRectFlip(frame, self->parent->cocoa.real->view); + [self->view setBounds:frame]; + } + [self nudge]; } -static void MwLLSetWHImpl(MwLL handle, int w, int height) { - [handle->cocoa.real setW:w H:height]; +static void MwLLSetWHImpl(MwLL handle, int w, int h) { + MilskoCocoa* self = handle->cocoa.real; + NSRect frame = [self->window frame]; + frame.size.width = w; + frame.size.height = h; + + self->rect = frame; + + [self->view setFrameSize:frame.size]; + if(self->parent) { + [self->view setFrame:frame]; + } else { + [self->window setFrame:frame display:YES animate:false]; + } + [self nudge]; } static void MwLLFreeColorImpl(MwLLColor color) { @@ -1123,15 +907,45 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return [handle->cocoa.real pending]; + MilskoCocoa* self = handle->cocoa.real; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MwBool isPending = [self->application pending]; + [self->application runModalSession:self->modalSession]; + [pool release]; + return self->_forceRender || self->_eventsPending || isPending; } static void MwLLNextEventImpl(MwLL handle) { - [handle->cocoa.real getNextEvent]; + MilskoCocoa* self = handle->cocoa.real; + MwLL h = [self->handle pointer]; + if(self->_forceRender) { + MwLLDispatch(h, draw, NULL); + self->_forceRender = MwFALSE; + } + if(self->_eventsPending) { + MwLLDispatch(h, draw, NULL); + self->_eventsPending = MwFALSE; + } + [self sendClipboardEvent]; + +#ifdef __APPLE__ + if(self->pointerLocked && [self->window isMainWindow] && self->lastEvent) { + struct CGPoint pos; + pos.x = [self->window frame].origin.x + [self->window frame].size.width / 2; + pos.y = [self->window frame].origin.y + [self->window frame].size.height / 2; + + CGWarpMouseCursorPosition(pos); + } +#endif + + [self->application updateWindows]; } static void MwLLSetTitleImpl(MwLL handle, const char* title) { - [handle->cocoa.real setTitle:title]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [handle->cocoa.real->window + setTitleWithRepresentedFilename:[NSString stringWithUTF8String:title]]; + [pool release]; } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, @@ -1154,7 +968,24 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, } static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { - [pixmap->cocoa.real updateWithData:pixmap->common.raw]; + MilskoCocoaPixmap* self = pixmap->cocoa.real; + memcpy(self->buf, pixmap->common.raw, pixmap->common.width * pixmap->common.height * 4); + if(self->rep) { + [self->image removeRepresentation:self->rep]; + [self->rep release]; + } + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf + pixelsWide:(int)pixmap->common.width + pixelsHigh:(int)pixmap->common.height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)pixmap->common.width * 4 + bitsPerPixel:32]; + [self->image addRepresentation:self->rep]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { @@ -1164,53 +995,141 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - [handle->cocoa.real drawPixmap:pixmap rect:rect]; + MilskoCocoa* self = handle->cocoa.real; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MilskoCocoaPixmap* p = pixmap->cocoa.real; + NSGraphicsContext* ctx = [self->view context]; + if(ctx) { + [NSGraphicsContext saveGraphicsState]; + [NSGraphicsContext setCurrentContext:ctx]; + + [[p image] + drawInRect:localRectFlip(NSMakeRect(rect->x, rect->y, rect->width, rect->height), self->view) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; + + [NSGraphicsContext restoreGraphicsState]; + + [self->view setNeedsDisplay:YES]; + } + [pool release]; MwLLForceRender(handle); } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { - [handle->cocoa.real setIcon:pixmap]; + [handle->cocoa.real->application setApplicationIconImage:[pixmap->cocoa.real image]]; } static void MwLLForceRenderImpl(MwLL handle) { - [handle->cocoa.real forceRender]; + handle->cocoa.real->_forceRender = MwTRUE; } static void MwLLSetCursorImpl(MwLL handle, MwCursor* image, MwCursor* mask) { - [handle->cocoa.real setCursor:image mask:mask]; + MilskoCocoa* self = handle->cocoa.real; + int y, x, ys, xs; + unsigned char* di = malloc(image->width * image->height * 4); + memset(di, 0, image->width * image->height * 4); + + if(self->cursorPixmap) { + [self->cursorPixmap destroy]; + } + self->cursorPixmap = + [MilskoCocoaPixmap newWithWidth:image->width + height:image->height]; + + xs = -mask->x + image->x; + ys = MwCursorDataHeight + mask->y; + ys = MwCursorDataHeight + image->y - ys; + + for(y = 0; y < mask->height; y++) { + unsigned int d = mask->data[y]; + for(x = mask->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * mask->width) + x) * 4; + + if(d & 1) { + di[idx + 3] = 255; + }; + d = d >> 1; + } + } + for(y = 0; y < image->height; y++) { + unsigned int d = image->data[y]; + for(x = image->width - 1; x >= 0; x--) { + int px = 0; + int idx = ((y * image->width) + x) * 4; + + if(d & 1) { + px = 255; + }; + + di[idx] = px; + di[idx + 1] = px; + di[idx + 2] = px; + d = d >> 1; + } + } + + [self->cursorPixmap updateWithData:di]; + + self->cursor = [[NSCursor alloc] + initWithImage:[self->cursorPixmap image] + hotSpot:NSMakePoint(image->x, image->y + image->height)]; + [self->cursor retain]; + + [self->cursor pop]; + [self->cursor push]; + + free(di); } static void MwLLDetachImpl(MwLL handle, MwPoint* point) { - [handle->cocoa.real detachWithPoint:point]; + [handle->cocoa.real->window setParentWindow:NULL]; } static void MwLLShowImpl(MwLL handle, int show) { - [handle->cocoa.real show:show]; + (void)show; } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { - [handle->cocoa.real makePopupWithParent:parent]; + (void)parent; } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { - [handle->cocoa.real setSizeHintsWithMinX:minx MinY:miny MaxX:maxx MaxY:maxy]; + MilskoCocoa* self = handle->cocoa.real; + [self->window setMinSize:NSMakeSize(minx, miny)]; + [self->window setMaxSize:NSMakeSize(maxx, maxy)]; } static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { - [handle->cocoa.real makeBorderless:toggle]; + MilskoCocoa* self = handle->cocoa.real; + MwU32 mask = [self->window styleMask]; + if(toggle) { + mask ^= NSBorderlessWindowMask; + mask |= NSTitledWindowMask; + } else { + mask |= NSBorderlessWindowMask; + mask ^= NSTitledWindowMask; + } + [self->window initWithContentRect:self->rect + styleMask:mask + backing:NSBackingStoreBuffered + defer:NO]; } static void MwLLFocusImpl(MwLL handle) { - [handle->cocoa.real focus]; + [handle->cocoa.real->application activateIgnoringOtherApps:MwTRUE]; } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { - [handle->cocoa.real grabPointer:toggle]; + handle->cocoa.real->pointerLocked = toggle; } static void MwLLSetClipboardImpl(MwLL handle, const char* text) { - [handle->cocoa.real setClipboard:text]; + (void)handle; + (void)text; } static void MwLLGetClipboardImpl(MwLL handle) { @@ -1218,15 +1137,26 @@ static void MwLLGetClipboardImpl(MwLL handle) { } static void MwLLMakeToolWindowImpl(MwLL handle) { - [handle->cocoa.real makeToolWindow]; + /* If my understand of what a "tool window" usually is is correct then I + * highly doubt the Mac OS has this and if they did they probably outright + * removed it along time ago is this kind of conflicts with modern UX. So + * we'll just make it borderless idgaf */ + MwLLMakeBorderlessImpl(handle, 1); } static void MwLLGetCursorCoordImpl(MwLL handle, MwPoint* point) { - [handle->cocoa.real getCursorCoord:point]; + NSPoint p = [NSEvent mouseLocation]; + point->x = p.x; + point->y = p.y; } static void MwLLGetScreenSizeImpl(MwLL handle, MwRect* rect) { - [handle->cocoa.real getScreenSize:rect]; + MilskoCocoa* self = handle->cocoa.real; + NSScreen* screen = [self->window screen]; + rect->x = [screen frame].origin.x; + rect->y = [screen frame].origin.y; + rect->width = [screen frame].size.width; + rect->height = [screen frame].size.height; } static void MwLLBeginStateChangeImpl(MwLL handle) { From c0d7cb3fbc71811cf4bd6346b58d579567ac890c Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 21:50:10 -0700 Subject: [PATCH 339/409] mac: add a few comments --- src/backend/cocoa.m | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index b43aef2b7..ec20af1c9 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -327,6 +327,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (void)handleKeyEvent:(NSEvent*)ev ll:(MwLL)ll down:(MwBool)isDown { int ch; + /* todo: consolidate these values into the below switch case. */ enum { kVK_ANSI_A = 0x00, kVK_ANSI_S = 0x01, @@ -682,10 +683,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { [c->view retain]; [c->window setContentView:c->view]; + /* In order for our application to be front and center when launched, we need to use this function introduced in 10.5. There's no function that works on 10.4 or below as far as I know because what you're actually supposed to do is use a feature of XCode project files to modify the settings of the compiled app to set the activation policy. */ if([c->application respondsToSelector:@selector(setActivationPolicy:)]) { [c->application setActivationPolicy:0 /* NSApplicationActivationPolicyRegular */]; } + [c->application activateIgnoringOtherApps:MwTRUE]; [c->application setDelegate:[[MilskoCocoaApplicationDelegate alloc] initWithAppl:c->application]]; @@ -694,12 +697,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { [c->view addTrackingRect:c->rect owner:c->view userData:NULL assumeInside:MwFALSE]; c->modalSession = [c->application beginModalSessionForWindow:c->window]; } else { - MilskoCocoa* p = parent->cocoa.real; + MilskoCocoa* p = parent->cocoa.real; + NSRect rect = localRectFlip(c->rect, p->view); c->window = p->window; - - NSRect rect = localRectFlip(c->rect, p->view); - c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; + c->view = [[MilskoCocoaView alloc] initWithFrame:rect]; [c->view setBounds:c->rect]; [c->view retain]; [c->view setChild]; @@ -729,6 +731,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { c->pointerLocked = MwFALSE; [pool release]; + r->cocoa.real = c; return r; From fe72bc92bfd3781b723c7c65ccbc36d8cc04cefb Mon Sep 17 00:00:00 2001 From: IoIxD Date: Mon, 13 Apr 2026 22:30:25 -0700 Subject: [PATCH 340/409] mac: actually dispatch close event. reorganize code slightly more now that less is in objective-c methods --- src/backend/cocoa.m | 317 ++++++++++++++++++++------------------------ 1 file changed, 143 insertions(+), 174 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index ec20af1c9..b88bd423b 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -64,139 +64,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } }; -@implementation MilskoCocoaPixmap - -+ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { - MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; - - p->width = width; - p->height = height; - p->image = NULL; - - p->buf = malloc(width * height * 4); - - p->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - assert(p->rep); - - p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; - assert(p->image); - [p->image addRepresentation:p->rep]; - - return p; -} -- (void)updateWithData:(unsigned char*)_data { - memcpy(self->buf, _data, width * height * 4); - if(self->rep) { - [self->image removeRepresentation:self->rep]; - [self->rep release]; - } - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf - pixelsWide:(int)width - pixelsHigh:(int)height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)width * 4 - bitsPerPixel:32]; - [self->image addRepresentation:self->rep]; -} -- (void)destroy { - free(self->buf); - [self->image removeRepresentation:self->rep]; - [self->image release]; - [self->rep release]; - self->image = NULL; - self->rep = NULL; -} -- (NSImage*)image { - return self->image; -} -@end - -@implementation MilskoCocoa -- (void)sendClipboardEvent { - /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; - NSArray* items = @[ - @"public.utf8-plain-text", - @"public.utf16-external-plain-text", - @"com.apple.traditional-mac-plain-text", - ]; - MwLL this = self->handle.pointer; - - if([pasteboard canReadItemWithDataConformingToTypes:items]) { - char* data = NULL; - size_t size = 0; - for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { - for(NSString* it in items) { - NSString* itemData = [item - stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && - strHash != [itemData hash]) { char* text = malloc([itemData length]); - strncpy(text, [itemData UTF8String], - [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", - text, this); free(text); - } - strHash = [itemData hash]; - } - } - } - } - - [pool release];*/ -} - -- (void)destroy { - [self->handle release]; - [self->window release]; -} - -- (MwLL)getParent { - return self->parent; -} - -- (NSView*)getView { - return view; -} -- (NSWindow*)getWindow { - return window; -} - -- (void)nudge { - MwLL p = self->parent; - self->_eventsPending = MwTRUE; - - if(p) { - [p->cocoa.real->view setNeedsDisplay:true]; - p = p->cocoa.real->parent; - } -} - -- (void)pushCursor { - [self->cursor push]; -} -- (void)popCursor { - [self->cursor pop]; -} - -- (MilskoFakePointer*)getHandle { - return handle; -} - -@end - @implementation MilskoCocoaApplication - (void)sendEvent:(NSEvent*)event { self->doPending = MwTRUE; @@ -555,17 +422,6 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { self->appl = _appl; return self; } -- (void)applicationDidBecomeActive:(NSNotification*)notification { - [self->appl activateIgnoringOtherApps:true]; - // printf("test\n"); -} -- (void)applicationWillFinishLaunching:(NSNotification*)notification { - // printf("test\n"); - // [self->appl activateIgnoringOtherApps:MwTRUE]; -} -- (void)applicationDidFinishLaunching:(NSNotification*)notification { - // [self->appl activateIgnoringOtherApps:MwTRUE]; -} @end @implementation MilskoCocoaWindowDelegate @@ -591,23 +447,19 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [self->w makeKeyAndOrderFront:nil]; } -- (void)windowDidResize:(NSNotification*)notification { - (void)notification; -} - -// This will close/terminate the application when the main window is closed. -- (void)windowWillClose:(NSNotification*)notification { - (void)notification; - // MilskoCocoa* window = notification.object; - // MwLL handle = [window getHandle].pointer; - // MwLLDispatch(handle, close, NULL); -} - - (MilskoCocoaWindowDelegate*)initWithWin:(NSWindow*)win { self->w = win; return self; } +- (void)windowWillClose:(NSNotification*)notification { + if([[[w contentView] subviews] count] != 0) { + MwLL h = [((MilskoFakePointer*)[[[w contentView] subviews] + objectAtIndex:0]) pointer]; + MwLLDispatch(h, close, NULL); + } +} + @end @implementation MilskoFakePointer @@ -638,6 +490,138 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @end +@implementation MilskoCocoaPixmap ++ (MilskoCocoaPixmap*)newWithWidth:(int)width height:(int)height { + MilskoCocoaPixmap* p = [MilskoCocoaPixmap alloc]; + + p->width = width; + p->height = height; + p->image = NULL; + + p->buf = malloc(width * height * 4); + + p->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&p->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + assert(p->rep); + + p->image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)]; + assert(p->image); + [p->image addRepresentation:p->rep]; + + return p; +} +- (void)updateWithData:(unsigned char*)_data { + memcpy(self->buf, _data, width * height * 4); + if(self->rep) { + [self->image removeRepresentation:self->rep]; + [self->rep release]; + } + self->rep = + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf + pixelsWide:(int)width + pixelsHigh:(int)height + bitsPerSample:8 + samplesPerPixel:4 + hasAlpha:YES + isPlanar:NO + colorSpaceName:NSDeviceRGBColorSpace + bytesPerRow:(int)width * 4 + bitsPerPixel:32]; + [self->image addRepresentation:self->rep]; +} +- (void)destroy { + free(self->buf); + [self->image removeRepresentation:self->rep]; + [self->image release]; + [self->rep release]; + self->image = NULL; + self->rep = NULL; +} +- (NSImage*)image { + return self->image; +} +@end + +@implementation MilskoCocoa +- (void)sendClipboardEvent { + /*NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + NSPasteboard* pasteboard = [NSPasteboard generalPasteboard]; + NSArray* items = @[ + @"public.utf8-plain-text", + @"public.utf16-external-plain-text", + @"com.apple.traditional-mac-plain-text", + ]; + MwLL this = self->handle.pointer; + + if([pasteboard canReadItemWithDataConformingToTypes:items]) { + char* data = NULL; + size_t size = 0; + for(NSPasteboardItem* item in [pasteboard pasteboardItems]) { + for(NSString* it in items) { + NSString* itemData = [item + stringForType:(NSString*)it]; if(itemData != NULL) { if(strHash != 0 && + strHash != [itemData hash]) { char* text = malloc([itemData length]); + strncpy(text, [itemData UTF8String], + [itemData length]); MwLLDispatch(this, clipboard, text); printf("%s -> %p\n", + text, this); free(text); + } + strHash = [itemData hash]; + } + } + } + } + + [pool release];*/ +} + +- (void)destroy { + [self->handle release]; + [self->window release]; +} + +- (MwLL)getParent { + return self->parent; +} + +- (NSView*)getView { + return view; +} +- (NSWindow*)getWindow { + return window; +} + +- (void)nudge { + MwLL p = self->parent; + self->_eventsPending = MwTRUE; + + if(p) { + [p->cocoa.real->view setNeedsDisplay:true]; + p = p->cocoa.real->parent; + } +} + +- (void)pushCursor { + [self->cursor push]; +} +- (void)popCursor { + [self->cursor pop]; +} + +- (MilskoFakePointer*)getHandle { + return handle; +} + +@end + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; @@ -953,9 +937,9 @@ static void MwLLSetTitleImpl(MwLL handle, const char* title) { static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { - (void)handle; - MwLLPixmap r = malloc(sizeof(*r)); + + (void)handle; memset(r, 0, sizeof(*r)); r->common.raw = malloc(4 * width * height); @@ -973,22 +957,7 @@ static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { MilskoCocoaPixmap* self = pixmap->cocoa.real; memcpy(self->buf, pixmap->common.raw, pixmap->common.width * pixmap->common.height * 4); - if(self->rep) { - [self->image removeRepresentation:self->rep]; - [self->rep release]; - } - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf - pixelsWide:(int)pixmap->common.width - pixelsHigh:(int)pixmap->common.height - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:(int)pixmap->common.width * 4 - bitsPerPixel:32]; - [self->image addRepresentation:self->rep]; + [pixmap->cocoa.real updateWithData:pixmap->common.raw]; } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { From 0e2e3a190157cc5f29fdbb1a54a2301383e9f97d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 13:13:17 -0700 Subject: [PATCH 341/409] some gnustep fixes, probably close to giving up on this ngl --- include/Mw/LowLevel/Cocoa.h | 2 ++ src/backend/cocoa.m | 8 ++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 3577ad03e..2a8c7ec7c 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -81,6 +81,8 @@ @end @interface MilskoCocoaView : NSView { + @public + unsigned char* buf; NSBitmapImageRep* rep; NSGraphicsContext* context; MwBool valid; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index b88bd423b..c336f7fb8 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -140,8 +140,11 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { - (void)initRepAndContextWithWidth:(float)w Height:(float)h { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + self->buf = malloc(w * h * 4); + memset(self->buf, 255, w * h * 4); + self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL + [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf pixelsWide:w pixelsHigh:h bitsPerSample:8 @@ -536,6 +539,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { colorSpaceName:NSDeviceRGBColorSpace bytesPerRow:(int)width * 4 bitsPerPixel:32]; + assert(self->rep); [self->image addRepresentation:self->rep]; } - (void)destroy { @@ -975,7 +979,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { [NSGraphicsContext saveGraphicsState]; [NSGraphicsContext setCurrentContext:ctx]; - [[p image] + [p->image drawInRect:localRectFlip(NSMakeRect(rect->x, rect->y, rect->width, rect->height), self->view) fromRect:NSZeroRect operation:NSCompositeSourceOver From f22f45d5bf61f1b2fb9dd819bfe6b3f73acfb303 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 13:34:49 -0700 Subject: [PATCH 342/409] give up on rounded borders --- include/Mw/Draw.h | 6 +- src/core.c | 1 - src/draw.c | 284 ++++++++++----------------------------- src/widget/box.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 2 +- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/listbox.c | 6 +- src/widget/menu.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 8 +- src/widget/window.c | 2 +- 15 files changed, 92 insertions(+), 233 deletions(-) diff --git a/include/Mw/Draw.h b/include/Mw/Draw.h index c6c361275..9208d725d 100644 --- a/include/Mw/Draw.h +++ b/include/Mw/Draw.h @@ -53,7 +53,7 @@ MWDECL void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color); * @param rect Rectangle area * @param color Color */ -MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounded); +MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color); /*! * @brief Draws a frame @@ -63,7 +63,7 @@ MWDECL void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int * @param invert Invert the 3D border color or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int rounded); +MWDECL void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert); /*! * @brief Does the DrawFrame/DrawRect combo used for drawing widget. @@ -96,7 +96,7 @@ MWDECL void MwDrawTriangle(MwWidget handle, MwRect* rect, MwLLColor color, int i * @param rounded Rounded or not * @warning `rect` gets changed to the area of rectangle inside */ -MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded); +MWDECL void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same); /*! * @brief Creates a pixmap from image diff --git a/src/core.c b/src/core.c index cdd0723b9..2b98ec5fc 100644 --- a/src/core.c +++ b/src/core.c @@ -606,7 +606,6 @@ int MwGetInteger(MwWidget handle, const char* key) { #else if(strcmp(key, MwNmodernLook) == 0) return inherit_integer(handle, key, 1); #endif - if(strcmp(key, MwNisRounded) == 0) return inherit_integer(handle, key, 1); if(strcmp(key, MwNdarkTheme) == 0) return inherit_integer(handle, key, 0); if(strcmp(key, MwNuseMonospace) == 0) return inherit_integer(handle, key, 0); } diff --git a/src/draw.c b/src/draw.c index 12ccb5127..f5e1368dd 100644 --- a/src/draw.c +++ b/src/draw.c @@ -11,10 +11,6 @@ #include "../external/stb_ds.h" -#define DEFAULT_ROUNDNESS 5 -#define MAX_ROUNDNESS 30 -#define BORDER_SMOOTHNESS 50 - static int get_color_diff(MwWidget handle) { if(MwGetInteger(handle, MwNmodernLook)) { return 40; @@ -106,7 +102,7 @@ void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPolygon(handle->lowlevel, p, 4, color); } -void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounded) { +void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; int y, i; double darken = 0.; @@ -115,17 +111,18 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz); MwRect r = *rect; - int roundness = MwGetInteger(handle, MwNroundness); double div; if(rect->width <= 0 || rect->height <= 0) { free(data); return; } - if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; - if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; - div = (roundness <= 10) ? 7. : 10.; memset(data, 0, sz); + r.x += 1; + r.y += 1; + r.width -= 2; + r.height -= 2; + for(y = 0; y < rect->height; y++) { MwLLColor col = MwLightenColor(handle, color, -darken, -darken, -darken); int idx = y * 4; @@ -138,42 +135,18 @@ void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color, int rounde } pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - if(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0) { - for(i = 0; i < roundness; i++) { - int x = (roundness + 2); - int y = rect->y + (roundness + 2); - double point = ((i + (M_PI * 4)) / div); - r.x = (roundness + 4) - (sin(point) * roundness); - r.y = y + (cos(point) * roundness) + 1; - r.width = roundness; - r.height = (rect->height - ((r.y - rect->y) * 2) - 1); - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - r.width = x + (sin(point + 1) * roundness); - r.x = ((rect->width - (roundness + 1)) + (sin(point) * roundness)) - r.width; - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - } - - r = *rect; - r.x += roundness; - r.y += 3; - r.width -= (roundness * 2) + 1; - r.height -= 6; - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - - } else { - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - } + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); MwLLDestroyPixmap(pixmap); free(data); } -void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int rounded) { +void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { int inv; if((inv = MwGetInteger(handle, MwNforceInverted)) != MwDEFAULT && inv) invert = 1; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0, rounded); + MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle), 0, 0); } else { int diff = get_color_diff(handle) / 3 * 2; @@ -181,18 +154,17 @@ void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int int i; int st = invert ? 1 : 0; for(i = st; i < st + 2; i++) { - if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0, 0); - if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0, 0); + if((i % 2) == 0) MwDrawFrameEx(handle, rect, color, invert, MwDefaultBorderWidth(handle) - 1, -diff, (handle->parent == NULL || handle->parent->lowlevel == NULL) ? 1 : 0); + if((i % 2) == 1) MwDrawFrameEx(handle, rect, color, invert, 1, diff, 0); } } else { - MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0, 0); + MwDrawFrameEx(handle, rect, color, invert, 1, 0, 0); } } } void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border) { MwLLColor col; - MwBool rounded = MwGetInteger(handle, MwNroundness) != MwDEFAULT && MwGetInteger(handle, MwNisRounded) != 0; if(rect->width <= 0 || rect->height <= 0) return; @@ -206,11 +178,11 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert } } - MwDrawFrame(handle, rect, color, invert, rounded); + MwDrawFrame(handle, rect, color, invert); } col = invert ? MwLightenColor(handle, color, -8, -8, -8) : color; if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawRectFading(handle, rect, col, rounded); + MwDrawRectFading(handle, rect, col); } else { MwDrawRect(handle, rect, col); } @@ -284,55 +256,47 @@ void MwDrawDiamond(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { MwLLFreeColor(darker); } -static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded) { +static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { MwPoint p[7]; int ColorDiff = get_color_diff(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, ColorDiff - diff, ColorDiff - diff, ColorDiff - diff); - int roundness = MwGetInteger(handle, MwNroundness); + p[0].x = rect->x; + p[0].y = rect->y; - if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; - if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; - if(!(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0)) { - p[0].x = rect->x; - p[0].y = rect->y; + p[1].x = rect->x + rect->width; + p[1].y = rect->y; - p[1].x = rect->x + rect->width; - p[1].y = rect->y; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + border; - p[3].x = rect->x + border; - p[3].y = rect->y + border; + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; - p[4].x = rect->x + border; - p[4].y = rect->y + rect->height - border; - - p[5].x = rect->x; - p[5].y = rect->y + rect->height; - } + p[5].x = rect->x; + p[5].y = rect->y + rect->height; MwLLPolygon(handle->lowlevel, p, 6, invert ? darker : lighter); - if(!(rounded && rect->height >= (roundness * 2) && rect->width >= (roundness * 2) && roundness > 0)) { - p[0].x = rect->x + rect->width; - p[0].y = rect->y; + p[0].x = rect->x + rect->width; + p[0].y = rect->y; - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border; + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; - p[3].x = rect->x + border; - p[3].y = rect->y + rect->height - border; + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; - p[4].x = rect->x; - p[4].y = rect->y + rect->height; + p[4].x = rect->x; + p[4].y = rect->y + rect->height; - p[5].x = rect->x + rect->width; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - } + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); MwLLFreeColor(lighter); MwLLFreeColor(darker); @@ -343,168 +307,64 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, rect->height -= border * 2; } -static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same, int rounded) { +static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { MwPoint p[7]; - int roundness = MwGetInteger(handle, MwNroundness); int i; (void)diff; (void)same; - if(roundness == MwDEFAULT) roundness = DEFAULT_ROUNDNESS; - if(roundness >= MAX_ROUNDNESS) roundness = MAX_ROUNDNESS; - if(rounded && rect->height >= (roundness * 4) && rect->width >= (roundness * 4) && roundness > 0) { - /* top left edge */ - for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { - MwPoint line[2]; - double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = rect->x + (roundness + 2); - int y = rect->y + (roundness + 2); + p[0].x = rect->x; + p[0].y = rect->y; - line[0].x = x - (sin(point) * roundness); - line[0].y = y + (cos(point) * roundness); - line[1].x = x - (sin(point + 1) * roundness); - line[1].y = y + (cos(point + 1) * roundness); - MwLLLine(handle->lowlevel, line, invert ? lighter : darker); - } + p[1].x = rect->x + rect->width; + p[1].y = rect->y; - p[0].x = rect->x + roundness; - p[0].y = rect->y + border; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + border; + p[3].x = rect->x + border; + p[3].y = rect->y + border; - p[1].x = rect->x + rect->width - border - roundness; - p[1].y = rect->y + border; + p[4].x = rect->x + border; + p[4].y = rect->y + rect->height - border; - p[2].x = rect->x + rect->width - border - roundness; - p[2].y = rect->y + border + roundness; - - p[3].x = rect->x + border; - p[3].y = rect->y + border + roundness; - - p[4].x = rect->x + border; - p[4].y = (rect->y + border) + rect->height - roundness; - - p[5].x = rect->x + roundness; - p[5].y = (rect->y + border) + rect->height - roundness; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - - /* top right edge */ - for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { - MwPoint line[2]; - double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = (rect->x + rect->width) - (roundness + 2); - int y = rect->y + (roundness + 2); - double placeholder = (sin(point) * roundness); - line[0].x = x + placeholder; - line[0].y = y + (cos(point) * roundness); - line[1].x = x + (sin(point + 1) * roundness); - line[1].y = y + (cos(point + 1) * roundness); - MwLLLine(handle->lowlevel, line, invert ? lighter : darker); - } - } else { - p[0].x = rect->x; - p[0].y = rect->y; - - p[1].x = rect->x + rect->width; - p[1].y = rect->y; - - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + border; - p[3].x = rect->x + border; - p[3].y = rect->y + border; - - p[4].x = rect->x + border; - p[4].y = rect->y + rect->height - border; - - p[5].x = rect->x; - p[5].y = rect->y + rect->height; - } + p[5].x = rect->x; + p[5].y = rect->y + rect->height; MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - if(rounded && rect->height >= (roundness * 4) && rect->width >= (roundness * 4) && roundness > 0) { - /* bottom left edge */ - for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { - MwPoint line[2]; - double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = rect->x + (roundness + 2); - int y = (rect->y + rect->height) - (roundness + 2); + p[0].x = rect->x + rect->width; + p[0].y = rect->y; - line[0].x = x - (sin(point) * roundness); - line[0].y = y - (cos(point) * roundness); - line[1].x = x - (sin(point + 1) * roundness); - line[1].y = y - (cos(point + 1) * roundness); - MwLLLine(handle->lowlevel, line, invert ? lighter : darker); - } - p[0].x = rect->x + roundness; - p[0].y = rect->y + border + roundness; + p[1].x = rect->x + rect->width - border; + p[1].y = rect->y + border; - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border + roundness; + p[2].x = rect->x + rect->width - border; + p[2].y = rect->y + rect->height - border; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border - roundness; + p[3].x = rect->x + border; + p[3].y = rect->y + rect->height - border; - p[3].x = rect->x + rect->width - border - roundness; - p[3].y = rect->y + rect->height - border; + p[4].x = rect->x; + p[4].y = rect->y + rect->height; - p[4].x = rect->x + border + roundness; - p[4].y = rect->y + rect->height - border; - - p[5].x = rect->x + roundness; - p[5].y = rect->y + rect->height - roundness; - - p[6].x = rect->x + rect->width - border - roundness; - p[6].y = rect->y + rect->height - roundness; - - MwLLPolygon(handle->lowlevel, p, 7, invert ? lighter : darker); - - /* bottom right edge */ - for(i = 0; i < BORDER_SMOOTHNESS; i += 2) { - MwPoint line[2]; - double point = ((i + (M_PI * (BORDER_SMOOTHNESS / 2.))) / (BORDER_SMOOTHNESS)); - int x = (rect->x + rect->width) - (roundness + 2); - int y = (rect->y + rect->height) - (roundness + 2); - - line[0].x = x + (sin(point) * roundness); - line[0].y = y - (cos(point) * roundness); - line[1].x = x + (sin(point + 1) * roundness); - line[1].y = y - (cos(point + 1) * roundness); - MwLLLine(handle->lowlevel, line, invert ? lighter : darker); - } - } else { - p[0].x = rect->x + rect->width; - p[0].y = rect->y; - - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border; - - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border; - - p[3].x = rect->x + border; - p[3].y = rect->y + rect->height - border; - - p[4].x = rect->x; - p[4].y = rect->y + rect->height; - - p[5].x = rect->x + rect->width; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - } + p[5].x = rect->x + rect->width; + p[5].y = rect->y + rect->height; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); } -static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded) { +static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { int ColorDiff = get_color_diff(handle); MwLLColor darker = MwLightenColor(handle, color, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff, -ColorDiff * 3 / 2 + diff); MwLLColor lighter = same ? MwLightenColor(handle, darker, 0, 0, 0) : MwLightenColor(handle, color, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff, (ColorDiff / 2) - diff); MwRect r = *rect; - frame_border_complex(handle, rect, lighter, darker, invert, border, diff, same, rounded); + frame_border_complex(handle, rect, lighter, darker, invert, border, diff, same); r.x += 1; r.y += 1; r.width -= 2; r.height -= 2; - frame_border_complex(handle, &r, lighter, darker, !invert, border, diff, same, rounded); + frame_border_complex(handle, &r, lighter, darker, !invert, border, diff, same); MwLLFreeColor(lighter); MwLLFreeColor(darker); @@ -515,11 +375,11 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color rect->height -= border * 2; } -void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same, int rounded) { +void MwDrawFrameEx(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { if(MwGetInteger(handle, MwNmodernLook)) { - MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same, rounded); + MwDrawFrameEx_complex(handle, rect, color, invert, border, diff, same); } else { - MwDrawFrameEx_simple(handle, rect, color, invert, border, diff, same, rounded); + MwDrawFrameEx_simple(handle, rect, color, invert, border, diff, same); } } diff --git a/src/widget/box.c b/src/widget/box.c index 0cc8df1f7..a87000f0e 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -86,7 +86,7 @@ static void draw(MwWidget handle) { r.height = MwGetInteger(handle, MwNheight); if(MwGetInteger(handle, MwNhasBorder)) { - MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted), 0); + MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); } MwDrawRect(handle, &r, base); diff --git a/src/widget/combobox.c b/src/widget/combobox.c index d52cc2503..22a90060f 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -72,7 +72,7 @@ static void draw(MwWidget handle) { r.y += r.height; r.height = MwDefaultBorderWidth(handle) * 2; - MwDrawFrame(handle, &r, base, 0, 0); + MwDrawFrame(handle, &r, base, 0); MwLLFreeColor(text); MwLLFreeColor(base); diff --git a/src/widget/entry.c b/src/widget/entry.c index 3a7aa764d..bd7dbe1b5 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -49,7 +49,7 @@ static void draw(MwWidget handle) { int attr; MwRect currc; - p.x = (r.width - (r.width / w * w)) / 2 + (MwGetInteger(handle, MwNisRounded) ? MwGetInteger(handle, MwNroundness) : 0); + p.x = (r.width - (r.width / w * w)) / 2; p.y = r.height / 2; len = (r.width - p.x * 2) / w; diff --git a/src/widget/frame.c b/src/widget/frame.c index 3c2ffe99f..117b0f8b9 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -22,7 +22,7 @@ static void draw(MwWidget handle) { fr.y = 0; fr.width = MwGetInteger(handle, MwNwidth); fr.height = MwGetInteger(handle, MwNheight); - MwDrawFrame(handle, &fr, base, inverted, 0); + MwDrawFrame(handle, &fr, base, inverted); rr.x = MwDefaultBorderWidth(handle); rr.y = MwDefaultBorderWidth(handle); diff --git a/src/widget/image.c b/src/widget/image.c index cadddb323..74ee0bfd6 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -20,7 +20,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted), 0); + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, base, MwGetInteger(handle, MwNinverted)); MwDrawRect(handle, &r, base); if(px != NULL) { diff --git a/src/widget/listbox.c b/src/widget/listbox.c index b25528fb7..9960e1d67 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -210,7 +210,7 @@ static void frame_draw(MwWidget handle) { p.x = MwDefaultBorderWidth(handle); p.y = MwDefaultBorderWidth(handle); - MwDrawFrame(handle, &r, base, 1, 0); + MwDrawFrame(handle, &r, base, 1); MwDrawRect(handle, &r, base2); r = r2; @@ -284,7 +284,7 @@ static void frame_draw(MwWidget handle) { handle->bgcolor = NULL; } - MwDrawFrame(handle, &r, base, 1, 0); + MwDrawFrame(handle, &r, base, 1); MwLLFreeColor(text2); MwLLFreeColor(text); @@ -403,7 +403,7 @@ static void draw(MwWidget handle) { r.y = 0; r.width = get_col_width(lb, i); r.height = MwDefaultBorderWidth(handle) * 2 + MwTextHeight(handle, NULL, "M"); - MwDrawFrame(handle, &r, base, 0, 0); + MwDrawFrame(handle, &r, base, 0); x += MwDefaultBorderWidth(handle); diff --git a/src/widget/menu.c b/src/widget/menu.c index 85753f9b3..0808f691d 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -100,7 +100,7 @@ static void draw(MwWidget handle) { BEGIN_MENU_LOOP; if(m->sub[i]->wsub != NULL || (in_area && handle->pressed)) { - MwDrawFrame(handle, &r, base, MwFALSE, 0); + MwDrawFrame(handle, &r, base, MwFALSE); MwDrawWidgetBack(handle, &r, base, 0, MwFALSE); } diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index 7be7bffd7..d85a8ddaf 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -23,7 +23,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - MwDrawFrame(handle, &r, base, 1, 0); + MwDrawFrame(handle, &r, base, 1); MwDrawRect(handle, &r, base); w = MwGetInteger(handle, MwNvalue) - MwGetInteger(handle, MwNminValue); w = w / (MwGetInteger(handle, MwNmaxValue) - MwGetInteger(handle, MwNminValue)); diff --git a/src/widget/separator.c b/src/widget/separator.c index 571c5dfa9..8fcfc5b71 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -25,7 +25,7 @@ static void draw(MwWidget handle) { r.y = (r.height - 2) / 2; r.height = 2; } - MwDrawFrameEx(handle, &r, base, 1, 1, 0, 0, MwGetInteger(handle, MwNmodernLook)); + MwDrawFrameEx(handle, &r, base, 1, 1, 0, 0); MwLLFreeColor(base); } diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 3b6460555..4990fd211 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -59,7 +59,7 @@ static void draw(MwWidget handle) { rc.x += MwGetInteger(handle, MwNleftPadding); - MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0, 0); + MwDrawFrameEx(handle, &rc, base, 1, 1, 0, 0); p.y += 2 + 1; } else { diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 16898ef90..acc35bf69 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -64,7 +64,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** const int len = 4; MwDrawRect(handle, &r, col); - MwDrawFrame(handle, &r, base, tree->opened, 0); + MwDrawFrame(handle, &r, base, tree->opened); if(tree->opened) { l[0].x = r.x + (r.width - len) / 2; l[0].y = r.y + r.height / 2; @@ -91,7 +91,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** MwLLLine(handle->lowlevel, &l[0], text); } r = r2; - MwDrawFrame(handle, &r, base, tree->opened, 0); + MwDrawFrame(handle, &r, base, tree->opened); if(col != base) MwLLFreeColor(col); } else { @@ -183,7 +183,7 @@ static void frame_draw(MwWidget handle) { p.x = MwDefaultBorderWidth(handle); p.y = MwDefaultBorderWidth(handle); - MwDrawFrame(handle, &r, base, 1, 0); + MwDrawFrame(handle, &r, base, 1); MwDrawRect(handle, &r, base2); r = r2; @@ -193,7 +193,7 @@ static void frame_draw(MwWidget handle) { recursion(handle, tv->tree[i], tv->tree, base, text, base2, text2, &p, 0, LineSpace, &skip, &shared, 1, NULL); } - MwDrawFrame(handle, &r, base, 1, 0); + MwDrawFrame(handle, &r, base, 1); MwLLFreeColor(text2); MwLLFreeColor(text); diff --git a/src/widget/window.c b/src/widget/window.c index 74a96e61e..979e073c8 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -18,7 +18,7 @@ static void draw(MwWidget handle) { r.width = MwGetInteger(handle, MwNwidth); r.height = MwGetInteger(handle, MwNheight); - if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, c, MwGetInteger(handle, MwNinverted), 0); + if(MwGetInteger(handle, MwNhasBorder)) MwDrawFrame(handle, &r, c, MwGetInteger(handle, MwNinverted)); MwDrawRect(handle, &r, c); From 1d59488927a823eabcd08b98b20b7820ab5eaafd Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 13:45:47 -0700 Subject: [PATCH 343/409] wayland: fix several places where we don't attach buffer if not configured --- src/backend/wayland.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 148ca4420..220f3901f 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1260,10 +1260,10 @@ static void wl_shm_interface_destroy(struct _MwLLWayland* wayland, wayland_proto } static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { - (void)self; memcpy(buffer->buf, buffer->buf_back, buffer->buf_size); // Yes this is needed every time, it's how we fix weston. - wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); + if(self->wayland.configured) + wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); wl_surface_commit(buffer->surface); } @@ -1338,7 +1338,8 @@ static void framebuffer_setup(struct _MwLLWayland* wayland) { wayland->front_cairo = cairo_create(wayland->front_cs); memset(wayland->framebuffer.buf_back, 0, wayland->framebuffer.buf_size); - wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); + if(wayland->configured) + wl_surface_attach(wayland->framebuffer.surface, wayland->framebuffer.shm_buffer, 0, 0); wl_surface_commit(wayland->framebuffer.surface); hang_until_configured((MwLL)wayland); @@ -1366,7 +1367,8 @@ static void backbuffer_setup(struct _MwLLWayland* wayland) { wayland->back_cairo = cairo_create(wayland->back_cs); memset(wayland->backbuffer.buf_back, 255, wayland->backbuffer.buf_size); - wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); + if(wayland->configured) + wl_surface_attach(wayland->backbuffer.surface, wayland->backbuffer.shm_buffer, 0, 0); wl_surface_commit(wayland->backbuffer.surface); hang_until_configured((MwLL)wayland); update_buffer((MwLL)wayland, &wayland->backbuffer); @@ -2293,11 +2295,11 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { } handle->wayland.icon->surface = wl_compositor_create_surface(handle->wayland.compositor); + buffer_setup(handle->wayland.icon, pixmap->common.width, pixmap->common.height); + wl_surface_attach(handle->wayland.icon->surface, handle->wayland.icon->shm_buffer, 0, 0); wl_surface_commit(handle->wayland.icon->surface); - buffer_setup(handle->wayland.icon, pixmap->common.width, pixmap->common.height); - for(; i < size; i += 2) { handle->wayland.icon->buf_back[i] = pixmap->common.raw[i + 2]; handle->wayland.icon->buf_back[i + 1] = pixmap->common.raw[i + 1]; @@ -2392,6 +2394,9 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { } static void MwLLShowImpl(MwLL handle, int show) { + if(!handle->wayland.configured) { + return; + } /* Some guy on a mailing list said that "abusing" wl_surface_attach for this purpose is bad? This is documented behavior so please I beg of you let me know if there's a compositor that actually has a problem with this. */ if(handle->wayland.framebuffer.surface) { wl_surface_attach(handle->wayland.framebuffer.surface, show ? handle->wayland.framebuffer.shm_buffer : NULL, 0, 0); From bfc6d8e9aff636a9143ac55592fab57cb25d3cd0 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 15:52:11 -0700 Subject: [PATCH 344/409] mac: ditch the image rep shit and try switching to a draw commands system --- include/Mw/LowLevel/Cocoa.h | 39 ++++-- src/backend/cocoa.m | 262 ++++++++++++++---------------------- 2 files changed, 124 insertions(+), 177 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index 2a8c7ec7c..f553af5f5 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -10,6 +10,29 @@ #include #include +typedef struct { + enum { + COCOA_DRAW_COMMAND_POLY = 0, + COCOA_DRAW_COMMAND_LINES, + COCOA_DRAW_COMMAND_PIXMAP, + } type; + union { + struct { + MwPoint* points; + int points_count; + MwLLColor color; + } poly; + struct { + MwPoint* points; + MwLLColor color; + } lines; + struct { + MwRect rect; + MwLLPixmap pixmap; + } pixmap; + }; +} draw_command; + #ifdef __OBJC__ #import #import @@ -81,23 +104,13 @@ @end @interface MilskoCocoaView : NSView { + MwBool _child; + @public - unsigned char* buf; - NSBitmapImageRep* rep; - NSGraphicsContext* context; - MwBool valid; - NSRect givenRect; - float x; - float y; - float width; - float height; - MwBool _child; + draw_command** commands; } -- (void)initRepAndContextWithWidth:(float)w Height:(float)h; -- (NSGraphicsContext*)context; - (void)destroy; -- (NSBitmapImageRep*)getRep; - (void)setChild; @end diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index c336f7fb8..e3f899e46 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -80,106 +80,101 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { @implementation MilskoCocoaView - (id)initWithFrame:(NSRect)frame { - givenRect = frame; - x = frame.origin.x; - y = frame.origin.y; - width = frame.size.width; - height = frame.size.height; - self = [super initWithFrame:frame]; - - if(width == 0 || height == 0) { - self->rep = NULL; - self->context = NULL; - } else { - [self initRepAndContextWithWidth:width Height:height]; - } - - self->_child = MwFALSE; - + [super initWithFrame:frame]; + self->commands = NULL; return self; } - (void)setChild { self->_child = MwTRUE; } - -- (NSGraphicsContext*)context { - return self->context; -} - -- (NSBitmapImageRep*)getRep { - return self->rep; -} +- (void)destroy { + arrfree(self->commands); +}; - (void)drawRect:(NSRect)dirtyRect { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSArray* subviews = [self subviews]; int i; + [super drawRect:dirtyRect]; - if(!self->rep) { - if(dirtyRect.size.width && dirtyRect.size.height) { - [self initRepAndContextWithWidth:dirtyRect.size.width - Height:dirtyRect.size.height]; - self->width = dirtyRect.size.width; - self->height = dirtyRect.size.height; - } else { - [pool release]; - return; + for(i = 0; i < arrlen(self->commands); i++) { + draw_command* cmd = self->commands[i]; + switch(cmd->type) { + case COCOA_DRAW_COMMAND_POLY: { + int i; + NSBezierPath* path = [NSBezierPath bezierPath]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:cmd->poly.color->common.red / 255. + green:cmd->poly.color->common.green / 255. + blue:cmd->poly.color->common.blue / 255. + alpha:1.0]; + + [nscolor setFill]; + for(i = 0; i < cmd->poly.points_count; i++) { + NSPoint p = localPointFlip(NSMakePoint(cmd->poly.points[i].x, cmd->poly.points[i].y), self); + if(i == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path fill]; + + free(cmd->poly.points); + MwLLFreeColor(cmd->poly.color); + free(cmd); + + } break; + + case COCOA_DRAW_COMMAND_LINES: { + int n; + NSBezierPath* path = [NSBezierPath bezierPath]; + + NSColor* nscolor = + [NSColor colorWithCalibratedRed:cmd->lines.color->common.red / 255. + green:cmd->lines.color->common.green / 255. + blue:cmd->lines.color->common.blue / 255. + alpha:1.0]; + + [nscolor setFill]; + for(n = 0; n < 2; n++) { + NSPoint p = localPointFlip(NSMakePoint(cmd->lines.points[n].x, cmd->lines.points[n].y), self); + if(n == 0) { + [path moveToPoint:p]; + } else { + [path lineToPoint:p]; + } + } + + [path closePath]; + [path stroke]; + + free(cmd->lines.points); + MwLLFreeColor(cmd->lines.color); + free(cmd); + } break; + + case COCOA_DRAW_COMMAND_PIXMAP: { + [cmd->pixmap.pixmap->cocoa.real.image + drawInRect:localRectFlip(NSMakeRect(cmd->pixmap.rect.x, cmd->pixmap.rect.y, cmd->pixmap.rect.width, cmd->pixmap.rect.height), self) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0]; + MwLLDestroyPixmap(cmd->pixmap.pixmap); + free(cmd); + } break; } } - [self->rep drawInRect:NSMakeRect(dirtyRect.origin.x, dirtyRect.origin.y, [self->rep pixelsWide], [self->rep pixelsHigh])]; + arrfree(self->commands); - for(i = 0; i < [subviews count]; i++) { - MilskoCocoaView* subview = [subviews objectAtIndex:i]; - NSRect bounds = [subview bounds]; - [subview drawRect:bounds]; - } [pool release]; } -- (void)initRepAndContextWithWidth:(float)w Height:(float)h { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - self->buf = malloc(w * h * 4); - memset(self->buf, 255, w * h * 4); - - self->rep = - [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:&self->buf - pixelsWide:w - pixelsHigh:h - bitsPerSample:8 - samplesPerPixel:4 - hasAlpha:YES - isPlanar:NO - colorSpaceName:NSDeviceRGBColorSpace - bytesPerRow:w * 4 - bitsPerPixel:32]; - assert(self->rep); - [self->rep retain]; - - [self->rep setOpaque:MwFALSE]; - [self->rep setAlpha:MwTRUE]; - - self->context = - [NSGraphicsContext graphicsContextWithBitmapImageRep:self->rep]; - assert(self->context); - [self->context retain]; - [pool release]; -} - -- (void)destroy { - [self->rep release]; - [self->context release]; -} - -- (void)setFrameSize:(NSSize)newSize { - [super setFrameSize:newSize]; - [self->rep setSize:newSize]; - - self->width = newSize.width; - self->height = newSize.height; -} - - (BOOL)canBecomeKeyView { return YES; } @@ -745,81 +740,31 @@ static void MwLLEndDrawImpl(MwLL handle) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - MilskoCocoa* self = handle->cocoa.real; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - int i; - NSBezierPath* path = [NSBezierPath bezierPath]; - /* whatever rect we use for coordinate flipping */ - NSRect _rect = self->parent ? [self->view bounds] : [self->window frame]; + draw_command* poly = malloc(sizeof(draw_command)); + poly->type = COCOA_DRAW_COMMAND_POLY; - NSColor* nscolor = - [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; + poly->poly.color = MwLLAllocColor(handle, color->common.red, color->common.blue, color->common.green); + poly->poly.points_count = points_count; - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + poly->poly.points = malloc(sizeof(MwPoint) * points_count); + memcpy(poly->poly.points, points, sizeof(MwPoint) * points_count); - [nscolor setFill]; - for(i = 0; i < points_count; i++) { - NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); - if(i == 0) { - [path moveToPoint:p]; - } else { - [path lineToPoint:p]; - } - } + arrpush(handle->cocoa.real->view->commands, poly); - [path closePath]; - [path fill]; - - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; + [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - MilskoCocoa* self = handle->cocoa.real; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - int i; - NSBezierPath* path = [NSBezierPath bezierPath]; - /* whatever rect we use for coordinate flipping */ - NSRect _rect = self->parent ? [self->view bounds] : [self->window frame]; + draw_command* lines = malloc(sizeof(draw_command)); + lines->type = COCOA_DRAW_COMMAND_LINES; - NSColor* nscolor = - [NSColor colorWithCalibratedRed:color->common.red / 255. - green:color->common.green / 255. - blue:color->common.blue / 255. - alpha:1.0]; + lines->lines.color = MwLLAllocColor(handle, color->common.red, color->common.blue, color->common.green); - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + lines->lines.points = malloc(sizeof(MwPoint) * 2); + memcpy(lines->lines.points, points, sizeof(MwPoint) * 2); - [nscolor setFill]; - for(i = 0; i < 2; i++) { - NSPoint p = localPointFlip(NSMakePoint(points[i].x, points[i].y), self->view); - if(i == 0) { - [path moveToPoint:p]; - } else { - [path lineToPoint:p]; - } - } - - [path closePath]; - [path stroke]; - - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; + arrpush(handle->cocoa.real->view->commands, lines); + [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -971,26 +916,15 @@ static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - MilskoCocoa* self = handle->cocoa.real; - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - MilskoCocoaPixmap* p = pixmap->cocoa.real; - NSGraphicsContext* ctx = [self->view context]; - if(ctx) { - [NSGraphicsContext saveGraphicsState]; - [NSGraphicsContext setCurrentContext:ctx]; + draw_command* pix = malloc(sizeof(draw_command)); + pix->type = COCOA_DRAW_COMMAND_PIXMAP; - [p->image - drawInRect:localRectFlip(NSMakeRect(rect->x, rect->y, rect->width, rect->height), self->view) - fromRect:NSZeroRect - operation:NSCompositeSourceOver - fraction:1.0]; + pix->pixmap.rect = *rect; + /* copy the pixmap into a new object that we'll free later */ + pix->pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); - [NSGraphicsContext restoreGraphicsState]; - - [self->view setNeedsDisplay:YES]; - } - [pool release]; - MwLLForceRender(handle); + arrpush(handle->cocoa.real->view->commands, pix); + [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { From d597dc941157a90ce0db86195f68874ad060395d Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 14 Apr 2026 16:58:28 -0700 Subject: [PATCH 345/409] new drawing system now works properly-ish --- src/backend/cocoa.m | 22 ++++++++++++---------- src/core.c | 4 +++- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index e3f899e46..5e9fa8bdb 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -93,16 +93,16 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { }; - (void)drawRect:(NSRect)dirtyRect { - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSArray* subviews = [self subviews]; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; int i; + [super drawRect:dirtyRect]; for(i = 0; i < arrlen(self->commands); i++) { draw_command* cmd = self->commands[i]; switch(cmd->type) { case COCOA_DRAW_COMMAND_POLY: { - int i; + int n; NSBezierPath* path = [NSBezierPath bezierPath]; NSColor* nscolor = @@ -112,9 +112,9 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { alpha:1.0]; [nscolor setFill]; - for(i = 0; i < cmd->poly.points_count; i++) { - NSPoint p = localPointFlip(NSMakePoint(cmd->poly.points[i].x, cmd->poly.points[i].y), self); - if(i == 0) { + for(n = 0; n < cmd->poly.points_count; n++) { + NSPoint p = localPointFlip(NSMakePoint(cmd->poly.points[n].x, cmd->poly.points[n].y), self); + if(n == 0) { [path moveToPoint:p]; } else { [path lineToPoint:p]; @@ -159,7 +159,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } break; case COCOA_DRAW_COMMAND_PIXMAP: { - [cmd->pixmap.pixmap->cocoa.real.image + [cmd->pixmap.pixmap->cocoa.real->image drawInRect:localRectFlip(NSMakeRect(cmd->pixmap.rect.x, cmd->pixmap.rect.y, cmd->pixmap.rect.width, cmd->pixmap.rect.height), self) fromRect:NSZeroRect operation:NSCompositeSourceOver @@ -736,6 +736,7 @@ static void MwLLBeginDrawImpl(MwLL handle) { static void MwLLEndDrawImpl(MwLL handle) { (void)handle; + [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, @@ -743,7 +744,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, draw_command* poly = malloc(sizeof(draw_command)); poly->type = COCOA_DRAW_COMMAND_POLY; - poly->poly.color = MwLLAllocColor(handle, color->common.red, color->common.blue, color->common.green); + poly->poly.color = MwLLAllocColor(handle, color->common.red, color->common.green, color->common.blue); poly->poly.points_count = points_count; poly->poly.points = malloc(sizeof(MwPoint) * points_count); @@ -752,13 +753,14 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, arrpush(handle->cocoa.real->view->commands, poly); [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; + // [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { draw_command* lines = malloc(sizeof(draw_command)); lines->type = COCOA_DRAW_COMMAND_LINES; - lines->lines.color = MwLLAllocColor(handle, color->common.red, color->common.blue, color->common.green); + lines->lines.color = MwLLAllocColor(handle, color->common.red, color->common.green, color->common.blue); lines->lines.points = malloc(sizeof(MwPoint) * 2); memcpy(lines->lines.points, points, sizeof(MwPoint) * 2); @@ -816,7 +818,7 @@ static void MwLLSetXYImpl(MwLL handle, int x, int y) { [self->window setFrame:frame display:MwTRUE animate:MwTRUE]; } else { frame = localRectFlip(frame, self->parent->cocoa.real->view); - [self->view setBounds:frame]; + [self->view setFrame:frame]; } [self nudge]; } diff --git a/src/core.c b/src/core.c index 2b98ec5fc..51018630b 100644 --- a/src/core.c +++ b/src/core.c @@ -2,7 +2,9 @@ #include "../external/stb_ds.h" -// #define PERIODIC +#ifdef __APPLE__ +#define PERIODIC +#endif #define DRAW(handle) \ { \ From 6e5057f8c62f903efecff3a81630710d35733396 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 18:04:00 -0700 Subject: [PATCH 346/409] cocoa: no more flickering --- src/backend/cocoa.m | 9 +++++---- src/core.c | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 5e9fa8bdb..ac694c836 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -602,7 +602,8 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { MwLL p = self->parent; self->_eventsPending = MwTRUE; - if(p) { + while(p) { + MwLLDispatch(p, draw, NULL); [p->cocoa.real->view setNeedsDisplay:true]; p = p->cocoa.real->parent; } @@ -752,7 +753,7 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, arrpush(handle->cocoa.real->view->commands, poly); - [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; + // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; // [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; } @@ -766,7 +767,7 @@ static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { memcpy(lines->lines.points, points, sizeof(MwPoint) * 2); arrpush(handle->cocoa.real->view->commands, lines); - [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; + // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -926,7 +927,7 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { pix->pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); arrpush(handle->cocoa.real->view->commands, pix); - [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; + // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { diff --git a/src/core.c b/src/core.c index 51018630b..cf45dddc2 100644 --- a/src/core.c +++ b/src/core.c @@ -2,7 +2,7 @@ #include "../external/stb_ds.h" -#ifdef __APPLE__ +#ifdef USE_COCOA #define PERIODIC #endif From a7d790698f75950f35634a944ede1ba29ef6d64a Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 14 Apr 2026 18:28:33 -0700 Subject: [PATCH 347/409] mac: getXYImpl should also flip whatever is given to it --- src/backend/cocoa.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index ac694c836..8e3ba2b66 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -793,7 +793,12 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, } else { frame = [self->window frame]; } - frame = rectFlip(frame); + + if(!self->parent) { + frame = rectFlip(frame); + } else { + frame = localRectFlip(frame, self->parent->cocoa.real->view); + } *x = frame.origin.x; *y = frame.origin.y; From a01e1a951480f34836dae2c7409ed354a0cfb738 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 20:54:05 -0500 Subject: [PATCH 348/409] milsko.xml: remove roundness --- milsko.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/milsko.xml b/milsko.xml index 18caed3c0..9fb45a608 100644 --- a/milsko.xml +++ b/milsko.xml @@ -81,7 +81,6 @@ - From 4d7b33741f5cacabf7c85a0030e44dd31903b9f6 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 19:38:52 -0700 Subject: [PATCH 349/409] fix mac os memleak, maybe fix stringisutf8 idk --- include/Mw/LowLevel/Cocoa.h | 12 +++--- src/backend/cocoa.m | 74 +++++++++++++++++-------------------- src/string.c | 2 +- 3 files changed, 40 insertions(+), 48 deletions(-) diff --git a/include/Mw/LowLevel/Cocoa.h b/include/Mw/LowLevel/Cocoa.h index f553af5f5..6c5f12b43 100644 --- a/include/Mw/LowLevel/Cocoa.h +++ b/include/Mw/LowLevel/Cocoa.h @@ -18,13 +18,13 @@ typedef struct { } type; union { struct { - MwPoint* points; - int points_count; - MwLLColor color; + MwPoint* points; + int points_count; + struct _MwLLCommonColor color; } poly; struct { - MwPoint* points; - MwLLColor color; + MwPoint* points; + struct _MwLLCommonColor color; } lines; struct { MwRect rect; @@ -107,7 +107,7 @@ typedef struct { MwBool _child; @public - draw_command** commands; + draw_command* commands; } - (void)destroy; diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 8e3ba2b66..705136721 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -99,21 +99,21 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [super drawRect:dirtyRect]; for(i = 0; i < arrlen(self->commands); i++) { - draw_command* cmd = self->commands[i]; - switch(cmd->type) { + draw_command cmd = self->commands[i]; + switch(cmd.type) { case COCOA_DRAW_COMMAND_POLY: { int n; NSBezierPath* path = [NSBezierPath bezierPath]; NSColor* nscolor = - [NSColor colorWithCalibratedRed:cmd->poly.color->common.red / 255. - green:cmd->poly.color->common.green / 255. - blue:cmd->poly.color->common.blue / 255. + [NSColor colorWithCalibratedRed:cmd.poly.color.red / 255. + green:cmd.poly.color.green / 255. + blue:cmd.poly.color.blue / 255. alpha:1.0]; [nscolor setFill]; - for(n = 0; n < cmd->poly.points_count; n++) { - NSPoint p = localPointFlip(NSMakePoint(cmd->poly.points[n].x, cmd->poly.points[n].y), self); + for(n = 0; n < cmd.poly.points_count; n++) { + NSPoint p = localPointFlip(NSMakePoint(cmd.poly.points[n].x, cmd.poly.points[n].y), self); if(n == 0) { [path moveToPoint:p]; } else { @@ -124,10 +124,7 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [path closePath]; [path fill]; - free(cmd->poly.points); - MwLLFreeColor(cmd->poly.color); - free(cmd); - + free(cmd.poly.points); } break; case COCOA_DRAW_COMMAND_LINES: { @@ -135,14 +132,14 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { NSBezierPath* path = [NSBezierPath bezierPath]; NSColor* nscolor = - [NSColor colorWithCalibratedRed:cmd->lines.color->common.red / 255. - green:cmd->lines.color->common.green / 255. - blue:cmd->lines.color->common.blue / 255. + [NSColor colorWithCalibratedRed:cmd.lines.color.red / 255. + green:cmd.lines.color.green / 255. + blue:cmd.lines.color.blue / 255. alpha:1.0]; [nscolor setFill]; for(n = 0; n < 2; n++) { - NSPoint p = localPointFlip(NSMakePoint(cmd->lines.points[n].x, cmd->lines.points[n].y), self); + NSPoint p = localPointFlip(NSMakePoint(cmd.lines.points[n].x, cmd.lines.points[n].y), self); if(n == 0) { [path moveToPoint:p]; } else { @@ -153,19 +150,16 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { [path closePath]; [path stroke]; - free(cmd->lines.points); - MwLLFreeColor(cmd->lines.color); - free(cmd); + free(cmd.lines.points); } break; case COCOA_DRAW_COMMAND_PIXMAP: { - [cmd->pixmap.pixmap->cocoa.real->image - drawInRect:localRectFlip(NSMakeRect(cmd->pixmap.rect.x, cmd->pixmap.rect.y, cmd->pixmap.rect.width, cmd->pixmap.rect.height), self) + [cmd.pixmap.pixmap->cocoa.real->image + drawInRect:localRectFlip(NSMakeRect(cmd.pixmap.rect.x, cmd.pixmap.rect.y, cmd.pixmap.rect.width, cmd.pixmap.rect.height), self) fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; - MwLLDestroyPixmap(cmd->pixmap.pixmap); - free(cmd); + MwLLDestroyPixmap(cmd.pixmap.pixmap); } break; } } @@ -742,32 +736,28 @@ static void MwLLEndDrawImpl(MwLL handle) { static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - draw_command* poly = malloc(sizeof(draw_command)); - poly->type = COCOA_DRAW_COMMAND_POLY; + draw_command poly; + poly.type = COCOA_DRAW_COMMAND_POLY; - poly->poly.color = MwLLAllocColor(handle, color->common.red, color->common.green, color->common.blue); - poly->poly.points_count = points_count; + poly.poly.color = color->common; + poly.poly.points_count = points_count; - poly->poly.points = malloc(sizeof(MwPoint) * points_count); - memcpy(poly->poly.points, points, sizeof(MwPoint) * points_count); + poly.poly.points = malloc(sizeof(MwPoint) * points_count); + memcpy(poly.poly.points, points, sizeof(MwPoint) * points_count); arrpush(handle->cocoa.real->view->commands, poly); - - // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; - // [handle->cocoa.real->view displayRect:[handle->cocoa.real->window frame]]; } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { - draw_command* lines = malloc(sizeof(draw_command)); - lines->type = COCOA_DRAW_COMMAND_LINES; + draw_command lines; + lines.type = COCOA_DRAW_COMMAND_LINES; - lines->lines.color = MwLLAllocColor(handle, color->common.red, color->common.green, color->common.blue); + lines.lines.color = color->common; - lines->lines.points = malloc(sizeof(MwPoint) * 2); - memcpy(lines->lines.points, points, sizeof(MwPoint) * 2); + lines.lines.points = malloc(sizeof(MwPoint) * 2); + memcpy(lines.lines.points, points, sizeof(MwPoint) * 2); arrpush(handle->cocoa.real->view->commands, lines); - // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -918,18 +908,20 @@ static void MwLLPixmapUpdateImpl(MwLLPixmap pixmap) { } static void MwLLDestroyPixmapImpl(MwLLPixmap pixmap) { + free(pixmap->common.raw); [pixmap->cocoa.real destroy]; [pixmap->cocoa.real release]; free(pixmap); } static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { - draw_command* pix = malloc(sizeof(draw_command)); - pix->type = COCOA_DRAW_COMMAND_PIXMAP; + draw_command pix; + pix.type = COCOA_DRAW_COMMAND_PIXMAP; + + pix.pixmap.rect = *rect; - pix->pixmap.rect = *rect; /* copy the pixmap into a new object that we'll free later */ - pix->pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); + pix.pixmap.pixmap = MwLLCreatePixmap(handle, pixmap->common.raw, pixmap->common.width, pixmap->common.height); arrpush(handle->cocoa.real->view->commands, pix); // [handle->cocoa.real->view setNeedsDisplay:MwTRUE]; diff --git a/src/string.c b/src/string.c index f48169599..943867aec 100644 --- a/src/string.c +++ b/src/string.c @@ -51,7 +51,7 @@ void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { }; MWDECL MwBool MwStringIsKeyUTF8(MwU32 key) { - unsigned char bytes[sizeof(MwU32)]; + unsigned char bytes[sizeof(MwU32) * 16]; int i; memcpy(bytes, &key, sizeof(MwU32)); From 32f99b62b6931a2a6c081cddcb040eabb863dd21 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 19:51:52 -0700 Subject: [PATCH 350/409] have MwStringIsKeyUTF8 not use ub --- src/string.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/string.c b/src/string.c index 943867aec..2a1504639 100644 --- a/src/string.c +++ b/src/string.c @@ -51,9 +51,18 @@ void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { }; MWDECL MwBool MwStringIsKeyUTF8(MwU32 key) { - unsigned char bytes[sizeof(MwU32) * 16]; - int i; - memcpy(bytes, &key, sizeof(MwU32)); + /* little endian */ +#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) || defined(__aarch64__) || defined(_M_ARM64) + unsigned char bytes[4] = { + (key & 0x000000FF), + (key & 0x0000FF00) >> 8, + (key & 0x00FF0000) >> 16, + (key & 0xFF000000) >> 24, + }; +#else +#error Unspecified architecture! This error exists here because above it is endian-specific code. Add your architecture above. +#endif + int i; for(i = 0; i < sizeof(MwU32); i++) { if(( // ASCII From 065b0d824cf29926b74e7c91ba549176435aa506 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 20:03:59 -0700 Subject: [PATCH 351/409] cocoa: untested vulkan code --- CMakeLists.txt | 5 +++++ pl/rules.pl | 1 + src/backend/cocoa.m | 17 +++++++++++++++++ src/widget/vulkan.c | 20 ++++++++++++++++++++ 4 files changed, 43 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 585fb4ddd..0cc795308 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,11 @@ if(MW_TRY_VULKAN) if(HAVE_VULKAN_VULKAN_H) set(MW_BUILD_VULKAN ON) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") + target_compile_definitions( + Mw + PRIVATE + MW_VULKAN + ) message(STATUS "Vulkan widget has been enabled") else() message(WARNING "Vulkan widget has been disabled") diff --git a/pl/rules.pl b/pl/rules.pl index 6c23006bd..3da19289e 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -131,6 +131,7 @@ if (param_get("opengl")) { new_object("src/widget/opengl.c"); } if (param_get("vulkan")) { + add_cflags("-DMW_VULKAN"); new_object("src/widget/vulkan.c"); } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 705136721..4cdc5b2b6 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -2,6 +2,11 @@ #include "../../external/stb_ds.h" #include "Mw/LowLevel/Cocoa.h" +#ifdef MW_VULKAN +#include +#include +#endif + #ifdef __clang__ #pragma clang push #pragma clang diagnostic ignored "-Wdeprecated-declarations" @@ -1087,5 +1092,17 @@ static int MwLLCocoaCallInitImpl(void) { return 0; } +#ifdef MW_VULKAN +VkMetalSurfaceCreateInfoEXT MwCocoaGetMetalSurfaceCreateInfo(MwWidget handle) { + VkMetalSurfaceCreateInfoEXT createInfo = { + .sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT, + .pNext = NULL, + .flags = 0, + .pLayer = (CAMetalLayer*)[handle->lowlevel->cocoa.real->view layer], + }; + return createInfo; +}; +#endif + #include "call.c" CALL(Cocoa); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 1a9ea1234..195384c61 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -26,6 +26,9 @@ #ifdef USE_WAYLAND #include #endif +#ifdef USE_COCOA +#include +#endif #ifdef HAS_VK_ENUM_STRING_HELPER #include @@ -167,6 +170,8 @@ static void destroy(MwWidget handle) { static void* vulkan_lib_load() { #ifdef _WIN32 return MwDynamicOpen("vulkan-1.dll"); +#elif defined(__APPLE__) + return MwDynamicOpen("libvulkan.dylib"); #else return MwDynamicOpen("libvulkan.so"); #endif @@ -230,6 +235,11 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { MwWaylandAlwaysRender = MwTRUE; } #endif +#ifdef USE_WAYLAND + if(handle->lowlevel->common.type == MwLLBackendCocoa) { + arrput(enabledExtensions, VK_EXT_METAL_SURFACE_EXTENSION_NAME); + } +#endif /* passing null gives us all the extensions provided by the current vulkan implementation */ VK_CMD(_vkEnumerateInstanceExtensionProperties(NULL, &extension_count, NULL)); @@ -338,6 +348,16 @@ static int vulkan_surface_setup(MwWidget handle, vulkan_t* o) { }; VK_CMD(_vkCreateWaylandSurfaceKHR(o->vkInstance, &createInfo, NULL, &o->vkSurface)); } +#endif +#ifdef USE_COCOA + if(handle->lowlevel->common.type == MwLLBackendCocoa) { + VkMetalSurfaceCreateInfoEXT MwCocoaGetMetalSurfaceCreateInfo(MwWidget handle); + VkMetalSurfaceCreateInfoEXT inf = MwCocoaGetMetalSurfaceCreateInfo(handle); + + LOAD_VK_FUNCTION(vkCreateMetalSurfaceEXT); + + VK_CMD(_vkCreateMetalSurfaceEXT(o->vkInstance, &inf, NULL, &o->vkSurface)); + } #endif return 0; } From 28f6d6ac56acfbf4a0f7ef63a0909ff634fff8ca Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 20:08:45 -0700 Subject: [PATCH 352/409] cocoa: untested vulkan code --- src/widget/vulkan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 195384c61..8d4aa3daa 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -235,7 +235,7 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { MwWaylandAlwaysRender = MwTRUE; } #endif -#ifdef USE_WAYLAND +#ifdef USE_COCOA if(handle->lowlevel->common.type == MwLLBackendCocoa) { arrput(enabledExtensions, VK_EXT_METAL_SURFACE_EXTENSION_NAME); } From 391f5a69245e3e1182d6110713ce151135f0209d Mon Sep 17 00:00:00 2001 From: Nishi Date: Wed, 15 Apr 2026 12:23:54 +0900 Subject: [PATCH 353/409] remove endian related error --- WatMakefile | 2 +- src/string.c | 16 +++++----------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/WatMakefile b/WatMakefile index 231820788..633a259a3 100644 --- a/WatMakefile +++ b/WatMakefile @@ -1,4 +1,4 @@ -CC = wcc386 -bt=nt -q -bd +CC = wcc386 -bt=nt -q -bd -d3 LD = wlink option quiet CFLAGS = -i=include -i=external/libz/include -d_MILSKO -dUSE_GDI -dUSE_STB_TRUETYPE -dUSE_STB_IMAGE -dSTBI_NO_SIMD diff --git a/src/string.c b/src/string.c index 2a1504639..a7c23381c 100644 --- a/src/string.c +++ b/src/string.c @@ -51,18 +51,12 @@ void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { }; MWDECL MwBool MwStringIsKeyUTF8(MwU32 key) { - /* little endian */ -#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86) || defined(__aarch64__) || defined(_M_ARM64) - unsigned char bytes[4] = { - (key & 0x000000FF), - (key & 0x0000FF00) >> 8, - (key & 0x00FF0000) >> 16, - (key & 0xFF000000) >> 24, - }; -#else -#error Unspecified architecture! This error exists here because above it is endian-specific code. Add your architecture above. -#endif + unsigned char bytes[4]; int i; + bytes[0] = (key & 0x000000FF); + bytes[1] = (key & 0x0000FF00) >> 8; + bytes[2] = (key & 0x00FF0000) >> 16; + bytes[3] = (key & 0xFF000000) >> 24; for(i = 0; i < sizeof(MwU32); i++) { if(( // ASCII From 83f5f7a8200fad133462421d053a676248f870b9 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 23:04:13 -0500 Subject: [PATCH 354/409] examples cmake doesnt need win32 --- examples/basic/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/basic/CMakeLists.txt b/examples/basic/CMakeLists.txt index acda320d2..ab58a5c1a 100644 --- a/examples/basic/CMakeLists.txt +++ b/examples/basic/CMakeLists.txt @@ -6,7 +6,7 @@ file( foreach(PATH IN LISTS EXAMPLES_BASIC_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) - add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) target_link_libraries( ${TARGET} PRIVATE From aac2b410c08f6b0157cddf8542e0d113047711a3 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 23:04:39 -0500 Subject: [PATCH 355/409] gl cmake doesnt need win32 --- examples/gldemos/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/gldemos/CMakeLists.txt b/examples/gldemos/CMakeLists.txt index 122f62c59..0a8fa78e6 100644 --- a/examples/gldemos/CMakeLists.txt +++ b/examples/gldemos/CMakeLists.txt @@ -10,7 +10,7 @@ foreach(PATH IN LISTS EXAMPLES_GL_SOURCES) if(${TARGET} STREQUAL "glutlayer") continue() endif() - add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) target_link_libraries( ${TARGET} PRIVATE From 714842461cffc43a906ac2b04b8741c15cbce8b4 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 23:04:59 -0500 Subject: [PATCH 356/409] Update examples/vkdemos/CMakeLists.txt --- examples/vkdemos/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/vkdemos/CMakeLists.txt b/examples/vkdemos/CMakeLists.txt index a315bf91b..41f832c2d 100644 --- a/examples/vkdemos/CMakeLists.txt +++ b/examples/vkdemos/CMakeLists.txt @@ -7,7 +7,7 @@ find_package(Vulkan) foreach(PATH IN LISTS EXAMPLES_VULKAN_SOURCES) get_filename_component(TARGET ${PATH} NAME_WE) - add_executable(${TARGET} WIN32 MACOSX_BUNDLE ${PATH}) + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) target_include_directories( ${TARGET} PRIVATE From fc8330f4772b2d9564bdf958b89aff7cf62a866a Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 00:29:16 -0500 Subject: [PATCH 357/409] uninitialized --- src/backend/wayland.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 220f3901f..bbc1220e6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2583,7 +2583,7 @@ static int MwLLWaylandCallInitImpl(void) { * - manually checking environment variables */ #ifdef __linux__ - MwBool loadWayland; + MwBool loadWayland = MwFALSE; if(getenv("MILSKO_BACKEND")) { loadWayland |= (strcmp(getenv("MILSKO_BACKEND"), "wayland") == 0); From 4ab846ad51d701842afbddaf2af41879418056d3 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Tue, 14 Apr 2026 22:53:20 -0700 Subject: [PATCH 358/409] fix fpe in text drawing code --- src/text/ft2.c | 15 ++++++--------- src/text/stbtt.c | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/text/ft2.c b/src/text/ft2.c index 17381f98a..32e658775 100644 --- a/src/text/ft2.c +++ b/src/text/ft2.c @@ -69,16 +69,13 @@ static int ft2_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const c int ox = x + (ttf->face->glyph->metrics.horiBearingX / 64) + cx + ttf->face->glyph->bitmap_left; int oy = y + (ttf->face->height * ttf->px / ttf->face->units_per_EM) - ttf->face->glyph->bitmap_top + cy + (ttf->face->descender * ttf->px / ttf->face->units_per_EM); unsigned char* opx = &px[(oy * tw + ox) * 4]; - - if(opx[3] == 0) { - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = bmp->buffer[cy * bmp->pitch + cx]; + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + /* overflow check */ + if(opx[3] + bmp->buffer[cy * bmp->pitch + cx] < opx[3]) { + opx[3] = 255; } else { - opx[0] = (opx[0] / color->common.red) / 255; - opx[1] = (opx[1] / color->common.green) / 255; - opx[2] = (opx[2] / color->common.blue) / 255; opx[3] = bmp->buffer[cy * bmp->pitch + cx]; } } diff --git a/src/text/stbtt.c b/src/text/stbtt.c index 5e23f6cb5..a84190769 100644 --- a/src/text/stbtt.c +++ b/src/text/stbtt.c @@ -52,16 +52,13 @@ static int stbtt_MwDrawText(MwWidget handle, MwFLFont ttf, MwPoint* point, const int ox = x + ceil(lsb * ttf->scale) + cx; int oy = y + ceil(ttf->ascent * ttf->scale) + y0 + cy; unsigned char* opx = &px[(oy * tw + ox) * 4]; - - if(opx[3] == 0) { - opx[0] = color->common.red; - opx[1] = color->common.green; - opx[2] = color->common.blue; - opx[3] = out[cy * ow + cx]; + opx[0] = color->common.red; + opx[1] = color->common.green; + opx[2] = color->common.blue; + /* overflow check */ + if(opx[3] + out[cy * ow + cx] < opx[3]) { + opx[3] = 255; } else { - opx[0] = (opx[0] / color->common.red) / 255; - opx[1] = (opx[1] / color->common.green) / 255; - opx[2] = (opx[2] / color->common.blue) / 255; opx[3] = out[cy * ow + cx]; } } From 0c822d5bfafdff603eed4dd44960ed87066412c0 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Tue, 14 Apr 2026 23:49:04 -0700 Subject: [PATCH 359/409] some wayland fixes curtosey of valgrind --- include/Mw/LowLevel/Wayland.h | 3 +++ src/backend/wayland.c | 9 ++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7b31bd7e3..ce1630c5b 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -123,6 +123,7 @@ typedef struct wayland_call_table { void (*cairo_pattern_set_filter)(cairo_pattern_t* pattern, cairo_filter_t filter); void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); + void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); } wayland_call_table_t; @@ -220,6 +221,7 @@ MwInline int wayland_load_funcs() { CAIRO_FUNC(cairo_stroke); CAIRO_FUNC(cairo_set_source_surface); CAIRO_FUNC(cairo_fill); + CAIRO_FUNC(cairo_set_operator); CAIRO_FUNC(cairo_pattern_set_filter); #undef CAIRO_FUNC @@ -277,6 +279,7 @@ MwInline int wayland_load_funcs() { #define cairo_stroke wl_call_tbl.cairo_stroke #define cairo_set_source_surface wl_call_tbl.cairo_set_source_surface #define cairo_fill wl_call_tbl.cairo_fill +#define cairo_set_operator wl_call_tbl.cairo_set_operator #define cairo_pattern_set_filter wl_call_tbl.cairo_pattern_set_filter #ifndef WL_PROTOCOLS_DEFINED diff --git a/src/backend/wayland.c b/src/backend/wayland.c index bbc1220e6..8bb6f3eed 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2082,7 +2082,9 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } cairo_close_path(handle->wayland.front_cairo); + cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_SOURCE); cairo_fill(handle->wayland.front_cairo); + cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_OVER); handle->wayland.events_pending = 1; } @@ -2264,6 +2266,8 @@ static void MwLLDrawPixmapImpl(MwLL handle, MwRect* rect, MwLLPixmap pixmap) { cairo_set_source_surface(c, pixmap->wayland.cs, 0, 0); cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); + cairo_set_operator(handle->wayland.front_cairo, CAIRO_OPERATOR_OVER); + cairo_paint(c); cairo_set_source_surface(selected_cairo, cs, rect->x, rect->y); @@ -2577,11 +2581,6 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } static int MwLLWaylandCallInitImpl(void) { - /* - * Order of precedence: - * - MILSKO_BACKEND - * - manually checking environment variables - */ #ifdef __linux__ MwBool loadWayland = MwFALSE; if(getenv("MILSKO_BACKEND")) { From 5cb9b5cab93d9a215012eb7d83c92cb11193a52c Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 00:54:47 -0700 Subject: [PATCH 360/409] have color picker check for dark theme --- examples/basic/colorpicker.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 0096ae64a..4c246f763 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -28,7 +28,7 @@ void color_picker(MwWidget handle, void* user_data, void* call_data) { MwAddUserHandler(cpicker, MwNcolorChosenHandler, color_callback, NULL); - MwSetText(cpicker, MwNbackground, MwDefaultBackground); + MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultForeground : MwDefaultBackground); } int main() { @@ -41,7 +41,7 @@ int main() { button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); - MwSetText(button, MwNbackground, MwDefaultBackground); + MwSetText(button, MwNbackground, MwGetInteger(button, MwNdarkTheme) ? MwDefaultForeground : MwDefaultBackground); MwAddUserHandler(button, MwNactivateHandler, color_picker, NULL); From 6ff6b22644b03d70452f4c2675ff3ab60da9aa9b Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 01:05:51 -0700 Subject: [PATCH 361/409] border around color picker wheel --- src/dialog/colorpicker.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 2be8df2ec..3b7d33188 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -1,7 +1,7 @@ #include #define WIN_SIZE 464 -#define PICKER_SIZE 360 +#define PICKER_SIZE 364 #define IMG_POS_X(w) ((w - PICKER_SIZE) / 2) #define IMG_POS_Y(h) ((h - PICKER_SIZE) / 2) #define SCROLL_BAR_WIDTH 16 @@ -104,11 +104,16 @@ static void color_picker_image_update(color_picker_t* picker) { int _y = y - (PICKER_SIZE / 2); double dist = sqrt(_x * _x + _y * _y); - if(dist >= 180.) { + if(dist >= 182.) { picker->color_picker_image_data[i] = 0; picker->color_picker_image_data[i + 1] = 0; picker->color_picker_image_data[i + 2] = 0; picker->color_picker_image_data[i + 3] = 0; + } else if(dist >= 180.) { + picker->color_picker_image_data[i] = dist; + picker->color_picker_image_data[i + 1] = dist; + picker->color_picker_image_data[i + 2] = dist; + picker->color_picker_image_data[i + 3] = 255; } else { MwHSV hsv_v; MwRGB color; From 5c386e766504014d942ff2762bef1a3aec274940 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 03:08:55 -0500 Subject: [PATCH 362/409] Update examples/basic/colorpicker.c --- examples/basic/colorpicker.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 4c246f763..22e647cc8 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -1,4 +1,3 @@ - #include MwWidget cpicker; @@ -28,7 +27,7 @@ void color_picker(MwWidget handle, void* user_data, void* call_data) { MwAddUserHandler(cpicker, MwNcolorChosenHandler, color_callback, NULL); - MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultForeground : MwDefaultBackground); + MwSetText(cpicker, MwNbackground, MwGetInteger(cpicker, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); } int main() { @@ -41,7 +40,7 @@ int main() { button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); - MwSetText(button, MwNbackground, MwGetInteger(button, MwNdarkTheme) ? MwDefaultForeground : MwDefaultBackground); + MwSetText(button, MwNbackground, MwGetInteger(button, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); MwAddUserHandler(button, MwNactivateHandler, color_picker, NULL); From b641a03bae430feb77c180777107db6fcd12ed0f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 10:58:46 -0700 Subject: [PATCH 363/409] clipboard refactoring --- examples/basic/clipboard.c | 33 +++++++++---- include/Mw/Core.h | 5 +- include/Mw/LowLevel.h | 4 +- include/Mw/LowLevel/Wayland.h | 5 +- include/Mw/TypeDefs.h | 8 +++ src/backend/cocoa.m | 6 ++- src/backend/gdi.c | 6 ++- src/backend/wayland.c | 92 ++++++++++++++++++----------------- src/backend/x11.c | 4 +- src/core.c | 4 +- src/lowlevel.c | 4 +- src/widget/entry.c | 18 ++++++- 12 files changed, 116 insertions(+), 73 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index e6a75023f..38084a184 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -1,6 +1,6 @@ #include -MwWidget window, instructions, text; +MwWidget window, instructions, text1, text2, cur_text; static void resize(MwWidget handle, void* user_data, void* call_data) { unsigned int w, h; @@ -17,9 +17,14 @@ static void resize(MwWidget handle, void* user_data, void* call_data) { MwNheight, h - 125 - 50 * 3, NULL); - MwVaApply(text, - MwNy, 200, - MwNwidth, w - 50 * 2, + MwVaApply(text1, + MwNy, 150, + MwNwidth, w - 25 * 2, + MwNheight, h - 125 - 50 * 3, + NULL); + MwVaApply(text2, + MwNy, 250, + MwNwidth, w - 25 * 2, MwNheight, h - 125 - 50 * 3, NULL); } @@ -30,14 +35,17 @@ static void clipboard(MwWidget handle, void* user_data, void* call_data) { (void)user_data; if(clipboard != NULL) { - MwVaApply(text, MwNtext, clipboard, NULL); - MwForceRender(text); + MwVaApply(cur_text, MwNtext, clipboard, NULL); + MwForceRender(cur_text); } - MwForceRender(window); } static void tick(MwWidget handle, void* user_data, void* call_data) { - MwGetClipboard(handle); + cur_text = text1; + MwGetClipboard(handle, MwClipboardMain); + cur_text = text2; + MwGetClipboard(handle, MwClipboardPrimary); + MwForceRender(window); } int main() { @@ -49,14 +57,19 @@ int main() { instructions = MwVaCreateWidget(MwLabelClass, "button", window, 50, 50, 300, 125, MwNtext, "clipboard contents will show up below.", NULL); - text = MwVaCreateWidget(MwLabelClass, "label", window, 50, 200, 300, 125, + text1 = MwVaCreateWidget(MwLabelClass, "label", window, 25, 150, 300, 75, MwNtext, "", NULL); + text2 = MwVaCreateWidget(MwLabelClass, "label2", window, 25, 250, 300, 75, + MwNtext, "", + NULL); + + cur_text = text1; MwAddUserHandler(window, MwNresizeHandler, resize, NULL); MwAddUserHandler(window, MwNclipboardHandler, clipboard, NULL); MwAddUserHandler(instructions, MwNclipboardHandler, clipboard, NULL); - MwAddUserHandler(text, MwNclipboardHandler, clipboard, NULL); + MwAddUserHandler(cur_text, MwNclipboardHandler, clipboard, NULL); MwAddUserHandler(window, MwNtickHandler, tick, NULL); resize(window, NULL, NULL); diff --git a/include/Mw/Core.h b/include/Mw/Core.h index 4d3e4b99e..ad4cd19de 100644 --- a/include/Mw/Core.h +++ b/include/Mw/Core.h @@ -362,10 +362,11 @@ MWDECL void MwGetScreenSize(MwWidget handle, MwRect* rect); MWDECL int MwGetCoordinateType(MwWidget handle); /*! - * @brief Queue to get clipboard content + * @brief Queue to get clipboard content. * @param handle Widget + * @param clipboard_type The Clipboard Type to get. See MwClipboardType. This is ignored on backends that aren't X11/Wayland, so if you're unsure, just use MwClipboardMain */ -MWDECL void MwGetClipboard(MwWidget handle); +MWDECL void MwGetClipboard(MwWidget handle, int clipboard_type); #ifdef __cplusplus } diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index d5a0b1b5b..abe81b669 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -234,8 +234,8 @@ MWDECL void (*MwLLEndStateChange)(MwLL handle); MWDECL void (*MwLLFocus)(MwLL handle); MWDECL void (*MwLLGrabPointer)(MwLL handle, int toggle); -MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text); -MWDECL void (*MwLLGetClipboard)(MwLL handle); +MWDECL void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type); +MWDECL void (*MwLLGetClipboard)(MwLL handle, int clipboard_type); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index ce1630c5b..a94d1c812 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -439,7 +439,7 @@ struct _MwLLWayland { /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ - union { + struct { struct wl_data_device_manager* wl; struct zwp_primary_selection_device_manager_v1* zwp; } clipboard_manager; @@ -451,7 +451,8 @@ struct _MwLLWayland { MwBool supports_zwp; uint32_t clipboard_serial; - wl_clipboard_device_context_t** clipboard_devices; + wl_clipboard_device_context_t** clipboard_devices_wl; + wl_clipboard_device_context_t** clipboard_devices_zwp; struct wl_pointer* pointer; MwU32 pointer_serial; diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index 62380f008..bd0af3d78 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -239,4 +239,12 @@ enum MwCoordinateType { MwCoordinatesLocal, }; +/* The clipboard type that MwGetClipboard should return */ +enum MwClipboardType { + /* the clipboard that is present on every platform that supports it */ + MwClipboardMain = 0, + /* the "primary" clipboard that Wayland stores to emulate X11's behavior. */ + MwClipboardPrimary, +}; + #endif diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 4cdc5b2b6..240e5b87e 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1042,13 +1042,15 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { handle->cocoa.real->pointerLocked = toggle; } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { (void)handle; (void)text; + (void)clipboard_type; } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { (void)handle; + (void)clipboard_type; } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 5d89419d0..2941e5cab 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -735,8 +735,9 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { HGLOBAL hg; + (void)clipboard_type; if(OpenClipboard(handle->gdi.hWnd) != 0) { char* lock; @@ -753,7 +754,8 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text) { } } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)clipboard_type; handle->gdi.get_clipboard = 1; /* nishi: we do this to make clipboard api work similar to other backends */ } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8bb6f3eed..7f6247fb6 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -266,7 +266,7 @@ struct zwp_primary_selection_device_v1_listener zwp_primary_selection_device_v1_ .selection = zwp_primary_selection_device_v1_selection, }; -static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { +static void wl_clipboard_read(wl_clipboard_device_context_t* ctx, int clipboard_type) { int fds[2]; fd_set set; char* buf = NULL; @@ -282,7 +282,7 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx) { timeout.tv_sec = 0; timeout.tv_usec = 100; - if(ctx->ll->wayland.supports_zwp) { + if(clipboard_type == MwClipboardPrimary) { zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); } else if(ctx->offer.wl) { wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); @@ -427,7 +427,7 @@ static wayland_protocol_t* wl_data_device_manager_setup(MwU32 name, struct _MwLL static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { (void)data; - if(wayland->clipboard_manager.wl != NULL && !wayland->supports_zwp) { + if(wayland->clipboard_manager.wl != NULL) { wl_data_device_manager_destroy(wayland->clipboard_manager.wl); wl_data_source_destroy(wayland->clipboard_source.wl); wayland->clipboard_manager.wl = NULL; @@ -436,10 +436,6 @@ static void wl_data_device_manager_interface_destroy(struct _MwLLWayland* waylan /* zwp_primary_selection_device_manager_v1 setup function */ static wayland_protocol_t* zwp_primary_selection_device_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland) { - if(wayland->clipboard_manager.wl != NULL) { - wl_data_device_manager_interface_destroy(wayland, NULL); - } - wayland->clipboard_manager.zwp = wl_registry_bind(wayland->registry, name, &zwp_primary_selection_device_manager_v1_interface, 1); wayland->clipboard_source.zwp = zwp_primary_selection_device_manager_v1_create_source(wayland->clipboard_manager.zwp); @@ -621,10 +617,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri break; case BTN_MIDDLE: p.button = MwLLMouseMiddle; - for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { - wl_clipboard_read( - self->wayland.clipboard_devices[i]); - } break; case BTN_RIGHT: p.button = MwLLMouseRight; @@ -840,14 +832,6 @@ static void keyboard_key(void* data, } if((self->wayland.mod_state & 4) == 4) { - /* clipboard paste */ - if(key == 'V') { - int i; - for(i = 0; i < arrlen(self->wayland.clipboard_devices); i++) { - wl_clipboard_read( - self->wayland.clipboard_devices[i]); - } - } key |= MwLLControlMask; } if((self->wayland.mod_state & 8) == 8) { @@ -913,8 +897,9 @@ wl_seat_name(void* data, struct wl_seat* wl_seat, const char* name) { /* `wl_seat.capabilities` callback */ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, MwU32 capabilities) { - MwLL self = data; - wl_clipboard_device_context_t* device_ctx = malloc(sizeof(wl_clipboard_device_context_t)); + MwLL self = data; + wl_clipboard_device_context_t* device_ctx_zwp = NULL; + wl_clipboard_device_context_t* device_ctx_wl = malloc(sizeof(wl_clipboard_device_context_t)); WAYLAND_EVENT_OP_START(self); @@ -930,21 +915,23 @@ static void wl_seat_capabilities(void* data, struct wl_seat* wl_seat, if(self->wayland.clipboard_manager.wl != NULL) { if(self->wayland.supports_zwp) { - device_ctx->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); - } else { - device_ctx->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_zwp = malloc(sizeof(wl_clipboard_device_context_t)); + device_ctx_zwp->device.zwp = zwp_primary_selection_device_manager_v1_get_device(self->wayland.clipboard_manager.zwp, wl_seat); + device_ctx_zwp->ll = self; + device_ctx_zwp->seat = wl_seat; + device_ctx_zwp->capabilities = capabilities; } - device_ctx->ll = self; - device_ctx->seat = wl_seat; - device_ctx->capabilities = capabilities; + device_ctx_wl->device.wl = wl_data_device_manager_get_data_device(self->wayland.clipboard_manager.wl, wl_seat); + device_ctx_wl->ll = self; + device_ctx_wl->seat = wl_seat; + device_ctx_wl->capabilities = capabilities; if(self->wayland.supports_zwp) { - zwp_primary_selection_device_v1_add_listener(device_ctx->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx); - } else { - wl_data_device_add_listener(device_ctx->device.wl, &wl_data_device_listener, device_ctx); + zwp_primary_selection_device_v1_add_listener(device_ctx_zwp->device.zwp, &zwp_primary_selection_device_v1_listener, device_ctx_zwp); + arrpush(self->wayland.clipboard_devices_zwp, device_ctx_zwp); } - - arrpush(self->wayland.clipboard_devices, device_ctx); + wl_data_device_add_listener(device_ctx_wl->device.wl, &wl_data_device_listener, device_ctx_wl); + arrpush(self->wayland.clipboard_devices_wl, device_ctx_wl); } WAYLAND_EVENT_OP_END(self); @@ -2471,33 +2458,48 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { + int i; + if(handle->wayland.clipboard_buffer != NULL) { free(handle->wayland.clipboard_buffer); } handle->wayland.clipboard_buffer = malloc(strlen(text)); strcpy(handle->wayland.clipboard_buffer, text); - if(handle->wayland.supports_zwp) { - int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; - zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + if(clipboard_type == MwClipboardPrimary) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; + zwp_primary_selection_device_v1_set_selection(device->device.zwp, handle->wayland.clipboard_source.zwp, handle->wayland.keyboard_serial); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); } } else { - int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices[i]; + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_wl[i]; wl_data_device_set_selection(device->device.wl, handle->wayland.clipboard_source.wl, handle->wayland.keyboard_serial); } } } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { int i; - for(i = 0; i < arrlen(handle->wayland.clipboard_devices); i++) { - wl_clipboard_read( - handle->wayland.clipboard_devices[i]); + if(clipboard_type == MwClipboardPrimary) { + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + wl_clipboard_read( + handle->wayland.clipboard_devices_zwp[i], clipboard_type); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + } else { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_clipboard_read( + handle->wayland.clipboard_devices_wl[i], clipboard_type); + } } return; } diff --git a/src/backend/x11.c b/src/backend/x11.c index ad97d6885..4393317c4 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -1220,14 +1220,14 @@ static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { /* TODO */ (void)handle; (void)text; } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { if(handle->x11.clipboard_pending) return; XConvertSelection(handle->x11.display, handle->x11.clipboard, handle->x11.utf8_string, handle->x11.selection, handle->x11.window, CurrentTime); diff --git a/src/core.c b/src/core.c index cf45dddc2..de2774d85 100644 --- a/src/core.c +++ b/src/core.c @@ -958,6 +958,6 @@ int MwGetCoordinateType(MwWidget handle) { } } -void MwGetClipboard(MwWidget handle) { - MwLLGetClipboard(handle->lowlevel); +void MwGetClipboard(MwWidget handle, int clipboard_type) { + MwLLGetClipboard(handle->lowlevel, clipboard_type); } diff --git a/src/lowlevel.c b/src/lowlevel.c index 597a23a82..534ecd28d 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -45,8 +45,8 @@ void (*MwLLEndStateChange)(MwLL handle) = NULL; void (*MwLLFocus)(MwLL handle) = NULL; void (*MwLLGrabPointer)(MwLL handle, int toggle) = NULL; -void (*MwLLSetClipboard)(MwLL handle, const char* text) = NULL; -void (*MwLLGetClipboard)(MwLL handle) = NULL; +void (*MwLLSetClipboard)(MwLL handle, const char* text, int clipboard_type) = NULL; +void (*MwLLGetClipboard)(MwLL, int clipboard_type) = NULL; void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; diff --git a/src/widget/entry.c b/src/widget/entry.c index bd7dbe1b5..a8d094130 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -113,7 +113,7 @@ static void key(MwWidget handle, int code) { } else if(code == MwLLKeyEnter) { MwDispatchUserHandler(handle, MwNactivateHandler, NULL); } else if(code == (MwLLControlMask | 'v')) { - MwLLGetClipboard(handle->lowlevel); + MwLLGetClipboard(handle->lowlevel, MwClipboardMain); } else if(!(code & MwLLKeyMask)) { int incr = 0; out = malloc(strlen(str) + 5 + 1); @@ -133,6 +133,20 @@ static void key(MwWidget handle, int code) { MwForceRender(handle); } +#if defined(USE_X11) || defined(USE_WAYLAND) +static void mouse_up(MwWidget handle, void* ptr) { + if(handle->lowlevel->common.type == MwLLBackendWayland || handle->lowlevel->common.type == MwLLBackendX11) { + MwLLMouse* mouse = ptr; + if(mouse->button == MwLLMouseMiddle) { + MwLLGetClipboard(handle->lowlevel, MwClipboardPrimary); + } + } + MwForceRender2(handle, NULL); +} +#else +#define mouse_up MwForceRender2 +#endif + static void prop_change(MwWidget handle, const char* prop) { if(strcmp(prop, MwNtext) == 0 || strcmp(prop, MwNhideInput) == 0) MwForceRender(handle); @@ -179,7 +193,7 @@ MwClassRec MwEntryClassRec = { NULL, /* parent_resize */ prop_change, /* prop_change */ NULL, /* mouse_move */ - MwForceRender2, /* mouse_up */ + mouse_up, /* mouse_up */ MwForceRender2, /* mouse_down */ key, /* key */ NULL, /* execute */ From e77eb5e08a48d6df3d9d4066e245d29baaa9f4fd Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 11:14:13 -0700 Subject: [PATCH 364/409] add clipboard stuff to milsko.xml --- milsko.xml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/milsko.xml b/milsko.xml index 9fb45a608..70503a1d8 100644 --- a/milsko.xml +++ b/milsko.xml @@ -1,4 +1,4 @@ - + + @@ -146,6 +149,10 @@ + + 0 + + 0x0fffffff @@ -399,6 +406,19 @@ + + + + + + + + + + + + +
From f7eb9840def45894a416521cb5f0b555dad29ca6 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 11:19:10 -0700 Subject: [PATCH 365/409] milsko.xml: MwClipboardType should be marked as an enum for MwGetClipboard --- milsko.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/milsko.xml b/milsko.xml index 70503a1d8..d42f7e961 100644 --- a/milsko.xml +++ b/milsko.xml @@ -409,7 +409,7 @@ - + From a3bbcf30b2b94c88a3b59f86260a59cee3d6715d Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 12:25:51 -0700 Subject: [PATCH 366/409] wayland: dark theme detection --- include/Mw/LowLevel/Wayland.h | 53 ++++++++++++++++- pl/rules.pl | 2 + src/backend/wayland.c | 105 ++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index ce1630c5b..9377bc837 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -14,6 +14,7 @@ #include #include #include +#include MWDECL int MwLLWaylandCallInit(void); @@ -35,8 +36,7 @@ typedef struct wayland_call_table { void* lib; void* xkb_lib; void* cairo_lib; -#if WAYLAND_LOAD_OPENGL -#endif + void* dbus_lib; int (*wl_display_dispatch_pending)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display); @@ -125,6 +125,21 @@ typedef struct wayland_call_table { void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); + void (*dbus_error_init)(DBusError* error); + DBusConnection* (*dbus_bus_get)(DBusBusType type, DBusError* error); + dbus_bool_t (*dbus_error_is_set)(const DBusError* error); + void (*dbus_error_free)(DBusError* error); + DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); + void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + void (*dbus_message_unref)(DBusMessage* message); + dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); + void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_connection_unref)(DBusConnection* connection); + void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); + } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; @@ -225,6 +240,34 @@ MwInline int wayland_load_funcs() { CAIRO_FUNC(cairo_pattern_set_filter); #undef CAIRO_FUNC + wl_call_tbl.dbus_lib = MwDynamicOpen("libdbus-1.so"); + if(!wl_call_tbl.dbus_lib) { + fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus library (libdbus-1.so) not found.\n"); + return 0; + } + +#define DBUS_FUNC(x) \ + wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.dbus_lib, #x); \ + if(!x) { \ + fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus function %s (libdbus-1.so) not found.\n", #x); \ + return 0; \ + } + + DBUS_FUNC(dbus_error_init); + DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_error_is_set); + DBUS_FUNC(dbus_error_free); + DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_iter_init_append); + DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_send_with_reply_and_block); + DBUS_FUNC(dbus_message_unref); + DBUS_FUNC(dbus_message_iter_init); + DBUS_FUNC(dbus_message_iter_get_arg_type); + DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_connection_unref); + DBUS_FUNC(dbus_message_iter_get_basic); + return 0; } @@ -436,6 +479,12 @@ struct _MwLLWayland { struct zwp_locked_pointer_v1* locked_pointer; MwBool pointer_constrained; + DBusConnection* dbus_conn; + DBusError dbus_err; + DBusMessage* dbus_msg; + DBusMessage* dbus_reply; + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; + /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/pl/rules.pl b/pl/rules.pl index 3da19289e..d6f72fb6e 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,6 +49,8 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); + add_cflags("-I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include"); + $gl_libs = "-lGL -lGLU"; } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 8bb6f3eed..e1e8ee4d0 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1829,6 +1829,99 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh MwLLEndDraw(r); } } + +static void dark_theme_detection_setup(MwLL handle) { + + if(!wl_call_tbl.dbus_lib) { + return; + } + + wl_call_tbl.dbus_error_init(&handle->wayland.dbus_err); + + handle->wayland.dbus_conn = wl_call_tbl.dbus_bus_get(0 /* DBUS_BUS_SESSION */, &handle->wayland.dbus_err); + if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { + fprintf(stderr, "[WARNING] Could not detect dark theme: Connection error: %s\n", handle->wayland.dbus_err.message); + wl_call_tbl.dbus_error_free(&handle->wayland.dbus_err); + return; + } + if(!handle->wayland.dbus_conn) { + fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to connect to session bus\n"); + return; + } +} + +static void detect_dark_theme(MwLL handle) { + const char* namespace = "org.freedesktop.appearance"; + const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ + MwU32 value = 0; + int translated_value = 0; + + if(!handle->wayland.dbus_conn) { + return; + } + + handle->wayland.dbus_msg = wl_call_tbl.dbus_message_new_method_call( + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + "org.freedesktop.portal.Settings", + "Read"); + if(!handle->wayland.dbus_msg) { + fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to create message\n"); + return; + } + + wl_call_tbl.dbus_message_iter_init_append(handle->wayland.dbus_msg, &handle->wayland.dbus_args); + wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &namespace); + wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &key); + + handle->wayland.dbus_reply = wl_call_tbl.dbus_connection_send_with_reply_and_block(handle->wayland.dbus_conn, handle->wayland.dbus_msg, 100, &handle->wayland.dbus_err); + wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); + + if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { + fprintf(stderr, "[WARNING] Could not detect dark theme: Send error: %s\n", handle->wayland.dbus_err.message); + wl_call_tbl.dbus_error_free(&handle->wayland.dbus_err); + return; + } + if(!handle->wayland.dbus_reply) { + fprintf(stderr, "[WARNING] Could not detect dark theme: No reply received\n"); + return; + } + + if(!wl_call_tbl.dbus_message_iter_init(handle->wayland.dbus_reply, &handle->wayland.dbus_args)) { + fprintf(stderr, "[WARNING] Could not detect dark theme: Reply has no arguments\n"); + wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); + return; + } + + if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_args) != 'v') { + fprintf(stderr, "[WARNING] Could not detect dark theme: Expected outer variant\n"); + wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); + return; + } + wl_call_tbl.dbus_message_iter_recurse(&handle->wayland.dbus_args, &handle->wayland.dbus_variant); + + /* Some portals wrap the value in a second variant */ + if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_variant) == 'v') { + wl_call_tbl.dbus_message_iter_recurse(&handle->wayland.dbus_variant, &handle->wayland.dbus_inner_variant); + wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_inner_variant, &value); + } else { + wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_variant, &value); + } + + translated_value = (value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &translated_value); +} + +static void dark_theme_detection_destroy(MwLL handle) { + if(!wl_call_tbl.dbus_lib) { + return; + } + + wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); + wl_call_tbl.dbus_connection_unref(handle->wayland.dbus_conn); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -1837,6 +1930,10 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); + if(!parent) { + dark_theme_detection_setup(r); + } + return r; } @@ -1856,6 +1953,10 @@ static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); + if(!handle->wayland.dbus_conn) { + dark_theme_detection_destroy(handle); + } + event_loop(handle); /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ @@ -2144,6 +2245,10 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; + if(handle->wayland.dbus_conn) { + detect_dark_theme(handle); + } + if(!handle->wayland.did_initial_resize) { recursive_dispatch_resize(handle); handle->wayland.did_initial_resize = 1; From d05e31b154baea11d14f76c99deb00b682e56f8f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 13:00:59 -0700 Subject: [PATCH 367/409] wayland: don't poll for dark theme, that doesn't work --- include/Mw/LowLevel/Wayland.h | 2 ++ src/backend/wayland.c | 49 +++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 9377bc837..d4ebdef93 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -479,6 +479,8 @@ struct _MwLLWayland { struct zwp_locked_pointer_v1* locked_pointer; MwBool pointer_constrained; + MwBool dark_theme_detection; + time_t dbus_timer; DBusConnection* dbus_conn; DBusError dbus_err; DBusMessage* dbus_msg; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index e1e8ee4d0..68207b871 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1831,11 +1831,17 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } static void dark_theme_detection_setup(MwLL handle) { + const char* namespace = "org.freedesktop.appearance"; + const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ + MwU32 value = 0; + int translated_value = 0; if(!wl_call_tbl.dbus_lib) { return; } + time(&handle->wayland.dbus_timer); + wl_call_tbl.dbus_error_init(&handle->wayland.dbus_err); handle->wayland.dbus_conn = wl_call_tbl.dbus_bus_get(0 /* DBUS_BUS_SESSION */, &handle->wayland.dbus_err); @@ -1848,17 +1854,6 @@ static void dark_theme_detection_setup(MwLL handle) { fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to connect to session bus\n"); return; } -} - -static void detect_dark_theme(MwLL handle) { - const char* namespace = "org.freedesktop.appearance"; - const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ - MwU32 value = 0; - int translated_value = 0; - - if(!handle->wayland.dbus_conn) { - return; - } handle->wayland.dbus_msg = wl_call_tbl.dbus_message_new_method_call( "org.freedesktop.portal.Desktop", @@ -1873,9 +1868,18 @@ static void detect_dark_theme(MwLL handle) { wl_call_tbl.dbus_message_iter_init_append(handle->wayland.dbus_msg, &handle->wayland.dbus_args); wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &namespace); wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &key); +} + +static void detect_dark_theme(MwLL handle) { + const char* namespace = "org.freedesktop.appearance"; + const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ + MwU32 value = 0; + + if(!handle->wayland.dbus_conn) { + return; + } handle->wayland.dbus_reply = wl_call_tbl.dbus_connection_send_with_reply_and_block(handle->wayland.dbus_conn, handle->wayland.dbus_msg, 100, &handle->wayland.dbus_err); - wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { fprintf(stderr, "[WARNING] Could not detect dark theme: Send error: %s\n", handle->wayland.dbus_err.message); @@ -1908,18 +1912,16 @@ static void detect_dark_theme(MwLL handle) { wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_variant, &value); } - translated_value = (value == 1) ? 1 : 0; - - MwLLDispatch(handle, dark_theme, &translated_value); + MwLLDispatch(handle, dark_theme, &value); } static void dark_theme_detection_destroy(MwLL handle) { if(!wl_call_tbl.dbus_lib) { return; } - - wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); - wl_call_tbl.dbus_connection_unref(handle->wayland.dbus_conn); + if(handle->wayland.dbus_msg) wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); + if(handle->wayland.dbus_reply) wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); + if(handle->wayland.dbus_conn) wl_call_tbl.dbus_connection_unref(handle->wayland.dbus_conn); } static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { @@ -1932,6 +1934,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(!parent) { dark_theme_detection_setup(r); + r->wayland.dark_theme_detection = MwTRUE; } return r; @@ -2245,8 +2248,11 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(handle->wayland.dbus_conn) { - detect_dark_theme(handle); + if(handle->wayland.dark_theme_detection) { + if(handle->wayland.dbus_conn) { + detect_dark_theme(handle); + handle->wayland.dark_theme_detection = MwFALSE; + } } if(!handle->wayland.did_initial_resize) { @@ -2652,6 +2658,9 @@ static void MwLLEndStateChangeImpl(MwLL handle) { widget_setup(handle, handle->wayland.parent, handle->wayland.detach_point.x, handle->wayland.detach_point.y, handle->wayland.ww, handle->wayland.wh, handle->wayland.type_to_be); + if(!handle->wayland.parent) + handle->wayland.dark_theme_detection = MwTRUE; + if(handle->common.user) { MwWidget w = handle->common.user; int i; From 64930db2fc89f2b08bc5e8d9cdcfa1ce565f0079 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 13:03:24 -0700 Subject: [PATCH 368/409] color picker example: have button match the background --- examples/basic/colorpicker.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 22e647cc8..8d0c0f369 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -35,12 +35,11 @@ int main() { window = MwVaCreateWidget(MwWindowClass, "main", NULL, MwDEFAULT, MwDEFAULT, 640, 480, MwNtitle, "color picker", NULL); - MwSetText(window, MwNbackground, "#000000"); + MwSetText(window, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); - MwSetText(button, MwNbackground, MwGetInteger(button, MwNdarkTheme) ? MwDefaultDarkBackground : MwDefaultBackground); MwAddUserHandler(button, MwNactivateHandler, color_picker, NULL); From a0c864d85b2bf782e78ef15068b0a293910fc017 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 13:58:50 -0700 Subject: [PATCH 369/409] fix wayland crash by having MwLLDestroy flush before actually destroying handle --- src/backend/wayland.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 68207b871..435033643 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1949,6 +1949,11 @@ static void MwLLDestroyImpl(MwLL handle) { }; int select_ret; + event_loop(handle); + // wl_display_cancel_read(handle->wayland.display); + + wl_flush(handle); + if(pthread_mutex_timedlock(&handle->wayland.eventsMutex, &t) != 0) { printf("WARNING: Couldn't call MwLLDestroyImpl due to deadlock.\n"); return; @@ -1956,12 +1961,6 @@ static void MwLLDestroyImpl(MwLL handle) { MwLLDestroyCommon(handle); - if(!handle->wayland.dbus_conn) { - dark_theme_detection_destroy(handle); - } - - event_loop(handle); - /* sleep long enough that any active attempts to wait for the mutex will have given up and we can safely unlock/destroy it */ tv.tv_sec = 0; tv.tv_usec = 1000; @@ -1972,7 +1971,10 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&handle->wayland.eventsMutex); pthread_mutex_destroy(&handle->wayland.eventsMutex); - // framebuffer_destroy(&handle->wayland); + if(!handle->wayland.dbus_conn) { + dark_theme_detection_destroy(handle); + } + buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); @@ -2005,7 +2007,12 @@ static void MwLLDestroyImpl(MwLL handle) { shfree(handle->wayland.wl_protocol_map); shfree(handle->wayland.wl_protocol_setup_map); - free(handle); + wl_keyboard_destroy(handle->wayland.keyboard); + wl_pointer_destroy(handle->wayland.pointer); + + wl_flush(handle); + + // free(handle); if(currentlyHeldWidget == handle) { currentlyHeldWidget = NULL; @@ -2252,6 +2259,7 @@ static int MwLLPendingImpl(MwLL handle) { if(handle->wayland.dbus_conn) { detect_dark_theme(handle); handle->wayland.dark_theme_detection = MwFALSE; + MwLLDispatch(handle, draw, NULL); } } From 12703d451e63bbf5d505ba0c33f00deab5d3989c Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 14:02:22 -0700 Subject: [PATCH 370/409] use pkg-config for dbus includes --- pl/rules.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl/rules.pl b/pl/rules.pl index d6f72fb6e..af1bb21cc 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,7 +49,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - add_cflags("-I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include"); + add_cflags(`pkg-config --cflags dbus-1.0`); $gl_libs = "-lGL -lGLU"; } From 43c66417c7f15a07b8207d432f27531bc1bbd6d5 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 14:03:48 -0700 Subject: [PATCH 371/409] use pkg-config for dbus includes --- pl/rules.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pl/rules.pl b/pl/rules.pl index af1bb21cc..2b222249b 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,7 +49,7 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - add_cflags(`pkg-config --cflags dbus-1.0`); + add_cflags(`pkg-config --cflags dbus-1`); $gl_libs = "-lGL -lGLU"; } From dc97522bb075527f428d8c3e44a8fdc50a29f0ac Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 15:21:16 -0700 Subject: [PATCH 372/409] wayland: abstract the dbus stuff a bit in case we need it later --- src/backend/wayland.c | 60 ++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 435033643..3c8c9cd20 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1830,11 +1830,9 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } -static void dark_theme_detection_setup(MwLL handle) { - const char* namespace = "org.freedesktop.appearance"; - const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ - MwU32 value = 0; - int translated_value = 0; +static void dbus_setup(MwLL handle) { + MwU32 value = 0; + int translated_value = 0; if(!wl_call_tbl.dbus_lib) { return; @@ -1854,51 +1852,47 @@ static void dark_theme_detection_setup(MwLL handle) { fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to connect to session bus\n"); return; } +} + +static void dbus_get(MwLL handle, const char* portal, const char* namespace, const char* key, void* out) { + if(!handle->wayland.dbus_conn) { + return; + } handle->wayland.dbus_msg = wl_call_tbl.dbus_message_new_method_call( "org.freedesktop.portal.Desktop", "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.Settings", + portal, "Read"); if(!handle->wayland.dbus_msg) { - fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to create message\n"); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Failed to create message\n", namespace, key); return; } wl_call_tbl.dbus_message_iter_init_append(handle->wayland.dbus_msg, &handle->wayland.dbus_args); wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &namespace); wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &key); -} - -static void detect_dark_theme(MwLL handle) { - const char* namespace = "org.freedesktop.appearance"; - const char* key = "color-scheme"; /* 0=no preference, 1=dark, 2=light */ - MwU32 value = 0; - - if(!handle->wayland.dbus_conn) { - return; - } handle->wayland.dbus_reply = wl_call_tbl.dbus_connection_send_with_reply_and_block(handle->wayland.dbus_conn, handle->wayland.dbus_msg, 100, &handle->wayland.dbus_err); if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { - fprintf(stderr, "[WARNING] Could not detect dark theme: Send error: %s\n", handle->wayland.dbus_err.message); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Send error: %s\n", namespace, key, handle->wayland.dbus_err.message); wl_call_tbl.dbus_error_free(&handle->wayland.dbus_err); return; } if(!handle->wayland.dbus_reply) { - fprintf(stderr, "[WARNING] Could not detect dark theme: No reply received\n"); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: No reply received\n", namespace, key); return; } if(!wl_call_tbl.dbus_message_iter_init(handle->wayland.dbus_reply, &handle->wayland.dbus_args)) { - fprintf(stderr, "[WARNING] Could not detect dark theme: Reply has no arguments\n"); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); return; } if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_args) != 'v') { - fprintf(stderr, "[WARNING] Could not detect dark theme: Expected outer variant\n"); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); return; } @@ -1907,19 +1901,27 @@ static void detect_dark_theme(MwLL handle) { /* Some portals wrap the value in a second variant */ if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_variant) == 'v') { wl_call_tbl.dbus_message_iter_recurse(&handle->wayland.dbus_variant, &handle->wayland.dbus_inner_variant); - wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_inner_variant, &value); + wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_inner_variant, out); } else { - wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_variant, &value); + wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_variant, out); } - - MwLLDispatch(handle, dark_theme, &value); + wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); } -static void dark_theme_detection_destroy(MwLL handle) { +static void detect_dark_theme(MwLL handle) { + MwU32 value = 0; + MwU32 dark_theme = 0; + dbus_get(handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + + dark_theme = (value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &dark_theme); +} + +static void dbus_destroy(MwLL handle) { if(!wl_call_tbl.dbus_lib) { return; } - if(handle->wayland.dbus_msg) wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); if(handle->wayland.dbus_reply) wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); if(handle->wayland.dbus_conn) wl_call_tbl.dbus_connection_unref(handle->wayland.dbus_conn); } @@ -1933,7 +1935,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); if(!parent) { - dark_theme_detection_setup(r); + dbus_setup(r); r->wayland.dark_theme_detection = MwTRUE; } @@ -1972,7 +1974,7 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_destroy(&handle->wayland.eventsMutex); if(!handle->wayland.dbus_conn) { - dark_theme_detection_destroy(handle); + dbus_destroy(handle); } buffer_destroy(&handle->wayland.cursor); From 9087782960496a271c184e9e2c913a38611139cd Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 15:23:55 -0700 Subject: [PATCH 373/409] wayland: fix DBUS_FUNC --- include/Mw/LowLevel/Wayland.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index d4ebdef93..6b2c08ff9 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -248,8 +248,9 @@ MwInline int wayland_load_funcs() { #define DBUS_FUNC(x) \ wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.dbus_lib, #x); \ - if(!x) { \ - fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus function %s (libdbus-1.so) not found.\n", #x); \ + if(!wl_call_tbl.x) { \ + fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus function %s not found.\n", #x); \ + dlclose(wl_call_tbl.dbus_lib); \ return 0; \ } From 54fed150e8be93fc89df79c430e528c28907fc98 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 16:12:38 -0700 Subject: [PATCH 374/409] dbus --- include/Mw/LowLevel.h | 37 +++++++++++ include/Mw/LowLevel/Wayland.h | 63 ++++-------------- include/Mw/LowLevel/X11.h | 6 ++ include/Mw/MachDep.h | 4 ++ pl/ostype/Linux.pl | 2 + src/backend/wayland.c | 100 +++------------------------- src/backend/x11.c | 35 ++++++++++ src/lowlevel.c | 119 ++++++++++++++++++++++++++++++++++ 8 files changed, 223 insertions(+), 143 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index d5a0b1b5b..c958e00d7 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -56,6 +56,43 @@ struct _MwLLCommonPixmap { void* user; }; +#ifdef USE_DBUS +typedef struct _MwLLDBusFuncTable { + void* lib; + + void (*dbus_error_init)(DBusError* error); + DBusConnection* (*dbus_bus_get)(DBusBusType type, DBusError* error); + dbus_bool_t (*dbus_error_is_set)(const DBusError* error); + void (*dbus_error_free)(DBusError* error); + DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); + void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + void (*dbus_message_unref)(DBusMessage* message); + dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); + void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_connection_unref)(DBusConnection* connection); + void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); +} MwLLDBusFuncTable; + +typedef struct _MwLLDBusContext { + DBusConnection* dbus_conn; + DBusError dbus_err; + DBusMessage* dbus_msg; + DBusMessage* dbus_reply; + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; +} MwLLDBusContext; + +/* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */ +MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl); + +MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); +MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out); +MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); + +#endif + #ifdef _MILSKO #ifdef USE_X11 #include diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 6b2c08ff9..77e43b3be 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -36,7 +36,10 @@ typedef struct wayland_call_table { void* lib; void* xkb_lib; void* cairo_lib; - void* dbus_lib; +#ifdef USE_DBUS + MwLLDBusFuncTable dbus; + MwBool has_dbus; +#endif int (*wl_display_dispatch_pending)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display); @@ -125,21 +128,6 @@ typedef struct wayland_call_table { void (*cairo_set_antialias)(cairo_t*, cairo_antialias_t); void (*cairo_set_operator)(cairo_t* cr, cairo_operator_t op); - void (*dbus_error_init)(DBusError* error); - DBusConnection* (*dbus_bus_get)(DBusBusType type, DBusError* error); - dbus_bool_t (*dbus_error_is_set)(const DBusError* error); - void (*dbus_error_free)(DBusError* error); - DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); - void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); - dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); - DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); - void (*dbus_message_unref)(DBusMessage* message); - dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); - int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); - void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); - void (*dbus_connection_unref)(DBusConnection* connection); - void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); - } wayland_call_table_t; extern wayland_call_table_t wl_call_tbl; @@ -240,34 +228,9 @@ MwInline int wayland_load_funcs() { CAIRO_FUNC(cairo_pattern_set_filter); #undef CAIRO_FUNC - wl_call_tbl.dbus_lib = MwDynamicOpen("libdbus-1.so"); - if(!wl_call_tbl.dbus_lib) { - fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus library (libdbus-1.so) not found.\n"); - return 0; - } - -#define DBUS_FUNC(x) \ - wl_call_tbl.x = MwDynamicSymbol(wl_call_tbl.dbus_lib, #x); \ - if(!wl_call_tbl.x) { \ - fprintf(stderr, "[WARNING] Will not be able to detect dark theme: dbus function %s not found.\n", #x); \ - dlclose(wl_call_tbl.dbus_lib); \ - return 0; \ - } - - DBUS_FUNC(dbus_error_init); - DBUS_FUNC(dbus_bus_get); - DBUS_FUNC(dbus_error_is_set); - DBUS_FUNC(dbus_error_free); - DBUS_FUNC(dbus_message_new_method_call); - DBUS_FUNC(dbus_message_iter_init_append); - DBUS_FUNC(dbus_message_iter_append_basic); - DBUS_FUNC(dbus_connection_send_with_reply_and_block); - DBUS_FUNC(dbus_message_unref); - DBUS_FUNC(dbus_message_iter_init); - DBUS_FUNC(dbus_message_iter_get_arg_type); - DBUS_FUNC(dbus_message_iter_recurse); - DBUS_FUNC(dbus_connection_unref); - DBUS_FUNC(dbus_message_iter_get_basic); +#ifdef USE_DBUS + wl_call_tbl.has_dbus = MwLLDBusFuncSetup(&wl_call_tbl.dbus); +#endif return 0; } @@ -480,13 +443,11 @@ struct _MwLLWayland { struct zwp_locked_pointer_v1* locked_pointer; MwBool pointer_constrained; - MwBool dark_theme_detection; - time_t dbus_timer; - DBusConnection* dbus_conn; - DBusError dbus_err; - DBusMessage* dbus_msg; - DBusMessage* dbus_reply; - DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; +#ifdef USE_DBUS + MwLLDBusContext dbus; +#endif + + MwBool dark_theme_detection; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/include/Mw/LowLevel/X11.h b/include/Mw/LowLevel/X11.h index 529a570c8..3d0e1252e 100644 --- a/include/Mw/LowLevel/X11.h +++ b/include/Mw/LowLevel/X11.h @@ -57,6 +57,12 @@ struct _MwLLX11 { unsigned long blue_mask; unsigned long blue_max; unsigned long blue_shift; + +#ifdef USE_DBUS + MwLLDBusContext dbus; +#endif + + MwBool dark_theme_detection; }; struct _MwLLX11Color { diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 50898f676..025fc29b4 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -53,6 +53,10 @@ #include #endif +#ifdef USE_DBUS +#include +#endif + #ifndef M_PI #define M_PI 3.14159265 #endif diff --git a/pl/ostype/Linux.pl b/pl/ostype/Linux.pl index 73905d60b..278cbfe0c 100644 --- a/pl/ostype/Linux.pl +++ b/pl/ostype/Linux.pl @@ -7,6 +7,8 @@ if (param_get("x11")) { push(@enabled_backends, "x11"); } +add_cflags("-DUSE_DBUS"); + use_backend(@enabled_backends); 1; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 3c8c9cd20..1fc68cb4c 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1830,102 +1830,16 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } -static void dbus_setup(MwLL handle) { - MwU32 value = 0; - int translated_value = 0; - - if(!wl_call_tbl.dbus_lib) { - return; - } - - time(&handle->wayland.dbus_timer); - - wl_call_tbl.dbus_error_init(&handle->wayland.dbus_err); - - handle->wayland.dbus_conn = wl_call_tbl.dbus_bus_get(0 /* DBUS_BUS_SESSION */, &handle->wayland.dbus_err); - if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { - fprintf(stderr, "[WARNING] Could not detect dark theme: Connection error: %s\n", handle->wayland.dbus_err.message); - wl_call_tbl.dbus_error_free(&handle->wayland.dbus_err); - return; - } - if(!handle->wayland.dbus_conn) { - fprintf(stderr, "[WARNING] Could not detect dark theme: Failed to connect to session bus\n"); - return; - } -} - -static void dbus_get(MwLL handle, const char* portal, const char* namespace, const char* key, void* out) { - if(!handle->wayland.dbus_conn) { - return; - } - - handle->wayland.dbus_msg = wl_call_tbl.dbus_message_new_method_call( - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - portal, - "Read"); - if(!handle->wayland.dbus_msg) { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Failed to create message\n", namespace, key); - return; - } - - wl_call_tbl.dbus_message_iter_init_append(handle->wayland.dbus_msg, &handle->wayland.dbus_args); - wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &namespace); - wl_call_tbl.dbus_message_iter_append_basic(&handle->wayland.dbus_args, 's', &key); - - handle->wayland.dbus_reply = wl_call_tbl.dbus_connection_send_with_reply_and_block(handle->wayland.dbus_conn, handle->wayland.dbus_msg, 100, &handle->wayland.dbus_err); - - if(wl_call_tbl.dbus_error_is_set(&handle->wayland.dbus_err)) { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Send error: %s\n", namespace, key, handle->wayland.dbus_err.message); - wl_call_tbl.dbus_error_free(&handle->wayland.dbus_err); - return; - } - if(!handle->wayland.dbus_reply) { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: No reply received\n", namespace, key); - return; - } - - if(!wl_call_tbl.dbus_message_iter_init(handle->wayland.dbus_reply, &handle->wayland.dbus_args)) { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); - wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); - return; - } - - if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_args) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); - wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); - return; - } - wl_call_tbl.dbus_message_iter_recurse(&handle->wayland.dbus_args, &handle->wayland.dbus_variant); - - /* Some portals wrap the value in a second variant */ - if(wl_call_tbl.dbus_message_iter_get_arg_type(&handle->wayland.dbus_variant) == 'v') { - wl_call_tbl.dbus_message_iter_recurse(&handle->wayland.dbus_variant, &handle->wayland.dbus_inner_variant); - wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_inner_variant, out); - } else { - wl_call_tbl.dbus_message_iter_get_basic(&handle->wayland.dbus_variant, out); - } - wl_call_tbl.dbus_message_unref(handle->wayland.dbus_msg); -} - static void detect_dark_theme(MwLL handle) { MwU32 value = 0; MwU32 dark_theme = 0; - dbus_get(handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); dark_theme = (value == 1) ? 1 : 0; MwLLDispatch(handle, dark_theme, &dark_theme); } -static void dbus_destroy(MwLL handle) { - if(!wl_call_tbl.dbus_lib) { - return; - } - if(handle->wayland.dbus_reply) wl_call_tbl.dbus_message_unref(handle->wayland.dbus_reply); - if(handle->wayland.dbus_conn) wl_call_tbl.dbus_connection_unref(handle->wayland.dbus_conn); -} - static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -1934,10 +1848,12 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { widget_setup(r, parent, x, y, width, height, MWLL_WAYLAND_UNKNOWN); - if(!parent) { - dbus_setup(r); +#ifdef USE_DBUS + if(!parent && wl_call_tbl.has_dbus) { + wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); r->wayland.dark_theme_detection = MwTRUE; } +#endif return r; } @@ -1973,8 +1889,8 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&handle->wayland.eventsMutex); pthread_mutex_destroy(&handle->wayland.eventsMutex); - if(!handle->wayland.dbus_conn) { - dbus_destroy(handle); + if(!wl_call_tbl.has_dbus) { + MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); } buffer_destroy(&handle->wayland.cursor); @@ -2258,7 +2174,7 @@ static int MwLLPendingImpl(MwLL handle) { int pending = 0; if(handle->wayland.dark_theme_detection) { - if(handle->wayland.dbus_conn) { + if(wl_call_tbl.has_dbus) { detect_dark_theme(handle); handle->wayland.dark_theme_detection = MwFALSE; MwLLDispatch(handle, draw, NULL); diff --git a/src/backend/x11.c b/src/backend/x11.c index ad97d6885..d8f028b32 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -9,6 +9,9 @@ static struct { void* lib_xrender; MwBool has_xrender; + MwLLDBusFuncTable dbus; + MwBool has_dbus; + int (*XClearWindow)(Display* display, Window w); XImage* (*XCreateImage)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int); Display* (*XOpenDisplay)(_Xconst char*); @@ -308,6 +311,16 @@ static XVisualInfo* get_visual_info(Display* display) { return XGetVisualInfo(display, VisualIDMask, &xvi, &n); } +static void detect_dark_theme(MwLL handle) { + MwU32 value = 0; + MwU32 dark_theme = 0; + MwLLDBusPortalGet(&xsymtbl.dbus, &handle->x11.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + + dark_theme = (value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &dark_theme); +} + static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; Window p; @@ -429,6 +442,14 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { } } +#ifdef USE_DBUS + memset(&r->x11.dbus, 0, sizeof(r->x11.dbus)); + if(!parent && xsymtbl.has_dbus) { + xsymtbl.has_dbus = MwLLDBusNewContext(&xsymtbl.dbus, &r->x11.dbus); + r->x11.dark_theme_detection = MwTRUE; + } +#endif + return r; } @@ -449,6 +470,10 @@ static void MwLLDestroyImpl(MwLL handle) { if(handle->x11.toplevel) XCloseDisplay(handle->x11.display); + if(!xsymtbl.has_dbus) { + MwLLDBusFreeContext(&xsymtbl.dbus, &handle->x11.dbus); + } + free(handle); } @@ -607,6 +632,14 @@ static void MwLLFreeColorImpl(MwLLColor color) { static int MwLLPendingImpl(MwLL handle) { XEvent ev; + if(handle->x11.dark_theme_detection) { + if(xsymtbl.has_dbus) { + detect_dark_theme(handle); + handle->x11.dark_theme_detection = MwFALSE; + MwLLDispatch(handle, draw, NULL); + } + } + if(handle->x11.clipboard_pending && (MwTimeGetTick() - handle->x11.clipboard_time) >= ClipboardTimeout) { return 1; } @@ -1388,6 +1421,8 @@ static int MwLLX11CallInitImpl(void) { XRENDER_FUNC_LOAD(XRenderSetPictureTransform) XRENDER_FUNC_LOAD(XRenderComposite) #endif + + xsymtbl.has_dbus = MwLLDBusFuncSetup(&xsymtbl.dbus); return 0; } diff --git a/src/lowlevel.c b/src/lowlevel.c index 597a23a82..32188aa99 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -61,3 +61,122 @@ void MwLLCreateCommon(MwLL handle) { void MwLLDestroyCommon(MwLL handle) { free(handle->common.handler); } + +#ifdef USE_DBUS +MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { + tbl->lib = MwDynamicOpen("libdbus-1.so"); + if(!tbl->lib) { + fprintf(stderr, "[WARNING] dbus library (libdbus-1.so) not found, will not be able to check for any XDG settings.\n"); + return MwFALSE; + } + +#define DBUS_FUNC(x) \ + tbl->x = MwDynamicSymbol(tbl->lib, #x); \ + if(!tbl->x) { \ + fprintf(stderr, "[WARNING] dbus function %s not found, will not be able to check for any XDG settings.\n", #x); \ + dlclose(tbl->lib); \ + return MwFALSE; \ + } + + DBUS_FUNC(dbus_error_init); + DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_error_is_set); + DBUS_FUNC(dbus_error_free); + DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_iter_init_append); + DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_send_with_reply_and_block); + DBUS_FUNC(dbus_message_unref); + DBUS_FUNC(dbus_message_iter_init); + DBUS_FUNC(dbus_message_iter_get_arg_type); + DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_connection_unref); + DBUS_FUNC(dbus_message_iter_get_basic); + + return MwTRUE; +} +#endif + +MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { + if(!tbl->lib) { + return MwFALSE; + } + + tbl->dbus_error_init(&ctx->dbus_err); + + ctx->dbus_conn = tbl->dbus_bus_get(DBUS_BUS_SESSION, &ctx->dbus_err); + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Could not initialize dbus: Connection error: %s\n", ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_conn) { + fprintf(stderr, "[WARNING] Could not initialize dbus: Failed to connect to session bus\n"); + return MwFALSE; + } + return MwTRUE; +}; + +MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { + if(!ctx->dbus_conn) { + return MwFALSE; + } + + ctx->dbus_msg = tbl->dbus_message_new_method_call( + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + portal, + "Read"); + if(!ctx->dbus_msg) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Failed to create message\n", namespace, key); + return MwFALSE; + } + + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &ctx->dbus_args); + tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &key); + + ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); + + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Send error: %s\n", namespace, key, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: No reply received\n", namespace, key); + return MwFALSE; + } + + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &ctx->dbus_args)) { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + + if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_args) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&ctx->dbus_args, &ctx->dbus_variant); + + /* Some portals wrap the value in a second variant */ + if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_variant) == 'v') { + tbl->dbus_message_iter_recurse(&ctx->dbus_variant, &ctx->dbus_inner_variant); + tbl->dbus_message_iter_get_basic(&ctx->dbus_inner_variant, out); + } else { + tbl->dbus_message_iter_get_basic(&ctx->dbus_variant, out); + } + tbl->dbus_message_unref(ctx->dbus_msg); + + return MwTRUE; +} + +void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { + if(!tbl->lib) { + return; + } + if(ctx->dbus_reply) tbl->dbus_message_unref(ctx->dbus_reply); + if(ctx->dbus_conn) tbl->dbus_connection_unref(ctx->dbus_conn); +}; From 677d8c8046d620fbc901a4e2b15000088bc7fe2f Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Wed, 15 Apr 2026 18:26:32 -0500 Subject: [PATCH 375/409] guard dbus function impls with ifdef --- src/lowlevel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lowlevel.c b/src/lowlevel.c index 32188aa99..13a7d4999 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -97,6 +97,7 @@ MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { } #endif +#ifdef USE_DBUS MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { if(!tbl->lib) { return MwFALSE; @@ -180,3 +181,4 @@ void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { if(ctx->dbus_reply) tbl->dbus_message_unref(ctx->dbus_reply); if(ctx->dbus_conn) tbl->dbus_connection_unref(ctx->dbus_conn); }; +#endif From 0fb9c45ea4cb39475fa7e97c8b6a4b8c26e35b5f Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 08:42:01 +0900 Subject: [PATCH 376/409] improve --- examples/basic/colorpicker.c | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/basic/colorpicker.c b/examples/basic/colorpicker.c index 8d0c0f369..6471b7822 100644 --- a/examples/basic/colorpicker.c +++ b/examples/basic/colorpicker.c @@ -40,6 +40,7 @@ int main() { button = MwVaCreateWidget(MwButtonClass, "button", window, 160, 180, 320, 120, MwNtext, "change window background", NULL); + MwSetText(button, MwNbackground, MwGetInteger(window, MwNdarkTheme) ? MwDefaultBackground : MwDefaultDarkBackground); MwAddUserHandler(button, MwNactivateHandler, color_picker, NULL); From a2c1489ffb0d70a13ad3c60032a08da8b6107486 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 09:35:53 +0900 Subject: [PATCH 377/409] add MwLLSetDarkTheme --- include/Mw/LowLevel.h | 2 ++ src/backend/call.c | 2 ++ src/backend/cocoa.m | 5 +++++ src/backend/gdi.c | 27 +++++++++++++++++++++++++++ src/backend/wayland.c | 5 +++++ src/backend/x11.c | 7 ++++++- src/core.c | 8 ++++++++ src/lowlevel.c | 2 ++ 8 files changed, 57 insertions(+), 1 deletion(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index c958e00d7..a1a469188 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -277,6 +277,8 @@ MWDECL void (*MwLLGetClipboard)(MwLL handle); MWDECL void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point); MWDECL void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect); +MWDECL void (*MwLLSetDarkTheme)(MwLL handle, int toggle); + /* font renderer */ MWDECL void MwFLSetup(void); diff --git a/src/backend/call.c b/src/backend/call.c index e2ce934c9..07cf1e08f 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -54,6 +54,8 @@ \ MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ +\ + MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ \ return 0; \ } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 4cdc5b2b6..95fd56db8 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1082,6 +1082,11 @@ static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ + (void)handle; + (void)toggle; +} + static int MwLLCocoaCallInitImpl(void) { #ifndef __APPLE__ printf("Using GNUStep Backend\n"); diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 5d89419d0..9fe139826 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -8,6 +8,14 @@ typedef struct userdata { int max_set; } userdata_t; +static struct symtbl { + void* lib_dwmapi; + + HRESULT (WINAPI *DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); +} wsymtbl; + +#define DwmSetWindowAttribute wsymtbl.DwmSetWindowAttribute + static void detect_darktheme(MwLL handle) { DWORD dw; DWORD sz = sizeof(dw); @@ -26,6 +34,12 @@ static void detect_darktheme(MwLL handle) { t = dw ? 0 : 1; + if(t && DwmSetWindowAttribute != NULL){ + LPARAM style = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); + BOOL v = TRUE; + if(!(style & WS_CHILD)) DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); + } + MwLLDispatch(handle, dark_theme, &t); } @@ -804,7 +818,20 @@ static void MwLLEndStateChangeImpl(MwLL handle) { (void)handle; } +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ + BOOL v = toggle ? TRUE : FALSE; + + DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); + +} + static int MwLLGDICallInitImpl(void) { + memset(&wsymtbl, 0, sizeof(wsymtbl)); + + wsymtbl.lib_dwmapi = MwDynamicOpen("dwmapi.dll"); + + if(wsymtbl.lib_dwmapi != NULL) DwmSetWindowAttribute = MwDynamicSymbol(wsymtbl.lib_dwmapi, "DwmSetWindowAttribute"); + /* TODO: check properly */ return 0; } diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 1fc68cb4c..bd4686081 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -2620,6 +2620,11 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } } +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ + (void)handle; + (void)toggle; +} + static int MwLLWaylandCallInitImpl(void) { #ifdef __linux__ MwBool loadWayland = MwFALSE; diff --git a/src/backend/x11.c b/src/backend/x11.c index d8f028b32..dcc41d7ad 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -4,7 +4,7 @@ #define ClipboardTimeout 100 -static struct { +static struct symtbl { void* lib_xlib; void* lib_xrender; MwBool has_xrender; @@ -1308,6 +1308,11 @@ static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ + (void)handle; + (void)toggle; +} + static int MwLLX11CallInitImpl(void) { MwBool loadX11 = MwFALSE; if(getenv("MILSKO_BACKEND")) { diff --git a/src/core.c b/src/core.c index cf45dddc2..1b00615c2 100644 --- a/src/core.c +++ b/src/core.c @@ -532,6 +532,14 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { if(strcmp(key, MwNmodernLook) == 0 || strcmp(key, MwNdarkTheme) == 0 || strcmp(key, MwNbitmapFont) == 0) { force_render_all(handle); } + + if(strcmp(key, MwNdarkTheme) == 0){ + MwWidget h = handle; + + while(h->parent != NULL && h->parent->widget_class != NULL) h = h->parent; + + MwLLSetDarkTheme(h->lowlevel, n); + } } void MwSetText(MwWidget handle, const char* key, const char* value) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 13a7d4999..e80b95b9c 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -51,6 +51,8 @@ void (*MwLLGetClipboard)(MwLL handle) = NULL; void (*MwLLGetCursorCoord)(MwLL handle, MwPoint* point) = NULL; void (*MwLLGetScreenSize)(MwLL handle, MwRect* rect) = NULL; +void (*MwLLSetDarkTheme)(MwLL handle, int toggle) = NULL; + void MwLLCreateCommon(MwLL handle) { handle->common.handler = malloc(sizeof(*handle->common.handler)); memset(handle->common.handler, 0, sizeof(*handle->common.handler)); From 48b847093beb5cd383ecff86aadaa0a96e20da29 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 09:50:08 +0900 Subject: [PATCH 378/409] oops --- src/backend/gdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 9fe139826..385c477fc 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -279,7 +279,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { r->common.copy_buffer = 1; r->common.type = MwLLBackendGDI; - r->gdi.get_clipboard = 1; + r->gdi.get_clipboard = 0; if(parent == NULL) r->gdi.get_darktheme = 1; r->gdi.force_render = 0; r->gdi.grabbed = 0; From 6f9b3c12a7a11d6c7a6c1aff20dd346770e38b7c Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 09:55:18 +0900 Subject: [PATCH 379/409] fix --- src/backend/gdi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 385c477fc..51e33df1d 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -36,8 +36,7 @@ static void detect_darktheme(MwLL handle) { if(t && DwmSetWindowAttribute != NULL){ LPARAM style = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); - BOOL v = TRUE; - if(!(style & WS_CHILD)) DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); + if(!(style & WS_CHILD)) MwLLSetDarkTheme(handle, 1); } MwLLDispatch(handle, dark_theme, &t); From 4e4da8659e1d2bcfdb4a564956fa1581cf400fd6 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 10:45:53 +0900 Subject: [PATCH 380/409] fix gdi opengl --- src/widget/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index d75b358f7..50fb7479f 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -381,7 +381,7 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { gdiopengl_t* o = handle->internal; - void (*swap_interval_ext)(int) = NULL; + int (__stdcall *swap_interval_ext)(int) = NULL; o->wglMakeCurrent(o->dc, o->gl); From 712a640f9df1b19f33bde1a608954acdd6aaceff Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 10:47:24 +0900 Subject: [PATCH 381/409] probably it is better to do this way --- src/widget/opengl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 50fb7479f..6ffef725b 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -381,7 +381,7 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { gdiopengl_t* o = handle->internal; - int (__stdcall *swap_interval_ext)(int) = NULL; + BOOL (APIENTRY *swap_interval_ext)(int) = NULL; o->wglMakeCurrent(o->dc, o->gl); From 5315f4ec4df13f09b73fcd49ff3244385b211ee7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 20:21:20 -0700 Subject: [PATCH 382/409] classic mac os --- .gitignore | 6 ++ configure | 63 +++++++---- include/Mw/LowLevel/ClassicMacOS.h | 27 +++++ include/Mw/MachDep.h | 17 ++- pl/ostype/ClassicMacOS68k.pl | 7 ++ pl/ostype/ClassicMacOSPPC.pl | 7 ++ pl/rules.pl | 7 ++ src/abstract/directory.c | 12 +++ src/abstract/dynamic.c | 30 ++++++ src/abstract/time.c | 21 ++++ src/backend/classicmacos.c | 167 +++++++++++++++++++++++++++++ src/dialog/filechooser.c | 4 +- src/widget/box.c | 2 +- src/widget/button.c | 2 +- src/widget/checkbox.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 2 +- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/label.c | 2 +- src/widget/listbox.c | 2 +- src/widget/menu.c | 2 +- src/widget/numberentry.c | 2 +- src/widget/opengl.c | 2 +- src/widget/opengl_cocoa.m | 4 +- src/widget/progressbar.c | 2 +- src/widget/radiobox.c | 2 +- src/widget/scrollbar.c | 8 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 2 +- src/widget/viewport.c | 2 +- src/widget/vulkan.c | 2 +- src/widget/window.c | 2 +- 34 files changed, 369 insertions(+), 51 deletions(-) create mode 100644 include/Mw/LowLevel/ClassicMacOS.h create mode 100644 pl/ostype/ClassicMacOS68k.pl create mode 100644 pl/ostype/ClassicMacOSPPC.pl create mode 100644 src/backend/classicmacos.c diff --git a/.gitignore b/.gitignore index 881607097..21058b8b1 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,9 @@ examples/*/*.exe compile_flags.txt .cache .DS_Store + +*.pef +*.dsk +*.bin +*.rsrc +*.finf diff --git a/configure b/configure index 5d9810863..5751b3d18 100755 --- a/configure +++ b/configure @@ -46,14 +46,6 @@ param_set("shared", 1); param_set("static", 1); param_set("examples", 1); - -if($target ne "Darwin") { - param_set("freetype2", 1); - param_set("stb-truetype", 0); -} else { - param_set("stb-truetype", 1); -} - my %features = ( "classic-theme" => "use classic theme", "stb-image" => "use stb_image, instead use libjpeg/libpng", @@ -77,13 +69,6 @@ my @features_keys = ( "1wayland", "1gnustep", ); -if($target eq "Linux") { - param_set("x11", 1); - if(!param_get("tiny")){ - param_set("wayland", 1); - } -} - foreach my $l (@ARGV) { if ($l =~ /^--with-([^=]+)=(.+)$/) { param_set($1, $2); @@ -146,6 +131,25 @@ foreach my $l (@ARGV) { } } +if($target ne "Darwin" and $target ne "ClassicMacOS68k" and $target ne "ClassicMacOSPPC") { + param_set("freetype2", 1); + param_set("stb-truetype", 0); +} else { + if($target ne "ClassicMacOS68k" and $target ne "ClassicMacOSPPC"){ + param_set("freetype2", 0); + param_set("stb-truetype", 1); + } else { + param_set("stb-truetype", 0); + } +} + +if($target eq "Linux") { + param_set("x11", 1); + if(!param_get("tiny")){ + param_set("wayland", 1); + } +} + if (-f "./pl/ostype/${target}.pl") { require("./pl/ostype/${target}.pl"); } @@ -256,7 +260,7 @@ foreach my $l (@library_targets) { } print(OUT "${l}: ${s}\n"); - print(OUT " \$(CC) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); + print(OUT " \$(CC) $warn \$\(INCDIR\) \$(CFLAGS\) -c -o ${l} ${s}\n"); } print(OUT "\n"); print(OUT "\n"); @@ -274,12 +278,18 @@ if (param_get("examples")) { $libs = $examples_libs{$l}; } - print(OUT -"${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" - ); + if (param_get("shared")) { + print(OUT + "${l}: ${s}${object_suffix} src/${library_prefix}Mw${library_suffix}\n" + ); + } else { + print(OUT + "${l}: ${s}${object_suffix} src/${library_prefix}Mw.a\n" + ); + } if (grep(/^cocoa$/, @backends)) { print(OUT -" \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" +" \$(CC) -L./src -I\$\(INCDIR\) \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); } else { @@ -287,10 +297,23 @@ if (param_get("examples")) { " \$(CC) -L src -Wl,-R./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); } + + if($target eq "ClassicMacOS") { + print(OUT +" ".$ENV{RETRO68_TOOLCHAIN_PATH}."/bin/MakePEF ${l} -o ${s}.pef\n"); + print(OUT +" Rez -I ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes/Retro68APPL.r -DCFRAG_NAME=\"example\" --data ${l}.pef --cc ${l}.dsk -t APPL\n" + ); + print(OUT "${s}${object_suffix}: ${s}.c\n"); print(OUT " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" ); + + + #print(OUT "Rez -I /path/to/Universal/RIncludes /path/to/libretro/RIncludes/Retro68APPL.r -DCFRAG_NAME="\"MyProgram\"" --data program.pef -o program.bin -t APPL"); + } + } } print(OUT "\n"); diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h new file mode 100644 index 000000000..01654387f --- /dev/null +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -0,0 +1,27 @@ +/*! + * @file Mw/LowLevel/ClassicMacOS.h + * @brief ClassicMacOS Backend + * @warning This is used internally + */ +#ifndef __MW_LOWLEVEL_ClassicMacOS_H__ +#define __MW_LOWLEVEL_ClassicMacOS_H__ + +#include +#include +#include + +struct _MwLLClassicMacOS { + struct _MwLLCommon common; +}; + +struct _MwLLClassicMacOSColor { + struct _MwLLCommonColor common; +}; + +struct _MwLLClassicMacOSPixmap { + struct _MwLLCommonPixmap common; +}; + +MWDECL int MwLLClassicMacOSCallInit(void); + +#endif diff --git a/include/Mw/MachDep.h b/include/Mw/MachDep.h index 025fc29b4..10a1a04b6 100644 --- a/include/Mw/MachDep.h +++ b/include/Mw/MachDep.h @@ -37,17 +37,28 @@ #define GET_WHEEL_DELTA_WPARAM(x) ((short)HIWORD(x)) #endif #endif - +#elif defined(CLASSIC_MAC_OS) +#include +#include +#include +#include +#include +#include +#include +#include #else #include #include -#include #include -#include #include #include #endif +#ifdef __unix__ +#include +#include +#endif + #ifdef __APPLE__ #include #include diff --git a/pl/ostype/ClassicMacOS68k.pl b/pl/ostype/ClassicMacOS68k.pl new file mode 100644 index 000000000..c9ceba8c6 --- /dev/null +++ b/pl/ostype/ClassicMacOS68k.pl @@ -0,0 +1,7 @@ +use_backend("classicmacos"); + +$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/m68k-apple-macos-gcc"; +$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/m68k-apple-macos-ar"; +add_cflags("-DCLASSIC_MAC_OS"); + +1; diff --git a/pl/ostype/ClassicMacOSPPC.pl b/pl/ostype/ClassicMacOSPPC.pl new file mode 100644 index 000000000..b2626d968 --- /dev/null +++ b/pl/ostype/ClassicMacOSPPC.pl @@ -0,0 +1,7 @@ +use_backend("classicmacos"); + +$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-gcc"; +$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-ar"; +add_cflags("-DCLASSIC_MAC_OS"); + +1; diff --git a/pl/rules.pl b/pl/rules.pl index 2b222249b..4d68cb94d 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -30,6 +30,13 @@ if (grep(/^gdi$/, @backends)) { $gl_libs = "-lopengl32 -lglu32"; } +if (grep(/^classicmacos$/, @backends)) { + #add_cflags("-DCLASSIC_MAC_OS"); + new_object("src/backend/classicmacos.c"); + + $gl_libs = ""; +} + if (grep(/^wayland$/, @backends)) { add_cflags("-DUSE_WAYLAND"); new_object("src/backend/wayland.c"); diff --git a/src/abstract/directory.c b/src/abstract/directory.c index aa516cf44..ac5a382d1 100644 --- a/src/abstract/directory.c +++ b/src/abstract/directory.c @@ -6,6 +6,10 @@ typedef struct dir { WIN32_FIND_DATA ffd; int next; } dir_t; +#elif defined(CLASSIC_MAC_OS) +typedef struct dir { + int dummy; +} dir_t; #else typedef struct dir { DIR* dir; @@ -31,6 +35,8 @@ void* MwDirectoryOpen(const char* path) { } free(p); dir->next = 1; +#elif defined(CLASSIC_MAC_OS) +/* todo */ #else if((dir->dir = opendir(path)) == NULL) { free(dir); @@ -47,6 +53,8 @@ void MwDirectoryClose(void* handle) { dir_t* dir = handle; #ifdef _WIN32 FindClose(dir->hFind); +#elif defined(CLASSIC_MAC_OS) +/* todo */ #else closedir(dir->dir); free(dir->base); @@ -80,6 +88,8 @@ MwDirectoryEntry* MwDirectoryRead(void* handle) { entry->mtime = l->QuadPart / 10000000 - 11644473600; dir->next = FindNextFile(dir->hFind, &dir->ffd); +#elif defined(CLASSIC_MAC_OS) +/* todo */ #else struct dirent* d; struct stat s; @@ -123,6 +133,8 @@ char* MwDirectoryCurrent(void) { GetCurrentDirectory(len, out); return out; +#elif CLASSIC_MAC_OS + return ""; #else return getcwd(NULL, 0); #endif diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index 79cad83fc..d9558af6d 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -12,6 +12,36 @@ void* MwDynamicSymbol(void* handle, const char* symbol) { void MwDynamicClose(void* handle) { FreeLibrary(handle); } +#elif defined(CLASSIC_MAC_OS) +void* MwDynamicOpen(const char* path) { + CFragConnectionID connID; + Ptr* addr; + unsigned char err[255]; + + if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, + &connID, addr, err)) { + printf("Error getting %s: %s\n", path, err); + return NULL; + }; + return connID; +} + +void* MwDynamicSymbol(void* handle, const char* symbol) { + CFragConnectionID connID = (CFragConnectionID)handle; + Ptr* symAddr; + CFragSymbolClass* symClass; + OSErr err; + if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { + printf("Error getting %s: %d\n", symbol, err); + return NULL; + }; + return symAddr; +} + +void MwDynamicClose(void* handle) { + CFragConnectionID connID = (CFragConnectionID)handle; + CloseConnection(&connID); +} #elif defined(__unix__) || defined(__APPLE__) void* MwDynamicOpen(const char* path) { return dlopen(path, RTLD_LOCAL | RTLD_LAZY); diff --git a/src/abstract/time.c b/src/abstract/time.c index 1050c46d3..52d998689 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -32,6 +32,27 @@ void MwTimeSleep(int ms) { nanosleep(&ts, NULL); } +#elif defined(CLASSIC_MAC_OS) +static TMTask tm; +static int timer; +void timerUpdateFunc(void) { + timer += 1; + PrimeTime((QElemPtr)&tm, 1); +}; + +long MwTimeGetTick(void) { + UnsignedWide h; + Microseconds(&h); + return *(long*)&h; +} +void MwTimeSleep(int ms) { + tm.tmAddr = NewTimerProc(timerUpdateFunc); + tm.tmWakeUp = 0; + tm.tmReserved = 0; + + InsTime((QElemPtr)&tm); + PrimeTime((QElemPtr)&tm, 1); +} #elif defined(__unix__) long MwTimeGetTick(void) { struct timespec ts; diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c new file mode 100644 index 000000000..01a9d9735 --- /dev/null +++ b/src/backend/classicmacos.c @@ -0,0 +1,167 @@ +#include + +#include "../../external/stb_ds.h" + +static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { + MwLL r; + + return r; +} + +static void MwLLDestroyImpl(MwLL handle) { + MwLLDestroyCommon(handle); + + free(handle); +} + +static void MwLLBeginDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLEndDrawImpl(MwLL handle) { + (void)handle; +} + +static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { + int i; +} + +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)); + MwLLColorUpdate(handle, c, r, g, b); + return c; +} + +static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { + c->common.red = r; + c->common.green = g; + c->common.blue = b; +} + +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) { + free(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.raw = malloc(4 * width * height); + memcpy(r->common.raw, data, 4 * width * height); + + MwLLPixmapUpdate(r); + return r; +} + +static void MwLLPixmapUpdateImpl(MwLLPixmap r) { +} + +static void MwLLDestroyPixmapImpl(MwLLPixmap 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) { + /* TODO */ + + (void)handle; + (void)text; +} + +static void MwLLGetClipboardImpl(MwLL handle) { +} + +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 void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { + (void)handle; + (void)toggle; +} + +static int MwLLClassicMacOSCallInitImpl(void) { + InitGraf(&qd.thePort); + InitFonts(); + FlushEvents(everyEvent, 0); + InitWindows(); + InitMenus(); + TEInit(); + InitDialogs(0L); + InitCursor(); + + return 0; +} + +#include "call.c" +CALL(ClassicMacOS); diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index cd23faaa4..d5faa4bad 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -53,7 +53,7 @@ static void destroy(MwWidget handle) { MwDestroyWidget(handle); } -static void cancel(MwWidget handle, void* user, void* call) { +static void filecancel(MwWidget handle, void* user, void* call) { (void)user; (void)call; @@ -147,7 +147,7 @@ static void nav_activate(MwWidget handle, void* user, void* call) { (void)user; if(strcmp(e, "Home") == 0) { -#ifdef _WIN32 +#if defined(_WIN32) || defined(CLASSIC_MAC_OS) #else struct passwd* p = getpwuid(getuid()); diff --git a/src/widget/box.c b/src/widget/box.c index a87000f0e..e96c00874 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -2,7 +2,7 @@ #include "../../external/stb_ds.h" -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwBox b = malloc(sizeof(*b)); memset(b, 0, sizeof(*b)); diff --git a/src/widget/button.c b/src/widget/button.c index c5f3a4b9f..6653b54ed 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -2,7 +2,7 @@ #include "../../external/stb_ds.h" -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNflat, 0); diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 1ccccd416..56b8f11ae 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNchecked, 0); diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 22a90060f..988bb24aa 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -2,7 +2,7 @@ #include "../../external/stb_ds.h" -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwComboBox cb = malloc(sizeof(*cb)); cb->list = NULL; diff --git a/src/widget/entry.c b/src/widget/entry.c index bd7dbe1b5..eca5e5ce4 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwEntry t = malloc(sizeof(*t)); t->cursor = 0; diff --git a/src/widget/frame.c b/src/widget/frame.c index 117b0f8b9..6f9d88129 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNhasBorder, 0); diff --git a/src/widget/image.c b/src/widget/image.c index 74ee0bfd6..90f3cbe7a 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNhasBorder, 0); diff --git a/src/widget/label.c b/src/widget/label.c index d29977caf..3c88eb921 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -4,7 +4,7 @@ #define Spacing 1 -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwLabel lab = malloc(sizeof(*lab)); lab->segment = NULL; diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 9960e1d67..7f4ef0b7d 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -347,7 +347,7 @@ static void resize(MwWidget handle) { NULL); } -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwListBox lb = malloc(sizeof(*lb)); memset(lb, 0, sizeof(*lb)); diff --git a/src/widget/menu.c b/src/widget/menu.c index 0808f691d..b36527885 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -18,7 +18,7 @@ static void set_xywh(MwWidget handle) { NULL); } -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwMenu m = malloc(sizeof(*m)); m->name = NULL; diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 7c317d36b..96860f84e 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { int st; MwEntry e; diff --git a/src/widget/opengl.c b/src/widget/opengl.c index d75b358f7..582db0cbd 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -101,7 +101,7 @@ typedef struct waylandopengl { } waylandopengl_t; #endif -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { void* r = NULL; MwWidget w = handle; diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index 2397a8473..27c21588a 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -20,7 +20,7 @@ @end -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { void* r = NULL; MwWidget w = handle; @@ -128,4 +128,4 @@ MwClassRec MwOpenGLClassRec = {create, /* create */ NULL, /* children_prop_change */ NULL, /* clipboard */ NULL, NULL, NULL, NULL}; -MwClass MwOpenGLClass = &MwOpenGLClassRec; \ No newline at end of file +MwClass MwOpenGLClass = &MwOpenGLClassRec; diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index d85a8ddaf..2a032b09d 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwVaApply(handle, MwNminValue, 0, diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index 3229faad3..2416b71d9 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -2,7 +2,7 @@ #include "../../external/stb_ds.h" -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNchecked, 0); diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index bb75939c1..e11ba6ac4 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwScrollBar scr = malloc(sizeof(*scr)); handle->internal = scr; @@ -58,9 +58,9 @@ static void draw(MwWidget handle) { MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); MwScrollBar scr = handle->internal; - int or ; - int uy, dy, ux, dx; - MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + int or; + int uy, dy, ux, dx; + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); r.x = 0; r.y = 0; diff --git a/src/widget/separator.c b/src/widget/separator.c index 8fcfc5b71..d7d6aae20 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNorientation, MwHORIZONTAL); diff --git a/src/widget/submenu.c b/src/widget/submenu.c index 4990fd211..a71d65b08 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -2,7 +2,7 @@ #include "../../external/stb_ds.h" -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwLLBeginStateChange(handle->lowlevel); MwSetDefault(handle); diff --git a/src/widget/treeview.c b/src/widget/treeview.c index acc35bf69..bd3067c4c 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -297,7 +297,7 @@ static void resize(MwWidget handle) { NULL); } -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwTreeView tv = malloc(sizeof(*tv)); memset(tv, 0, sizeof(*tv)); diff --git a/src/widget/viewport.c b/src/widget/viewport.c index de71af790..38ef89948 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -74,7 +74,7 @@ static void resize(MwWidget handle) { NULL); } -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwViewport vp = malloc(sizeof(*vp)); memset(vp, 0, sizeof(*vp)); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 8d4aa3daa..ab73fcafc 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -116,7 +116,7 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o); static int vulkan_surface_setup(MwWidget handle, vulkan_t* o); static int vulkan_devices_setup(MwWidget handle, vulkan_t* o); -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { vulkan_t* o = malloc(sizeof(*o)); int err; diff --git a/src/widget/window.c b/src/widget/window.c index 979e073c8..b4aaa8d22 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -1,6 +1,6 @@ #include -static int create(MwWidget handle) { +static int wcreate(MwWidget handle) { MwSetDefault(handle); MwSetInteger(handle, MwNhasBorder, 0); From 47fe57b31ccb2629c28e7b04ac673cef17520435 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 20:25:08 -0700 Subject: [PATCH 383/409] ok --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5751b3d18..1f3ee9e53 100755 --- a/configure +++ b/configure @@ -260,7 +260,7 @@ foreach my $l (@library_targets) { } print(OUT "${l}: ${s}\n"); - print(OUT " \$(CC) $warn \$\(INCDIR\) \$(CFLAGS\) -c -o ${l} ${s}\n"); + print(OUT " \$(CC) $warn \$\(INCDIR) \$(CFLAGS\) -c -o ${l} ${s}\n"); } print(OUT "\n"); print(OUT "\n"); @@ -289,7 +289,7 @@ if (param_get("examples")) { } if (grep(/^cocoa$/, @backends)) { print(OUT -" \$(CC) -L./src -I\$\(INCDIR\) \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" +" \$(CC) -L./src -I\$\(INCDIR) \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); } else { From f8a94b73805c6a93aab7d1f8e9a6ad2f47de805b Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 21:41:16 -0700 Subject: [PATCH 384/409] cmake --- .gitignore | 1 + CMakeLists.txt | 252 ++++++++++++++++------------- configure | 19 +-- examples/basic/CMakeLists.txt | 38 +++-- include/Mw/LowLevel.h | 6 + include/Mw/LowLevel/ClassicMacOS.h | 4 + pl/ostype/ClassicMacOS.pl | 10 ++ pl/ostype/ClassicMacOS68k.pl | 7 - pl/ostype/ClassicMacOSPPC.pl | 7 - src/backend/classicmacos.c | 12 +- src/dialog/filechooser.c | 2 +- src/widget/box.c | 2 +- src/widget/button.c | 2 +- src/widget/checkbox.c | 2 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 2 +- src/widget/frame.c | 2 +- src/widget/image.c | 2 +- src/widget/label.c | 2 +- src/widget/listbox.c | 2 +- src/widget/menu.c | 2 +- src/widget/numberentry.c | 2 +- src/widget/progressbar.c | 2 +- src/widget/radiobox.c | 2 +- src/widget/scrollbar.c | 2 +- src/widget/separator.c | 2 +- src/widget/submenu.c | 2 +- src/widget/treeview.c | 2 +- src/widget/viewport.c | 2 +- src/widget/vulkan.c | 2 +- src/widget/window.c | 2 +- 31 files changed, 219 insertions(+), 179 deletions(-) create mode 100644 pl/ostype/ClassicMacOS.pl delete mode 100644 pl/ostype/ClassicMacOS68k.pl delete mode 100644 pl/ostype/ClassicMacOSPPC.pl diff --git a/.gitignore b/.gitignore index 21058b8b1..8535b6514 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ compile_flags.txt *.bin *.rsrc *.finf +*.gdb diff --git a/CMakeLists.txt b/CMakeLists.txt index 0cc795308..835ecdd26 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,24 +9,34 @@ include(GNUInstallDirs) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" ON) -option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" ON) + option(MW_CLASSIC_THEME "Use classic theme" OFF) option(MW_BUILD_EXAMPLES "Build examples" OFF) option(MW_USE_STB_IMAGE "Use stb_image" ON) option(MW_USE_STB_TRUETYPE "Use stb_truetype" OFF) -option(MW_BUILD_SHARED "Build a shared library" ON) -option(MW_BUILD_STATIC "Build a static library" OFF) + +if(${CMAKE_SYSTEM_NAME} MATCHES Retro) + option(MW_BUILD_SHARED "Build a shared library" OFF) + option(MW_BUILD_STATIC "Build a static library" ON) + option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" OFF) + option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" OFF) +else() + option(MW_BUILD_SHARED "Build a shared library" ON) + option(MW_BUILD_STATIC "Build a static library" OFF) + option(MW_TRY_OPENGL "Try to compile OpenGL widget or not" ON) + option(MW_TRY_VULKAN "Try to compile Vulkan widget or not" ON) +endif() + option(MW_INSTALL_HEADERS "Install headers" ON) -if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) - option(MW_USE_FREETYPE2 "Use FreeType 2" OFF) +if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin OR ${CMAKE_SYSTEM_NAME} MATCHES Retro) + option(MW_USE_FREETYPE2 "Use FreeType 2" OFF) else() - option(MW_USE_FREETYPE2 "Use FreeType 2" ON) + option(MW_USE_FREETYPE2 "Use FreeType 2" ON) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL Linux) - option(MW_USE_WAYLAND "Enable Wayland backend" ON) + option(MW_USE_WAYLAND "Enable Wayland backend" ON) endif() file( @@ -39,83 +49,83 @@ list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") if(NOT MW_USE_STB_IMAGE) - list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c") + list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c") endif() if(NOT MW_USE_STB_TRUETYPE) - list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_truetype.c") + list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_truetype.c") endif() if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD") - list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/X11R7/include") - list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/pkg/include") + list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/X11R7/include") + list(APPEND CMAKE_REQUIRED_INCLUDES "/usr/pkg/include") endif() if(MW_TRY_OPENGL) - find_package(OpenGL) - if(OpenGL_FOUND) - set(MW_BUILD_OPENGL ON) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") - if(APPLE) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") - endif() - message(STATUS "OpenGL widget has been enabled") - else() - message(WARNING "OpenGL widget has been disabled") + find_package(OpenGL) + if(OpenGL_FOUND) + set(MW_BUILD_OPENGL ON) + list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") + if(APPLE) + list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") endif() + message(STATUS "OpenGL widget has been enabled") + else() + message(WARNING "OpenGL widget has been disabled") + endif() endif() if(MW_TRY_VULKAN) - check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) - if(HAVE_VULKAN_VULKAN_H) - set(MW_BUILD_VULKAN ON) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") - target_compile_definitions( + check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) + if(HAVE_VULKAN_VULKAN_H) + set(MW_BUILD_VULKAN ON) + list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") + target_compile_definitions( Mw PRIVATE MW_VULKAN ) - message(STATUS "Vulkan widget has been enabled") - else() - message(WARNING "Vulkan widget has been disabled") - endif() + message(STATUS "Vulkan widget has been enabled") + else() + message(WARNING "Vulkan widget has been disabled") + endif() endif() if(MW_BUILD_STATIC) - message(STATUS "Building Milsko as a static library") - add_library( + message(STATUS "Building Milsko as a static library") + add_library( Mw ${SOURCES} ) elseif(MW_BUILD_SHARED) - message(STATUS "Building Milsko as a shared library") - add_library( + message(STATUS "Building Milsko as a shared library") + add_library( Mw SHARED ${SOURCES} ) else() - message(ERROR "Must either build a shared library or a static library") + message(ERROR "Must either build a shared library or a static library") endif() if(MW_USE_STB_IMAGE) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_STB_IMAGE ) else() - file( + file( GLOB IMAGE_SOURCES external/libjpeg/src/*.c external/libpng/src/*.c ) - target_sources( + target_sources( Mw PRIVATE ${MW_IMAGE_SOURCES} ) - target_include_directories( + target_include_directories( Mw PRIVATE external/libjpeg/include external/libpng/include @@ -123,7 +133,7 @@ else() endif() if(MW_USE_STB_TRUETYPE) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_STB_TRUETYPE @@ -131,22 +141,22 @@ if(MW_USE_STB_TRUETYPE) endif() if(MW_USE_FREETYPE2) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_FREETYPE2 ) - find_package(PkgConfig) - pkg_check_modules(FT2 REQUIRED freetype2) - list(APPEND INCLUDE_DIRS ${FT2_INCLUDE_DIRS}) - list(APPEND LIBRARY_DIRS ${FT2_LIBRARY_DIRS}) - list(APPEND LIBRARIES ${FT2_LIBRARIES}) + find_package(PkgConfig) + pkg_check_modules(FT2 REQUIRED freetype2) + list(APPEND INCLUDE_DIRS ${FT2_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${FT2_LIBRARY_DIRS}) + list(APPEND LIBRARIES ${FT2_LIBRARIES}) endif() if(MW_USE_WAYLAND) - function(scan_wayland_protocol_core) - execute_process( + function(scan_wayland_protocol_core) + execute_process( COMMAND wayland-scanner private-code /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT ERROR_VARIABLE WAYLAND_SCANNER_ERROR @@ -154,12 +164,12 @@ if(MW_USE_WAYLAND) ECHO_ERROR_VARIABLE COMMAND_ECHO STDOUT ) - target_sources( + target_sources( Mw PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-core-protocol.c ) - execute_process( + execute_process( COMMAND wayland-scanner client-header /usr/share/wayland/wayland.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/wayland-core-protocol.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT @@ -168,11 +178,11 @@ if(MW_USE_WAYLAND) ECHO_ERROR_VARIABLE COMMAND_ECHO STDOUT ) - endfunction() + endfunction() - function(scan_wayland_protocol tier proto ver) - SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-${proto}-protocol.c) - execute_process( + function(scan_wayland_protocol tier proto ver) + SET(proto_c ${CMAKE_CURRENT_SOURCE_DIR}/src/backend/wayland-${proto}-protocol.c) + execute_process( COMMAND wayland-scanner private-code /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${proto_c} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT @@ -181,12 +191,12 @@ if(MW_USE_WAYLAND) ECHO_ERROR_VARIABLE COMMAND_ECHO STDOUT ) - target_sources( + target_sources( Mw PRIVATE ${proto_c} ) - execute_process( + execute_process( COMMAND wayland-scanner client-header /usr/share/wayland-protocols/${tier}/${proto}/${proto}${ver}.xml ${CMAKE_CURRENT_SOURCE_DIR}/include/Mw/LowLevel/Wayland/${proto}-client-protocol.h WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} OUTPUT_VARIABLE WAYLAND_SCANNER_OUTPUT @@ -195,49 +205,49 @@ if(MW_USE_WAYLAND) ECHO_ERROR_VARIABLE COMMAND_ECHO STDOUT ) - endfunction() + endfunction() - check_include_files(wayland-client.h HAVE_WL_H) - check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H) - check_include_files(cairo/cairo.h HAVE_CAIRO_H) - if(HAVE_WL_H) - if(HAVE_XKBCOMMON_H) - if(HAVE_CAIRO_H) - scan_wayland_protocol_core() - scan_wayland_protocol("stable" "xdg-shell" "") - scan_wayland_protocol("stable" "viewporter" "") - scan_wayland_protocol("stable" "tablet" "-v2") - scan_wayland_protocol("staging" "xdg-toplevel-icon" "-v1") - scan_wayland_protocol("staging" "cursor-shape" "-v1") - scan_wayland_protocol("unstable" "xdg-decoration" "-unstable-v1") - scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") - scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") - scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") + check_include_files(wayland-client.h HAVE_WL_H) + check_include_files(xkbcommon/xkbcommon.h HAVE_XKBCOMMON_H) + check_include_files(cairo/cairo.h HAVE_CAIRO_H) + if(HAVE_WL_H) + if(HAVE_XKBCOMMON_H) + if(HAVE_CAIRO_H) + scan_wayland_protocol_core() + scan_wayland_protocol("stable" "xdg-shell" "") + scan_wayland_protocol("stable" "viewporter" "") + scan_wayland_protocol("stable" "tablet" "-v2") + scan_wayland_protocol("staging" "xdg-toplevel-icon" "-v1") + scan_wayland_protocol("staging" "cursor-shape" "-v1") + scan_wayland_protocol("unstable" "xdg-decoration" "-unstable-v1") + scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") + scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") + scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") - target_sources( + target_sources( Mw PRIVATE src/backend/wayland.c ) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_WAYLAND ) - message(STATUS "Wayland backend has been enabled") - else() - message(WARNING "Wayland backend has been disabled") - endif() - else() - message(WARNING "Wayland backend has been disabled") - endif() - else() + message(STATUS "Wayland backend has been enabled") + else() message(WARNING "Wayland backend has been disabled") + endif() + else() + message(WARNING "Wayland backend has been disabled") endif() + else() + message(WARNING "Wayland backend has been disabled") + endif() endif() if(APPLE AND MW_BUILD_OPENGL) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE GL_SILENCE_DEPRECATION @@ -257,7 +267,7 @@ target_include_directories( ) if(MW_CLASSIC_THEME) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_CLASSIC_THEME @@ -265,60 +275,78 @@ if(MW_CLASSIC_THEME) endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_sources( + target_sources( Mw PRIVATE src/backend/gdi.c ) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_GDI ) - list(APPEND LIBRARIES gdi32) - target_link_options( + list(APPEND LIBRARIES gdi32) + target_link_options( Mw PRIVATE -static-libgcc ) elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - target_sources( + target_sources( Mw PRIVATE src/backend/cocoa.m ) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_COCOA ) - list(APPEND LIBRARIES objc) - target_link_options( + list(APPEND LIBRARIES objc) + target_link_options( Mw PRIVATE -framework Cocoa ) -else() - find_package(PkgConfig) - pkg_check_modules(X11 REQUIRED x11) - pkg_check_modules(XRENDER REQUIRED xrender) +elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") + target_sources( + Mw + PRIVATE + src/backend/classicmacos.c + ) + if(PLATFORM MATCHES retroppc) + endif() + if(PLATFORM MATCHES retroppc) + set_target_properties(Mw PROPERTIES COMPILE_FLAGS "-ffunction-sections -mcpu=601 -Os -Wall -Wextra -Wno-unused-parameter") + set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections") + endif() - target_sources( + target_compile_definitions( + Mw + PRIVATE + CLASSIC_MAC_OS + ) +else() + find_package(PkgConfig) + pkg_check_modules(X11 REQUIRED x11) + pkg_check_modules(XRENDER REQUIRED xrender) + + target_sources( Mw PRIVATE src/backend/x11.c ) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE USE_X11 ) - list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS} ${XRENDER_INCLUDE_DIRS}) - list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS} ${XRENDER_LIBRARY_DIRS}) - list(APPEND LIBRARIES ${X11_LIBRARIES} ${XRENDER_LIBRARIES} m) - if(CMAKE_SYSTEM_NAME STREQUAL "Linux") - list(APPEND LIBRARIES dl) - endif() + list(APPEND INCLUDE_DIRS ${X11_INCLUDE_DIRS} ${XRENDER_INCLUDE_DIRS}) + list(APPEND LIBRARY_DIRS ${X11_LIBRARY_DIRS} ${XRENDER_LIBRARY_DIRS}) + list(APPEND LIBRARIES ${X11_LIBRARIES} ${XRENDER_LIBRARIES} m) + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND LIBRARIES dl) + endif() endif() target_include_directories( @@ -338,14 +366,14 @@ target_link_libraries( ) if(MW_BUILD_VULKAN) - check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER) - if(HAS_VK_ENUM_STRING_HELPER) - target_compile_definitions( + check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER) + if(HAS_VK_ENUM_STRING_HELPER) + target_compile_definitions( Mw PRIVATE HAS_VK_ENUM_STRING_HELPER ) - endif() + endif() endif() target_compile_definitions( @@ -362,7 +390,7 @@ install( ) if(MW_INSTALL_HEADERS) - install( + install( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" @@ -370,5 +398,5 @@ if(MW_INSTALL_HEADERS) endif() if(MW_BUILD_EXAMPLES) - add_subdirectory(examples) + add_subdirectory(examples) endif() diff --git a/configure b/configure index 1f3ee9e53..a6e5941cf 100755 --- a/configure +++ b/configure @@ -46,6 +46,7 @@ param_set("shared", 1); param_set("static", 1); param_set("examples", 1); + my %features = ( "classic-theme" => "use classic theme", "stb-image" => "use stb_image, instead use libjpeg/libpng", @@ -131,16 +132,12 @@ foreach my $l (@ARGV) { } } -if($target ne "Darwin" and $target ne "ClassicMacOS68k" and $target ne "ClassicMacOSPPC") { +if($target ne "Darwin" and $target ne "ClassicMacOS") { param_set("freetype2", 1); param_set("stb-truetype", 0); } else { - if($target ne "ClassicMacOS68k" and $target ne "ClassicMacOSPPC"){ - param_set("freetype2", 0); - param_set("stb-truetype", 1); - } else { - param_set("stb-truetype", 0); - } + param_set("freetype2", 0); + param_set("stb-truetype", 0); } if($target eq "Linux") { @@ -289,7 +286,7 @@ if (param_get("examples")) { } if (grep(/^cocoa$/, @backends)) { print(OUT -" \$(CC) -L./src -I\$\(INCDIR) \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" +" \$(CC) -L./src \$\(LIBDIR) -o ${l} ${s}${object_suffix} -lMw ${math} ${libs}\n" ); } else { @@ -304,16 +301,12 @@ if (param_get("examples")) { print(OUT " Rez -I ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes ".$ENV{RETRO68_TOOLCHAIN_PATH}."/RIncludes/Retro68APPL.r -DCFRAG_NAME=\"example\" --data ${l}.pef --cc ${l}.dsk -t APPL\n" ); + } print(OUT "${s}${object_suffix}: ${s}.c\n"); print(OUT " \$(CC) -c \$\(INCDIR) -o ${s}${object_suffix} ${s}.c -lMw ${math}\n" ); - - - #print(OUT "Rez -I /path/to/Universal/RIncludes /path/to/libretro/RIncludes/Retro68APPL.r -DCFRAG_NAME="\"MyProgram\"" --data program.pef -o program.bin -t APPL"); - } - } } print(OUT "\n"); diff --git a/examples/basic/CMakeLists.txt b/examples/basic/CMakeLists.txt index ab58a5c1a..e69c4ae55 100644 --- a/examples/basic/CMakeLists.txt +++ b/examples/basic/CMakeLists.txt @@ -1,22 +1,26 @@ file( - GLOB - EXAMPLES_BASIC_SOURCES - *.c + GLOB + EXAMPLES_BASIC_SOURCES + *.c ) foreach(PATH IN LISTS EXAMPLES_BASIC_SOURCES) - get_filename_component(TARGET ${PATH} NAME_WE) - add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) - target_link_libraries( - ${TARGET} - PRIVATE - Mw - ) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") - target_link_libraries( - ${TARGET} - PRIVATE - m - ) - endif() + get_filename_component(TARGET ${PATH} NAME_WE) + if(CMAKE_SYSTEM_NAME MATCHES Retro) + add_application(${TARGET} ${PATH}) + else() + add_executable(${TARGET} MACOSX_BUNDLE ${PATH}) + endif() + target_link_libraries( + ${TARGET} + PRIVATE + Mw + ) + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + target_link_libraries( + ${TARGET} + PRIVATE + m + ) + endif() endforeach() diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index a1a469188..2a293b02a 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -106,6 +106,9 @@ MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); #ifdef USE_COCOA #include #endif +#ifdef CLASSIC_MAC_OS +#include +#endif union _MwLL { struct _MwLLCommon common; @@ -121,6 +124,9 @@ union _MwLL { #ifdef USE_COCOA struct _MwLLCocoa cocoa; #endif +#ifdef CLASSIC_MAC_OS + struct _MwLLClassicMacOS cmacos; +#endif }; union _MwLLColor { diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h index 01654387f..f377e4f91 100644 --- a/include/Mw/LowLevel/ClassicMacOS.h +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -12,6 +12,10 @@ struct _MwLLClassicMacOS { struct _MwLLCommon common; + + WindowRef window; + EventRecord event; + Rect winRect; }; struct _MwLLClassicMacOSColor { diff --git a/pl/ostype/ClassicMacOS.pl b/pl/ostype/ClassicMacOS.pl new file mode 100644 index 000000000..751525f7a --- /dev/null +++ b/pl/ostype/ClassicMacOS.pl @@ -0,0 +1,10 @@ +use_backend("classicmacos"); + +print("Compiling for Classic Mac OS via ./configure currently outputs a broken executable and it only supports PowerPC. Help is wanted. In the mean time, use CMake.") + +$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-gcc"; +$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-ar"; +add_cflags("-DCLASSIC_MAC_OS"); +add_cflags("-DSTBI_NO_THREAD_LOCALS"); + +1; diff --git a/pl/ostype/ClassicMacOS68k.pl b/pl/ostype/ClassicMacOS68k.pl deleted file mode 100644 index c9ceba8c6..000000000 --- a/pl/ostype/ClassicMacOS68k.pl +++ /dev/null @@ -1,7 +0,0 @@ -use_backend("classicmacos"); - -$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/m68k-apple-macos-gcc"; -$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/m68k-apple-macos-ar"; -add_cflags("-DCLASSIC_MAC_OS"); - -1; diff --git a/pl/ostype/ClassicMacOSPPC.pl b/pl/ostype/ClassicMacOSPPC.pl deleted file mode 100644 index b2626d968..000000000 --- a/pl/ostype/ClassicMacOSPPC.pl +++ /dev/null @@ -1,7 +0,0 @@ -use_backend("classicmacos"); - -$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-gcc"; -$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-ar"; -add_cflags("-DCLASSIC_MAC_OS"); - -1; diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 01a9d9735..929c4930f 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -5,6 +5,15 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; + MwLLCreateCommon(r); + + SetRect(&r->cmacos.winRect, 100, 100, width, height); + + r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, + documentProc, (WindowPtr)(-1), true, 0); + + SetPort(r->cmacos.window); + return r; } @@ -59,8 +68,7 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - - return 0; + return GetNextEvent(everyEvent, &handle->cmacos.event); } static void MwLLNextEventImpl(MwLL handle) { diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index d5faa4bad..c18027677 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -383,7 +383,7 @@ static void layout(MwWidget handle) { MwNtext, "Cancel", NULL); - MwAddUserHandler(fc->cancel, MwNactivateHandler, cancel, NULL); + MwAddUserHandler(fc->cancel, MwNactivateHandler, filecancel, NULL); } else { MwVaApply(fc->cancel, MwNx, wx, diff --git a/src/widget/box.c b/src/widget/box.c index e96c00874..6fb893550 100644 --- a/src/widget/box.c +++ b/src/widget/box.c @@ -135,7 +135,7 @@ static void children_update(MwWidget handle) { } MwClassRec MwBoxClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/button.c b/src/widget/button.c index 6653b54ed..7287f2a4e 100644 --- a/src/widget/button.c +++ b/src/widget/button.c @@ -93,7 +93,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwButtonClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ click, /* click */ diff --git a/src/widget/checkbox.c b/src/widget/checkbox.c index 56b8f11ae..2301aa0ff 100644 --- a/src/widget/checkbox.c +++ b/src/widget/checkbox.c @@ -38,7 +38,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwCheckBoxClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ click, /* click */ diff --git a/src/widget/combobox.c b/src/widget/combobox.c index 988bb24aa..c061512d7 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -189,7 +189,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwComboBoxClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ click, /* click */ diff --git a/src/widget/entry.c b/src/widget/entry.c index eca5e5ce4..4d1cc7364 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -172,7 +172,7 @@ static void clipboard(MwWidget handle, const char* data) { } MwClassRec MwEntryClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/frame.c b/src/widget/frame.c index 6f9d88129..0cc0c4163 100644 --- a/src/widget/frame.c +++ b/src/widget/frame.c @@ -46,7 +46,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwFrameClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/image.c b/src/widget/image.c index 90f3cbe7a..791570ecb 100644 --- a/src/widget/image.c +++ b/src/widget/image.c @@ -42,7 +42,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwImageClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/label.c b/src/widget/label.c index 3c88eb921..98a0d5fef 100644 --- a/src/widget/label.c +++ b/src/widget/label.c @@ -360,7 +360,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwLabelClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 7f4ef0b7d..98c86cf97 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -595,7 +595,7 @@ static void tick(MwWidget handle) { } MwClassRec MwListBoxClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/menu.c b/src/widget/menu.c index b36527885..b66108652 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -189,7 +189,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwMenuClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 96860f84e..05d590f5c 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -128,7 +128,7 @@ static void prop_change(MwWidget handle, const char* prop) { } MwClassRec MwNumberEntryClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/progressbar.c b/src/widget/progressbar.c index 2a032b09d..dedd7a911 100644 --- a/src/widget/progressbar.c +++ b/src/widget/progressbar.c @@ -46,7 +46,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwProgressBarClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/radiobox.c b/src/widget/radiobox.c index 2416b71d9..1342232e5 100644 --- a/src/widget/radiobox.c +++ b/src/widget/radiobox.c @@ -47,7 +47,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwRadioBoxClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ click, /* click */ diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index e11ba6ac4..a1df9b2db 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -257,7 +257,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwScrollBarClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/separator.c b/src/widget/separator.c index d7d6aae20..15919d0ed 100644 --- a/src/widget/separator.c +++ b/src/widget/separator.c @@ -35,7 +35,7 @@ static void prop_change(MwWidget handle, const char* key) { } MwClassRec MwSeparatorClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/submenu.c b/src/widget/submenu.c index a71d65b08..f14d6d5f4 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -241,7 +241,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwSubMenuClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ click, /* click */ diff --git a/src/widget/treeview.c b/src/widget/treeview.c index bd3067c4c..9d3320699 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -481,7 +481,7 @@ static void tick(MwWidget handle) { } MwClassRec MwTreeViewClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/viewport.c b/src/widget/viewport.c index 38ef89948..f05b18d5b 100644 --- a/src/widget/viewport.c +++ b/src/widget/viewport.c @@ -176,7 +176,7 @@ static void tick(MwWidget handle) { } MwClassRec MwViewportClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ draw, /* draw */ NULL, /* click */ diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index ab73fcafc..7cb33122a 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -556,7 +556,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } MwClassRec MwVulkanClassRec = { - create, /* create */ + wcreate, /* create */ destroy, /* destroy */ NULL, /* draw */ NULL, /* click */ diff --git a/src/widget/window.c b/src/widget/window.c index b4aaa8d22..2b596b50d 100644 --- a/src/widget/window.c +++ b/src/widget/window.c @@ -44,7 +44,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, va_list v } } MwClassRec MwWindowClassRec = { - create, /* create */ + wcreate, /* create */ NULL, /* destroy */ draw, /* draw */ NULL, /* click */ From 2228fa1a467ab724002a6c82a9405987338896ac Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 21:46:37 -0700 Subject: [PATCH 385/409] fix build --- src/widget/opengl.c | 6 +++--- src/widget/opengl_cocoa.m | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 2cb612eaa..39b5510c8 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -380,8 +380,8 @@ static void mwOpenGLMakeCurrentImpl(MwWidget handle) { #ifdef USE_GDI if(handle->lowlevel->common.type == MwLLBackendGDI) { - gdiopengl_t* o = handle->internal; - BOOL (APIENTRY *swap_interval_ext)(int) = NULL; + gdiopengl_t* o = handle->internal; + BOOL(APIENTRY * swap_interval_ext)(int) = NULL; o->wglMakeCurrent(o->dc, o->gl); @@ -498,7 +498,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, } } -MwClassRec MwOpenGLClassRec = {create, /* create */ +MwClassRec MwOpenGLClassRec = {wcreate, /* create */ destroy, /* destroy */ NULL, /* draw */ NULL, /* click */ diff --git a/src/widget/opengl_cocoa.m b/src/widget/opengl_cocoa.m index 27c21588a..a4d2bfa2f 100644 --- a/src/widget/opengl_cocoa.m +++ b/src/widget/opengl_cocoa.m @@ -111,7 +111,7 @@ static void func_handler(MwWidget handle, const char* name, void* out, @end -MwClassRec MwOpenGLClassRec = {create, /* create */ +MwClassRec MwOpenGLClassRec = {wcreate, /* create */ destroy, /* destroy */ NULL, /* draw */ NULL, /* click */ From 15c39a2405a62c47f91b7a683ac367bc67332af7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 21:48:52 -0700 Subject: [PATCH 386/409] windows shouldn't default to ft2 anyways --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index a6e5941cf..98a6b3a6e 100755 --- a/configure +++ b/configure @@ -132,7 +132,7 @@ foreach my $l (@ARGV) { } } -if($target ne "Darwin" and $target ne "ClassicMacOS") { +if($target ne "Darwin" and $target ne "ClassicMacOS" and $target ne "Windows") { param_set("freetype2", 1); param_set("stb-truetype", 0); } else { From b2ce5597b0ac205330bb0dceb33fd78c09fcf9b4 Mon Sep 17 00:00:00 2001 From: Nishi Date: Thu, 16 Apr 2026 14:07:20 +0900 Subject: [PATCH 387/409] fix warning --- src/draw.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/draw.c b/src/draw.c index f5e1368dd..68f6862e6 100644 --- a/src/draw.c +++ b/src/draw.c @@ -104,14 +104,13 @@ void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { MwLLPixmap pixmap; - int y, i; + int y; double darken = 0.; int ColorDiff = get_color_diff(handle); double darkenStep = (ColorDiff / 2.) / rect->height; unsigned long sz = 1 * rect->height * 4; unsigned char* data = malloc(sz); MwRect r = *rect; - double div; if(rect->width <= 0 || rect->height <= 0) { free(data); return; @@ -309,8 +308,7 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { MwPoint p[7]; - int i; - + (void)diff; (void)same; From 5ca241ad0af271f98fb6c3d780242d2046d76eca Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 22:20:13 -0700 Subject: [PATCH 388/409] update time.c to not do a cast --- CMakeLists.txt | 2 -- src/abstract/time.c | 4 +++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 835ecdd26..c0c7f0b9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -314,8 +314,6 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") PRIVATE src/backend/classicmacos.c ) - if(PLATFORM MATCHES retroppc) - endif() if(PLATFORM MATCHES retroppc) set_target_properties(Mw PROPERTIES COMPILE_FLAGS "-ffunction-sections -mcpu=601 -Os -Wall -Wextra -Wno-unused-parameter") set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections") diff --git a/src/abstract/time.c b/src/abstract/time.c index 52d998689..cdebc4b93 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -43,7 +43,7 @@ void timerUpdateFunc(void) { long MwTimeGetTick(void) { UnsignedWide h; Microseconds(&h); - return *(long*)&h; + return h.lo; } void MwTimeSleep(int ms) { tm.tmAddr = NewTimerProc(timerUpdateFunc); @@ -52,6 +52,8 @@ void MwTimeSleep(int ms) { InsTime((QElemPtr)&tm); PrimeTime((QElemPtr)&tm, 1); + + DisposeTimerUPP(tm.tmAddr); } #elif defined(__unix__) long MwTimeGetTick(void) { From 0e96b715b00c388f785940a1b86663f57d196edd Mon Sep 17 00:00:00 2001 From: IoIxD Date: Wed, 15 Apr 2026 22:25:26 -0700 Subject: [PATCH 389/409] classic mac os: comment out MwTimeSleep because I realize that wouldn't work either way --- src/abstract/time.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/abstract/time.c b/src/abstract/time.c index cdebc4b93..cd09b94d9 100644 --- a/src/abstract/time.c +++ b/src/abstract/time.c @@ -33,12 +33,12 @@ void MwTimeSleep(int ms) { nanosleep(&ts, NULL); } #elif defined(CLASSIC_MAC_OS) -static TMTask tm; -static int timer; -void timerUpdateFunc(void) { - timer += 1; - PrimeTime((QElemPtr)&tm, 1); -}; +// static TMTask tm; +// static int timer; +// void timerUpdateFunc(void) { +// timer += 1; +// PrimeTime((QElemPtr)&tm, 1); +// }; long MwTimeGetTick(void) { UnsignedWide h; @@ -46,14 +46,14 @@ long MwTimeGetTick(void) { return h.lo; } void MwTimeSleep(int ms) { - tm.tmAddr = NewTimerProc(timerUpdateFunc); - tm.tmWakeUp = 0; - tm.tmReserved = 0; + // tm.tmAddr = NewTimerProc(timerUpdateFunc); + // tm.tmWakeUp = 0; + // tm.tmReserved = 0; - InsTime((QElemPtr)&tm); - PrimeTime((QElemPtr)&tm, 1); + // InsTime((QElemPtr)&tm); + // PrimeTime((QElemPtr)&tm, 1); - DisposeTimerUPP(tm.tmAddr); + // DisposeTimerUPP(tm.tmAddr); } #elif defined(__unix__) long MwTimeGetTick(void) { From 9b138c458ec518121955abc77c0c9a239092c0a6 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 16 Apr 2026 00:45:59 -0700 Subject: [PATCH 390/409] cmacos: very untested code but it's all so basic that it should work --- include/Mw/LowLevel.h | 5 ++- include/Mw/LowLevel/ClassicMacOS.h | 1 + src/backend/classicmacos.c | 65 +++++++++++++++++++++++++----- 3 files changed, 59 insertions(+), 12 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 5ba698e9c..e025cb293 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -125,7 +125,7 @@ union _MwLL { struct _MwLLCocoa cocoa; #endif #ifdef CLASSIC_MAC_OS - struct _MwLLClassicMacOS cmacos; + struct _MwLLClassicMacOS cmacos; #endif }; @@ -159,6 +159,9 @@ union _MwLLPixmap { #ifdef USE_COCOA struct _MwLLCocoaPixmap cocoa; #endif +#ifdef CLASSIC_MAC_OS + struct _MwLLClassicMacOSPixmap cmacos; +#endif }; #endif #include diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h index f377e4f91..4b32f6cd4 100644 --- a/include/Mw/LowLevel/ClassicMacOS.h +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -24,6 +24,7 @@ struct _MwLLClassicMacOSColor { struct _MwLLClassicMacOSPixmap { struct _MwLLCommonPixmap common; + BitMap bmp; }; MWDECL int MwLLClassicMacOSCallInit(void); diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 929c4930f..168541559 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -7,12 +7,13 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLCreateCommon(r); - SetRect(&r->cmacos.winRect, 100, 100, width, height); - - r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, - documentProc, (WindowPtr)(-1), true, 0); - - SetPort(r->cmacos.window); + if(!parent) { + SetRect(&r->cmacos.winRect, 100, 100, width, height); + r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, + documentProc, (WindowPtr)(-1), true, 0); + SetPort(r->cmacos.window); + // + } return r; } @@ -32,10 +33,42 @@ static void MwLLEndDrawImpl(MwLL handle) { } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { - int i; + int i; + PolyHandle p = OpenPoly(); + RGBColor col; + + col.red = color->common.red; + col.green = color->common.green; + col.blue = color->common.blue; + + RGBBackColor(&col); + RGBForeColor(&col); + + for(i = 0; i < points_count; i++) { + if(i == 0) { + MoveTo(points[i].x, points[i].y); + } else { + LineTo(points[i].x, points[i].y); + } + } + + ClosePoly(); + PaintPoly(p); + KillPoly(p); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { + RGBColor col; + + col.red = color->common.red; + col.green = color->common.green; + col.blue = color->common.blue; + + RGBBackColor(&col); + RGBForeColor(&col); + + MoveTo(points[0].x, points[0].y); + LineTo(points[1].x, points[1].y); } static MwLLColor MwLLAllocColorImpl(MwLL handle, int r, int g, int b) { @@ -51,16 +84,20 @@ static void MwLLColorUpdateImpl(MwLL handle, MwLLColor c, int r, int g, int b) { } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { - *x = 0; - *y = 0; - *w = 0; - *h = 0; + Rect bounds; + GetWindowBounds(handle->cmacos.window, kWindowContentRgn, &bounds); + *x = bounds.left; + *y = bounds.top; + *w = bounds.right; + *h = bounds.bottom; } static void MwLLSetXYImpl(MwLL handle, int x, int y) { + MoveWindow(handle->cmacos.window, x, y, MwTRUE); } static void MwLLSetWHImpl(MwLL handle, int w, int h) { + SizeWindow(handle->cmacos.window, w, h, MwTRUE); } static void MwLLFreeColorImpl(MwLLColor color) { @@ -75,6 +112,7 @@ static void MwLLNextEventImpl(MwLL handle) { } static void MwLLSetTitleImpl(MwLL handle, const char* title) { + setwtitle(handle->cmacos.window, title); } static MwLLPixmap MwLLCreatePixmapImpl(MwLL handle, unsigned char* data, int width, int height) { @@ -109,6 +147,10 @@ static void MwLLDetachImpl(MwLL handle, MwPoint* point) { } static void MwLLShowImpl(MwLL handle, int show) { + if(show) + ShowWindow(handle->cmacos.window); + else + HideWindow(handle->cmacos.window); } static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { @@ -121,6 +163,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { } static void MwLLFocusImpl(MwLL handle) { + HiliteWindow(handle->cmacos.window, MwTRUE); } static void MwLLGrabPointerImpl(MwLL handle, int toggle) { From 8b176d3a008e796ebaa036375256411ba15a3f03 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 16 Apr 2026 00:53:37 -0700 Subject: [PATCH 391/409] cmacos: remove parent check oops --- src/backend/classicmacos.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 168541559..8745c0ce5 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -7,13 +7,11 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLLCreateCommon(r); - if(!parent) { - SetRect(&r->cmacos.winRect, 100, 100, width, height); - r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, - documentProc, (WindowPtr)(-1), true, 0); - SetPort(r->cmacos.window); - // - } + /* todo: how do we set parent windows? If we can't, what is our equivalant to MacOS's NSViews, Wayland's subsurfaces, etc.? */ + SetRect(&r->cmacos.winRect, x, y, width, height); + r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, + documentProc, (WindowPtr)(-1), true, 0); + SetPort(r->cmacos.window); return r; } From c88dc48817d92d9103a4852a56c494d95e1dc214 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 16 Apr 2026 00:55:18 -0700 Subject: [PATCH 392/409] cmacos: Right we can just use the lowercase newcwindow instead of worrying about pascal conversions --- src/backend/classicmacos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 8745c0ce5..4fa7ab373 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -9,7 +9,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { /* todo: how do we set parent windows? If we can't, what is our equivalant to MacOS's NSViews, Wayland's subsurfaces, etc.? */ SetRect(&r->cmacos.winRect, x, y, width, height); - r->cmacos.window = NewCWindow(nil, &r->cmacos.winRect, (ConstStr255Param) "\p", true, + r->cmacos.window = newcwindow(nil, &r->cmacos.winRect, "", true, documentProc, (WindowPtr)(-1), true, 0); SetPort(r->cmacos.window); From 79efc31c55093b3c6b1cfdd900e6e7af0ac16f07 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 16 Apr 2026 23:40:29 +0900 Subject: [PATCH 393/409] dbus should work on netbsd now --- include/Mw/LowLevel.h | 2 +- pl/ostype/ClassicMacOS.pl | 8 +++++--- pl/ostype/NetBSD.pl | 2 ++ pl/rules.pl | 13 ++++++++----- src/backend/call.c | 2 +- src/backend/cocoa.m | 2 +- src/backend/gdi.c | 7 +++---- src/backend/wayland.c | 10 ++++++++-- src/backend/x11.c | 17 +++++++++++++++-- src/core.c | 2 +- src/draw.c | 2 +- src/string.c | 2 +- src/widget/scrollbar.c | 6 +++--- 13 files changed, 50 insertions(+), 25 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index e025cb293..ea31aefea 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -6,7 +6,7 @@ #ifndef __MW_LOWLEVEL_H__ #define __MW_LOWLEVEL_H__ -#include "Mw/BaseTypes.h" +#include #include typedef struct _MwLLHandler* MwLLHandler; diff --git a/pl/ostype/ClassicMacOS.pl b/pl/ostype/ClassicMacOS.pl index 751525f7a..1f2e532d6 100644 --- a/pl/ostype/ClassicMacOS.pl +++ b/pl/ostype/ClassicMacOS.pl @@ -1,9 +1,11 @@ use_backend("classicmacos"); -print("Compiling for Classic Mac OS via ./configure currently outputs a broken executable and it only supports PowerPC. Help is wanted. In the mean time, use CMake.") +print( +"Compiling for Classic Mac OS via ./configure currently outputs a broken executable and it only supports PowerPC. Help is wanted. In the mean time, use CMake." +); -$cc = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-gcc"; -$ar = $ENV{RETRO68_TOOLCHAIN_PATH}."/bin/powerpc-apple-macos-ar"; +$cc = $ENV{RETRO68_TOOLCHAIN_PATH} . "/bin/powerpc-apple-macos-gcc"; +$ar = $ENV{RETRO68_TOOLCHAIN_PATH} . "/bin/powerpc-apple-macos-ar"; add_cflags("-DCLASSIC_MAC_OS"); add_cflags("-DSTBI_NO_THREAD_LOCALS"); diff --git a/pl/ostype/NetBSD.pl b/pl/ostype/NetBSD.pl index 936725069..6556cab20 100644 --- a/pl/ostype/NetBSD.pl +++ b/pl/ostype/NetBSD.pl @@ -4,4 +4,6 @@ add_libdir( use_backend("x11"); add_libs("-lpthread"); +add_cflags("-DUSE_DBUS"); + 1; diff --git a/pl/rules.pl b/pl/rules.pl index 4d68cb94d..6f64a174c 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -31,6 +31,7 @@ if (grep(/^gdi$/, @backends)) { } if (grep(/^classicmacos$/, @backends)) { + #add_cflags("-DCLASSIC_MAC_OS"); new_object("src/backend/classicmacos.c"); @@ -56,18 +57,20 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - add_cflags(`pkg-config --cflags dbus-1`); - $gl_libs = "-lGL -lGLU"; } +if (grep(/( |^)-DUSE_DBUS( |$)/, $cflags)) { + add_cflags(`pkg-config --cflags dbus-1`); +} + if (grep(/^cocoa$/, @backends) || param_get("gnustep")) { add_cflags("-DUSE_COCOA"); new_object("src/backend/cocoa.m"); - if(param_get("gnustep")){ - add_incdir("-I".`gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`); - add_libdir("-L".`gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`); + if (param_get("gnustep")) { + add_incdir("-I" . `gnustep-config --variable=GNUSTEP_SYSTEM_HEADERS`); + add_libdir("-L" . `gnustep-config --variable=GNUSTEP_SYSTEM_LIBRARIES`); add_cflags("-fobjc-runtime=gnustep-2.0 -fblocks"); add_ldflags("-lobjc -lgnustep-base -lm -lgnustep-gui"); } diff --git a/src/backend/call.c b/src/backend/call.c index 07cf1e08f..14338ecc9 100644 --- a/src/backend/call.c +++ b/src/backend/call.c @@ -55,7 +55,7 @@ MwLLGetCursorCoord = MwLLGetCursorCoordImpl; \ MwLLGetScreenSize = MwLLGetScreenSizeImpl; \ \ - MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ + MwLLSetDarkTheme = MwLLSetDarkThemeImpl; \ \ return 0; \ } diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index 3177d14c2..cfac1add0 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -1084,7 +1084,7 @@ static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } -static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; } diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 8813ba24b..055b6c26d 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -11,7 +11,7 @@ typedef struct userdata { static struct symtbl { void* lib_dwmapi; - HRESULT (WINAPI *DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); + HRESULT(WINAPI* DwmSetWindowAttribute)(HWND hwnd, DWORD dwAttribute, LPCVOID pvAttribute, DWORD cbAttribute); } wsymtbl; #define DwmSetWindowAttribute wsymtbl.DwmSetWindowAttribute @@ -34,7 +34,7 @@ static void detect_darktheme(MwLL handle) { t = dw ? 0 : 1; - if(t && DwmSetWindowAttribute != NULL){ + if(t && DwmSetWindowAttribute != NULL) { LPARAM style = GetWindowLongPtr(handle->gdi.hWnd, GWL_STYLE); if(!(style & WS_CHILD)) MwLLSetDarkTheme(handle, 1); } @@ -819,11 +819,10 @@ static void MwLLEndStateChangeImpl(MwLL handle) { (void)handle; } -static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { BOOL v = toggle ? TRUE : FALSE; DwmSetWindowAttribute(handle->gdi.hWnd, 20, &v, sizeof(v)); - } static int MwLLGDICallInitImpl(void) { diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 425308d7e..fc4a67fc4 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -1817,6 +1817,7 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } +#ifdef USE_DBUS static void detect_dark_theme(MwLL handle) { MwU32 value = 0; MwU32 dark_theme = 0; @@ -1826,6 +1827,7 @@ static void detect_dark_theme(MwLL handle) { MwLLDispatch(handle, dark_theme, &dark_theme); } +#endif static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; @@ -1876,9 +1878,11 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&handle->wayland.eventsMutex); pthread_mutex_destroy(&handle->wayland.eventsMutex); +#ifdef USE_DBUS if(!wl_call_tbl.has_dbus) { MwLLDBusFreeContext(&wl_call_tbl.dbus, &handle->wayland.dbus); } +#endif buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); @@ -2161,11 +2165,13 @@ static int MwLLPendingImpl(MwLL handle) { int pending = 0; if(handle->wayland.dark_theme_detection) { + handle->wayland.dark_theme_detection = MwFALSE; +#ifdef USE_DBUS if(wl_call_tbl.has_dbus) { detect_dark_theme(handle); - handle->wayland.dark_theme_detection = MwFALSE; MwLLDispatch(handle, draw, NULL); } +#endif } if(!handle->wayland.did_initial_resize) { @@ -2622,7 +2628,7 @@ static void MwLLEndStateChangeImpl(MwLL handle) { } } -static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; } diff --git a/src/backend/x11.c b/src/backend/x11.c index a556c1c6f..898da85c0 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -9,8 +9,10 @@ static struct symtbl { void* lib_xrender; MwBool has_xrender; +#ifdef USE_DBUS MwLLDBusFuncTable dbus; MwBool has_dbus; +#endif int (*XClearWindow)(Display* display, Window w); XImage* (*XCreateImage)(Display*, Visual*, unsigned int, int, int, char*, unsigned int, unsigned int, int, int); @@ -311,6 +313,7 @@ static XVisualInfo* get_visual_info(Display* display) { return XGetVisualInfo(display, VisualIDMask, &xvi, &n); } +#ifdef USE_DBUS static void detect_dark_theme(MwLL handle) { MwU32 value = 0; MwU32 dark_theme = 0; @@ -320,6 +323,7 @@ static void detect_dark_theme(MwLL handle) { MwLLDispatch(handle, dark_theme, &dark_theme); } +#endif static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; @@ -470,9 +474,11 @@ static void MwLLDestroyImpl(MwLL handle) { if(handle->x11.toplevel) XCloseDisplay(handle->x11.display); +#ifdef USE_DBUS if(!xsymtbl.has_dbus) { MwLLDBusFreeContext(&xsymtbl.dbus, &handle->x11.dbus); } +#endif free(handle); } @@ -633,11 +639,13 @@ static int MwLLPendingImpl(MwLL handle) { XEvent ev; if(handle->x11.dark_theme_detection) { + handle->x11.dark_theme_detection = MwFALSE; +#ifdef USE_DBUS if(xsymtbl.has_dbus) { detect_dark_theme(handle); - handle->x11.dark_theme_detection = MwFALSE; MwLLDispatch(handle, draw, NULL); } +#endif } if(handle->x11.clipboard_pending && (MwTimeGetTick() - handle->x11.clipboard_time) >= ClipboardTimeout) { @@ -1258,9 +1266,12 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty (void)handle; (void)text; + (void)clipboard_type; } static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { + (void)clipboard_type; + if(handle->x11.clipboard_pending) return; XConvertSelection(handle->x11.display, handle->x11.clipboard, handle->x11.utf8_string, handle->x11.selection, handle->x11.window, CurrentTime); @@ -1308,7 +1319,7 @@ static void MwLLEndStateChangeImpl(MwLL handle) { MwLLShow(handle, 1); } -static void MwLLSetDarkThemeImpl(MwLL handle, int toggle){ +static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)handle; (void)toggle; } @@ -1427,7 +1438,9 @@ static int MwLLX11CallInitImpl(void) { XRENDER_FUNC_LOAD(XRenderComposite) #endif +#ifdef USE_DBUS xsymtbl.has_dbus = MwLLDBusFuncSetup(&xsymtbl.dbus); +#endif return 0; } diff --git a/src/core.c b/src/core.c index 6c08970a8..0404fa72b 100644 --- a/src/core.c +++ b/src/core.c @@ -533,7 +533,7 @@ void MwSetInteger(MwWidget handle, const char* key, int n) { force_render_all(handle); } - if(strcmp(key, MwNdarkTheme) == 0){ + if(strcmp(key, MwNdarkTheme) == 0) { MwWidget h = handle; while(h->parent != NULL && h->parent->widget_class != NULL) h = h->parent; diff --git a/src/draw.c b/src/draw.c index 68f6862e6..8dde8418e 100644 --- a/src/draw.c +++ b/src/draw.c @@ -308,7 +308,7 @@ static void MwDrawFrameEx_simple(MwWidget handle, MwRect* rect, MwLLColor color, static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same) { MwPoint p[7]; - + (void)diff; (void)same; diff --git a/src/string.c b/src/string.c index a7c23381c..f56b9acb7 100644 --- a/src/string.c +++ b/src/string.c @@ -52,7 +52,7 @@ void MwStringPrintIntoBuffer(char* out, MwU32 size, const char* fmt, ...) { MWDECL MwBool MwStringIsKeyUTF8(MwU32 key) { unsigned char bytes[4]; - int i; + int i; bytes[0] = (key & 0x000000FF); bytes[1] = (key & 0x0000FF00) >> 8; bytes[2] = (key & 0x00FF0000) >> 16; diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index a1df9b2db..bed80c0b2 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -58,9 +58,9 @@ static void draw(MwWidget handle) { MwLLColor base = MwParseColor(handle, MwGetText(handle, MwNbackground)); MwLLColor dark = MwLightenColor(handle, base, -64, -64, -64); MwScrollBar scr = handle->internal; - int or; - int uy, dy, ux, dx; - MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); + int or ; + int uy, dy, ux, dx; + MwLLPixmap bgpx = MwGetVoid(handle, MwNbackgroundPixmap); r.x = 0; r.y = 0; From b82e13cb2e4ba772e342c68cbe30bb3ac210120f Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Thu, 16 Apr 2026 23:53:29 +0900 Subject: [PATCH 394/409] define opengl/vulkan symbols anyways --- CMakeLists.txt | 10 +++++----- pl/rules.pl | 6 ++++-- src/widget/opengl.c | 7 +++++++ src/widget/vulkan.c | 11 ++++++++++- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c0c7f0b9d..a4f4eb3ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,9 +45,6 @@ file( external/libz/src/*.c src/*.c src/cursor/*.c src/icon/*.c src/widget/*.c src/text/*.c src/text/font/*.c src/dialog/*.c src/abstract/*.c external/*.c ) -list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") -list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") - if(NOT MW_USE_STB_IMAGE) list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/stb_image.c") endif() @@ -65,7 +62,11 @@ if(MW_TRY_OPENGL) find_package(OpenGL) if(OpenGL_FOUND) set(MW_BUILD_OPENGL ON) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl.c") + target_compile_definitions( + Mw + PRIVATE + MW_OPENGL + ) if(APPLE) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") endif() @@ -79,7 +80,6 @@ if(MW_TRY_VULKAN) check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) if(HAVE_VULKAN_VULKAN_H) set(MW_BUILD_VULKAN ON) - list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/vulkan.c") target_compile_definitions( Mw PRIVATE diff --git a/pl/rules.pl b/pl/rules.pl index 6f64a174c..7ad414db7 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -139,12 +139,14 @@ new_object("src/widget/treeview.c"); new_object("src/widget/viewport.c"); new_object("src/widget/window.c"); +new_object("src/widget/opengl.c"); +new_object("src/widget/vulkan.c"); + if (param_get("opengl")) { - new_object("src/widget/opengl.c"); + add_cflags("-DMW_OPENGL"); } if (param_get("vulkan")) { add_cflags("-DMW_VULKAN"); - new_object("src/widget/vulkan.c"); } new_object("src/dialog/*.c"); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 39b5510c8..e8b222c25 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -1,6 +1,8 @@ #ifndef __APPLE__ #include + +#ifdef MW_OPENGL #include #ifdef USE_GDI @@ -516,5 +518,10 @@ MwClassRec MwOpenGLClassRec = {wcreate, /* create */ NULL, /* clipboard */ NULL, NULL, NULL, NULL}; MwClass MwOpenGLClass = &MwOpenGLClassRec; +#else +MWDECL MwClass MwOpenGLClass; + +MwClass MwOpenGLClass = NULL; +#endif #endif diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 7cb33122a..394c9e5a0 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -1,10 +1,12 @@ #include -#include /** * ioixd maintains this file. nishi doesn't know vulkan at all */ +#ifdef MW_VULKAN +#include + #ifdef USE_GDI #define VK_USE_PLATFORM_WIN32_KHR 1 #endif @@ -165,6 +167,8 @@ static int _destroy(MwWidget handle) { static void destroy(MwWidget handle) { int err = _destroy(handle); + + (void)err; } static void* vulkan_lib_load() { @@ -577,3 +581,8 @@ MwClassRec MwVulkanClassRec = { NULL, NULL}; MwClass MwVulkanClass = &MwVulkanClassRec; +#else +MWDECL MwClass MwVulkanClass; + +MwClass MwVulkanClass = NULL; +#endif From 5201c46a219a8225d28206c1015b93e168ba1f84 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 00:20:29 +0900 Subject: [PATCH 395/409] update vulkan/opengl --- include/Mw/Widget/Vulkan.h | 14 ++++---- milsko.xml | 69 +++++++++++++++++++++++++++++++------- src/widget/opengl.c | 5 ++- src/widget/vulkan.c | 29 ++++++++++++---- 4 files changed, 92 insertions(+), 25 deletions(-) diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 3297d2271..217f0e56e 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -15,8 +15,10 @@ #error Vulkan is unsupported on the requested platform. #endif +#if !defined(MW_VULKAN_NO_INCLUDE) #include #include +#endif #include #include @@ -46,19 +48,19 @@ MWDECL void MwVulkanEnableLayer(const char* ext_name); /*! * @brief Configuration options that can be passed to setup Vulkan before a widget is created. */ -typedef struct MwVulkanConfig_T { +typedef struct _MwVulkanConfig { /*! * @brief Vulkan API version (default: VK_API_VERSION_1_0) */ - uint32_t api_version; + MwU32 api_version; /*! * @brief Vulkan version (default: VK_VERSION_1_0) */ - uint32_t vk_version; + MwU32 vk_version; /*! * @brief Whether or not to enable validation layers (default: false) */ - VkBool32 validation_layers; + int validation_layers; } MwVulkanConfig; /*! @@ -71,7 +73,7 @@ MWDECL void MwVulkanConfigure(MwVulkanConfig cfg); /*! * @brief Field that can be gotten from Vulkan. */ -typedef enum MwVulkanField_T { +typedef enum _MwVulkanField { /*! * @brief The address of the vulkan widget's vkGetInstanceProcAddr function (PFN_vkGetInstanceProcAddr) */ @@ -120,7 +122,7 @@ MwInline void* MwVulkanGetField(MwWidget handle, MwVulkanField field, int* out) /*! * @brief Return whether Vulkan is installed on the target platform. */ -MWDECL VkBool32 MwVulkanSupported(void); +MWDECL int MwVulkanSupported(void); #ifdef __cplusplus } diff --git a/milsko.xml b/milsko.xml index d42f7e961..2e522bd1d 100644 --- a/milsko.xml +++ b/milsko.xml @@ -67,10 +67,6 @@ - @@ -88,6 +84,9 @@ + + + @@ -150,9 +149,20 @@ - 0 + 0 + + 0 + + + + + + + + + 0x0fffffff @@ -409,14 +419,14 @@ - + - - + + @@ -502,6 +512,8 @@
+ + @@ -721,15 +733,48 @@ - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/widget/opengl.c b/src/widget/opengl.c index e8b222c25..252d7ad56 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -2,9 +2,12 @@ #include -#ifdef MW_OPENGL +#ifndef MW_OPENGL +#define MW_OPENGL_NO_INCLUDE +#endif #include +#ifdef MW_OPENGL #ifdef USE_GDI typedef HGLRC(WINAPI* MWwglCreateContext)(HDC); typedef BOOL(WINAPI* MWwglMakeCurrent)(HDC, HGLRC); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 394c9e5a0..e87164627 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -4,9 +4,12 @@ * ioixd maintains this file. nishi doesn't know vulkan at all */ -#ifdef MW_VULKAN +#ifndef MW_VULKAN +#define MW_VULKAN_NO_INCLUDE +#endif #include +#ifdef MW_VULKAN #ifdef USE_GDI #define VK_USE_PLATFORM_WIN32_KHR 1 #endif @@ -498,7 +501,7 @@ void MwVulkanEnableLayer(const char* name) { arrput(enabledLayers, name); } -VkBool32 MwVulkanSupported(void) { +int MwVulkanSupported(void) { if(vulkan_supported == VULKAN_SUPPORTED_UNKNOWN) { void* lib = vulkan_lib_load(); if(lib == NULL) { @@ -509,9 +512,9 @@ VkBool32 MwVulkanSupported(void) { } } if(vulkan_supported == VULKAN_SUPPORTED_YES) { - return VK_TRUE; + return 1; } else { - return VK_FALSE; + return 0; } }; @@ -582,7 +585,21 @@ MwClassRec MwVulkanClassRec = { NULL}; MwClass MwVulkanClass = &MwVulkanClassRec; #else -MWDECL MwClass MwVulkanClass; - MwClass MwVulkanClass = NULL; + +void MwVulkanEnableExtension(const char* ext_name) { + (void)ext_name; +} + +void MwVulkanEnableLayer(const char* ext_name) { + (void)ext_name; +} + +void MwVulkanConfigure(MwVulkanConfig cfg) { + (void)cfg; +} + +int MwVulkanSupported(void) { + return 0; +} #endif From 13a2db7fa85c57bc5d3426d73248ee58c4d24d1e Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 00:26:02 +0900 Subject: [PATCH 396/409] better for binding --- include/Mw/Widget/Vulkan.h | 2 +- milsko.xml | 6 +++--- src/widget/vulkan.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 217f0e56e..4f8a5e3db 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -113,7 +113,7 @@ typedef enum _MwVulkanField { * @brief Function for getting a field from within Vulkan. * @warning Consult the documentation for MwVulkanField to know what type is expected for out. */ -MwInline void* MwVulkanGetField(MwWidget handle, MwVulkanField field, int* out) { +MwInline void* MwVulkanGetField(MwWidget handle, int field, int* out) { void* field_out; MwVaWidgetExecute(handle, "mwVulkanGetField", &field_out, field, out); return field_out; diff --git a/milsko.xml b/milsko.xml index 2e522bd1d..253a4fee8 100644 --- a/milsko.xml +++ b/milsko.xml @@ -419,14 +419,14 @@ - + - + @@ -770,7 +770,7 @@ - + diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index e87164627..817644c3e 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -518,7 +518,7 @@ int MwVulkanSupported(void) { } }; -static void* mwVulkanGetFieldImpl(MwWidget handle, MwVulkanField field, int* out) { +static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* out) { vulkan_t* o = handle->internal; char buf[1024]; @@ -556,9 +556,9 @@ static void* mwVulkanGetFieldImpl(MwWidget handle, MwVulkanField field, int* out static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { if(strcmp(name, "mwVulkanGetField") == 0) { - MwVulkanField field = va_arg(va, MwVulkanField); - int* err = va_arg(va, int*); - *(void**)out = mwVulkanGetFieldImpl(handle, field, err); + int field = va_arg(va, int); + int* err = va_arg(va, int*); + *(void**)out = mwVulkanGetFieldImpl(handle, field, err); } } From 7a2ca3aa2dcb4f42c383d696694bffd6d049375b Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 00:27:04 +0900 Subject: [PATCH 397/409] oops --- milsko.xml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/milsko.xml b/milsko.xml index 253a4fee8..cca24fc6b 100644 --- a/milsko.xml +++ b/milsko.xml @@ -417,17 +417,17 @@ - - - - + + + + - - - - - + + + + + @@ -770,8 +770,8 @@ - - + + From 5220f742be8f1304415848f669f3c9444e805c2d Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:03:14 +0900 Subject: [PATCH 398/409] some changes --- include/Mw/Widget/Vulkan.h | 2 +- milsko.xml | 19 +++++++++++++++++++ src/widget/vulkan.c | 6 +++--- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 4f8a5e3db..1b008e5a4 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -68,7 +68,7 @@ typedef struct _MwVulkanConfig { * @warning This must be called before MwCreateWidget. * @warning The configuration provided will be used for future initializations of the Vulkan widget (unless it's changed) */ -MWDECL void MwVulkanConfigure(MwVulkanConfig cfg); +MWDECL void MwVulkanConfigure(MwVulkanConfig* cfg); /*! * @brief Field that can be gotten from Vulkan. diff --git a/milsko.xml b/milsko.xml index cca24fc6b..76d4755e2 100644 --- a/milsko.xml +++ b/milsko.xml @@ -38,6 +38,11 @@ + + + + + +
+ + + + + + + + + + +
diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 817644c3e..e836ac379 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -489,8 +489,8 @@ static int vulkan_devices_setup(MwWidget handle, vulkan_t* o) { return 0; } -void MwVulkanConfigure(MwVulkanConfig cfg) { - vulkan_config = cfg; +void MwVulkanConfigure(MwVulkanConfig* cfg) { + vulkan_config = *cfg; } void MwVulkanEnableExtension(const char* name) { @@ -595,7 +595,7 @@ void MwVulkanEnableLayer(const char* ext_name) { (void)ext_name; } -void MwVulkanConfigure(MwVulkanConfig cfg) { +void MwVulkanConfigure(MwVulkanConfig* cfg) { (void)cfg; } From 570f05540ef6dc88bfd2f8cedb9de10bab0313e1 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:36:34 +0900 Subject: [PATCH 399/409] many things changed --- examples/basic/clipboard.c | 4 +- examples/gldemos/tripaint.c | 6 +-- examples/vkdemos/vulkan.c | 18 ++++----- include/Mw/Constants.h | 22 +++++++++++ include/Mw/LowLevel.h | 14 ------- include/Mw/StringDefs.h | 41 ++++++++++---------- include/Mw/TypeDefs.h | 20 +++------- include/Mw/Widget/Vulkan.h | 24 ++++++------ milsko.xml | 74 ++++++++++++++++++++++++++++++------- src/backend/cocoa.m | 68 +++++++++++++++++----------------- src/backend/gdi.c | 24 ++++++------ src/backend/wayland.c | 34 ++++++++--------- src/backend/x11.c | 24 ++++++------ src/core.c | 17 +++++---- src/dialog/colorpicker.c | 2 +- src/dialog/filechooser.c | 4 +- src/widget/combobox.c | 2 +- src/widget/entry.c | 8 ++-- src/widget/listbox.c | 14 +++---- src/widget/menu.c | 4 +- src/widget/numberentry.c | 4 +- src/widget/scrollbar.c | 8 ++-- src/widget/submenu.c | 2 +- src/widget/treeview.c | 10 ++--- src/widget/vulkan.c | 18 ++++----- 25 files changed, 258 insertions(+), 208 deletions(-) diff --git a/examples/basic/clipboard.c b/examples/basic/clipboard.c index 38084a184..94a192f22 100644 --- a/examples/basic/clipboard.c +++ b/examples/basic/clipboard.c @@ -42,9 +42,9 @@ static void clipboard(MwWidget handle, void* user_data, void* call_data) { static void tick(MwWidget handle, void* user_data, void* call_data) { cur_text = text1; - MwGetClipboard(handle, MwClipboardMain); + MwGetClipboard(handle, MwCLIPBOARD_MAIN); cur_text = text2; - MwGetClipboard(handle, MwClipboardPrimary); + MwGetClipboard(handle, MwCLIPBOARD_PRIMARY); MwForceRender(window); } diff --git a/examples/gldemos/tripaint.c b/examples/gldemos/tripaint.c index 2cc7aa844..1208b26ae 100644 --- a/examples/gldemos/tripaint.c +++ b/examples/gldemos/tripaint.c @@ -51,12 +51,12 @@ static void tick(MwWidget handle, void* user, void* call) { } static void mouse(MwWidget handle, void* user, void* call) { - MwLLMouse* mouse = call; + MwMouse* mouse = call; (void)handle; (void)user; - if(mouse->button == MwLLMouseLeft) { + if(mouse->button == MwMOUSE_LEFT) { t[ct].points[click * 2 + 0] = mouse->point.x; t[ct].points[click * 2 + 1] = mouse->point.y; click++; @@ -82,7 +82,7 @@ static void mouse(MwWidget handle, void* user, void* call) { for(i = 0; i < ct; i++) t[i] = old[i]; free(old); } - } else if(mouse->button == MwLLMouseRight) { + } else if(mouse->button == MwMOUSE_RIGHT) { if(click > 0) { click = 0; } else if(ct > 0) { diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 0c59891ad..7e20a5be7 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -232,15 +232,15 @@ void vulkan_setup(MwWidget handle) { VkFenceCreateInfo fenceInfo = {}; int err = 0; - _vkGetInstanceProcAddr = MwVulkanGetField(handle, MwVulkanField_GetInstanceProcAddr, &err); - instance = MwVulkanGetField(handle, MwVulkanField_Instance, &err); - device = MwVulkanGetField(handle, MwVulkanField_LogicalDevice, &err); - physicalDevice = MwVulkanGetField(handle, MwVulkanField_PhysicalDevice, &err); - graphicsQueue = MwVulkanGetField(handle, MwVulkanField_GraphicsQueue, &err); - presentQueue = MwVulkanGetField(handle, MwVulkanField_PresentQueue, &err); - surface = MwVulkanGetField(handle, MwVulkanField_Surface, &err); - presentQueueIndex = MwVulkanGetField(handle, MwVulkanField_PresentQueueIndex, &err); - graphicsQueueIndex = MwVulkanGetField(handle, MwVulkanField_GraphicsQueueIndex, &err); + _vkGetInstanceProcAddr = MwVulkanGetField(handle, MwVULKANFIELD_GETINSTANCEPROCADDR, &err); + instance = MwVulkanGetField(handle, MwVULKANFIELD_INSTANCE, &err); + device = MwVulkanGetField(handle, MwVULKANFIELD_LOGICALDEVICE, &err); + physicalDevice = MwVulkanGetField(handle, MwVULKANFIELD_PHYSICALDEVICE, &err); + graphicsQueue = MwVulkanGetField(handle, MwVULKANFIELD_GRAPHICSQUEUE, &err); + presentQueue = MwVulkanGetField(handle, MwVULKANFIELD_PRESENTQUEUE, &err); + surface = MwVulkanGetField(handle, MwVULKANFIELD_SURFACE, &err); + presentQueueIndex = MwVulkanGetField(handle, MwVULKANFIELD_PRESENTQUEUEINDEX, &err); + graphicsQueueIndex = MwVulkanGetField(handle, MwVULKANFIELD_GRAPHICSQUEUEINDEX, &err); LOAD_VK_FUNCTION(vkCreateShaderModule); LOAD_VK_FUNCTION(vkCreatePipelineLayout); diff --git a/include/Mw/Constants.h b/include/Mw/Constants.h index bc4757f49..d710ca006 100644 --- a/include/Mw/Constants.h +++ b/include/Mw/Constants.h @@ -99,4 +99,26 @@ enum MwMB_ICON { */ #define MwMB_BUTTONYESNOCANCEL (MwMB_BUTTONYES | MwMB_BUTTONNO | MwMB_BUTTONCANCEL) +/* Whether or not GetXY/SetXY works with global or local coordinates */ +enum MwCOORDINATE { + MwCOORDINATE_GLOBAL = 0, + MwCOORDINATE_LOCAL, +}; + +/* The clipboard type that MwGetClipboard should return */ +enum MwCLIPBOARD { + /* the clipboard that is present on every platform that supports it */ + MwCLIPBOARD_MAIN = 0, + /* the "primary" clipboard that Wayland stores to emulate X11's behavior. */ + MwCLIPBOARD_PRIMARY, +}; + +enum MwMOUSE { + MwMOUSE_LEFT = 1, + MwMOUSE_MIDDLE, + MwMOUSE_RIGHT, + MwMOUSE_WHEELUP, + MwMOUSE_WHEELDOWN +}; + #endif diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index ea31aefea..cbc67f9e0 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -10,7 +10,6 @@ #include typedef struct _MwLLHandler* MwLLHandler; -typedef struct _MwLLMouse MwLLMouse; typedef struct _MwLLCommon* MwLLCommon; typedef struct _MwLLCommonColor* MwLLCommonColor; typedef struct _MwLLCommonPixmap* MwLLCommonPixmap; @@ -187,19 +186,6 @@ enum MwLLKeyEnum { #define MwLLControlMask MwLLKeyMask | (1 << 30) #define MwLLAltMask MwLLKeyMask | (1 << 29) -enum MwLLMouseEnum { - MwLLMouseLeft = 1, - MwLLMouseMiddle, - MwLLMouseRight, - MwLLMouseWheelUp, - MwLLMouseWheelDown -}; - -struct _MwLLMouse { - MwPoint point; - int button; -}; - struct _MwLLHandler { void (*draw)(MwLL handle, void* data); void (*up)(MwLL handle, void* data); diff --git a/include/Mw/StringDefs.h b/include/Mw/StringDefs.h index cac605a5e..c657a637e 100644 --- a/include/Mw/StringDefs.h +++ b/include/Mw/StringDefs.h @@ -60,24 +60,27 @@ #define MwNmonospaceFont "VmonospaceFont" #define MwNboldMonospaceFont "VboldMonospaceFont" -#define MwNactivateHandler "Cactivate" /* NULL/int* (MwListBox)/void* (MwTreeView) */ -#define MwNresizeHandler "Cresize" /* NULL */ -#define MwNtickHandler "Ctick" /* NULL */ -#define MwNmenuHandler "Cmenu" /* MwMenu */ -#define MwNmouseDownHandler "CmouseDown" /* MwLLMouse* */ -#define MwNmouseUpHandler "CmouseUp" /* same as MwNmouseDownHandler */ -#define MwNmouseMoveHandler "CmouseMove" /* MwPoint* */ -#define MwNchangedHandler "Cchanged" /* NULL/int* (MwComboBox) */ -#define MwNkeyHandler "Ckey" /* int* (MwLLKeyEnum or character code) */ -#define MwNkeyReleaseHandler "CkeyRelease" /* same as MwNkeyHandler */ -#define MwNcloseHandler "Cclose" /* NULL */ -#define MwNfocusInHandler "CfocusIn" /* NULL */ -#define MwNfocusOutHandler "CfocusOut" /* NULL */ -#define MwNfileChosenHandler "CfileChosen" /* char* */ -#define MwNdirectoryChosenHandler "CdirectoryChosen" /* char* */ -#define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */ -#define MwNdrawHandler "Cdraw" /* NULL */ -#define MwNclipboardHandler "Cclipboard" /* char* */ -#define MwNdarkThemeHandler "CdarkTheme" /* int* */ +#define MwNactivateHandler "Cactivate" /* NULL */ +#define MwNlistBoxActivateHandler "ClistBoxActivate" /* int* */ +#define MwNtreeViewActivateHandler "CtreeViewActivate" /* void* */ +#define MwNresizeHandler "Cresize" /* NULL */ +#define MwNtickHandler "Ctick" /* NULL */ +#define MwNmenuHandler "Cmenu" /* MwMenu */ +#define MwNmouseDownHandler "CmouseDown" /* MwMouse* */ +#define MwNmouseUpHandler "CmouseUp" /* same as MwNmouseDownHandler */ +#define MwNmouseMoveHandler "CmouseMove" /* MwPoint* */ +#define MwNchangedHandler "Cchanged" /* NULL */ +#define MwNcomboBoxChangedHandler "CcomboBoxChanged" /* int* */ +#define MwNkeyHandler "Ckey" /* int* (MwLLKeyEnum or character code) */ +#define MwNkeyReleaseHandler "CkeyRelease" /* same as MwNkeyHandler */ +#define MwNcloseHandler "Cclose" /* NULL */ +#define MwNfocusInHandler "CfocusIn" /* NULL */ +#define MwNfocusOutHandler "CfocusOut" /* NULL */ +#define MwNfileChosenHandler "CfileChosen" /* char* */ +#define MwNdirectoryChosenHandler "CdirectoryChosen" /* char* */ +#define MwNcolorChosenHandler "CcolorChosen" /* MwRGB* */ +#define MwNdrawHandler "Cdraw" /* NULL */ +#define MwNclipboardHandler "Cclipboard" /* char* */ +#define MwNdarkThemeHandler "CdarkTheme" /* int* */ #endif diff --git a/include/Mw/TypeDefs.h b/include/Mw/TypeDefs.h index bd0af3d78..ca8e32b05 100644 --- a/include/Mw/TypeDefs.h +++ b/include/Mw/TypeDefs.h @@ -28,6 +28,7 @@ typedef struct _MwTreeViewEntry MwTreeViewEntry; typedef struct _MwDirectoryEntry MwDirectoryEntry; typedef struct _MwListBoxPacket MwListBoxPacket; typedef struct _MwBox* MwBox; +typedef struct _MwMouse MwMouse; #ifdef _MILSKO typedef struct _MwWidget* MwWidget; #else @@ -210,6 +211,11 @@ struct _MwBox { int layout; }; +struct _MwMouse { + MwPoint point; + int button; +}; + struct _MwClass { MwHandlerWithStatus create; MwHandler destroy; @@ -233,18 +239,4 @@ struct _MwClass { void* reserved4; }; -/* Whether or not GetXY/SetXY works with global or local coordinates */ -enum MwCoordinateType { - MwCoordinatesGlobal = 0, - MwCoordinatesLocal, -}; - -/* The clipboard type that MwGetClipboard should return */ -enum MwClipboardType { - /* the clipboard that is present on every platform that supports it */ - MwClipboardMain = 0, - /* the "primary" clipboard that Wayland stores to emulate X11's behavior. */ - MwClipboardPrimary, -}; - #endif diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 1b008e5a4..ccfb02446 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -73,45 +73,45 @@ MWDECL void MwVulkanConfigure(MwVulkanConfig* cfg); /*! * @brief Field that can be gotten from Vulkan. */ -typedef enum _MwVulkanField { +enum MwVULKANFIELD { /*! * @brief The address of the vulkan widget's vkGetInstanceProcAddr function (PFN_vkGetInstanceProcAddr) */ - MwVulkanField_GetInstanceProcAddr = 0, + MwVULKANFIELD_GETINSTANCEPROCADDR = 0, /*! * @brief The address of the vulkan widget's instance (VkInstance) */ - MwVulkanField_Instance, + MwVULKANFIELD_INSTANCE, /*! * @brief The address of the vulkan widget's surface (VkSurfaceKHR) */ - MwVulkanField_Surface, + MwVULKANFIELD_SURFACE, /*! * @brief The address of the vulkan widget's physical device (VkPhysicalDevice) */ - MwVulkanField_PhysicalDevice, + MwVULKANFIELD_PHYSICALDEVICE, /*! * @brief The address of the vulkan widget's logical device (VkDevice) */ - MwVulkanField_LogicalDevice, + MwVULKANFIELD_LOGICALDEVICE, /*! * @brief The address of the index that the vulkan widget uses for the graphics queue (uint32_t *) */ - MwVulkanField_GraphicsQueueIndex, + MwVULKANFIELD_GRAPHICSQUEUEINDEX, /*! * @brief The address of the index that the vulkan widget uses for the present queue (uint32_t *) */ - MwVulkanField_PresentQueueIndex, - MwVulkanField_GraphicsQueue, + MwVULKANFIELD_PRESENTQUEUEINDEX, + MwVULKANFIELD_GRAPHICSQUEUE, /*! * @brief The address of the vulkan widget's graphics queue (VkQueue) */ - MwVulkanField_PresentQueue, -} MwVulkanField; + MwVULKANFIELD_PRESENTQUEUE, +}; /*! * @brief Function for getting a field from within Vulkan. - * @warning Consult the documentation for MwVulkanField to know what type is expected for out. + * @warning Consult the documentation for MwVULKANFIELD to know what type is expected for out. */ MwInline void* MwVulkanGetField(MwWidget handle, int field, int* out) { void* field_out; diff --git a/milsko.xml b/milsko.xml index 76d4755e2..2edcd4169 100644 --- a/milsko.xml +++ b/milsko.xml @@ -38,6 +38,10 @@ + + + + @@ -109,24 +113,55 @@ + + + + + + - - - - + + + + + + + + + + + + - - + + + + + + + + + - - - + + + + + + + + + - - + + + + + + @@ -153,9 +188,20 @@ - - 0 - + + 0 + + + + 0 + + + + 1 + + + + 0 diff --git a/src/backend/cocoa.m b/src/backend/cocoa.m index cfac1add0..d9c6382ee 100644 --- a/src/backend/cocoa.m +++ b/src/backend/cocoa.m @@ -347,12 +347,12 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)mouseMoved:(NSEvent*)ev { - MwLLMouse mouse; - NSPoint mousePoint = pointFlip([ev locationInWindow]); - MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mouse.button = MwLLMouseLeft; - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + MwMouse mouse; + NSPoint mousePoint = pointFlip([ev locationInWindow]); + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; MwLLDispatch(this, move, &mouse); [this->cocoa.real nudge]; [super mouseMoved:ev]; @@ -362,51 +362,51 @@ static void recursive_dispatch_key_released(MwLL handle, int* k) { } - (void)mouseDown:(NSEvent*)ev { - MwLLMouse mouse; - NSPoint mousePoint = [ev locationInWindow]; - MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - mouse.button = MwLLMouseLeft; - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); [this->cocoa.real nudge]; [super mouseDown:ev]; } - (void)mouseUp:(NSEvent*)ev { - MwLLMouse mouse; - NSPoint mousePoint = [ev locationInWindow]; - MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - mouse.button = MwLLMouseLeft; - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_LEFT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); [this->cocoa.real nudge]; [super mouseUp:ev]; } - (void)rightMouseDown:(NSEvent*)ev { - MwLLMouse mouse; - NSPoint mousePoint = [ev locationInWindow]; - MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - mouse.button = MwLLMouseRight; - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_RIGHT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; MwLLDispatch(this, down, &mouse); [this->cocoa.real nudge]; [super rightMouseDown:ev]; } - (void)rightMouseUp:(NSEvent*)ev { - MwLLMouse mouse; - NSPoint mousePoint = [ev locationInWindow]; - MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; - mousePoint.y = [[ev window] frame].size.height - mousePoint.y; - mouse.button = MwLLMouseRight; - mouse.point.x = mousePoint.x; - mouse.point.y = mousePoint.y; + MwMouse mouse; + NSPoint mousePoint = [ev locationInWindow]; + MwLL this = [((MilskoFakePointer*)[[self subviews] objectAtIndex:0]) pointer]; + mousePoint.y = [[ev window] frame].size.height - mousePoint.y; + mouse.button = MwMOUSE_RIGHT; + mouse.point.x = mousePoint.x; + mouse.point.y = mousePoint.y; MwLLDispatch(this, up, &mouse); [this->cocoa.real nudge]; [super rightMouseUp:ev]; diff --git a/src/backend/gdi.c b/src/backend/gdi.c index 055b6c26d..024959e9d 100644 --- a/src/backend/gdi.c +++ b/src/backend/gdi.c @@ -79,44 +79,44 @@ static LRESULT CALLBACK wndproc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { EndPaint(hWnd, &ps); } } else if(msg == WM_LBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_RBUTTONDOWN) { - MwLLMouse p; + MwMouse p; p.point.x = LOWORD(lp); p.point.y = HIWORD(lp); if(msg == WM_LBUTTONDOWN) { - p.button = MwLLMouseLeft; + p.button = MwMOUSE_LEFT; } else if(msg == WM_MBUTTONDOWN) { - p.button = MwLLMouseMiddle; + p.button = MwMOUSE_MIDDLE; } else if(msg == WM_RBUTTONDOWN) { - p.button = MwLLMouseRight; + p.button = MwMOUSE_RIGHT; } SetCapture(hWnd); SetFocus(hWnd); MwLLDispatch(u->ll, down, &p); } else if(msg == WM_LBUTTONUP || msg == WM_MBUTTONUP || msg == WM_RBUTTONUP) { - MwLLMouse p; + MwMouse p; p.point.x = LOWORD(lp); p.point.y = HIWORD(lp); if(msg == WM_LBUTTONUP) { - p.button = MwLLMouseLeft; + p.button = MwMOUSE_LEFT; } else if(msg == WM_MBUTTONUP) { - p.button = MwLLMouseMiddle; + p.button = MwMOUSE_MIDDLE; } else if(msg == WM_RBUTTONUP) { - p.button = MwLLMouseRight; + p.button = MwMOUSE_RIGHT; } SetCapture(NULL); MwLLDispatch(u->ll, up, &p); } else if(msg == WM_MOUSEWHEEL) { - int d = GET_WHEEL_DELTA_WPARAM(wp); - MwLLMouse p; + int d = GET_WHEEL_DELTA_WPARAM(wp); + MwMouse p; p.point.x = LOWORD(lp); p.point.y = HIWORD(lp); if(d > 0) { - p.button = MwLLMouseWheelUp; + p.button = MwMOUSE_WHEELUP; } else if(d < 0) { - p.button = MwLLMouseWheelDown; + p.button = MwMOUSE_WHEELDOWN; } MwLLDispatch(u->ll, down, &p); diff --git a/src/backend/wayland.c b/src/backend/wayland.c index fc4a67fc4..31eefb20e 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -119,7 +119,7 @@ static void recursive_dispatch_resize(MwLL handle) { }; /* Recursively dispatch a move event to a widget and its children */ -static void recursive_dispatch_move(MwLL handle, MwLLMouse* p) { +static void recursive_dispatch_move(MwLL handle, MwMouse* p) { MwWidget h = (MwWidget)handle->common.user; if(h) { int i; @@ -282,7 +282,7 @@ static void wl_clipboard_read(wl_clipboard_device_context_t* ctx, int clipboard_ timeout.tv_sec = 0; timeout.tv_usec = 100; - if(clipboard_type == MwClipboardPrimary) { + if(clipboard_type == MwCLIPBOARD_PRIMARY) { zwp_primary_selection_offer_v1_receive(ctx->offer.zwp, "text/plain", fds[1]); } else if(ctx->offer.wl) { wl_data_offer_receive(ctx->offer.wl, "text/plain", fds[1]); @@ -501,7 +501,7 @@ static void pointer_leave(void* data, struct wl_pointer* wl_pointer, MwU32 seria WAYLAND_EVENT_OP_END(self); }; -static void xdg_borderless_step(MwLL self, MwLLMouse p, MwU32 serial) { +static void xdg_borderless_step(MwLL self, MwMouse p, MwU32 serial) { if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL && self->wayland.backbuffer.surface == curSurface) { if(p.point.y >= (self->wayland.wh + CSD_BORDER_FRAME_TOP + CSD_BORDER_FRAME_BOTTOM) - 5) { if(p.point.x >= (self->wayland.ww + CSD_BORDER_FRAME_LEFT + CSD_BORDER_FRAME_RIGHT) - 5) { @@ -535,8 +535,8 @@ static void relative_pointer_motion(void* data, wl_fixed_t dy, wl_fixed_t dxUnaccel, wl_fixed_t dyUnaccel) { - MwLL self = data; - MwLLMouse p; + MwLL self = data; + MwMouse p; WAYLAND_EVENT_OP_START(self); @@ -567,9 +567,9 @@ static void zwp_relative_pointer_manager_v1_interface_destroy(struct _MwLLWaylan /* `wl_pointer.motion` callback */ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time, wl_fixed_t surface_x, wl_fixed_t surface_y) { - MwLL self = data; - MwLL topmost_parent = self; - MwLLMouse p; + MwLL self = data; + MwLL topmost_parent = self; + MwMouse p; (void)time; (void)wl_pointer; @@ -590,9 +590,9 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time /* `wl_pointer.button` callback */ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 serial, MwU32 time, MwU32 button, MwU32 state) { - MwLL self = data; - MwLLMouse p; - MwBool inArea = MwFALSE; + MwLL self = data; + MwMouse p; + MwBool inArea = MwFALSE; (void)wl_pointer; (void)serial; @@ -613,13 +613,13 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri switch(button) { case BTN_LEFT: - p.button = MwLLMouseLeft; + p.button = MwMOUSE_LEFT; break; case BTN_MIDDLE: - p.button = MwLLMouseMiddle; + p.button = MwMOUSE_MIDDLE; break; case BTN_RIGHT: - p.button = MwLLMouseRight; + p.button = MwMOUSE_RIGHT; break; } self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; @@ -1757,7 +1757,7 @@ static void wl_logger(const char* fmt, va_list args) { static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int height, enum _MwLLWaylandType ty) { /* Wayland does not report global coordinates ever. Compositors are not even expected to have knowledge of this. */ - r->common.coordinate_type = MwCoordinatesLocal; + r->common.coordinate_type = MwCOORDINATE_LOCAL; r->common.type = MwLLBackendWayland; @@ -2510,7 +2510,7 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty handle->wayland.clipboard_buffer = malloc(strlen(text)); strcpy(handle->wayland.clipboard_buffer, text); - if(clipboard_type == MwClipboardPrimary) { + if(clipboard_type == MwCLIPBOARD_PRIMARY) { if(handle->wayland.supports_zwp) { for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { wl_clipboard_device_context_t* device = handle->wayland.clipboard_devices_zwp[i]; @@ -2529,7 +2529,7 @@ static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_ty static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { int i; - if(clipboard_type == MwClipboardPrimary) { + if(clipboard_type == MwCLIPBOARD_PRIMARY) { if(handle->wayland.supports_zwp) { for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { wl_clipboard_read( diff --git a/src/backend/x11.c b/src/backend/x11.c index 898da85c0..cc76ed66e 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -694,38 +694,38 @@ static void MwLLNextEventImpl(MwLL handle) { handle->x11.force_render = 0; render = 1; } else if(ev.type == ButtonPress) { - MwLLMouse p; + MwMouse p; p.point.x = ev.xbutton.x; p.point.y = ev.xbutton.y; if(ev.xbutton.button == Button1) { - p.button = MwLLMouseLeft; + p.button = MwMOUSE_LEFT; } else if(ev.xbutton.button == Button2) { - p.button = MwLLMouseMiddle; + p.button = MwMOUSE_MIDDLE; } else if(ev.xbutton.button == Button3) { - p.button = MwLLMouseRight; + p.button = MwMOUSE_RIGHT; } else if(ev.xbutton.button == Button4) { - p.button = MwLLMouseWheelUp; + p.button = MwMOUSE_WHEELUP; } else if(ev.xbutton.button == Button5) { - p.button = MwLLMouseWheelDown; + p.button = MwMOUSE_WHEELDOWN; } XSetInputFocus(handle->x11.display, handle->x11.window, RevertToNone, CurrentTime); MwLLDispatch(handle, down, &p); } else if(ev.type == ButtonRelease) { - MwLLMouse p; + MwMouse p; p.point.x = ev.xbutton.x; p.point.y = ev.xbutton.y; if(ev.xbutton.button == Button1) { - p.button = MwLLMouseLeft; + p.button = MwMOUSE_LEFT; } else if(ev.xbutton.button == Button2) { - p.button = MwLLMouseMiddle; + p.button = MwMOUSE_MIDDLE; } else if(ev.xbutton.button == Button3) { - p.button = MwLLMouseRight; + p.button = MwMOUSE_RIGHT; } else if(ev.xbutton.button == Button4) { - p.button = MwLLMouseWheelUp; + p.button = MwMOUSE_WHEELUP; } else if(ev.xbutton.button == Button5) { - p.button = MwLLMouseWheelDown; + p.button = MwMOUSE_WHEELDOWN; } MwLLDispatch(handle, up, &p); diff --git a/src/core.c b/src/core.c index 0404fa72b..0c8360ef9 100644 --- a/src/core.c +++ b/src/core.c @@ -52,22 +52,23 @@ static void lldrawhandler(MwLL handle, void* data) { } static void lluphandler(MwLL handle, void* data) { - MwWidget h = (MwWidget)handle->common.user; - MwLLMouse* p = data; + MwWidget h = (MwWidget)handle->common.user; + MwMouse* p = data; - if(p->button == MwLLMouseLeft) h->pressed = 0; + if(p->button == MwMOUSE_LEFT) h->pressed = 0; h->mouse_point.x = p->point.x; h->mouse_point.y = p->point.y; - if(p->button == MwLLMouseLeft) MwDispatch(h, click); + if(p->button == MwMOUSE_LEFT) MwDispatch(h, click); MwDispatch3(h, mouse_up, data); MwDispatchUserHandler(h, MwNmouseUpHandler, data); } static void lldownhandler(MwLL handle, void* data) { - MwWidget h = (MwWidget)handle->common.user; - MwLLMouse* p = data; - if(p->button == MwLLMouseLeft) h->pressed = 1; + MwWidget h = (MwWidget)handle->common.user; + MwMouse* p = data; + + if(p->button == MwMOUSE_LEFT) h->pressed = 1; h->mouse_point.x = p->point.x; h->mouse_point.y = p->point.y; @@ -962,7 +963,7 @@ int MwGetCoordinateType(MwWidget handle) { if(handle->parent == NULL || handle->parent->lowlevel == NULL) { return handle->lowlevel->common.coordinate_type; } else { - return MwCoordinatesLocal; + return MwCOORDINATE_LOCAL; } } diff --git a/src/dialog/colorpicker.c b/src/dialog/colorpicker.c index 3b7d33188..c08b53589 100644 --- a/src/dialog/colorpicker.c +++ b/src/dialog/colorpicker.c @@ -160,7 +160,7 @@ static void color_picker_image_update(color_picker_t* picker) { static void color_picker_click(MwWidget handle, void* user, void* call) { color_picker_t* picker = user; - MwLLMouse* mouse = call; + MwMouse* mouse = call; char hexColor[8]; int i; char fgColor[8]; diff --git a/src/dialog/filechooser.c b/src/dialog/filechooser.c index c18027677..ff1683c36 100644 --- a/src/dialog/filechooser.c +++ b/src/dialog/filechooser.c @@ -221,7 +221,7 @@ static void layout(MwWidget handle) { MwNleftPadding, 16, NULL); MwListBoxInsert(fc->nav, -1, p); - MwAddUserHandler(fc->nav, MwNactivateHandler, nav_activate, NULL); + MwAddUserHandler(fc->nav, MwNlistBoxActivateHandler, nav_activate, NULL); MwListBoxDestroyPacket(p); } else { @@ -242,7 +242,7 @@ static void layout(MwWidget handle) { MwNhasHeading, 1, MwNleftPadding, 16, NULL); - MwAddUserHandler(fc->files, MwNactivateHandler, files_activate, NULL); + MwAddUserHandler(fc->files, MwNlistBoxActivateHandler, files_activate, NULL); } else { MwVaApply(fc->files, MwNx, wx, diff --git a/src/widget/combobox.c b/src/widget/combobox.c index c061512d7..4c964f105 100644 --- a/src/widget/combobox.c +++ b/src/widget/combobox.c @@ -89,7 +89,7 @@ static void listbox_activate(MwWidget handle, void* user, void* client) { MwForceRender(handle->parent); - MwDispatchUserHandler(handle->parent, MwNchangedHandler, client); + MwDispatchUserHandler(handle->parent, MwNcomboBoxChangedHandler, client); MwDestroyWidget(handle); } diff --git a/src/widget/entry.c b/src/widget/entry.c index 846dc1979..41b976e83 100644 --- a/src/widget/entry.c +++ b/src/widget/entry.c @@ -113,7 +113,7 @@ static void key(MwWidget handle, int code) { } else if(code == MwLLKeyEnter) { MwDispatchUserHandler(handle, MwNactivateHandler, NULL); } else if(code == (MwLLControlMask | 'v')) { - MwLLGetClipboard(handle->lowlevel, MwClipboardMain); + MwLLGetClipboard(handle->lowlevel, MwCLIPBOARD_MAIN); } else if(!(code & MwLLKeyMask)) { int incr = 0; out = malloc(strlen(str) + 5 + 1); @@ -136,9 +136,9 @@ static void key(MwWidget handle, int code) { #if defined(USE_X11) || defined(USE_WAYLAND) static void mouse_up(MwWidget handle, void* ptr) { if(handle->lowlevel->common.type == MwLLBackendWayland || handle->lowlevel->common.type == MwLLBackendX11) { - MwLLMouse* mouse = ptr; - if(mouse->button == MwLLMouseMiddle) { - MwLLGetClipboard(handle->lowlevel, MwClipboardPrimary); + MwMouse* mouse = ptr; + if(mouse->button == MwMOUSE_MIDDLE) { + MwLLGetClipboard(handle->lowlevel, MwCLIPBOARD_PRIMARY); } } MwForceRender2(handle, NULL); diff --git a/src/widget/listbox.c b/src/widget/listbox.c index 98c86cf97..6f2a9db2a 100644 --- a/src/widget/listbox.c +++ b/src/widget/listbox.c @@ -119,12 +119,12 @@ static void vscroll_changed(MwWidget handle, void* user, void* call) { } static void frame_mouse_down(MwWidget handle, void* user, void* call) { - MwListBox lb = handle->parent->internal; - MwLLMouse* m = call; + MwListBox lb = handle->parent->internal; + MwMouse* m = call; (void)user; - if(m->button == MwLLMouseLeft) { + if(m->button == MwMOUSE_LEFT) { int st = 0; int i; int y = MwDefaultBorderWidth(handle); @@ -140,7 +140,7 @@ static void frame_mouse_down(MwWidget handle, void* user, void* call) { if((((t = MwTimeGetTick()) - lb->click_time) < MwDoubleClickTimeout && old == st + i) || MwGetInteger(handle->parent, MwNsingleClickSelectable)) { int n = MwGetInteger(handle->parent, MwNvalue); - MwDispatchUserHandler(handle->parent, MwNactivateHandler, &n); + MwDispatchUserHandler(handle->parent, MwNlistBoxActivateHandler, &n); } lb->click_time = t; @@ -154,12 +154,12 @@ static void frame_mouse_down(MwWidget handle, void* user, void* call) { } static void frame_mouse_up(MwWidget handle, void* user, void* call) { - MwListBox lb = handle->parent->internal; - MwLLMouse* m = call; + MwListBox lb = handle->parent->internal; + MwMouse* m = call; (void)user; - if(m->button == MwLLMouseLeft) { + if(m->button == MwMOUSE_LEFT) { lb->pressed = 0; } } diff --git a/src/widget/menu.c b/src/widget/menu.c index b66108652..1517591bc 100644 --- a/src/widget/menu.c +++ b/src/widget/menu.c @@ -118,7 +118,7 @@ static void parent_resize(MwWidget handle) { static void mouse_down(MwWidget handle, void* ptr) { MENU_LOOP_DECL; - if(((MwLLMouse*)ptr)->button != MwLLMouseLeft) return; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; BEGIN_MENU_LOOP; if(in_area) { @@ -150,7 +150,7 @@ static void mouse_down(MwWidget handle, void* ptr) { static void mouse_up(MwWidget handle, void* ptr) { MENU_LOOP_DECL; - if(((MwLLMouse*)ptr)->button != MwLLMouseLeft) return; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; BEGIN_MENU_LOOP; if(in_area && m->sub[i]->wsub != NULL) { diff --git a/src/widget/numberentry.c b/src/widget/numberentry.c index 05d590f5c..69ee4c9d5 100644 --- a/src/widget/numberentry.c +++ b/src/widget/numberentry.c @@ -98,7 +98,7 @@ static void mouse_up(MwWidget handle, void* ptr) { int h = MwGetInteger(handle, MwNheight); const char* str = MwGetText(handle, MwNtext); - if(((MwLLMouse*)ptr)->button != MwLLMouseLeft) return; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; if(e->mouse.x >= (w - e->right)) { char s[512]; @@ -116,7 +116,7 @@ static void mouse_up(MwWidget handle, void* ptr) { static void mouse_down(MwWidget handle, void* ptr) { MwEntry e = handle->internal; - if(((MwLLMouse*)ptr)->button != MwLLMouseLeft) return; + if(((MwMouse*)ptr)->button != MwMOUSE_LEFT) return; e->mouse = handle->mouse_point; diff --git a/src/widget/scrollbar.c b/src/widget/scrollbar.c index bed80c0b2..58ed578b2 100644 --- a/src/widget/scrollbar.c +++ b/src/widget/scrollbar.c @@ -170,9 +170,9 @@ static void mouse_down(MwWidget handle, void* ptr) { int wh = MwGetInteger(handle, MwNheight); int or = MwGetInteger(handle, MwNorientation); MwScrollBar scr = handle->internal; - MwLLMouse* m = ptr; + MwMouse* m = ptr; - if(m->button == MwLLMouseWheelUp) { + if(m->button == MwMOUSE_WHEELUP) { int min = MwGetInteger(handle, MwNminValue); int val = MwGetInteger(handle, MwNvalue); int diff = MwGetInteger(handle, MwNareaShown); @@ -184,7 +184,7 @@ static void mouse_down(MwWidget handle, void* ptr) { MwSetInteger(handle, MwNvalue, val); MwSetInteger(handle, MwNchangedBy, -diff); MwDispatchUserHandler(handle, MwNchangedHandler, NULL); - } else if(m->button == MwLLMouseWheelDown) { + } else if(m->button == MwMOUSE_WHEELDOWN) { int max = MwGetInteger(handle, MwNmaxValue); int val = MwGetInteger(handle, MwNvalue); int diff = MwGetInteger(handle, MwNareaShown); @@ -197,7 +197,7 @@ static void mouse_down(MwWidget handle, void* ptr) { MwSetInteger(handle, MwNchangedBy, diff); MwDispatchUserHandler(handle, MwNchangedHandler, NULL); } - if(m->button != MwLLMouseLeft) return; + if(m->button != MwMOUSE_LEFT) return; scr->point = handle->mouse_point; scr->drag = 0; diff --git a/src/widget/submenu.c b/src/widget/submenu.c index f14d6d5f4..c937a9ca4 100644 --- a/src/widget/submenu.c +++ b/src/widget/submenu.c @@ -183,7 +183,7 @@ static void mwSubMenuAppearImpl(MwWidget handle, MwMenu menu, MwPoint* point, in MwLLMakeToolWindow(handle->lowlevel); MwLLDetach(handle->lowlevel, &p); - if(handle->lowlevel->common.coordinate_type == MwCoordinatesGlobal) { + if(handle->lowlevel->common.coordinate_type == MwCOORDINATE_GLOBAL) { if(MwGetInteger(handle, MwNy) + sz.height > rc.height) { MwVaApply(handle, MwNy, rc.height - sz.height, diff --git a/src/widget/treeview.c b/src/widget/treeview.c index 9d3320699..99f12e27e 100644 --- a/src/widget/treeview.c +++ b/src/widget/treeview.c @@ -128,7 +128,7 @@ static void recursion(MwWidget handle, MwTreeViewEntry* tree, MwTreeViewEntry** set_all(root, 0); tree->selected = 1; if(((t = MwTimeGetTick()) - tree->click_time) < MwDoubleClickTimeout || MwGetInteger(handle->parent, MwNsingleClickSelectable)) { - MwDispatchUserHandler(handle->parent, MwNactivateHandler, tree); + MwDispatchUserHandler(handle->parent, MwNtreeViewActivateHandler, tree); } tree->click_time = t; @@ -213,11 +213,11 @@ static int recursive_length(MwTreeViewEntry** e) { static void frame_mouse_down(MwWidget handle, void* user, void* call) { MwTreeView tv = handle->parent->internal; - MwLLMouse* mouse = call; + MwMouse* mouse = call; (void)user; - if(mouse->button == MwLLMouseLeft) tv->pressed = mouse->point; + if(mouse->button == MwMOUSE_LEFT) tv->pressed = mouse->point; } static void resize(MwWidget handle); @@ -227,11 +227,11 @@ static void frame_mouse_up(MwWidget handle, void* user, void* call) { int shared = 0; int skip = MwGetInteger(tv->vscroll, MwNvalue) * (MwGetInteger(tv->vscroll, MwNmaxValue) - MwGetInteger(tv->vscroll, MwNareaShown)) / MwGetInteger(tv->vscroll, MwNmaxValue); MwPoint p; - MwLLMouse* mouse = call; + MwMouse* mouse = call; (void)user; - if(mouse->button == MwLLMouseLeft) { + if(mouse->button == MwMOUSE_LEFT) { int i; p.x = MwDefaultBorderWidth(tv->frame); p.y = MwDefaultBorderWidth(tv->frame); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index e836ac379..0116cb974 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -523,23 +523,23 @@ static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* out) { char buf[1024]; switch(field) { - case MwVulkanField_GetInstanceProcAddr: + case MwVULKANFIELD_GETINSTANCEPROCADDR: return o->vkGetInstanceProcAddr; - case MwVulkanField_Instance: + case MwVULKANFIELD_INSTANCE: return o->vkInstance; - case MwVulkanField_Surface: + case MwVULKANFIELD_SURFACE: return o->vkSurface; - case MwVulkanField_PhysicalDevice: + case MwVULKANFIELD_PHYSICALDEVICE: return o->vkPhysicalDevice; - case MwVulkanField_LogicalDevice: + case MwVULKANFIELD_LOGICALDEVICE: return o->vkLogicalDevice; - case MwVulkanField_GraphicsQueueIndex: + case MwVULKANFIELD_GRAPHICSQUEUEINDEX: return &o->vkGraphicsFamilyIDX; - case MwVulkanField_PresentQueueIndex: + case MwVULKANFIELD_PRESENTQUEUEINDEX: return &o->vkPresentFamilyIDX; - case MwVulkanField_GraphicsQueue: + case MwVULKANFIELD_GRAPHICSQUEUE: return o->vkGraphicsQueue; - case MwVulkanField_PresentQueue: + case MwVULKANFIELD_PRESENTQUEUE: return o->vkPresentQueue; default: MwStringPrintIntoBuffer(buf, 1024, "Unknown vulkan field request (%d given)", field); From 6259f5767793fcdf4c7a25f01e4c44c93ff8bec3 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:39:59 +0900 Subject: [PATCH 400/409] fix cmake --- CMakeLists.txt | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f4eb3ee..948a83c82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,11 +62,6 @@ if(MW_TRY_OPENGL) find_package(OpenGL) if(OpenGL_FOUND) set(MW_BUILD_OPENGL ON) - target_compile_definitions( - Mw - PRIVATE - MW_OPENGL - ) if(APPLE) list(APPEND SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/widget/opengl_cocoa.m") endif() @@ -80,11 +75,6 @@ if(MW_TRY_VULKAN) check_include_files(vulkan/vulkan.h HAVE_VULKAN_VULKAN_H) if(HAVE_VULKAN_VULKAN_H) set(MW_BUILD_VULKAN ON) - target_compile_definitions( - Mw - PRIVATE - MW_VULKAN - ) message(STATUS "Vulkan widget has been enabled") else() message(WARNING "Vulkan widget has been disabled") @@ -363,6 +353,14 @@ target_link_libraries( ${LIBRARIES} ) +if(MW_BUILD_OPENGL) + target_compile_definitions( + Mw + PRIVATE + MW_OPENGL + ) +endif() + if(MW_BUILD_VULKAN) check_include_files(vulkan/vk_enum_string_helper.h HAS_VK_ENUM_STRING_HELPER) if(HAS_VK_ENUM_STRING_HELPER) @@ -372,6 +370,12 @@ if(MW_BUILD_VULKAN) HAS_VK_ENUM_STRING_HELPER ) endif() + + target_compile_definitions( + Mw + PRIVATE + MW_VULKAN + ) endif() target_compile_definitions( From c0e36df063279f116da5d54ccbba12d1c6490075 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:44:17 +0900 Subject: [PATCH 401/409] oops --- milsko.xml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/milsko.xml b/milsko.xml index 2edcd4169..62fb422ad 100644 --- a/milsko.xml +++ b/milsko.xml @@ -694,20 +694,6 @@
- - - - - - - - - - - - - - From d6538d44104be5184fe620f289b44342ffd31803 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:46:47 +0900 Subject: [PATCH 402/409] fix --- include/Mw/Widget/Vulkan.h | 6 +++--- milsko.xml | 2 +- src/widget/vulkan.c | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index ccfb02446..0565022e5 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -111,11 +111,11 @@ enum MwVULKANFIELD { /*! * @brief Function for getting a field from within Vulkan. - * @warning Consult the documentation for MwVULKANFIELD to know what type is expected for out. + * @note Consult the documentation for MwVULKANFIELD to know what type is expected for output. */ -MwInline void* MwVulkanGetField(MwWidget handle, int field, int* out) { +MwInline void* MwVulkanGetField(MwWidget handle, int field, int* err) { void* field_out; - MwVaWidgetExecute(handle, "mwVulkanGetField", &field_out, field, out); + MwVaWidgetExecute(handle, "mwVulkanGetField", &field_out, field, err); return field_out; } diff --git a/milsko.xml b/milsko.xml index 62fb422ad..5d7a6374b 100644 --- a/milsko.xml +++ b/milsko.xml @@ -822,7 +822,7 @@ - + diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index 0116cb974..1e67ea923 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -518,7 +518,7 @@ int MwVulkanSupported(void) { } }; -static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* out) { +static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* err) { vulkan_t* o = handle->internal; char buf[1024]; @@ -544,21 +544,21 @@ static void* mwVulkanGetFieldImpl(MwWidget handle, int field, int* out) { default: MwStringPrintIntoBuffer(buf, 1024, "Unknown vulkan field request (%d given)", field); MwDispatchError(1, buf); - if(out != NULL) { - *out = 1; + if(err != NULL) { + *err = 1; } return NULL; } - if(out != NULL) { - *out = 0; + if(err != NULL) { + *err = 0; } }; -static void func_handler(MwWidget handle, const char* name, void* out, va_list va) { +static void func_handler(MwWidget handle, const char* name, void* output, va_list va) { if(strcmp(name, "mwVulkanGetField") == 0) { int field = va_arg(va, int); int* err = va_arg(va, int*); - *(void**)out = mwVulkanGetFieldImpl(handle, field, err); + *(void**)output = mwVulkanGetFieldImpl(handle, field, err); } } From 9caa50b94d1d774a69355b77191ee1e8e4ea1848 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Fri, 17 Apr 2026 01:52:04 +0900 Subject: [PATCH 403/409] fix enum --- milsko.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/milsko.xml b/milsko.xml index 5d7a6374b..5c8370430 100644 --- a/milsko.xml +++ b/milsko.xml @@ -203,16 +203,16 @@ - - 0 - - - - - - - - + + 0 + + + + + + + + From e41dbd43c13693c2bdc5b4fdb53e34205c357414 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Thu, 16 Apr 2026 13:22:21 -0700 Subject: [PATCH 404/409] fix warnings --- src/backend/wayland.c | 48 ++++++++++--------------------------------- src/backend/x11.c | 2 +- 2 files changed, 12 insertions(+), 38 deletions(-) diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 31eefb20e..c227e9b2d 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -132,34 +132,6 @@ static void recursive_dispatch_move(MwLL handle, MwMouse* p) { } }; -/* Recursively dispatch a key event to a widget and its children */ -static void recursive_dispatch_key(MwLL handle, int* k) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, key, k); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, key, k); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_key(h->children[i]->lowlevel, k); - } - } - } -}; -/* Recursively dispatch a key released event to a widget and its children */ -static void recursive_dispatch_key_released(MwLL handle, int* k) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, key_released, k); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, key_released, k); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_key_released(h->children[i]->lowlevel, k); - } - } - } -}; static void wl_offer(void* data, struct wl_data_offer* wl_data_offer, const char* mime_type) { @@ -538,6 +510,12 @@ static void relative_pointer_motion(void* data, MwLL self = data; MwMouse p; + (void)pointer; + (void)timeHi; + (void)timeLo; + (void)dx; + (void)dy; + WAYLAND_EVENT_OP_START(self); p.point.x = wl_fixed_to_int(dxUnaccel); @@ -609,8 +587,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri inArea |= self->wayland.backbuffer.surface == curSurface; } if(inArea) { - int i; - switch(button) { case BTN_LEFT: p.button = MwMOUSE_LEFT; @@ -741,8 +717,8 @@ static void keyboard_key(void* data, MwU32 time, MwU32 key, MwU32 state) { - MwLL self = data; - MwBool inArea; + MwLL self = data; + MwBool inArea = 0; (void)wl_keyboard; (void)serial; @@ -760,7 +736,7 @@ static void keyboard_key(void* data, if(inArea) { xkb_layout_index_t layout; MwU32 levels; - xkb_level_index_t level; + xkb_level_index_t level = 0; const xkb_keysym_t* syms_out; MwU32 keycode = key + 8; MwU64 syms_num; @@ -785,9 +761,8 @@ static void keyboard_key(void* data, } for(i = 0; i < syms_num; i++) { - int sym = syms_out[i]; - int key = -1; - const char* name; + int sym = syms_out[i]; + int key = -1; switch(sym) { case XKB_KEY_BackSpace: @@ -1975,7 +1950,6 @@ static void MwLLSetWHImpl(MwLL handle, int w, int h) { setup_popup(handle, handle->wayland.x, handle->wayland.y, handle->wayland.parent); } -refresh: region_setup(handle); framebuffer_destroy(&handle->wayland); diff --git a/src/backend/x11.c b/src/backend/x11.c index cc76ed66e..704bd7bd6 100644 --- a/src/backend/x11.c +++ b/src/backend/x11.c @@ -72,7 +72,7 @@ static struct symtbl { char* (*XSetLocaleModifiers)(const char*); XIM (*XOpenIM)(Display*, struct _XrmHashBucketRec*, char*, char*); Status (*XCloseIM)(XIM); - XIC (*XCreateIC)(XIM, ...) _X_SENTINEL(0); + XIC (*XCreateIC)(XIM, ...); void (*XDestroyIC)(XIC); void (*XSetICFocus)(XIC); From 3e49278a154875ce325dd50a40bce85656b02723 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 16 Apr 2026 18:36:42 -0700 Subject: [PATCH 405/409] added wip fuzzer, fixed alot of memory leaks with wayland --- include/Mw/LowLevel/Wayland.h | 14 ++-- src/backend/wayland.c | 122 ++++++++++++++++++---------------- tools/.gitignore | 2 + tools/Makefile | 7 +- tools/fuzzer.c | 85 +++++++++++++++++++++++ 5 files changed, 167 insertions(+), 63 deletions(-) create mode 100644 tools/.gitignore create mode 100644 tools/fuzzer.c diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7debc8872..7f9e7625a 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -41,6 +41,7 @@ typedef struct wayland_call_table { MwBool has_dbus; #endif + int (*wl_display_dispatch)(struct wl_display* display); int (*wl_display_dispatch_pending)(struct wl_display* display); void (*wl_display_disconnect)(struct wl_display* display); void (*wl_display_cancel_read)(struct wl_display* display); @@ -58,6 +59,7 @@ typedef struct wayland_call_table { uint32_t flags, ...); struct wl_display* (*wl_display_connect)(const char* name); uint32_t (*wl_proxy_get_version)(struct wl_proxy* proxy); + struct wl_display* (*wl_display_connect_to_fd)(int fd); struct xkb_context* (*xkb_context_new)(enum xkb_context_flags flags); void (*xkb_context_unref)(struct xkb_context* context); @@ -156,6 +158,7 @@ MwInline int wayland_load_funcs() { return 1; \ }; + WAYLAND_FUNC(wl_display_dispatch) WAYLAND_FUNC(wl_display_dispatch_pending) WAYLAND_FUNC(wl_display_disconnect) WAYLAND_FUNC(wl_display_cancel_read) @@ -170,6 +173,7 @@ MwInline int wayland_load_funcs() { WAYLAND_FUNC(wl_proxy_marshal_flags) WAYLAND_FUNC(wl_display_connect) WAYLAND_FUNC(wl_proxy_get_version) + WAYLAND_FUNC(wl_display_connect_to_fd) #undef WAYLAND_FUNC @@ -235,6 +239,7 @@ MwInline int wayland_load_funcs() { return 0; } +#define wl_display_dispatch wl_call_tbl.wl_display_dispatch #define wl_display_dispatch_pending wl_call_tbl.wl_display_dispatch_pending #define wl_display_disconnect wl_call_tbl.wl_display_disconnect #define wl_display_cancel_read wl_call_tbl.wl_display_cancel_read @@ -249,6 +254,7 @@ MwInline int wayland_load_funcs() { #define wl_proxy_marshal_flags wl_call_tbl.wl_proxy_marshal_flags #define wl_display_connect wl_call_tbl.wl_display_connect #define wl_proxy_get_version wl_call_tbl.wl_proxy_get_version +#define wl_display_connect_to_fd wl_call_tbl.wl_display_connect_to_fd #define xkb_state_unref wl_call_tbl.xkb_state_unref #define xkb_context_new wl_call_tbl.xkb_context_new @@ -373,11 +379,11 @@ enum _MwLLWaylandType { }; typedef struct wl_clipboard_device_context { - union { + struct { struct wl_data_device* wl; struct zwp_primary_selection_device_v1* zwp; } device; - union { + struct { struct wl_data_offer* wl; struct zwp_primary_selection_offer_v1* zwp; } offer; @@ -409,13 +415,13 @@ struct _MwLLWayland { /* Map of Wayland interfaces to their relevant setup functions. */ struct { - const char* key; + char key[255]; wayland_protocol_callback_table_t* value; }* wl_protocol_setup_map; /* Map of Wayland interfaces to any information we keep about them once we've registered them. */ struct { - const char* key; + char key[255]; wayland_protocol_t* value; }* wl_protocol_map; diff --git a/src/backend/wayland.c b/src/backend/wayland.c index c227e9b2d..94bb3da6a 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -62,9 +62,7 @@ static void new_protocol(void* data, struct wl_registry* registry, wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { - char* inter = malloc(strlen(interface) + 1); - strcpy(inter, interface); - shput(self->wayland.wl_protocol_map, inter, cb->setup(name, data)); + shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data)); /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ } else if(strcmp(interface, "wp_alpha_modifier_v1") == 0) { self->common.supports_transparency = MwTRUE; @@ -651,19 +649,24 @@ static void keyboard_keymap(void* data, MwLL self = data; (void)wl_keyboard; - if(self->wayland.type == MWLL_WAYLAND_TOPLEVEL) { + if(!self->wayland.parent) { + char* map_shm; + struct xkb_keymap* xkb_keymap; + struct xkb_state* xkb_state; + xkb_state = NULL; + assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1); - char* map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + map_shm = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); assert(map_shm != MAP_FAILED); - struct xkb_keymap* xkb_keymap = xkb_keymap_new_from_string( + xkb_keymap = xkb_keymap_new_from_string( self->wayland.xkb_context, map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS); munmap(map_shm, size); close(fd); - struct xkb_state* xkb_state = xkb_state_new(xkb_keymap); + xkb_state = xkb_state_new(xkb_keymap); self->wayland.xkb_keymap = xkb_keymap; self->wayland.xkb_state = xkb_state; @@ -976,6 +979,7 @@ static wayland_protocol_t* wl_seat_setup(MwU32 name, MwLL ll) { static void wl_seat_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { (void)wayland; free(data->listener); + free(data); } /* wl_output setup function */ @@ -1120,6 +1124,8 @@ static int event_loop(MwLL handle) { if(wl_display_dispatch_pending(wayland->display) < 0) { wl_display_cancel_read(wayland->display); } + wl_display_flush(handle->wayland.display); + return 1; } @@ -1230,66 +1236,46 @@ static void update_buffer(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { } static void buffer_setup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height) { - int stride = width * 4; - char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; - char temp_name_back[] = "/tmp/milsko-wl-shm-back-XXXXXX"; + int stride = width * 4; + char temp_name[] = "/tmp/milsko-wl-shm-XXXXXX"; buffer->buf_size = width * height * 4; - buffer->fd = mkstemp(temp_name); - buffer->fd_back = mkstemp(temp_name_back); - + buffer->fd = mkstemp(temp_name); unlink(temp_name); - unlink(temp_name_back); if(posix_fallocate(buffer->fd, 0, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); close(buffer->fd); return; } - if(posix_fallocate(buffer->fd_back, 0, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not fallocate. %s.\n", strerror(errno)); - close(buffer->fd_back); - return; - } if(ftruncate(buffer->fd, buffer->buf_size) != 0) { printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); close(buffer->fd); return; } - if(ftruncate(buffer->fd_back, buffer->buf_size) != 0) { - printf("failure setting up wl_shm: could not truncate. %s.\n", strerror(errno)); - close(buffer->fd_back); - return; - } buffer->buf = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd, 0); - buffer->buf_back = mmap(NULL, buffer->buf_size, PROT_WRITE, MAP_SHARED, buffer->fd_back, 0); + buffer->buf_back = malloc(buffer->buf_size); fsync(buffer->fd); - fsync(buffer->fd_back); if(!(buffer->shm_pool = wl_shm_create_pool(buffer->shm, buffer->fd, buffer->buf_size))) { + close(buffer->fd); printf("failure setting up wl_shm: could not create pool.\n"); + return; } - if(!(buffer->shm_pool_back = wl_shm_create_pool(buffer->shm, buffer->fd_back, buffer->buf_size))) { - printf("failure setting up wl_shm: could not create pool.\n"); - } - buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->shm_buffer_back = wl_shm_pool_create_buffer(buffer->shm_pool_back, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); - buffer->setup = MwTRUE; + buffer->shm_buffer = wl_shm_pool_create_buffer(buffer->shm_pool, 0, width, height, stride, WL_SHM_FORMAT_ARGB8888); + buffer->setup = MwTRUE; } static void buffer_destroy(struct _MwLLWaylandShmBuffer* buffer) { - if(!buffer->setup) { - return; - } + close(buffer->fd); + if(buffer->buf) munmap(buffer->buf, buffer->buf_size); + if(buffer->buf_back) free(buffer->buf_back); if(buffer->shm_buffer) wl_buffer_destroy(buffer->shm_buffer); - if(buffer->shm_buffer_back) wl_buffer_destroy(buffer->shm_buffer_back); if(buffer->shm_pool) wl_shm_pool_destroy(buffer->shm_pool); if(buffer->shm_pool_back) wl_shm_pool_destroy(buffer->shm_pool_back); - close(buffer->fd); - close(buffer->fd_back); buffer->setup = MwFALSE; } @@ -1528,12 +1514,12 @@ static void destroy_toplevel(MwLL r) { xdg_toplevel_destroy(r->wayland.toplevel->xdg_top_level); - xkb_keymap_unref(r->wayland.xkb_keymap); - xkb_state_unref(r->wayland.xkb_state); xkb_context_unref(r->wayland.xkb_context); + xkb_keymap_unref(r->wayland.xkb_keymap); + free(r->wayland.toplevel); wl_registry_destroy(r->wayland.registry); @@ -1553,8 +1539,6 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.type = MWLL_WAYLAND_SUBLEVEL; - r->wayland.display = parent->wayland.display; - setup_callbacks(&r->wayland); r->wayland.registry = wl_display_get_registry(parent->wayland.display); @@ -1592,11 +1576,10 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { /* Sublevel setup function */ static void destroy_sublevel(MwLL r) { - backbuffer_destroy(&r->wayland); - framebuffer_destroy(&r->wayland); - wl_subsurface_destroy(r->wayland.sublevel->subsurface); + wl_registry_destroy(r->wayland.registry); + free(r->wayland.sublevel); r->wayland.configured = MwFALSE; @@ -1774,6 +1757,9 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } } + framebuffer_destroy(&r->wayland); + backbuffer_destroy(&r->wayland); + framebuffer_setup(&r->wayland); backbuffer_setup(&r->wayland); @@ -1832,8 +1818,6 @@ static void MwLLDestroyImpl(MwLL handle) { int select_ret; event_loop(handle); - // wl_display_cancel_read(handle->wayland.display); - wl_flush(handle); if(pthread_mutex_timedlock(&handle->wayland.eventsMutex, &t) != 0) { @@ -1859,7 +1843,6 @@ static void MwLLDestroyImpl(MwLL handle) { } #endif - buffer_destroy(&handle->wayland.cursor); wl_region_destroy(handle->wayland.region); if(handle->wayland.supports_zwp) { @@ -1867,10 +1850,6 @@ static void MwLLDestroyImpl(MwLL handle) { } else { wl_data_source_destroy(handle->wayland.clipboard_source.wl); } - if(handle->wayland.icon != NULL) { - buffer_destroy(handle->wayland.icon); - wl_surface_destroy(handle->wayland.icon->surface); - } if(handle->wayland.type == MWLL_WAYLAND_TOPLEVEL) { destroy_toplevel(handle); @@ -1880,6 +1859,20 @@ static void MwLLDestroyImpl(MwLL handle) { destroy_popup(handle); } + if(handle->wayland.framebuffer.setup) { + framebuffer_destroy(&handle->wayland); + wl_surface_destroy(handle->wayland.framebuffer.surface); + } + if(handle->wayland.backbuffer.setup) { + backbuffer_destroy(&handle->wayland); + wl_surface_destroy(handle->wayland.backbuffer.surface); + } + buffer_destroy(&handle->wayland.cursor); + if(handle->wayland.icon != NULL) { + buffer_destroy(handle->wayland.icon); + wl_surface_destroy(handle->wayland.icon->surface); + } + for(i = 0; i < shlen(handle->wayland.wl_protocol_setup_map); i++) { void* ctx = shget(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].key); @@ -1887,17 +1880,30 @@ static void MwLLDestroyImpl(MwLL handle) { handle->wayland.wl_protocol_setup_map[i].value->destroy(&handle->wayland, ctx); } shdel(handle->wayland.wl_protocol_map, handle->wayland.wl_protocol_setup_map[i].value); + free(handle->wayland.wl_protocol_setup_map[i].value); + free(ctx); } shfree(handle->wayland.wl_protocol_map); shfree(handle->wayland.wl_protocol_setup_map); - wl_keyboard_destroy(handle->wayland.keyboard); - wl_pointer_destroy(handle->wayland.pointer); + // wl_keyboard_destroy(handle->wayland.keyboard); + // wl_pointer_destroy(handle->wayland.pointer); + + if(handle->wayland.supports_zwp) { + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_zwp); i++) { + if(handle->wayland.clipboard_devices_zwp[i]->device.zwp) zwp_primary_selection_device_v1_destroy(handle->wayland.clipboard_devices_zwp[i]->device.zwp); + free(handle->wayland.clipboard_devices_zwp[i]); + } + } else { + printf("[WARNING] Primary clipboard requested for MwLLSetClipboard, but this Wayland compositor doesn't support it.\n"); + } + for(i = 0; i < arrlen(handle->wayland.clipboard_devices_wl); i++) { + wl_data_device_destroy(handle->wayland.clipboard_devices_wl[i]->device.wl); + free(handle->wayland.clipboard_devices_wl[i]); + } wl_flush(handle); - // free(handle); - if(currentlyHeldWidget == handle) { currentlyHeldWidget = NULL; } @@ -2159,6 +2165,7 @@ static int MwLLPendingImpl(MwLL handle) { wl_display_cancel_read(handle->wayland.display); } else { wl_display_read_events(handle->wayland.display); + wl_display_flush(handle->wayland.display); if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } @@ -2167,6 +2174,7 @@ static int MwLLPendingImpl(MwLL handle) { if((pending = wl_display_dispatch_pending(handle->wayland.display)) < 0) { wl_display_cancel_read(handle->wayland.display); } + wl_display_flush(handle->wayland.display); } if(MwWaylandAlwaysRender) { @@ -2317,7 +2325,7 @@ static void MwLLSetIconImpl(MwLL handle, MwLLPixmap pixmap) { if(handle->wayland.configured) update_buffer(handle, handle->wayland.icon); - xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer_back, 1); + xdg_toplevel_icon_v1_add_buffer(icon, handle->wayland.icon->shm_buffer, 1); xdg_toplevel_icon_manager_v1_set_icon(icon_manager, handle->wayland.toplevel->xdg_top_level, icon); } diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000000000..0581170fb --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,2 @@ +font +fuzzer diff --git a/tools/Makefile b/tools/Makefile index fbfc51a7d..ef8636836 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -6,7 +6,10 @@ LIBS = `freetype-config --libs` .PHONY: all clean .SUFFIXES: .c .o -all: font +all: fuzzer font + +fuzzer: fuzzer.o + $(CC) -g -L../src/ -Wl,-R../src -lMw -o $@ fuzzer.o font: font.o $(CC) $(LDFLAGS) -o $@ font.o $(LIBS) @@ -15,4 +18,4 @@ font: font.o $(CC) $(CFLAGS) -c -o $@ $< clean: - rm -f *.o font + rm -f *.o font fuzzer diff --git a/tools/fuzzer.c b/tools/fuzzer.c new file mode 100644 index 000000000..5b4224e93 --- /dev/null +++ b/tools/fuzzer.c @@ -0,0 +1,85 @@ +#include + +#define WIDGET_AMOUNT 1 + +int main() { + MwWidget window, widget; + + MwLibraryInit(); + + window = MwCreateWidget(MwWindowClass, "window", NULL, 0, 0, 400, 400); + + while(true) { + int r = rand() % WIDGET_AMOUNT; + MwClass cls; + switch(r) { + case 0: + cls = MwBoxClass; + break; + case 1: + cls = MwButtonClass; + break; + case 2: + cls = MwCheckBoxClass; + break; + case 3: + cls = MwComboBoxClass; + break; + case 4: + cls = MwEntryClass; + break; + case 5: + cls = MwFrameClass; + break; + case 6: + cls = MwImageClass; + break; + case 7: + cls = MwLabelClass; + break; + case 8: + cls = MwListBoxClass; + break; + case 9: + cls = MwMenuClass; + break; + case 10: + cls = MwNumberEntryClass; + break; + case 12: + cls = MwProgressBarClass; + break; + case 13: + cls = MwRadioBoxClass; + break; + case 14: + cls = MwScrollBarClass; + break; + case 15: + cls = MwSeparatorClass; + break; + // case 16: + // cls = MwSubMenuClass; + // break; + case 17: + cls = MwTreeViewClass; + break; + case 18: + cls = MwViewportClass; + break; + default: + cls = NULL; + break; + } + if(cls) { + widget = MwCreateWidget(cls, "Cls", window, 0, 0, 100, 100); + } + + if(MwPending(window)) { + MwStep(window); + } + if(cls) { + MwDestroyWidget(widget); + } + } +} From bc942153fe49630ac10ed85f60ee9bee4683f4b7 Mon Sep 17 00:00:00 2001 From: IoIxD Date: Thu, 16 Apr 2026 22:58:16 -0700 Subject: [PATCH 406/409] cmacos: working? --- CMakeLists.txt | 4 +- include/Mw/LowLevel/ClassicMacOS.h | 9 +- include/Mw/Widget/Vulkan.h | 2 +- src/abstract/dynamic.c | 46 ++++---- src/backend/classicmacos.c | 167 ++++++++++++++++++++++++++--- src/core.c | 6 ++ 6 files changed, 196 insertions(+), 38 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 948a83c82..a6f823d31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,6 +309,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Retro") set_target_properties(Mw PROPERTIES LINK_FLAGS "-Wl,-gc-sections") endif() + list(APPEND LIBRARIES InterfaceLib WindowsLib ThreadsLib) + target_compile_definitions( Mw PRIVATE @@ -354,7 +356,7 @@ target_link_libraries( ) if(MW_BUILD_OPENGL) - target_compile_definitions( + target_compile_definitions( Mw PRIVATE MW_OPENGL diff --git a/include/Mw/LowLevel/ClassicMacOS.h b/include/Mw/LowLevel/ClassicMacOS.h index 4b32f6cd4..958b5e8b1 100644 --- a/include/Mw/LowLevel/ClassicMacOS.h +++ b/include/Mw/LowLevel/ClassicMacOS.h @@ -13,9 +13,12 @@ struct _MwLLClassicMacOS { struct _MwLLCommon common; - WindowRef window; - EventRecord event; - Rect winRect; + MwLL parent; + + WindowRef window; + ControlHandle control; + EventRecord event; + Rect winRect; }; struct _MwLLClassicMacOSColor { diff --git a/include/Mw/Widget/Vulkan.h b/include/Mw/Widget/Vulkan.h index 0565022e5..0b7db3ac8 100644 --- a/include/Mw/Widget/Vulkan.h +++ b/include/Mw/Widget/Vulkan.h @@ -11,7 +11,7 @@ #ifndef __MW_WIDGET_VULKAN_H__ #define __MW_WIDGET_VULKAN_H__ -#if !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#if defined(MW_VULKAN) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) #error Vulkan is unsupported on the requested platform. #endif diff --git a/src/abstract/dynamic.c b/src/abstract/dynamic.c index d9558af6d..ae31e82bf 100644 --- a/src/abstract/dynamic.c +++ b/src/abstract/dynamic.c @@ -14,33 +14,39 @@ void MwDynamicClose(void* handle) { } #elif defined(CLASSIC_MAC_OS) void* MwDynamicOpen(const char* path) { - CFragConnectionID connID; - Ptr* addr; - unsigned char err[255]; + // CFragConnectionID connID; + // Ptr* addr; + // unsigned char err[255]; - if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, - &connID, addr, err)) { - printf("Error getting %s: %s\n", path, err); - return NULL; - }; - return connID; + // if(GetSharedLibrary((ConstStr63Param)path, kPowerPCCFragArch, kPrivateCFragCopy, + // &connID, addr, err)) { + // printf("Error getting %s: %s\n", path, err); + // return NULL; + // }; + // return connID; + printf("MwDynamicOpen not implemented yet.\n"); + getchar(); + return NULL; } void* MwDynamicSymbol(void* handle, const char* symbol) { - CFragConnectionID connID = (CFragConnectionID)handle; - Ptr* symAddr; - CFragSymbolClass* symClass; - OSErr err; - if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { - printf("Error getting %s: %d\n", symbol, err); - return NULL; - }; - return symAddr; + // CFragConnectionID connID = (CFragConnectionID)handle; + // Ptr* symAddr; + // CFragSymbolClass* symClass; + // OSErr err; + // if((err = FindSymbol(connID, (ConstStr63Param)symbol, symAddr, symClass))) { + // printf("Error getting %s: %d\n", symbol, err); + // return NULL; + // }; + // return symAddr; + printf("MwDynamicSymbol not implemented yet.\n"); + getchar(); + return NULL; } void MwDynamicClose(void* handle) { - CFragConnectionID connID = (CFragConnectionID)handle; - CloseConnection(&connID); + // CFragConnectionID connID = (CFragConnectionID)handle; + // CloseConnection(&connID); } #elif defined(__unix__) || defined(__APPLE__) void* MwDynamicOpen(const char* path) { diff --git a/src/backend/classicmacos.c b/src/backend/classicmacos.c index 4fa7ab373..d7db43318 100644 --- a/src/backend/classicmacos.c +++ b/src/backend/classicmacos.c @@ -1,12 +1,24 @@ #include +#include +#include #include "../../external/stb_ds.h" static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; - + r = malloc(sizeof(*r)); + memset(r, 0, sizeof(*r)); MwLLCreateCommon(r); + r->cmacos.parent = parent; + + if(x == MwDEFAULT) { + x = (qd.screenBits.bounds.right / 2) - (width / 2); + } + if(y == MwDEFAULT) { + y = (qd.screenBits.bounds.bottom / 2) - (height / 2); + } + /* todo: how do we set parent windows? If we can't, what is our equivalant to MacOS's NSViews, Wayland's subsurfaces, etc.? */ SetRect(&r->cmacos.winRect, x, y, width, height); r->cmacos.window = newcwindow(nil, &r->cmacos.winRect, "", true, @@ -23,24 +35,26 @@ static void MwLLDestroyImpl(MwLL handle) { } static void MwLLBeginDrawImpl(MwLL handle) { - (void)handle; } static void MwLLEndDrawImpl(MwLL handle) { - (void)handle; } static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLLColor color) { int i; - PolyHandle p = OpenPoly(); + PolyHandle p; RGBColor col; - col.red = color->common.red; - col.green = color->common.green; - col.blue = color->common.blue; + SetPort(handle->cmacos.window); + BeginUpdate(handle->cmacos.window); + + p = OpenPoly(); + col.red = color->common.red * 0x101; + col.green = color->common.green * 0x101; + col.blue = color->common.blue * 0x101; - RGBBackColor(&col); RGBForeColor(&col); + PenMode(patCopy); for(i = 0; i < points_count; i++) { if(i == 0) { @@ -51,20 +65,24 @@ static void MwLLPolygonImpl(MwLL handle, MwPoint* points, int points_count, MwLL } ClosePoly(); - PaintPoly(p); + FillCPoly(p, &qd.ltGray); KillPoly(p); + + EndUpdate(handle->cmacos.window); } static void MwLLLineImpl(MwLL handle, MwPoint* points, MwLLColor color) { RGBColor col; + SetPort(handle->cmacos.window); col.red = color->common.red; col.green = color->common.green; col.blue = color->common.blue; - RGBBackColor(&col); RGBForeColor(&col); + PenMode(patCopy); + MoveTo(points[0].x, points[0].y); LineTo(points[1].x, points[1].y); } @@ -103,10 +121,133 @@ static void MwLLFreeColorImpl(MwLLColor color) { } static int MwLLPendingImpl(MwLL handle) { - return GetNextEvent(everyEvent, &handle->cmacos.event); + YieldToAnyThread(); + return EventAvail(everyEvent, &handle->cmacos.event); } static void MwLLNextEventImpl(MwLL handle) { + EventRecord event; + GetNextEvent(everyEvent, &event); + + switch(event.what) { + case updateEvt: { + } + // MwLLDispatch(handle, draw, NULL); + break; + case osEvt: + break; + case mouseUp: { + // MwLLMouse m; + // m.button = MwLLMouseLeft; + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_RELEASE, mods); + // } + // } + } + case mouseDown: { + // // start with callback stuff + // if(___curWindow->mouseButtonCallback != NULL) { + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // if(___curWindow->keyStateMap[MK_LCTRL] == 1) { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_RIGHT, GLFW_PRESS, mods); + // } else { + // ___curWindow->mouseButtonCallback( + // ___curWindow, GLFW_MOUSE_BUTTON_LEFT, GLFW_PRESS, mods); + // } + // } + + // then do system stuff + switch(FindWindow(event.where, &handle->cmacos.window)) { + case inDrag: + DragWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + // if(___curWindow->windowPosCallback != NULL) { + // ___curWindow->windowPosCallback(___curWindow, event.where.h, + // event.where.v); + // } + break; + case inGrow: { + long growResult = + GrowWindow(handle->cmacos.window, event.where, &qd.screenBits.bounds); + + int width = growResult & 0xFFFF; + int height = growResult >> 16; + + SizeWindow(handle->cmacos.window, growResult & 0xFFFF, growResult >> 16, true); + + Rect rect; + GetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + rect.right = width; + rect.bottom = height; + SetWindowBounds(handle->cmacos.window, kWindowStructureRgn, &rect); + + // ___curWindow->width = width; + // ___curWindow->height = height; + + // if(___curWindow->windowSizeCallback != NULL) { + // ___curWindow->windowSizeCallback(___curWindow, width, height); + // } + // if(___curWindow->windowSetFramebufferSizeCallback != NULL) { + // ___curWindow->windowSetFramebufferSizeCallback(___curWindow, + // width, height); + // } + } break; + + case inGoAway: { + if(TrackGoAway(handle->cmacos.window, event.where)) { + MwLLDispatch(handle, close, NULL); + // if(___curWindow->windowCloseCallback != NULL) { + // ___curWindow->windowCloseCallback(___curWindow); + // } + // ___curWindow->shouldClose = true; + } + } break; + } + } + case autoKey: + case keyDown: + case keyUp: { + // // key char stuff + // unsigned char ch = (event.message & charCodeMask); + // if(*___curWindow->charCallback != NULL) { + // ___curWindow->charCallback(___curWindow, ch); + // } + + // // key state map + // unsigned char key = (event.message & keyCodeMask) >> 8; + // ___curWindow->keyStateMap[key] = 0; + // if(event.what == keyDown || event.what == autoKey) { + // ___curWindow->keyStateMap[key] &= 1; + // } + + // if(*___curWindow->keyCallback != NULL) { + // int key = MacKeyToGLFWKey(event.message); + // int scancode = (event.message & adbAddrMask) >> 16; + + // int mods = MacModifiersToGLFWModifiers(event.modifiers); + + // int action; + // if(event.what == keyUp) { + // action = GLFW_RELEASE; + // } else { + // action = GLFW_PRESS; + // } + // ___curWindow->keyCallback(___curWindow, key, scancode, action, + // mods); + // } + } + } + + FlushEvents(everyEvent, -1); + YieldToAnyThread(); } static void MwLLSetTitleImpl(MwLL handle, const char* title) { @@ -167,14 +308,14 @@ static void MwLLFocusImpl(MwLL handle) { static void MwLLGrabPointerImpl(MwLL handle, int toggle) { } -static void MwLLSetClipboardImpl(MwLL handle, const char* text) { +static void MwLLSetClipboardImpl(MwLL handle, const char* text, int clipboard_type) { /* TODO */ (void)handle; (void)text; } -static void MwLLGetClipboardImpl(MwLL handle) { +static void MwLLGetClipboardImpl(MwLL handle, int clipboard_type) { } static void MwLLMakeToolWindowImpl(MwLL handle) { diff --git a/src/core.c b/src/core.c index 0c8360ef9..6476ccbb6 100644 --- a/src/core.c +++ b/src/core.c @@ -878,6 +878,9 @@ int MwLibraryInit(void) { #endif #ifdef USE_GDI MwLLGDICallInit, +#endif +#ifdef CLASSIC_MAC_OS + MwLLClassicMacOSCallInit, #endif NULL}; int i; @@ -900,6 +903,9 @@ int MwLibraryInit(void) { #endif #ifdef USE_GDI " GDI" +#endif +#ifdef CLASSIC_MAC_OS + " ClassicMacOS" #endif "\n"); From 138555f41d6e12d762390d153ce0a949bd4c31ed Mon Sep 17 00:00:00 2001 From: maelstrom Date: Thu, 16 Apr 2026 23:05:41 +0200 Subject: [PATCH 407/409] auto detect dark theme change via dbus signals --- include/Mw/LowLevel.h | 4 +++ src/backend/wayland.c | 26 +++++++++++++----- src/lowlevel.c | 63 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 7 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index cbc67f9e0..2ba3ff0ba 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -83,11 +83,15 @@ typedef struct _MwLLDBusContext { DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; +typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); + /* setup the dbus func table. Returns false and prints a warning if dbus couldn't be found. */ MWDECL MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl); MWDECL MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out); +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal); +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener); MWDECL void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx); #endif diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 94bb3da6a..566012582 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,6 +17,8 @@ wayland_call_table_t wl_call_tbl; MwBool MwWaylandAlwaysRender = MwFALSE; +MwU32 wl_dark_theme = -1; + /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ do { \ @@ -1779,14 +1781,21 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh } #ifdef USE_DBUS +static void dark_theme_listener(MwLL handle, MwU32 new_value) { + wl_dark_theme = (new_value == 1) ? 1 : 0; + + MwLLDispatch(handle, dark_theme, &wl_dark_theme); +} + static void detect_dark_theme(MwLL handle) { MwU32 value = 0; - MwU32 dark_theme = 0; + MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); + wl_dark_theme = (value == 1) ? 1 : 0; - dark_theme = (value == 1) ? 1 : 0; + MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - MwLLDispatch(handle, dark_theme, &dark_theme); + MwLLDispatch(handle, dark_theme, &wl_dark_theme); } #endif @@ -2144,15 +2153,18 @@ static int MwLLPendingImpl(MwLL handle) { }; int pending = 0; - if(handle->wayland.dark_theme_detection) { - handle->wayland.dark_theme_detection = MwFALSE; #ifdef USE_DBUS - if(wl_call_tbl.has_dbus) { + if(wl_call_tbl.has_dbus) { + if(handle->wayland.dark_theme_detection) { + + handle->wayland.dark_theme_detection = MwFALSE; detect_dark_theme(handle); MwLLDispatch(handle, draw, NULL); + } else { + MwLLDBusPortalPoll(&wl_call_tbl.dbus, &handle->wayland.dbus, handle, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &dark_theme_listener); } -#endif } +#endif if(!handle->wayland.did_initial_resize) { recursive_dispatch_resize(handle); diff --git a/src/lowlevel.c b/src/lowlevel.c index 2a874e6c8..935bf9b3d 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -176,6 +176,69 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwTRUE; } +MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + if(!ctx->dbus_conn) { + return MwFALSE; + } + + char filter_string[2048]; + MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); + + dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + dbus_connection_flush(ctx->dbus_conn); + + return MwTRUE; +} + +// Technically this will swallow all other results, so this is not usable multiple times. +// TODO: Use a hashmap instead +MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { + DBusMessage* msg; + DBusMessageIter args, msg_value; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; + + if(!ctx->dbus_conn) { + return MwFALSE; + } + + dbus_connection_read_write(ctx->dbus_conn, 0); + msg = dbus_connection_pop_message(ctx->dbus_conn); + + if (NULL == msg) { + return MwFALSE; + } + + // check if the message is a signal from the correct interface and with the correct name + if (dbus_message_is_signal(msg, portal, "SettingChanged")) { + // read the parameters + if (!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "[WARNING] Message has no arguments\n"); + else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "[WARNING] Argument is not string\n"); + else { + dbus_message_iter_get_basic(&args, &msg_namespace); + + dbus_message_iter_next(&args); + dbus_message_iter_get_basic(&args, &msg_key); + + // Check that key and namespace match + if (strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + // Assuming the value is a basic type + dbus_message_iter_next(&args); + dbus_message_iter_recurse(&args, &msg_value); + dbus_message_iter_get_basic(&msg_value, &msg_value_content); + + listener(handle, msg_value_content); + } + } + } + + // free the message + dbus_message_unref(msg); +} + void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { if(!tbl->lib) { return; From 30c84a915ac53065bd82cbed4d012ff477d08206 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 17 Apr 2026 09:22:30 +0200 Subject: [PATCH 408/409] minor adjustments for compliance --- include/Mw/LowLevel/Wayland.h | 1 + src/backend/wayland.c | 15 ++++++------- src/lowlevel.c | 42 +++++++++++++++++------------------ 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/include/Mw/LowLevel/Wayland.h b/include/Mw/LowLevel/Wayland.h index 7f9e7625a..a21c0da1e 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -454,6 +454,7 @@ struct _MwLLWayland { #endif MwBool dark_theme_detection; + MwU32 dark_theme; /* clipboard related stuff. * Note that unlike most interfaces, we don't keep zwp_primary_selection stuff in a wayland_protocol_t because we use wl_data_device as a fallback and want to have it share memory space.*/ diff --git a/src/backend/wayland.c b/src/backend/wayland.c index 566012582..a738aa3eb 100644 --- a/src/backend/wayland.c +++ b/src/backend/wayland.c @@ -17,8 +17,6 @@ wayland_call_table_t wl_call_tbl; MwBool MwWaylandAlwaysRender = MwFALSE; -MwU32 wl_dark_theme = -1; - /* Standard procedure before most event callbacks in Wayland ("most" because the setup ones don't need this). Wait for the Mutex to be freed, if we're deadlocking for longer then a quarter of a second then do nothing with the event. */ #define WAYLAND_EVENT_OP_START(self) \ do { \ @@ -1782,20 +1780,20 @@ static void widget_setup(MwLL r, MwLL parent, int x, int y, int width, int heigh #ifdef USE_DBUS static void dark_theme_listener(MwLL handle, MwU32 new_value) { - wl_dark_theme = (new_value == 1) ? 1 : 0; + handle->wayland.dark_theme = (new_value == 1) ? 1 : 0; - MwLLDispatch(handle, dark_theme, &wl_dark_theme); + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); } static void detect_dark_theme(MwLL handle) { - MwU32 value = 0; + MwU32 value = 0; MwLLDBusPortalGet(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings", "org.freedesktop.appearance", "color-scheme", &value); - wl_dark_theme = (value == 1) ? 1 : 0; + handle->wayland.dark_theme = (value == 1) ? 1 : 0; MwLLDBusPortalWatch(&wl_call_tbl.dbus, &handle->wayland.dbus, "org.freedesktop.portal.Settings"); - MwLLDispatch(handle, dark_theme, &wl_dark_theme); + MwLLDispatch(handle, dark_theme, &handle->wayland.dark_theme); } #endif @@ -1811,6 +1809,7 @@ static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { if(!parent && wl_call_tbl.has_dbus) { wl_call_tbl.has_dbus = MwLLDBusNewContext(&wl_call_tbl.dbus, &r->wayland.dbus); r->wayland.dark_theme_detection = MwTRUE; + r->wayland.dark_theme = -1; } #endif @@ -2439,7 +2438,7 @@ static void MwLLShowImpl(MwLL handle, int show) { static void MwLLMakePopupImpl(MwLL handle, MwLL parent) { (void)handle; (void)parent; - /* Wayland doesn't have "popups" in the Milsko sense persay. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ + /* Wayland doesn't have "popups" in the Milsko sense per se. xdg_popup is closer to ToolWindow and as such is what we use there. So just like the Mac backend, this is just left alone. */ } static void MwLLSetSizeHintsImpl(MwLL handle, int minx, int miny, int maxx, int maxy) { diff --git a/src/lowlevel.c b/src/lowlevel.c index 935bf9b3d..32d5bcaca 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -184,48 +184,48 @@ MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - dbus_connection_flush(ctx->dbus_conn); + dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + dbus_connection_flush(ctx->dbus_conn); return MwTRUE; } -// Technically this will swallow all other results, so this is not usable multiple times. -// TODO: Use a hashmap instead +/* Technically this will swallow all other results, so this is not usable multiple times. + TODO: Use a hashmap instead */ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { - DBusMessage* msg; + DBusMessage* msg; DBusMessageIter args, msg_value; - const char* msg_namespace; - const char* msg_key; - MwU32 msg_value_content; + const char* msg_namespace; + const char* msg_key; + MwU32 msg_value_content; if(!ctx->dbus_conn) { return MwFALSE; } - dbus_connection_read_write(ctx->dbus_conn, 0); + dbus_connection_read_write(ctx->dbus_conn, 0); msg = dbus_connection_pop_message(ctx->dbus_conn); - if (NULL == msg) { + if(NULL == msg) { return MwFALSE; } - // check if the message is a signal from the correct interface and with the correct name - if (dbus_message_is_signal(msg, portal, "SettingChanged")) { - // read the parameters - if (!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "[WARNING] Message has no arguments\n"); - else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "[WARNING] Argument is not string\n"); + /* check if the message is a signal from the correct interface and with the correct name */ + if(dbus_message_is_signal(msg, portal, "SettingChanged")) { + /* read the parameters */ + if(!dbus_message_iter_init(msg, &args)) + fprintf(stderr, "[WARNING] Message has no arguments\n"); + else if(DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) + fprintf(stderr, "[WARNING] Argument is not string\n"); else { dbus_message_iter_get_basic(&args, &msg_namespace); dbus_message_iter_next(&args); dbus_message_iter_get_basic(&args, &msg_key); - // Check that key and namespace match - if (strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { - // Assuming the value is a basic type + /* Check that key and namespace match */ + if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { + /* Assuming the value is a basic type */ dbus_message_iter_next(&args); dbus_message_iter_recurse(&args, &msg_value); dbus_message_iter_get_basic(&msg_value, &msg_value_content); @@ -235,7 +235,7 @@ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, M } } - // free the message + /* free the message */ dbus_message_unref(msg); } From d6b96d0f8cca830e09b1a37a551855bd4c90b776 Mon Sep 17 00:00:00 2001 From: maelstrom Date: Fri, 17 Apr 2026 10:05:35 +0200 Subject: [PATCH 409/409] major surgery on dbus code --- include/Mw/LowLevel.h | 7 ++- src/lowlevel.c | 118 +++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 32 deletions(-) diff --git a/include/Mw/LowLevel.h b/include/Mw/LowLevel.h index 2ba3ff0ba..1b5ec5299 100644 --- a/include/Mw/LowLevel.h +++ b/include/Mw/LowLevel.h @@ -66,11 +66,17 @@ typedef struct _MwLLDBusFuncTable { DBusMessage* (*dbus_message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); void (*dbus_message_iter_init_append)(DBusMessage* message, DBusMessageIter* iter); dbus_bool_t (*dbus_message_iter_append_basic)(DBusMessageIter* iter, int type, const void* value); + void (*dbus_connection_flush)(DBusConnection* connection); + dbus_bool_t (*dbus_connection_read_write)(DBusConnection* connection, int timeout_milliseconds); DBusMessage* (*dbus_connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); + DBusMessage* (*dbus_connection_pop_message)(DBusConnection* connection); + void (*dbus_bus_add_match)(DBusConnection* connection, const char* rule, DBusError* error); void (*dbus_message_unref)(DBusMessage* message); dbus_bool_t (*dbus_message_iter_init)(DBusMessage* message, DBusMessageIter* iter); + dbus_bool_t (*dbus_message_is_signal)(DBusMessage* message, const char* iface, const char* signal_name); int (*dbus_message_iter_get_arg_type)(DBusMessageIter* iter); void (*dbus_message_iter_recurse)(DBusMessageIter* iter, DBusMessageIter* sub); + void (*dbus_message_iter_next)(DBusMessageIter* iter); void (*dbus_connection_unref)(DBusConnection* connection); void (*dbus_message_iter_get_basic)(DBusMessageIter* iter, void* value); } MwLLDBusFuncTable; @@ -80,7 +86,6 @@ typedef struct _MwLLDBusContext { DBusError dbus_err; DBusMessage* dbus_msg; DBusMessage* dbus_reply; - DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; } MwLLDBusContext; typedef void (*MwLLDBusPortalPollListener)(MwLL handle, MwU32 new_value); diff --git a/src/lowlevel.c b/src/lowlevel.c index 32d5bcaca..7dfeea169 100644 --- a/src/lowlevel.c +++ b/src/lowlevel.c @@ -82,16 +82,22 @@ MwBool MwLLDBusFuncSetup(MwLLDBusFuncTable* tbl) { DBUS_FUNC(dbus_error_init); DBUS_FUNC(dbus_bus_get); + DBUS_FUNC(dbus_bus_add_match); DBUS_FUNC(dbus_error_is_set); DBUS_FUNC(dbus_error_free); DBUS_FUNC(dbus_message_new_method_call); + DBUS_FUNC(dbus_message_is_signal); DBUS_FUNC(dbus_message_iter_init_append); DBUS_FUNC(dbus_message_iter_append_basic); + DBUS_FUNC(dbus_connection_flush); + DBUS_FUNC(dbus_connection_pop_message); + DBUS_FUNC(dbus_connection_read_write); DBUS_FUNC(dbus_connection_send_with_reply_and_block); DBUS_FUNC(dbus_message_unref); DBUS_FUNC(dbus_message_iter_init); DBUS_FUNC(dbus_message_iter_get_arg_type); DBUS_FUNC(dbus_message_iter_recurse); + DBUS_FUNC(dbus_message_iter_next); DBUS_FUNC(dbus_connection_unref); DBUS_FUNC(dbus_message_iter_get_basic); @@ -121,6 +127,8 @@ MwBool MwLLDBusNewContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) { }; MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal, const char* namespace, const char* key, void* out) { + DBusMessageIter dbus_args, dbus_variant, dbus_inner_variant; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } @@ -135,9 +143,9 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - tbl->dbus_message_iter_init_append(ctx->dbus_msg, &ctx->dbus_args); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &namespace); - tbl->dbus_message_iter_append_basic(&ctx->dbus_args, 's', &key); + tbl->dbus_message_iter_init_append(ctx->dbus_msg, &dbus_args); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &namespace); + tbl->dbus_message_iter_append_basic(&dbus_args, 's', &key); ctx->dbus_reply = tbl->dbus_connection_send_with_reply_and_block(ctx->dbus_conn, ctx->dbus_msg, 100, &ctx->dbus_err); @@ -151,25 +159,35 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co return MwFALSE; } - if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &ctx->dbus_args)) { + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &dbus_args)) { fprintf(stderr, "[WARNING] Couldn't get %s::%s: Reply has no arguments\n", namespace, key); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_args) != 'v') { - fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant\n", namespace, key); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); tbl->dbus_message_unref(ctx->dbus_reply); return MwFALSE; } - tbl->dbus_message_iter_recurse(&ctx->dbus_args, &ctx->dbus_variant); + tbl->dbus_message_iter_recurse(&dbus_args, &dbus_variant); /* Some portals wrap the value in a second variant */ - if(tbl->dbus_message_iter_get_arg_type(&ctx->dbus_variant) == 'v') { - tbl->dbus_message_iter_recurse(&ctx->dbus_variant, &ctx->dbus_inner_variant); - tbl->dbus_message_iter_get_basic(&ctx->dbus_inner_variant, out); + arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_variant); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&dbus_variant, &dbus_inner_variant); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&dbus_inner_variant)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&dbus_inner_variant, out); + } else if (arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&dbus_variant, out); } else { - tbl->dbus_message_iter_get_basic(&ctx->dbus_variant, out); + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; } tbl->dbus_message_unref(ctx->dbus_msg); @@ -177,15 +195,15 @@ MWDECL MwBool MwLLDBusPortalGet(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, co } MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, const char* portal) { + char filter_string[2048]; if(!ctx->dbus_conn) { return MwFALSE; } - char filter_string[2048]; MwStringPrintIntoBuffer(filter_string, sizeof(filter_string), "type='%s',interface=%s", "signal", portal); - dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); - dbus_connection_flush(ctx->dbus_conn); + tbl->dbus_bus_add_match(ctx->dbus_conn, filter_string, &ctx->dbus_err); + tbl->dbus_connection_flush(ctx->dbus_conn); return MwTRUE; } @@ -193,42 +211,79 @@ MWDECL MwBool MwLLDBusPortalWatch(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, /* Technically this will swallow all other results, so this is not usable multiple times. TODO: Use a hashmap instead */ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, MwLL handle, const char* portal, const char* namespace, const char* key, MwLLDBusPortalPollListener listener) { - DBusMessage* msg; - DBusMessageIter args, msg_value; + DBusMessageIter args, msg_value, msg_value_inner; const char* msg_namespace; const char* msg_key; MwU32 msg_value_content; + char arg_type; if(!ctx->dbus_conn) { return MwFALSE; } - dbus_connection_read_write(ctx->dbus_conn, 0); - msg = dbus_connection_pop_message(ctx->dbus_conn); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + tbl->dbus_connection_read_write(ctx->dbus_conn, 0); + ctx->dbus_reply = tbl->dbus_connection_pop_message(ctx->dbus_conn); - if(NULL == msg) { + if(tbl->dbus_error_is_set(&ctx->dbus_err)) { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Poll error: %s\n", portal, ctx->dbus_err.message); + tbl->dbus_error_free(&ctx->dbus_err); + return MwFALSE; + } + if(!ctx->dbus_reply) { return MwFALSE; } /* check if the message is a signal from the correct interface and with the correct name */ - if(dbus_message_is_signal(msg, portal, "SettingChanged")) { + if(tbl->dbus_message_is_signal(ctx->dbus_reply, portal, "SettingChanged")) { /* read the parameters */ - if(!dbus_message_iter_init(msg, &args)) - fprintf(stderr, "[WARNING] Message has no arguments\n"); - else if(DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args)) - fprintf(stderr, "[WARNING] Argument is not string\n"); + if(!tbl->dbus_message_iter_init(ctx->dbus_reply, &args)) + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged has no arguments\n", portal); else { - dbus_message_iter_get_basic(&args, &msg_namespace); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'namespace', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_namespace); - dbus_message_iter_next(&args); - dbus_message_iter_get_basic(&args, &msg_key); + tbl->dbus_message_iter_next(&args); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 's') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 's' (string) for 'key', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&args, &msg_key); /* Check that key and namespace match */ if(strcmp(msg_namespace, namespace) == 0 && strcmp(msg_key, key) == 0) { /* Assuming the value is a basic type */ - dbus_message_iter_next(&args); - dbus_message_iter_recurse(&args, &msg_value); - dbus_message_iter_get_basic(&msg_value, &msg_value_content); + tbl->dbus_message_iter_next(&args); + + if((arg_type = tbl->dbus_message_iter_get_arg_type(&args)) != 'v') { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected outer variant, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_recurse(&args, &msg_value); + + /* Some portals wrap the value in a second variant */ + arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value); + if(arg_type == 'v') { + tbl->dbus_message_iter_recurse(&msg_value, &msg_value_inner); + if((arg_type = tbl->dbus_message_iter_get_arg_type(&msg_value_inner)) != 'u') { + fprintf(stderr, "[WARNING] Signal reply for %s::SettingChanged: Expected 'u' (uint32) for 'value', got: %c\n", portal, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } + tbl->dbus_message_iter_get_basic(&msg_value_inner, &msg_value_content); + } else if (arg_type == 'u') { + tbl->dbus_message_iter_get_basic(&msg_value, &msg_value_content); + } else { + fprintf(stderr, "[WARNING] Couldn't get %s::%s: Expected variant or string, got: %c\n", namespace, key, arg_type); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwFALSE; + } listener(handle, msg_value_content); } @@ -236,7 +291,8 @@ MWDECL MwBool MwLLDBusPortalPoll(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx, M } /* free the message */ - dbus_message_unref(msg); + tbl->dbus_message_unref(ctx->dbus_reply); + return MwTRUE; } void MwLLDBusFreeContext(MwLLDBusFuncTable* tbl, MwLLDBusContext* ctx) {