From 9d65e9c6bf37a21c625a95a43410c030af4fc855 Mon Sep 17 00:00:00 2001 From: IoI_xD Date: Mon, 23 Mar 2026 12:05:32 -0700 Subject: [PATCH] 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 384cbc6..57d5792 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 0e1842d..29547ce 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 9659ac5..00556da 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 0a21590..2e32ced 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 591258f..6b54373 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 b78e742..e2dfa4c 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;