diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ec1ed85..d072daf3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -261,7 +261,6 @@ if(MW_USE_WAYLAND) scan_wayland_protocol("unstable" "primary-selection" "-unstable-v1") scan_wayland_protocol("unstable" "pointer-constraints" "-unstable-v1") scan_wayland_protocol("unstable" "relative-pointer" "-unstable-v1") - scan_wayland_protocol("staging" "fifo" "-v1") scan_wayland_protocol_from_file("wlr-layer-shell" "wlr-layer-shell-unstable-v1.xml") target_sources( @@ -270,6 +269,7 @@ if(MW_USE_WAYLAND) src/backend/cairo.c src/backend/wayland/wayland.c src/backend/wayland/buffer.c + src/backend/wayland/hyprland.c src/backend/wayland/interfaces.c src/backend/wayland/region.c ) diff --git a/examples/vkdemos/vulkan.c b/examples/vkdemos/vulkan.c index 60154152..9060a970 100644 --- a/examples/vkdemos/vulkan.c +++ b/examples/vkdemos/vulkan.c @@ -257,8 +257,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 5e43c34d..0f570e32 100644 --- a/include/Mw/LowLevel/Wayland.h +++ b/include/Mw/LowLevel/Wayland.h @@ -207,7 +207,6 @@ MwInline int wayland_load_funcs() { #include "Wayland/relative-pointer-client-protocol.h" #include "Wayland/xdg-toplevel-icon-client-protocol.h" #include "Wayland/wlr-layer-shell-client-protocol.h" -#include "Wayland/fifo-client-protocol.h" #endif typedef struct wayland_protocol { @@ -239,6 +238,8 @@ struct _MwLLWaylandTopLevel { }; struct _MwLLWaylandSublevel { + struct wl_subsurface* subsurface; + struct wl_subcompositor* subcompositor; MwLL parent; @@ -267,7 +268,6 @@ struct _MwLLWaylandShmBuffer { struct wl_buffer* shm_buffer_back; struct wl_surface* surface; struct wl_output* output; - struct wp_fifo_v1* fifo; MwU8* buf; MwU8* buf_back; @@ -414,7 +414,7 @@ struct _MwLLWayland { MwI32 ox, oy; MwU32 ww, wh; /* Window position */ MwPoint cur_mouse_pos; /* Currently known mouse position */ - MwLL* currentlyHeldWidgets; + MwLL currentlyHeldWidget; MwLL focusedWidget; int resizing; @@ -426,8 +426,6 @@ struct _MwLLWayland { MwBool force_render; MwBool did_event_loop_early; - MwBool do_cascading_draw; - int cascading_child_num; MwBool dispatching_resize; @@ -437,8 +435,6 @@ struct _MwLLWayland { struct _MwLLWaylandShmBuffer backbuffer; struct _MwLLWaylandShmBuffer cursor; struct _MwLLWaylandShmBuffer* icon; - MwBool fifo_wait; - MwBool disable_fifo; MwLLPixmap icon_pixmap; @@ -458,6 +454,8 @@ struct _MwLLWayland { MwU64 next_elapsed; long start_time; long end_time; + + MwBool on_hyprland; }; struct _MwLLWaylandColor { @@ -476,17 +474,6 @@ void MwLLWaylandBackbufferSetup(struct _MwLLWayland* wayland); /* Destroy the backbuffer */ void MwLLWaylandBackbufferDestroy(struct _MwLLWayland* handle); -/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ -void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer); -/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ -void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer); -/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ -void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer); - -#ifdef MW_VULKAN -#warning Wayland backend currently disabled by default when Vulkan enabled. Use with caution (MW_BACKEND=wayland to override). -#endif - void MwLLWaylandBufferSetup(struct _MwLLWaylandShmBuffer* buffer, MwU32 width, MwU32 height); void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer); void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer); @@ -503,7 +490,6 @@ void MwLLWaylandHangUntilConfigured(MwLL handle); MwBool MwLLWaylandWidgetIsDestroyed(MwLL self); void MwLLWaylandWidgetUndestroy(MwLL self); -void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)); /* Function for setting up the callbacks/structs that will be registered upon the relevant interfaces being found. */ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland); @@ -513,8 +499,6 @@ void MwLLWaylandClipboardRead(wl_clipboard_device_context_t* ctx, int clipboard_ /* Flush Wayland events */ void MwLLWaylandFlush(MwLL handle); -void MwLLWaylandCascadeChildren(MwLL handle); - /* Standard procedure before event callbacks in Wayland */ #define WAYLAND_EVENT_OP_START(self) \ if(MwLLWaylandWidgetIsDestroyed(self)) { \ diff --git a/pl/rules.pl b/pl/rules.pl index 6c4df63f..80f930d9 100644 --- a/pl/rules.pl +++ b/pl/rules.pl @@ -49,6 +49,7 @@ if (grep(/^wayland$/, @backends)) { new_object("src/backend/cairo.c"); new_object("src/backend/wayland/wayland.c"); new_object("src/backend/wayland/buffer.c"); + new_object("src/backend/wayland/hyprland.c"); new_object("src/backend/wayland/interfaces.c"); new_object("src/backend/wayland/region.c"); @@ -66,7 +67,6 @@ if (grep(/^wayland$/, @backends)) { scan_wayland_protocol("unstable", "primary-selection", "-unstable-v1"); scan_wayland_protocol("unstable", "pointer-constraints", "-unstable-v1"); scan_wayland_protocol("unstable", "relative-pointer", "-unstable-v1"); - scan_wayland_protocol("staging", "fifo", "-v1"); scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml"); $gl_libs = "-lGL -lGLU"; diff --git a/src/backend/cairo.c b/src/backend/cairo.c index d70de1b9..65380fba 100644 --- a/src/backend/cairo.c +++ b/src/backend/cairo.c @@ -212,8 +212,8 @@ static void MwLLFreeColorImpl(MwLLColor color) {} static MwBool lmao = MwFALSE; static int MwLLPendingImpl(MwLL handle) { - lmao = !lmao; - return lmao; + lmao = !lmao; + return lmao; } static void MwLLNextEventImpl(MwLL handle) { MwLLDispatch(handle, draw, NULL); @@ -257,10 +257,10 @@ static void MwLLRaiseImpl(MwLL handle) {} static void MwLLClipImpl(MwLL handle, MwRect* rect) {} static void MwLLSetupDragAndDropImpl(MwLL handle) {} static int MwLLCairoCallInitImpl(void) { - if(cairo_load_funcs() != 0) { - return 1; - } - return 0; + if(cairo_load_funcs() != 0) { + return 1; + } + return 0; } #include "call.c" CALL(Cairo); diff --git a/src/backend/wayland/buffer.c b/src/backend/wayland/buffer.c index 3ee5e3ca..df1de797 100644 --- a/src/backend/wayland/buffer.c +++ b/src/backend/wayland/buffer.c @@ -1,39 +1,5 @@ #include #include -#include "../../../external/stb_ds.h" - -/* Bind a wp_fifo_v1 object to `buffer`'s surface, if wp_fifo_manager_v1 is available and it doesn't have one already. */ -void MwLLWaylandFifoSurfaceSetup(struct _MwLLWayland* wayland, struct _MwLLWaylandShmBuffer* buffer) { - wayland_protocol_t* fifo_manager; - - if(buffer->fifo || !buffer->surface) { - return; - } - - fifo_manager = shget(wayland->wl_protocol_map, wp_fifo_manager_v1_interface.name); - if(!fifo_manager) { - return; - } - - buffer->fifo = wp_fifo_manager_v1_get_fifo(fifo_manager->context, buffer->surface); -} - -/* Destroy `buffer`'s wp_fifo_v1 object, if any. */ -void MwLLWaylandFifoSurfaceDestroy(struct _MwLLWaylandShmBuffer* buffer) { - if(buffer->fifo) { - wp_fifo_v1_destroy(buffer->fifo); - buffer->fifo = NULL; - } -} - -/* Commit `buffer`'s surface, constraining the update to the next display refresh via wp_fifo_v1 if bound. */ -void MwLLWaylandFifoCommit(struct _MwLLWaylandShmBuffer* buffer) { - if(buffer->fifo) { - wp_fifo_v1_set_barrier(buffer->fifo); - wp_fifo_v1_wait_barrier(buffer->fifo); - } - wl_surface_commit(buffer->surface); -} void MwLLWaylandFramebufferSetup(struct _MwLLWayland* wayland) { MwLLWaylandBufferSetup(&wayland->framebuffer, wayland->ww, wayland->wh); diff --git a/src/backend/wayland/hyprland.c b/src/backend/wayland/hyprland.c new file mode 100644 index 00000000..e6c86790 --- /dev/null +++ b/src/backend/wayland/hyprland.c @@ -0,0 +1,60 @@ +#include + +int MwLLWaylandDoRoundness(MwLL handle) { + if(handle->common.type == MwLLBackendWayland) { + return handle->wayland.on_hyprland; + } else { + return 0; + }; +}; + +int MwLLWaylandHyprlandGetRoundness(void) { + char* home = getenv("HOME"); + int fallback = 20; + char path[PATH_MAX]; + int roundness = fallback; + char line[512]; + FILE* f = NULL; + + if(home == NULL) { + return fallback; + } + + snprintf(path, sizeof(path), "%s/.config/hypr/hyprland.lua", home); + + f = fopen(path, "r"); + if(f == NULL) { + return fallback; + } + + while(fgets(line, sizeof(line), f) != NULL) { + char* key = strstr(line, "roundness"); + char* eq; + char* end; + long value; + + if(key == NULL) { + continue; + } + + eq = strchr(key, '='); + if(eq == NULL) { + continue; + } + eq++; + + while(*eq != '\0' && isspace((unsigned char)*eq)) { + eq++; + } + + value = strtol(eq, &end, 10); + if(end == eq) { + continue; + } + + roundness = (int)value; + } + + fclose(f); + return roundness; +} diff --git a/src/backend/wayland/interfaces.c b/src/backend/wayland/interfaces.c index 9ce42611..a7245912 100644 --- a/src/backend/wayland/interfaces.c +++ b/src/backend/wayland/interfaces.c @@ -19,35 +19,6 @@ static void setup_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_clipboard(MwLL self, struct wl_seat* wl_seat); static void destroy_zwp_clipboard(MwLL self, struct wl_seat* wl_seat); -/* 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); - } - } - } -}; - /* Recursively dispatch a move event to a widget and its children */ static void recursive_dispatch_move(MwLL handle, MwMouse* p) { MwWidget h = (MwWidget)handle->common.user; @@ -69,15 +40,19 @@ static void new_protocol(void* data, struct wl_registry* registry, MwLL self = data; (void)version; (void)registry; + wayland_protocol_callback_table_t* cb; WAYLAND_EVENT_OP_START(self); - wayland_protocol_callback_table_t* cb = shget(self->wayland.wl_protocol_setup_map, interface); + cb = shget(self->wayland.wl_protocol_setup_map, interface); if(cb != NULL) { shput(self->wayland.wl_protocol_map, interface, cb->setup(name, data, version)); - /* 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) { + /* we don't care for adding this protocol, we just use it to know if the compositor will let us have transparent surfaces */ self->common.supports_transparency = MwTRUE; + } else if(strstr(interface, "hyprland") != NULL) { + /* we have nothing to make use of with hyprland, we just want to check if we're running under it. */ + self->wayland.on_hyprland = MwTRUE; } else { // printf("unknown interface %s\n", interface); } @@ -560,9 +535,8 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time MwLL self = data; MwLL topmost_parent = self; MwMouse p; - MwBool inArea = MwFALSE; - MwLL* currentlyHeldWidgets = NULL; - int i; + MwBool inArea = MwFALSE; + MwLL currentlyHeldWidget = NULL; (void)time; (void)wl_pointer; @@ -570,7 +544,7 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time WAYLAND_EVENT_OP_START(self); while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - currentlyHeldWidgets = topmost_parent->wayland.currentlyHeldWidgets; + currentlyHeldWidget = topmost_parent->wayland.currentlyHeldWidget; if(self->wayland.framebuffer.surface) { inArea |= self->wayland.framebuffer.surface == curSurface; @@ -582,128 +556,30 @@ static void pointer_motion(void* data, struct wl_pointer* wl_pointer, MwU32 time self->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); self->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + if(currentlyHeldWidget != NULL) { + currentlyHeldWidget->wayland.cur_mouse_pos.x = wl_fixed_to_int(surface_x); + currentlyHeldWidget->wayland.cur_mouse_pos.y = wl_fixed_to_int(surface_y); + } if(inArea) { p.point = self->wayland.cur_mouse_pos; MwLLDispatch(self, move, &p); + wl_pointer_set_cursor(self->wayland.pointer, self->wayland.pointer_serial, self->wayland.cursor.surface, 0, 0); + } else if(currentlyHeldWidget == self) { + p.point = currentlyHeldWidget->wayland.cur_mouse_pos; + MwLLDispatch(currentlyHeldWidget, move, &p); } - for(i = 0; i < arrlen(currentlyHeldWidgets); i++) { - MwLL new_topmost = currentlyHeldWidgets[i]; - p.point = topmost_parent->wayland.cur_mouse_pos; - while(new_topmost->wayland.parent) { - p.point.x -= new_topmost->wayland.x; - p.point.y -= new_topmost->wayland.y; - new_topmost = new_topmost->wayland.parent; - } - - MwLLDispatch(currentlyHeldWidgets[i], move, &p); - } - - MwLLWaylandCascadeChildren(self); WAYLAND_EVENT_OP_END(self); }; -static void recursive_dispatch_mouse_down(MwLL handle, MwMouse* p) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, down, p); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, down, p); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_mouse_down(h->children[i]->lowlevel, p); - } - } - } -}; -static void recursive_dispatch_mouse_up(MwLL handle, MwMouse* p) { - MwWidget h = (MwWidget)handle->common.user; - MwLLDispatch(handle, up, p); - if(h) { - int i; - for(i = 0; i < arrlen(h->children); i++) { - MwLLDispatch(h->children[i]->lowlevel, up, p); - if(arrlen(h->children[i]->children) > 0) { - recursive_dispatch_mouse_up(h->children[i]->lowlevel, p); - } - } - } -}; - -static void mouse_dispatch(MwLL self, MwMouse p, MwU32 state) { - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - MwLLDispatch(self, down, &p); - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - MwLLDispatch(self, up, &p); - break; - } - - if(self->common.user) { - MwWidget w = self->common.user; - int i, n; - for(i = 0; i < arrlen(w->children); i++) { - if(w->children[i]->lowlevel->wayland.type == MwLL_WAYLAND_SUBLEVEL) { - MwLL child = w->children[i]->lowlevel; - MwLL topmost_parent = child; - MwPoint point; - MwPoint relative_mouse_pos; - MwPoint absolute_pos; - - absolute_pos.x = child->wayland.x; - absolute_pos.y = child->wayland.y; - while(topmost_parent->wayland.parent) { - topmost_parent = topmost_parent->wayland.parent; - if(topmost_parent) { - absolute_pos.x += topmost_parent->wayland.x; - absolute_pos.y += topmost_parent->wayland.y; - } - } - - point = topmost_parent->wayland.cur_mouse_pos; - relative_mouse_pos.x = point.x - absolute_pos.x; - relative_mouse_pos.y = point.y - absolute_pos.y; - - if( - point.x >= absolute_pos.x && point.x <= absolute_pos.x + child->wayland.ww && - point.y >= absolute_pos.y && point.y <= absolute_pos.y + child->wayland.wh) { - int idx = -1; - for(n = 0; n < arrlen(topmost_parent->wayland.currentlyHeldWidgets); n++) { - if(topmost_parent->wayland.currentlyHeldWidgets[n] == child) { - idx = n; - } - } - p.point = relative_mouse_pos; - - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - if(idx == -1) { - arrpush(topmost_parent->wayland.currentlyHeldWidgets, child); - } - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - if(idx != -1) { - arrdel(topmost_parent->wayland.currentlyHeldWidgets, idx); - } - break; - } - - mouse_dispatch(child, p, state); - } - } - } - } -} - /* `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; MwMouse p; + MwBool inArea = MwFALSE; MwLL topmost_parent = self; - int i; (void)wl_pointer; (void)serial; @@ -711,35 +587,48 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri WAYLAND_EVENT_OP_START(self); + p.point = self->wayland.cur_mouse_pos; while(topmost_parent->wayland.parent) topmost_parent = topmost_parent->wayland.parent; - p.point = self->wayland.cur_mouse_pos; + if(self->wayland.framebuffer.surface) { + inArea |= self->wayland.framebuffer.surface == curSurface; + } + if(self->wayland.backbuffer.surface) { + inArea |= self->wayland.backbuffer.surface == curSurface; + } + if(inArea) { + switch(button) { + case BTN_LEFT: + p.button = MwMOUSE_LEFT; + break; + case BTN_MIDDLE: + p.button = MwMOUSE_MIDDLE; + break; + case BTN_RIGHT: + p.button = MwMOUSE_RIGHT; + break; + } + self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - switch(button) { - case BTN_LEFT: - p.button = MwMOUSE_LEFT; - break; - case BTN_MIDDLE: - p.button = MwMOUSE_MIDDLE; - break; - case BTN_RIGHT: - p.button = MwMOUSE_RIGHT; - break; - } - self->wayland.held_down = state == WL_POINTER_BUTTON_STATE_PRESSED; - switch(state) { - case WL_POINTER_BUTTON_STATE_PRESSED: - MwLLDispatch(self, down, &p); - break; - case WL_POINTER_BUTTON_STATE_RELEASED: - MwLLDispatch(self, up, &p); - break; - } + switch(state) { + case WL_POINTER_BUTTON_STATE_PRESSED: + if(button == BTN_LEFT) { + topmost_parent->wayland.focusedWidget = self; + } + MwLLDispatch(self, down, &p); + topmost_parent->wayland.currentlyHeldWidget = self; - for(i = 0; i < arrlen(self->wayland.currentlyHeldWidgets); i++) { - arrdel(self->wayland.currentlyHeldWidgets, i); + break; + case WL_POINTER_BUTTON_STATE_RELEASED: + if(topmost_parent->wayland.currentlyHeldWidget != NULL) { + MwLLDispatch(topmost_parent->wayland.currentlyHeldWidget, up, &p); + topmost_parent->wayland.currentlyHeldWidget = NULL; + } else { + MwLLDispatch(self, up, &p); + } + break; + } } - mouse_dispatch(self, p, state); if(!self->wayland.has_decorations && self->wayland.do_csd) { if(state != WL_POINTER_BUTTON_STATE_RELEASED) @@ -748,8 +637,6 @@ static void pointer_button(void* data, struct wl_pointer* wl_pointer, MwU32 seri xdg_borderless_step_mup(self, p, serial); } - MwLLForceRender(self); - WAYLAND_EVENT_OP_END(self); }; @@ -952,11 +839,15 @@ static void keyboard_key(void* data, if(key != -1) { if(state == WL_KEYBOARD_KEY_STATE_PRESSED) { - recursive_dispatch_key(self, &key); + MwLL topmost_parent = self; + while(topmost_parent->wayland.parent) { + MwLLDispatch(topmost_parent, key, &key); + topmost_parent = topmost_parent->wayland.parent; + } self->wayland.holding_key = MwTRUE; self->wayland.last_pressed_key = key; } else { - recursive_dispatch_key_released(self, &key); + MwLLDispatch(self, key_released, &key); self->wayland.holding_key = MwFALSE; } self->wayland.start_time = MwTimeGetTick(); @@ -1169,7 +1060,7 @@ static wayland_protocol_t* wl_subcompositor_setup(MwU32 name, struct _MwLLWaylan 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); + wayland->sublevel->subcompositor = wl_registry_bind(wayland->registry, name, &wl_subcompositor_interface, 1); } return NULL; @@ -1180,7 +1071,7 @@ static void wl_subcompositor_interface_destroy(struct _MwLLWayland* wayland, way if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { wl_subcompositor_destroy(wayland->toplevel->scompositor); } else { - // wl_subcompositor_destroy(wayland->sublevel->subcompositor); + wl_subcompositor_destroy(wayland->sublevel->subcompositor); } } @@ -1218,24 +1109,6 @@ static void wp_viewporter_interface_destroy(struct _MwLLWayland* wayland, waylan (void)data; } -/* wp_fifo_manager_v1 setup function */ -static wayland_protocol_t* wp_fifo_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { - wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); - (void)version; - proto->listener = NULL; - proto->context = wl_registry_bind(wayland->registry, name, &wp_fifo_manager_v1_interface, 1); - - return proto; -} - -static void wp_fifo_manager_v1_interface_destroy(struct _MwLLWayland* wayland, wayland_protocol_t* data) { - (void)wayland; - if(data->context) { - wp_fifo_manager_v1_destroy(data->context); - } - free(data); -} - /* zxdg_decoration_manager_v1 setup function */ static wayland_protocol_t* zxdg_decoration_manager_v1_setup(MwU32 name, struct _MwLLWayland* wayland, MwU32 version) { wayland_protocol_t* proto = malloc(sizeof(wayland_protocol_t)); @@ -1332,27 +1205,23 @@ void MwLLWaylandSetupCallbacks(struct _MwLLWayland* wayland) { WL_INTERFACE(wl_shm); 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); WL_INTERFACE(zwp_pointer_constraints_v1); WL_INTERFACE(zwp_relative_pointer_manager_v1); WL_INTERFACE(xdg_wm_base); - WL_INTERFACE(wp_fifo_manager_v1); WL_INTERFACE(zwlr_layer_shell_v1); /* Only used for layer surface, but we use it always if it's turned into a tool window */ if(wayland->type == MwLL_WAYLAND_TOPLEVEL) { WL_INTERFACE(wp_viewporter); WL_INTERFACE(zxdg_decoration_manager_v1); WL_INTERFACE(xdg_toplevel_icon_manager_v1); WL_INTERFACE(wl_subcompositor); - WL_INTERFACE(wl_seat); } else if(wayland->type == MwLL_WAYLAND_POPUP) { - WL_INTERFACE(wl_seat); } else if(wayland->type == MwLL_WAYLAND_LAYER_SURFACE) { WL_INTERFACE(wp_viewporter); WL_INTERFACE(wl_subcompositor); - WL_INTERFACE(wl_seat); - WL_INTERFACE(wl_seat); } else { WL_INTERFACE(wl_subcompositor); } diff --git a/src/backend/wayland/wayland.c b/src/backend/wayland/wayland.c index 433001b5..82c053ea 100644 --- a/src/backend/wayland/wayland.c +++ b/src/backend/wayland/wayland.c @@ -45,19 +45,6 @@ void MwLLWaylandWidgetUndestroy(MwLL self) { return; } -void MwLLWaylandChildrenIterate(MwLL handle, void (*func)(MwLL handle, MwLL child)) { - 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; - func(handle, child); - } - } - } -} - static int event_loop(MwLL handle); /* Recursively dispatch a resize event to a widget and its children */ @@ -259,11 +246,7 @@ void MwLLWaylandBufferUpdate(MwLL self, struct _MwLLWaylandShmBuffer* buffer) { // Yes this is needed every time, it's how we fix weston. if(self->wayland.configured) wl_surface_attach(buffer->surface, buffer->shm_buffer, 0, 0); - if(self->wayland.fifo_wait) { - MwLLWaylandFifoCommit(buffer); - } else { - wl_surface_commit(buffer->surface); - } + wl_surface_commit(buffer->surface); } } } @@ -312,9 +295,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.backbuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.backbuffer); - r->wayland.toplevel->ssurface = wl_subcompositor_get_subsurface(r->wayland.toplevel->scompositor, r->wayland.framebuffer.surface, r->wayland.backbuffer.surface); + 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 = @@ -389,8 +370,18 @@ static void destroy_toplevel(MwLL r) { wl_pointer_destroy(r->wayland.pointer); wl_keyboard_destroy(r->wayland.keyboard); - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - MwLLWaylandFifoSurfaceDestroy(&r->wayland.backbuffer); + if(r->common.user) { + MwWidget w = r->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; + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + child->wayland.sublevel->subsurface = NULL; + } + } + } + wl_surface_destroy(r->wayland.framebuffer.surface); free(r->wayland.toplevel); @@ -429,7 +420,15 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { } r->wayland.framebuffer.surface = wl_compositor_create_surface(compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); + + 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); + + if(parent) { + wl_subsurface_place_above(r->wayland.sublevel->subsurface, parent->wayland.framebuffer.surface); + } r->wayland.xkb_keymap = parent->wayland.xkb_keymap; r->wayland.xkb_state = parent->wayland.xkb_state; @@ -437,6 +436,7 @@ static void setup_sublevel(MwLL parent, MwLL r, int x, int y) { r->wayland.configured = MwTRUE; MwLLWaylandFramebufferSetup(&r->wayland); + MwLLWaylandBackbufferSetup(&r->wayland); } /* Sublevel setup function */ @@ -444,6 +444,8 @@ static void destroy_sublevel(MwLL r) { MwLLWaylandBackbufferDestroy(&r->wayland); MwLLWaylandFramebufferDestroy(&r->wayland); + wl_subsurface_destroy(r->wayland.sublevel->subsurface); + free(r->wayland.sublevel); r->wayland.configured = MwFALSE; @@ -554,7 +556,6 @@ static void setup_popup(MwLL r, int x, int y, MwLL parent) { r->wayland.xkb_state = topmost_parent->wayland.xkb_state; r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.popup->xdg_surface = xdg_wm_base_get_xdg_surface(WAYLAND_GET_INTERFACE(r->wayland, xdg_wm_base)->context, r->wayland.framebuffer.surface); @@ -596,8 +597,6 @@ static void destroy_popup(MwLL r) { xdg_positioner_destroy(r->wayland.popup->xdg_positioner); - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - wl_surface_destroy(r->wayland.framebuffer.surface); wl_registry_destroy(r->wayland.registry); @@ -681,7 +680,6 @@ static void setup_layer_surface(MwLL r, int x, int y, int width, int height) { r->wayland.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); r->wayland.framebuffer.surface = wl_compositor_create_surface(r->wayland.compositor); - MwLLWaylandFifoSurfaceSetup(&r->wayland, &r->wayland.framebuffer); r->wayland.layer_surface->surface = zwlr_layer_shell_v1_get_layer_surface(layer_shell, r->wayland.framebuffer.surface, NULL, ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "milsko-surfaces"); @@ -712,8 +710,6 @@ static void destroy_layer_surface(MwLL r) { zxdg_decoration_manager_v1_destroy(dec->manager); } - MwLLWaylandFifoSurfaceDestroy(&r->wayland.framebuffer); - wl_surface_destroy(r->wayland.framebuffer.surface); wl_compositor_destroy(r->wayland.compositor); @@ -961,60 +957,6 @@ static void detect_dark_theme(MwLL handle) { } #endif -static void draw_child(MwLL handle, MwLL child); -static void draw_children(MwLL handle); - -static void draw_child(MwLL handle, MwLL child) { - cairo_t* c; - cairo_surface_t* cs; - cairo_t* selected_cairo = handle->wayland.cairo.front_cairo; - - wl_surface_commit(child->wayland.framebuffer.surface); - - cs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, child->wayland.ww, child->wayland.wh); - c = cairo_create(cs); - - cairo_set_source_surface(c, child->wayland.cairo.front_cs, 0, 0); - cairo_pattern_set_filter(cairo_get_source(c), CAIRO_FILTER_NEAREST); - - cairo_set_operator(handle->wayland.cairo.front_cairo, CAIRO_OPERATOR_OVER); - - cairo_paint(c); - - cairo_set_source_surface(selected_cairo, cs, child->wayland.x, child->wayland.y); - cairo_paint(selected_cairo); - - cairo_destroy(c); - cairo_surface_destroy(cs); - - draw_children(child); -} - -static void draw_children(MwLL handle) { - wl_surface_damage(handle->wayland.framebuffer.surface, 0, 0, handle->wayland.ww, handle->wayland.wh); - - MwLLWaylandChildrenIterate(handle, draw_child); - - if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - handle->wayland.events_pending = MwFALSE; -} - -static void cascade_child(MwLL handle, MwLL child) { - child->wayland.do_cascading_draw = 10; -} - -static void count_child(MwLL handle, MwLL child) { - handle->wayland.cascading_child_num++; -} - -void MwLLWaylandCascadeChildren(MwLL handle) { - handle->wayland.cascading_child_num = 0; - MwLLWaylandChildrenIterate(handle, count_child); - - handle->wayland.do_cascading_draw = handle->wayland.cascading_child_num * 10; - MwLLWaylandChildrenIterate(handle, cascade_child); -} - static MwLL MwLLCreateImpl(MwLL parent, int x, int y, int width, int height) { MwLL r; r = malloc(sizeof(*r)); @@ -1093,6 +1035,10 @@ static void MwLLDestroyImpl(MwLL handle) { pthread_mutex_unlock(&destroyedWidgetsTableMutex); free(handle); + + // if(topmost_parent->wayland.currentlyHeldWidget == handle) { + // topmost_parent->wayland.currentlyHeldWidget = NULL; + // } } static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsigned int* h) { @@ -1112,18 +1058,15 @@ static void MwLLGetXYWHImpl(MwLL handle, int* x, int* y, unsigned int* w, unsign static void MwLLSetXYImpl(MwLL handle, int x, int y) { WIDGET_CHECK(handle); MwLLWaylandRegionInvalidate(handle); - - if(handle->wayland.type != MwLL_WAYLAND_TOPLEVEL) { - handle->wayland.x = x; - handle->wayland.y = y; - } + handle->wayland.x = x; + handle->wayland.y = y; switch(handle->wayland.type) { case MwLL_WAYLAND_TOPLEVEL: /* toplevels cannot be moved */ break; case MwLL_WAYLAND_SUBLEVEL: - /* sublevels are drawn according to their own x/y */ + wl_subsurface_set_position(handle->wayland.sublevel->subsurface, x, y); break; case MwLL_WAYLAND_POPUP: xdg_positioner_set_anchor_rect(handle->wayland.popup->xdg_positioner, handle->wayland.parent->wayland.x, handle->wayland.parent->wayland.y, handle->wayland.ww, handle->wayland.wh); @@ -1361,8 +1304,6 @@ static void MwLLEndDrawImpl(MwLL handle) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); - - MwLLWaylandCascadeChildren(handle); } } @@ -1431,12 +1372,6 @@ static int MwLLPendingImpl(MwLL handle) { handle->wayland.setting_wh = 0; } - if(handle->wayland.do_cascading_draw) { - draw_children(handle); - if(handle->wayland.do_cascading_draw > 0) - handle->wayland.do_cascading_draw--; - } - handle->wayland.end_time = MwTimeGetTick(); if(handle->wayland.holding_key) { @@ -1485,19 +1420,16 @@ static int MwLLPendingImpl(MwLL handle) { return pending; } - if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwTRUE; MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); if(handle->wayland.type == MwLL_WAYLAND_TOPLEVEL) { MwLLWaylandBufferUpdate(handle, &handle->wayland.backbuffer); } - if(!handle->wayland.disable_fifo) handle->wayland.fifo_wait = MwFALSE; return handle->wayland.force_render || handle->wayland.events_pending || pending; } static void MwLLNextEventImpl(MwLL handle) { WIDGET_CHECK(handle); - if(!MwWaylandVulkan) { if(handle->wayland.did_event_loop_early) { handle->wayland.did_event_loop_early = MwFALSE; @@ -1507,11 +1439,9 @@ static void MwLLNextEventImpl(MwLL handle) { } if(handle->wayland.force_render) { - handle->wayland.fifo_wait = MwTRUE; MwLLDispatch(handle, draw, NULL); if(handle->wayland.configured) MwLLWaylandBufferUpdate(handle, &handle->wayland.framebuffer); handle->wayland.force_render = 0; - handle->wayland.fifo_wait = MwFALSE; } if(handle->wayland.events_pending) { handle->wayland.events_pending = 0; @@ -1740,7 +1670,7 @@ static void MwLLMakeBorderlessImpl(MwLL handle, int toggle) { dec->decoration, toggle ? ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE : ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); } else { handle->wayland.do_csd = !toggle; - // wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); + wl_subsurface_set_position(handle->wayland.toplevel->ssurface, handle->wayland.do_csd ? CSD_BORDER_FRAME_LEFT : 0, handle->wayland.do_csd ? CSD_BORDER_FRAME_TOP : 0); } } } @@ -1908,6 +1838,31 @@ static void MwLLEndStateChangeImpl(MwLL handle) { if(!handle->wayland.parent) handle->wayland.dark_theme_detection = MwTRUE; + 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->xdg_surface = handle->wayland.popup->xdg_surface; + if(child->wayland.sublevel->subsurface) + wl_subsurface_destroy(child->wayland.sublevel->subsurface); + MwLLWaylandFlush(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); + + if(topmost_parent) { + topmost_parent->wayland.currentlyHeldWidget = NULL; + } + } + } + } + recursive_render(handle); handle->wayland.events_pending = 1; @@ -1919,8 +1874,7 @@ static void MwLLSetDarkThemeImpl(MwLL handle, int toggle) { (void)toggle; /* Not Really what's supposed to happen with this function, but take this opprutunity to do the handlers that will force everything to redraw. */ - MwLLDispatch(handle, draw, NULL); - // MwLLDispatch(handle, resize, NULL); + MwLLDispatch(handle, resize, NULL); MwLLDispatch(handle, draw, NULL); } @@ -1973,14 +1927,10 @@ static int MwLLWaylandCallInitImpl(void) { } else { loadWayland |= (strcmp(mw_backend_env, "wayland") == 0); } - } - /* NOTE: when vulkan is enabled, refuse to default to wayland. Remove this if I ever get Vulkan widget working with the new surfaces system. */ -#ifndef MW_VULKAN - else if(getenv("WAYLAND_DISPLAY")) { + } else if(getenv("WAYLAND_DISPLAY")) { loadWayland |= (getenv("WAYLAND_DISPLAY") != NULL); } -#endif #ifdef MW_OPENGL if(getenv("WSLENV") || getenv("WSL_DISTRO_NAME")) { diff --git a/src/draw.c b/src/draw.c index c7869e0f..19b4081a 100644 --- a/src/draw.c +++ b/src/draw.c @@ -53,6 +53,105 @@ static void color_set_disabled_if_disabled(MwWidget handle, MwLLColor rgb) { } }; +/* Whether (x, y) within a w*h rect falls inside a rounded-rect mask of the + * given corner radius. Shared by every raster-based rounded fill below so + * they all cut the same corner shape. */ +static int rounded_rect_contains(int x, int y, int w, int h, int rad) { + int cx = -1; + int cy = -1; + + if(x < rad && y < rad) { + cx = rad; + cy = rad; + } else if(x >= w - rad && y < rad) { + cx = w - rad - 1; + cy = rad; + } else if(x < rad && y >= h - rad) { + cx = rad; + cy = h - rad - 1; + } else if(x >= w - rad && y >= h - rad) { + cx = w - rad - 1; + cy = h - rad - 1; + } + + if(cx < 0) { + return 1; + } + + { + int dx = x - cx; + int dy = y - cy; + return (dx * dx + dy * dy) <= rad * rad; + } +} + +static void fill_rect(MwWidget handle, MwRect* rect, MwLLColor color) { + MwPoint p[4]; + + 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; + p[2].y = rect->y + rect->height; + + p[3].x = rect->x; + p[3].y = rect->y + rect->height; + + MwLLPolygon(handle->lowlevel, p, 4, color); +} + +/* Flat-colored rounded-rect fill, for backdrops that need to match a rounded + * border/fill's shape instead of a plain MwDrawRect square. */ +static void fill_rect_rounded(MwWidget handle, MwRect* rect, MwLLColor color, int roundness) { + MwLLPixmap pixmap; + int x, y; + int w = rect->width; + int h = rect->height; + int rad = roundness; + unsigned char* data; + + if(w <= 0 || h <= 0) { + return; + } + + if(rad > w / 2) rad = w / 2; + if(rad > h / 2) rad = h / 2; + + if(rad <= 0) { + fill_rect(handle, rect, color); + return; + } + + data = malloc((unsigned long)w * h * 4); + if(!data) { + return; + } + + memset(data, 0, (unsigned long)w * h * 4); + + for(y = 0; y < h; y++) { + for(x = 0; x < w; x++) { + if(rounded_rect_contains(x, y, w, h, rad)) { + unsigned char* pout = &data[(y * w + x) * 4]; + + pout[0] = (unsigned char)color->common.red; + pout[1] = (unsigned char)color->common.green; + pout[2] = (unsigned char)color->common.blue; + pout[3] = 255; + } + } + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); + MwLLDrawPixmap(handle->lowlevel, rect, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); +} + void MwParseColorNoAllocate(const char* text, MwRGB* rgb) { if(text[0] == '#' && strlen(text) == 4) { rgb->red = hex(text + 1, 1); @@ -100,63 +199,104 @@ MwLLColor MwLightenColor(MwWidget handle, MwLLColor color, int r, int g, int b) } void MwDrawRect(MwWidget handle, MwRect* rect, MwLLColor color) { - MwPoint p[4]; - - 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; - p[2].y = rect->y + rect->height; - - p[3].x = rect->x; - p[3].y = rect->y + rect->height; - - MwLLPolygon(handle->lowlevel, p, 4, color); + if(MwLLWaylandDoRoundness(handle->lowlevel)) { + fill_rect_rounded(handle, rect, color, MwLLWaylandHyprlandGetRoundness()); + } else { + fill_rect(handle, rect, color); + } } void MwDrawRectFading(MwWidget handle, MwRect* rect, MwLLColor color) { - MwLLPixmap pixmap; - 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 * 2); - MwRect r = *rect; - if(!data) { - return; - } + MwLLPixmap pixmap; + int y; + double darken = 0.; + int ColorDiff = get_color_diff(handle); + MwRect r = *rect; + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; + if(rect->width <= 0 || rect->height <= 0) { - free(data); return; } - 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, (int)-darken, (int)-darken, (int)-darken); - int idx = y * 4; - color_set_disabled_if_disabled(handle, col); - data[idx] = col->common.red; - data[idx + 1] = col->common.green; - data[idx + 2] = col->common.blue; - data[idx + 3] = 255; - MwLLFreeColor(col); - darken += darkenStep; + if(r.width <= 0 || r.height <= 0) { + return; } - pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); - MwLLDrawPixmap(handle->lowlevel, &r, pixmap); - MwLLDestroyPixmap(pixmap); + if(roundness <= 0) { + double darkenStep = (ColorDiff / 2.) / rect->height; + unsigned long sz = 1 * rect->height * 4; + unsigned char* data = malloc(sz * 2); + if(!data) { + return; + } + memset(data, 0, sz); - free(data); + for(y = 0; y < rect->height; y++) { + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); + int idx = y * 4; + color_set_disabled_if_disabled(handle, col); + data[idx] = col->common.red; + data[idx + 1] = col->common.green; + data[idx + 2] = col->common.blue; + data[idx + 3] = 255; + MwLLFreeColor(col); + darken += darkenStep; + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, 1, rect->height); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); + return; + } else { + int w = r.width; + int h = r.height; + int rad = roundness; + int x; + double darkenStep; + unsigned char* data; + + if(rad > w / 2) rad = w / 2; + if(rad > h / 2) rad = h / 2; + + darkenStep = (ColorDiff / 2.) / h; + data = malloc((unsigned long)w * h * 4); + if(!data) { + return; + } + memset(data, 0, (unsigned long)w * h * 4); + + for(y = 0; y < h; y++) { + MwLLColor col = MwLightenColor(handle, color, (int)-darken, (int)-darken, (int)-darken); + color_set_disabled_if_disabled(handle, col); + + for(x = 0; x < w; x++) { + if(rounded_rect_contains(x, y, w, h, rad)) { + unsigned char* pout = &data[(y * w + x) * 4]; + + pout[0] = (unsigned char)col->common.red; + pout[1] = (unsigned char)col->common.green; + pout[2] = (unsigned char)col->common.blue; + pout[3] = 255; + } + } + + MwLLFreeColor(col); + darken += darkenStep; + } + + pixmap = MwLLCreatePixmap(handle->lowlevel, data, w, h); + MwLLDrawPixmap(handle->lowlevel, &r, pixmap); + MwLLDestroyPixmap(pixmap); + + free(data); + } } void MwDrawFrame(MwWidget handle, MwRect* rect, MwLLColor color, int invert) { @@ -203,7 +343,8 @@ void MwDrawWidgetBack(MwWidget handle, MwRect* rect, MwLLColor color, int invert MwLLColor c = handle->parent == NULL ? NULL : MwParseColor(handle->parent, MwGetText(handle->parent, MwNbackground)); if(c != NULL) { - MwDrawRect(handle, rect, c); + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; + fill_rect_rounded(handle, rect, c, MwGetInteger(handle, MwNmodernLook) ? roundness : 0); MwLLFreeColor(c); } } @@ -454,48 +595,113 @@ 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) { - MwPoint p[7]; +#define FRAME_ARC_STEPS 6 + +/* Appends the points of an (up to) quarter-circle arc, sweeping from + * start_deg to end_deg (in degrees, either direction), to `points`. */ +static void frame_border_append_arc(MwPoint* points, int* count, int cx, int cy, int radius, double start_deg, double end_deg, int steps) { + int i; + for(i = 0; i <= steps; i++) { + double deg = start_deg + (end_deg - start_deg) * ((double)i / steps); + double rad = deg * M_PI / 180.0; + points[*count].x = cx + (int)(cos(rad) * radius); + points[*count].y = cy + (int)(sin(rad) * radius); + (*count)++; + } +} + +static void frame_border_complex(MwWidget handle, MwRect* rect, MwLLColor lighter, MwLLColor darker, int invert, int border, int diff, int same, int roundness) { + MwPoint p[36]; + int n; + int x = rect->x; + int y = rect->y; + int w = rect->width; + int h = rect->height; + int r = roundness; + int ib, ir; (void)diff; (void)same; - p[0].x = rect->x; - p[0].y = rect->y; + if(r < 0) r = 0; + if(r > w / 2) r = w / 2; + if(r > h / 2) r = h / 2; - p[1].x = rect->x + rect->width; - p[1].y = rect->y; + if(r <= 0) { + p[0].x = x; + p[0].y = 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[1].x = x + w; + p[1].y = y; - p[4].x = rect->x + border; - p[4].y = rect->y + rect->height - border; + p[2].x = x + w - border; + p[2].y = y + border; + p[3].x = x + border; + p[3].y = y + border; - p[5].x = rect->x; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[4].x = x + border; + p[4].y = y + h - border; - p[0].x = rect->x + rect->width; - p[0].y = rect->y; + p[5].x = x; + p[5].y = y + h; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); - p[1].x = rect->x + rect->width - border; - p[1].y = rect->y + border; + p[0].x = x + w; + p[0].y = y; - p[2].x = rect->x + rect->width - border; - p[2].y = rect->y + rect->height - border; + p[1].x = x + w - border; + p[1].y = y + border; - p[3].x = rect->x + border; - p[3].y = rect->y + rect->height - border; + p[2].x = x + w - border; + p[2].y = y + h - border; - p[4].x = rect->x; - p[4].y = rect->y + rect->height; + p[3].x = x + border; + p[3].y = y + h - border; - p[5].x = rect->x + rect->width; - p[5].y = rect->y + rect->height; - MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + p[4].x = x; + p[4].y = y + h; + + p[5].x = x + w; + p[5].y = y + h; + MwLLPolygon(handle->lowlevel, p, 6, invert ? lighter : darker); + return; + } + + /* With rounded outer corners, each half still meets the other along + * the same two diagonals as the sharp-cornered version above, except + * the TR and BL corners (shared between both halves) are cut by an + * arc whose midpoint lies on that diagonal, and each half draws + * exactly one side of it. The TL/BR corners belong entirely to one + * half, so they get the full quarter-circle arc. + * + * The inner (border-offset) corners get the same treatment, using the + * same corner centers as the outer arcs but shrunk by the border + * width, so the border ring keeps a uniform thickness all the way + * around the curve instead of jumping to a sharp point. If the border + * is thicker than the roundness, this collapses back to the ordinary + * sharp inner corner (ib == border, ir == 0). */ + ib = (r > border) ? r : border; + ir = (r > border) ? (r - border) : 0; + + /* Top-left half: TL (full), TR (near side), BL (near side). */ + n = 0; + frame_border_append_arc(p, &n, x + r, y + r, r, 180, 270, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + w - r, y + r, r, 270, 315, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 270, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + ib, y + ib, ir, 270, 180, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 180, 135, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 180, FRAME_ARC_STEPS / 2); + MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); + + /* Bottom-right half: TR (far side), BL (far side), BR (full). */ + n = 0; + frame_border_append_arc(p, &n, x + w - r, y + r, r, 360, 315, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + ib, ir, 315, 360, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - ib, y + h - ib, ir, 0, 90, FRAME_ARC_STEPS); + frame_border_append_arc(p, &n, x + ib, y + h - ib, ir, 90, 135, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + r, y + h - r, r, 135, 90, FRAME_ARC_STEPS / 2); + frame_border_append_arc(p, &n, x + w - r, y + h - r, r, 90, 0, FRAME_ARC_STEPS); + MwLLPolygon(handle->lowlevel, p, n, invert ? lighter : darker); } static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color, int invert, int border, int diff, int same) { @@ -503,18 +709,19 @@ static void MwDrawFrameEx_complex(MwWidget handle, MwRect* rect, MwLLColor color 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; + int roundness = MwLLWaylandDoRoundness(handle->lowlevel) ? MwLLWaylandHyprlandGetRoundness() : 0; color_set_disabled_if_disabled(handle, darker); color_set_disabled_if_disabled(handle, lighter); - frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same); + frame_border_complex(handle, rect, lighter, darker, invert, border == 1 ? 1 : (border / 2), diff, same, roundness); if(border > 1) { r.x += border / 2; r.y += border / 2; r.width -= border; r.height -= border; - frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same); + frame_border_complex(handle, &r, lighter, darker, !invert, border / 2, diff, same, roundness); } MwLLFreeColor(lighter); diff --git a/src/widget/opengl.c b/src/widget/opengl.c index 9e1b91e8..30a1cee8 100644 --- a/src/widget/opengl.c +++ b/src/widget/opengl.c @@ -240,12 +240,6 @@ static int wcreate(MwWidget handle) { waylandopengl_t* o = r = malloc(sizeof(*o)); int gbm_format = 0; EGLConfig egl_configs[1024]; - MwWidget topmost_parent = handle; - - /* Disable fifo waiting when we have an OpenGL widget */ - while(topmost_parent->parent) topmost_parent = topmost_parent->parent; - topmost_parent->lowlevel->wayland.disable_fifo = MwTRUE; - memset(o, 0, sizeof(waylandopengl_t)); o->gllib = MwDynamicOpen("libEGL.so"); diff --git a/src/widget/vulkan.c b/src/widget/vulkan.c index acffda3a..f4c53402 100644 --- a/src/widget/vulkan.c +++ b/src/widget/vulkan.c @@ -240,8 +240,6 @@ static int vulkan_instance_setup(MwWidget handle, vulkan_t* o) { #endif #ifdef USE_WAYLAND if(handle->lowlevel->common.type == MwLLBackendWayland) { - MwWidget topmost_parent = handle; - arrput(o->enabledExtensions, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME); /* take this opprutunity to set the widget to always render */ MwWaylandVulkan = MwTRUE;