fix for hyprland that should go away very quickly
Some checks failed
pyrite-dev/milsko/pipeline/head There was a failure building this commit

This commit is contained in:
IoIxD 2026-09-11 18:05:42 -07:00
commit 5479cb3e30
6 changed files with 358 additions and 79 deletions

View file

@ -269,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
)
@ -331,7 +332,7 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_SYSTEM_NAME STREQUAL "MSYS")
)
list(APPEND LIBRARIES gdi32 ole32 uuid)
if(NOT MSVC)
target_link_options(
target_link_options(
Mw
PRIVATE
-static-libgcc
@ -468,7 +469,7 @@ if(MW_BUILD_VULKAN)
check_include_files(vulkan/VULKAN.h HAS_VK_HEADER)
if(HAS_VK_HEADER)
target_compile_definitions(
target_compile_definitions(
Mw
PRIVATE
MW_VULKAN

View file

@ -454,6 +454,8 @@ struct _MwLLWayland {
MwU64 next_elapsed;
long start_time;
long end_time;
MwBool on_hyprland;
};
struct _MwLLWaylandColor {
@ -479,6 +481,11 @@ void MwLLWaylandBufferDestroy(struct _MwLLWaylandShmBuffer* buffer);
void MwLLWaylandRegionSetup(MwLL handle);
void MwLLWaylandRegionInvalidate(MwLL handle);
int MwLLWaylandDoRoundness(MwLL handle);
/* Reads the "roundness" value out of ~/.config/hypr/hyprland.lua, or returns `fallback` if unavailable. */
int MwLLWaylandHyprlandGetRoundness(void);
void MwLLWaylandHangUntilConfigured(MwLL handle);
MwBool MwLLWaylandWidgetIsDestroyed(MwLL self);

View file

@ -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,8 +67,7 @@ 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_from_file("wlr-layer-shell",
"wlr-layer-shell-unstable-v1.xml");
scan_wayland_protocol_from_file("wlr-layer-shell", "wlr-layer-shell-unstable-v1.xml");
$gl_libs = "-lGL -lGLU";
}

View file

@ -0,0 +1,60 @@
#include <Mw/Milsko.h>
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;
}

View file

@ -40,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);
}

View file

@ -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);