← recipes

Commit 36ac353

13
plików
+141
dodanych
-446
usuniętych
@@ -67,3 +67,10 @@ pagbuild recipes/core/acl/PAGBUILD.yaml
67 67 ## Narzędzia
68 68
69 69 - `migrate-recipes.py` — konwertuje receptury `cards` (Pkgfile) na `PAGBUILD.yaml`
70 +
71 +## Polityka forków
72 +
73 +Fork-first w całym repo: [`../../FORK-POLICY.md`](../../FORK-POLICY.md).
74 +Krótko: co możemy zrobić forkiem, robimy forkiem — źródła w repo, pakiet
75 +`-pagan`, lokalny tarball + wyliczony sha256 (build bez sieci) i adnotacja
76 +licencyjna o statusie forka (`FORK.md` + `NOTICE`).
@@ -1,29 +1,41 @@
1 +# GENEROWANY PLIK — nie edytować ręcznie.
2 +# Źródło prawdy: config/ i session/ (dom projektu PaganBuild/PaganDE).
3 +# Regeneracja: make tarball-meta && make recipe
4 +
1 5 pkgname: pagande
2 -pkgver: '0.1.0'
3 -pkgrel: 2
4 -pkgdesc: PaganDE — nowoczesne, modułowe środowisko Wayland z pływającymi oknami (własny shell, bez GTK/Qt)
6 +pkgver: '0.2.0'
7 +pkgrel: 1
8 +pkgdesc: 'PaganDE — lekkie środowisko Wayland: fork labwc-pagan (rc.ini + live reload), wlroots-pagan, Catppuccin Mocha (waybar, rofi, mako, foot, kanshi, swaybg, swaylock)'
5 9 url: 'https://paganlinux.eu'
6 10 arch: x86_64
7 11 license:
8 12 - MIT
9 13 depends:
14 +- cantarell-fonts
15 +- catppuccin-gtk-theme
16 +- foot
17 +- kanshi
10 18 - labwc-pagan
11 -- pagande-shell
19 +- mako
20 +- network-manager-applet
21 +- papirus-icon-theme
22 +- pavucontrol
12 23 - pipewire
13 24 - polkit-gnome
14 -- network-manager-applet
25 +- rofi
26 +- swaybg
27 +- swaylock
28 +- thunar
29 +- thunar-archive-plugin
30 +- waybar
31 +- xcursor-dmz
15 32 - xdg-desktop-portal
16 33 - xdg-desktop-portal-gtk
17 -- papirus-icon-theme
18 -- cantarell-fonts
19 -- xcursor-dmz
20 -- alacritty
21 -- thunar
22 34 makedepends: []
23 35 source:
24 36 - pagande-${pkgver}.tar.gz
25 37 sha256sums:
26 -- 5a59c3503f4cfd52280a500aff530e29830f57d375d02c4483e6ebb9af1aa870
38 +- '8ebe4df2514491a50a6485db5d4f790f6c81f6d6fc50b999806e2413b204e1d1'
27 39 build: |
28 40 cd ${pkgname}
29 41
@@ -34,13 +46,18 @@ build: |
34 46 install -dm755 "${PKGDIR}/usr/share/wayland-sessions"
35 47 install -m644 session/pagande.desktop "${PKGDIR}/usr/share/wayland-sessions/pagande.desktop"
36 48
37 - # ── Motyw okien (fork labwc) ────────────────────────────────
49 + # ── Motyw okien labwc (config/theme/* → /usr/share/themes) ─
38 50 install -dm755 "${PKGDIR}/usr/share/themes"
39 - cp -a config/theme/pagan "${PKGDIR}/usr/share/themes/pagan"
51 + cp -a config/theme/. "${PKGDIR}/usr/share/themes/"
40 52
41 53 # ── Domyślne konfiguracje (sesja rozkłada je do ~/.config) ─
42 54 install -dm755 "${PKGDIR}/etc/xdg/pagande"
43 55 cp -a config/labwc "${PKGDIR}/etc/xdg/pagande/labwc"
44 - cp -a config/shell "${PKGDIR}/etc/xdg/pagande/shell"
56 + cp -a config/waybar "${PKGDIR}/etc/xdg/pagande/waybar"
57 + cp -a config/rofi "${PKGDIR}/etc/xdg/pagande/rofi"
58 + cp -a config/mako "${PKGDIR}/etc/xdg/pagande/mako"
59 + cp -a config/foot "${PKGDIR}/etc/xdg/pagande/foot"
60 + cp -a config/kanshi "${PKGDIR}/etc/xdg/pagande/kanshi"
61 + cp -a config/gtk-3.0 "${PKGDIR}/etc/xdg/pagande/gtk-3.0"
45 62 package: |
46 63 true
47 64 deleted file mode 100644
48 65 Binary files a/de/pagande/pagande-0.1.0.tar.gz and /dev/null differ
49 66 new file mode 100644
50 67 Binary files /dev/null and b/de/pagande/pagande-0.2.0.tar.gz differ
51 68 new file mode 100644
@@ -0,0 +1,25 @@
1 +pkgname: catppuccin-gtk-theme
2 +pkgver: '1.0.3'
3 +pkgrel: '1'
4 +pkgdesc: 'Catppuccin GTK (Mocha, Blue, Standard) - motyw GTK3/GTK4 spójny z paleta PaganDE (dark/light w srodku)'
5 +url: 'https://github.com/catppuccin/gtk'
6 +arch: x86_64
7 +license:
8 +- MIT
9 +depends: []
10 +makedepends:
11 +- unzip
12 +source:
13 +- 'https://github.com/catppuccin/gtk/releases/download/v${pkgver}/catppuccin-mocha-blue-standard+default.zip'
14 +sha256sums:
15 +- SKIP
16 +build: |
17 + # Asset z release'u: kompletny motyw (gtk-3.0, gtk-4.0, gnome-shell, ...).
18 + # Instalujemy pod nazwa uzywana przez PaganDE (config/gtk-3.0/settings.ini
19 + # oraz GTK_THEME w config/labwc/environment).
20 + mkdir -p "${PKGDIR}/usr/share/themes"
21 + unzip -q catppuccin-mocha-blue-standard+default.zip
22 + mv catppuccin-mocha-blue-standard+default \
23 + "${PKGDIR}/usr/share/themes/Catppuccin-Mocha-Standard-Blue-Dark"
24 +package: |
25 + true
0 26 new file mode 100644
@@ -0,0 +1,25 @@
1 +pkgname: kanshi
2 +pkgver: '1.2.0'
3 +pkgrel: '1'
4 +pkgdesc: 'Kanshi - automatyczne profile monitorow dla Wayland (PaganDE: profile w ~/.config/kanshi/config)'
5 +url: 'https://github.com/emersion/kanshi'
6 +arch: x86_64
7 +license:
8 +- MIT
9 +depends:
10 +- wayland
11 +makedepends:
12 +- meson
13 +- ninja
14 +- wayland-protocols
15 +source:
16 +- 'https://github.com/emersion/kanshi/archive/refs/tags/v${pkgver}.tar.gz'
17 +sha256sums:
18 +- SKIP
19 +build: |
20 + cd kanshi-${pkgver}
21 + meson setup build --prefix=/usr -Dman-pages=disabled
22 + ninja -C build
23 + DESTDIR=${PKGDIR} ninja -C build install
24 +package: |
25 + true
@@ -7,7 +7,7 @@ arch: x86_64
7 7 license:
8 8 - GPL-2.0-only
9 9 depends:
10 -- wlroots
10 +- wlroots-pagan
11 11 - libxkbcommon
12 12 - xorg-libdrm
13 13 - libxml2
@@ -27,7 +27,7 @@ makedepends:
27 27 source:
28 28 - labwc-pagan-${pkgver}.tar.gz
29 29 sha256sums:
30 -- e1e8726326cf362193d48bef7363bfad63d9d1d5930aa208d48a6e63615351a3
30 +- 3119b39714853dc1a66eeffe745a053fad068c6c491d4980412297b1968e1b5b
31 31 build: |
32 32 cd ${pkgname}
33 33
34 34 Binary files a/gui/labwc-pagan/labwc-pagan-0.20.2.tar.gz and b/gui/labwc-pagan/labwc-pagan-0.20.2.tar.gz differ
35 35 new file mode 100644
@@ -0,0 +1,49 @@
1 +pkgname: wlroots-pagan
2 +pkgver: '0.20.2'
3 +pkgrel: 1
4 +pkgdesc: 'Wlroots PaganDE (fork) - fundament kompozytora labwc-pagan: zaokraglone rogi okien (rounded clip) + poprawka kanalow BGR888; zrodla w paganDE/compositor/wlroots'
5 +url: 'https://paganlinux.eu'
6 +arch: x86_64
7 +license:
8 +- MIT
9 +depends:
10 +- wayland
11 +- xorg-libdrm
12 +- libinput
13 +- libxkbcommon
14 +- xorg-pixman
15 +- mesa
16 +- libdisplay-info
17 +- libliftoff
18 +- seatd
19 +- hwdata
20 +- systemd
21 +makedepends:
22 +- meson
23 +- ninja
24 +- wayland-protocols
25 +- systemd
26 +source:
27 +- wlroots-pagan-${pkgver}.tar.gz
28 +sha256sums:
29 +- 6b7664a16f942094d4a222ac0a33321895c2db1d817b4f1ef06c87cb95ca3f6b
30 +build: |
31 + cd ${pkgname}
32 +
33 + # Nasz fork: zmiany PaganDE (rounded clip + BGR888) sa juz wpiete w zrodla,
34 + # nie nakladamy patche w buildzie. Patrz paganDE/compositor/wlroots/pagan/FORK.md.
35 + # pagbuild dodaje -D_GNU_SOURCE do CFLAGS, a wlroots sam go definiuje
36 + # (render/allocator/udmabuf.c) -> "_GNU_SOURCE redefined" + -Werror = blad.
37 + # -std=gnu17 i tak implikuje _GNU_SOURCE, wiec usuwamy nadmiarowa definicje.
38 + CFLAGS="${CFLAGS/-D_GNU_SOURCE/}" CPPFLAGS="${CPPFLAGS/-D_GNU_SOURCE/}" \
39 + meson setup build --prefix=/usr \
40 + -Dexamples=false \
41 + -Drenderers=gles2 \
42 + -Dbackends=drm,libinput \
43 + -Dxwayland=disabled \
44 + -Dcolor-management=disabled
45 +
46 + ninja -C build
47 + DESTDIR=${PKGDIR} ninja -C build install
48 +package: |
49 + true
0 50 new file mode 100644
1 51 Binary files /dev/null and b/gui/wlroots-pagan/wlroots-pagan-0.20.2.tar.gz differ
@@ -1,7 +1,7 @@
1 1 pkgname: wlroots
2 2 pkgver: '0.20.2'
3 -pkgrel: 3
4 -pkgdesc: 'Modular Wayland compositor library (fundament labwc; patch PaganDE: zaokrąglone rogi okien + poprawka kanałów BGR888)'
3 +pkgrel: 4
4 +pkgdesc: 'Modular Wayland compositor library (upstream, bez zmian PaganDE; nasz fork z poprawkami: wlroots-pagan)'
5 5 url: https://gitlab.freedesktop.org/wlroots/wlroots
6 6 arch: x86_64
7 7 license:
@@ -25,26 +25,11 @@ makedepends:
25 25 - systemd
26 26 source:
27 27 - https://gitlab.freedesktop.org/wlroots/wlroots/-/archive/${pkgver}/${pkgname}-${pkgver}.tar.gz
28 -- wlroots-0.20.2-rounded-clip.patch
29 -- wlroots-0.20.2-bgr888-read-pixels.patch
30 28 sha256sums:
31 29 - SKIP
32 -- SKIP
33 -- SKIP
34 30 build: |
35 31 cd ${pkgname}
36 32
37 - # PaganDE: wlr_scene_buffer_set_rounded_clip() — renderer gles2 przycina
38 - # tekstury do prostokąta z zaokrąglonymi rogami (używane przez labwc-pagan
39 - # do zaokrąglania treści okien; patrz paganDE/compositor/labwc/pagan/FORK.md).
40 - patch -p1 -i ../wlroots-0.20.2-rounded-clip.patch
41 -
42 - # PaganDE: glReadPixels(GL_RGB) dla DRM_FORMAT_BGR888 zwraca bajty R,G,B,
43 - # a układ BGR888 oczekuje B,G,R — bez tego screencopy/zrzuty miały zamienione
44 - # kanały czerwony i niebieski (widoczne na llvmpipe, gdzie preferred read
45 - # format to BGR888).
46 - patch -p1 -i ../wlroots-0.20.2-bgr888-read-pixels.patch
47 -
48 33 # pagbuild dodaje -D_GNU_SOURCE do CFLAGS, a wlroots sam go definiuje
49 34 # (render/allocator/udmabuf.c) -> "_GNU_SOURCE redefined" + -Werror = błąd.
50 35 # -std=gnu17 i tak implikuje _GNU_SOURCE, więc usuwamy nadmiarową definicję.
51 36 deleted file mode 100644
@@ -1,45 +0,0 @@
1 -From: PaganDE <dev@paganlinux.org>
2 -Subject: [PATCH] gles2: fix R/B swap when reading DRM_FORMAT_BGR888
3 -
4 -GLES2 has no GL_BGR, so wlroots maps DRM_FORMAT_BGR888 to
5 -glReadPixels(GL_RGB, GL_UNSIGNED_BYTE). GL_RGB returns bytes in
6 -R,G,B order while the BGR888 layout expects B,G,R - the resulting
7 -buffer ends up with red and blue swapped.
8 -
9 -On llvmpipe the implementation read format is GL_RGB, so
10 -wlr_output_preferred_read_format() reports BGR888 and screencopy
11 -clients receive a buffer with inverted channels.
12 -
13 -Origin: PaganDE fork of wlroots 0.20.2
14 - render/gles2/texture.c | 19 +++++++++++++++++++
15 - 1 file changed, 19 insertions(+)
16 -
17 -+++ b/render/gles2/texture.c 2026-08-31 14:04:58.836879583 +0200
18 -@@ -225,6 +225,25 @@
19 - }
20 - }
21 -
22 -+ /*
23 -+ * DRM_FORMAT_BGR888 has no GLES2 equivalent: we read it as GL_RGB,
24 -+ * which returns bytes in R,G,B order, while the BGR888 layout
25 -+ * expects B,G,R. Swap the channels so the buffer actually contains
26 -+ * BGR data. Otherwise screencopy/screenshot clients see red and
27 -+ * blue swapped (visible on llvmpipe, where the preferred read
28 -+ * format is BGR888).
29 -+ */
30 -+ if (drm_fmt->drm_format == DRM_FORMAT_BGR888) {
31 -+ for (int32_t i = 0; i < src.height; ++i) {
32 -+ unsigned char *row = p + (size_t)i * options->stride;
33 -+ for (int32_t x = 0; x < src.width; ++x) {
34 -+ unsigned char tmp = row[x * 3];
35 -+ row[x * 3] = row[x * 3 + 2];
36 -+ row[x * 3 + 2] = tmp;
37 -+ }
38 -+ }
39 -+ }
40 -+
41 - wlr_egl_restore_context(&prev_ctx);
42 - pop_gles2_debug(texture->renderer);
43 -
44 0 deleted file mode 100644
@@ -1,368 +0,0 @@
1 -diff -ruN a/include/render/gles2.h b/include/render/gles2.h
2 -+++ b/include/render/gles2.h 2026-08-31 12:49:04.008068765 +0200
3 -@@ -35,6 +35,12 @@
4 - GLint tex;
5 - GLint alpha;
6 - GLint pos_attrib;
7 -+ /* PaganDE: rounded clip */
8 -+ GLint rounded;
9 -+ GLint box_pos;
10 -+ GLint box_size;
11 -+ GLint radius;
12 -+ GLint corners;
13 - };
14 -
15 - struct wlr_gles2_renderer {
16 -diff -ruN a/include/wlr/render/pass.h b/include/wlr/render/pass.h
17 -+++ b/include/wlr/render/pass.h 2026-08-31 12:49:04.007446160 +0200
18 -@@ -84,6 +84,14 @@
19 - WLR_SCALE_FILTER_NEAREST,
20 - };
21 -
22 -+/* PaganDE: rounded corners bitmask (see corner_radius below) */
23 -+enum wlr_rounded_corner {
24 -+ WLR_ROUNDED_CORNER_TOP_LEFT = 1 << 0,
25 -+ WLR_ROUNDED_CORNER_TOP_RIGHT = 1 << 1,
26 -+ WLR_ROUNDED_CORNER_BOTTOM_RIGHT = 1 << 2,
27 -+ WLR_ROUNDED_CORNER_BOTTOM_LEFT = 1 << 3,
28 -+};
29 -+
30 - struct wlr_render_texture_options {
31 - /* Source texture */
32 - struct wlr_texture *texture;
33 -@@ -95,6 +103,12 @@
34 - const float *alpha;
35 - /* Clip region, leave NULL to disable clipping */
36 - const pixman_region32_t *clip;
37 -+ /* PaganDE: rounded corners. When corner_radius > 0 and rounded_corners != 0,
38 -+ * the texture is clipped to a rectangle with rounded corners (bitmask of
39 -+ * enum wlr_rounded_corner). Renderers that do not support this feature
40 -+ * must ignore these fields. */
41 -+ float corner_radius;
42 -+ uint32_t rounded_corners;
43 - /* Transform applied to the source texture */
44 - enum wl_output_transform transform;
45 - /* Filtering */
46 -diff -ruN a/include/wlr/types/wlr_scene.h b/include/wlr/types/wlr_scene.h
47 -+++ b/include/wlr/types/wlr_scene.h 2026-08-31 12:49:04.007705726 +0200
48 -@@ -215,6 +215,11 @@
49 -
50 - // True if the underlying buffer is a wlr_single_pixel_buffer_v1
51 - bool is_single_pixel_buffer;
52 -+
53 -+ // PaganDE: rounded clip applied when rendering this buffer
54 -+ // (see wlr_scene_buffer_set_rounded_clip)
55 -+ float clip_radius;
56 -+ uint32_t clip_corners;
57 - // If is_single_pixel_buffer is set, contains the color of the buffer
58 - // as {R, G, B, A} where the max value of each component is UINT32_MAX
59 - uint32_t single_pixel_buffer_color[4];
60 -@@ -549,6 +554,16 @@
61 - enum wl_output_transform transform);
62 -
63 - /**
64 -+ * PaganDE: clip the buffer to a rectangle with rounded corners.
65 -+ *
66 -+ * radius is the corner radius in output pixels; corners is a bitmask of
67 -+ * enum wlr_rounded_corner. Passing radius 0 (or corners 0) disables the clip.
68 -+ * Renderers without support (e.g. pixman) ignore this.
69 -+ */
70 -+void wlr_scene_buffer_set_rounded_clip(struct wlr_scene_buffer *scene_buffer,
71 -+ float radius, uint32_t corners);
72 -+
73 -+/**
74 - * Sets the opacity of this buffer
75 - */
76 - void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
77 -diff -ruN a/render/gles2/pass.c b/render/gles2/pass.c
78 -+++ b/render/gles2/pass.c 2026-08-31 12:53:51.197412809 +0200
79 -@@ -247,6 +247,19 @@
80 - set_proj_matrix(shader->proj, pass->projection_matrix, &dst_box);
81 - set_tex_matrix(shader->tex_proj, options->transform, &src_fbox);
82 -
83 -+ bool rounded = options->corner_radius > 0 && options->rounded_corners != 0;
84 -+ glUniform1f(shader->rounded, rounded ? 1.0f : 0.0f);
85 -+ if (rounded) {
86 -+ glUniform2f(shader->box_pos, dst_box.x, dst_box.y);
87 -+ glUniform2f(shader->box_size, dst_box.width, dst_box.height);
88 -+ glUniform1f(shader->radius, options->corner_radius);
89 -+ glUniform4f(shader->corners,
90 -+ (options->rounded_corners & WLR_ROUNDED_CORNER_TOP_LEFT) ? 1.0f : 0.0f,
91 -+ (options->rounded_corners & WLR_ROUNDED_CORNER_TOP_RIGHT) ? 1.0f : 0.0f,
92 -+ (options->rounded_corners & WLR_ROUNDED_CORNER_BOTTOM_RIGHT) ? 1.0f : 0.0f,
93 -+ (options->rounded_corners & WLR_ROUNDED_CORNER_BOTTOM_LEFT) ? 1.0f : 0.0f);
94 -+ }
95 -+
96 - render(&dst_box, options->clip, shader->pos_attrib);
97 -
98 - glBindTexture(texture->target, 0);
99 -diff -ruN a/render/gles2/renderer.c b/render/gles2/renderer.c
100 -+++ b/render/gles2/renderer.c 2026-08-31 12:49:04.008364833 +0200
101 -@@ -652,6 +652,11 @@
102 - renderer->shaders.tex_rgba.tex = glGetUniformLocation(prog, "tex");
103 - renderer->shaders.tex_rgba.alpha = glGetUniformLocation(prog, "alpha");
104 - renderer->shaders.tex_rgba.pos_attrib = glGetAttribLocation(prog, "pos");
105 -+ renderer->shaders.tex_rgba.rounded = glGetUniformLocation(prog, "u_rounded");
106 -+ renderer->shaders.tex_rgba.box_pos = glGetUniformLocation(prog, "u_box_pos");
107 -+ renderer->shaders.tex_rgba.box_size = glGetUniformLocation(prog, "u_box_size");
108 -+ renderer->shaders.tex_rgba.radius = glGetUniformLocation(prog, "u_radius");
109 -+ renderer->shaders.tex_rgba.corners = glGetUniformLocation(prog, "u_corners");
110 -
111 - renderer->shaders.tex_rgbx.program = prog =
112 - link_program(renderer, common_vert_src, tex_rgbx_frag_src);
113 -@@ -663,6 +668,11 @@
114 - renderer->shaders.tex_rgbx.tex = glGetUniformLocation(prog, "tex");
115 - renderer->shaders.tex_rgbx.alpha = glGetUniformLocation(prog, "alpha");
116 - renderer->shaders.tex_rgbx.pos_attrib = glGetAttribLocation(prog, "pos");
117 -+ renderer->shaders.tex_rgbx.rounded = glGetUniformLocation(prog, "u_rounded");
118 -+ renderer->shaders.tex_rgbx.box_pos = glGetUniformLocation(prog, "u_box_pos");
119 -+ renderer->shaders.tex_rgbx.box_size = glGetUniformLocation(prog, "u_box_size");
120 -+ renderer->shaders.tex_rgbx.radius = glGetUniformLocation(prog, "u_radius");
121 -+ renderer->shaders.tex_rgbx.corners = glGetUniformLocation(prog, "u_corners");
122 -
123 - if (renderer->exts.OES_egl_image_external) {
124 - renderer->shaders.tex_ext.program = prog =
125 -@@ -675,6 +685,11 @@
126 - renderer->shaders.tex_ext.tex = glGetUniformLocation(prog, "tex");
127 - renderer->shaders.tex_ext.alpha = glGetUniformLocation(prog, "alpha");
128 - renderer->shaders.tex_ext.pos_attrib = glGetAttribLocation(prog, "pos");
129 -+ renderer->shaders.tex_ext.rounded = glGetUniformLocation(prog, "u_rounded");
130 -+ renderer->shaders.tex_ext.box_pos = glGetUniformLocation(prog, "u_box_pos");
131 -+ renderer->shaders.tex_ext.box_size = glGetUniformLocation(prog, "u_box_size");
132 -+ renderer->shaders.tex_ext.radius = glGetUniformLocation(prog, "u_radius");
133 -+ renderer->shaders.tex_ext.corners = glGetUniformLocation(prog, "u_corners");
134 - }
135 -
136 - pop_gles2_debug(renderer);
137 -diff -ruN a/render/gles2/shaders/tex_external.frag b/render/gles2/shaders/tex_external.frag
138 -+++ b/render/gles2/shaders/tex_external.frag 2026-08-31 12:53:34.209558298 +0200
139 -@@ -10,6 +10,51 @@
140 - uniform samplerExternalOES texture0;
141 - uniform float alpha;
142 -
143 -+
144 -+// PaganDE: rounded clip (discard fragments outside the rounded rect)
145 -+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
146 -+uniform float u_rounded;
147 -+uniform vec2 u_box_pos;
148 -+uniform vec2 u_box_size;
149 -+uniform float u_radius;
150 -+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
151 -+
152 -+void rounded_clip() {
153 -+ if (u_rounded == 0.0) {
154 -+ return;
155 -+ }
156 -+ vec2 p = gl_FragCoord.xy - u_box_pos;
157 -+ float r = u_radius;
158 -+ /* top-left */
159 -+ if (u_corners.x > 0.5) {
160 -+ if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
161 -+ discard;
162 -+ }
163 -+ }
164 -+ /* top-right */
165 -+ if (u_corners.y > 0.5) {
166 -+ if (p.x >= u_box_size.x - r && p.y <= r
167 -+ && distance(p, vec2(u_box_size.x - r, r)) > r) {
168 -+ discard;
169 -+ }
170 -+ }
171 -+ /* bottom-right */
172 -+ if (u_corners.z > 0.5) {
173 -+ if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
174 -+ && distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
175 -+ discard;
176 -+ }
177 -+ }
178 -+ /* bottom-left */
179 -+ if (u_corners.w > 0.5) {
180 -+ if (p.x <= r && p.y >= u_box_size.y - r
181 -+ && distance(p, vec2(r, u_box_size.y - r)) > r) {
182 -+ discard;
183 -+ }
184 -+ }
185 -+}
186 -+
187 - void main() {
188 -+ rounded_clip();
189 - gl_FragColor = texture2D(texture0, v_texcoord) * alpha;
190 - }
191 -diff -ruN a/render/gles2/shaders/tex_rgba.frag b/render/gles2/shaders/tex_rgba.frag
192 -+++ b/render/gles2/shaders/tex_rgba.frag 2026-08-31 12:53:34.209518897 +0200
193 -@@ -8,6 +8,51 @@
194 - uniform sampler2D tex;
195 - uniform float alpha;
196 -
197 -+
198 -+// PaganDE: rounded clip (discard fragments outside the rounded rect)
199 -+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
200 -+uniform float u_rounded;
201 -+uniform vec2 u_box_pos;
202 -+uniform vec2 u_box_size;
203 -+uniform float u_radius;
204 -+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
205 -+
206 -+void rounded_clip() {
207 -+ if (u_rounded == 0.0) {
208 -+ return;
209 -+ }
210 -+ vec2 p = gl_FragCoord.xy - u_box_pos;
211 -+ float r = u_radius;
212 -+ /* top-left */
213 -+ if (u_corners.x > 0.5) {
214 -+ if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
215 -+ discard;
216 -+ }
217 -+ }
218 -+ /* top-right */
219 -+ if (u_corners.y > 0.5) {
220 -+ if (p.x >= u_box_size.x - r && p.y <= r
221 -+ && distance(p, vec2(u_box_size.x - r, r)) > r) {
222 -+ discard;
223 -+ }
224 -+ }
225 -+ /* bottom-right */
226 -+ if (u_corners.z > 0.5) {
227 -+ if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
228 -+ && distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
229 -+ discard;
230 -+ }
231 -+ }
232 -+ /* bottom-left */
233 -+ if (u_corners.w > 0.5) {
234 -+ if (p.x <= r && p.y >= u_box_size.y - r
235 -+ && distance(p, vec2(r, u_box_size.y - r)) > r) {
236 -+ discard;
237 -+ }
238 -+ }
239 -+}
240 -+
241 - void main() {
242 -+ rounded_clip();
243 - gl_FragColor = texture2D(tex, v_texcoord) * alpha;
244 - }
245 -diff -ruN a/render/gles2/shaders/tex_rgbx.frag b/render/gles2/shaders/tex_rgbx.frag
246 -+++ b/render/gles2/shaders/tex_rgbx.frag 2026-08-31 12:53:34.209462266 +0200
247 -@@ -8,6 +8,51 @@
248 - uniform sampler2D tex;
249 - uniform float alpha;
250 -
251 -+
252 -+// PaganDE: rounded clip (discard fragments outside the rounded rect)
253 -+// GLSL ES 1.00: tylko floaty (bez bitowych operacji); maska rogów w vec4.
254 -+uniform float u_rounded;
255 -+uniform vec2 u_box_pos;
256 -+uniform vec2 u_box_size;
257 -+uniform float u_radius;
258 -+uniform vec4 u_corners; /* x=TL y=TR z=BR w=BL, 1.0 = zaokrąglony */
259 -+
260 -+void rounded_clip() {
261 -+ if (u_rounded == 0.0) {
262 -+ return;
263 -+ }
264 -+ vec2 p = gl_FragCoord.xy - u_box_pos;
265 -+ float r = u_radius;
266 -+ /* top-left */
267 -+ if (u_corners.x > 0.5) {
268 -+ if (p.x <= r && p.y <= r && distance(p, vec2(r, r)) > r) {
269 -+ discard;
270 -+ }
271 -+ }
272 -+ /* top-right */
273 -+ if (u_corners.y > 0.5) {
274 -+ if (p.x >= u_box_size.x - r && p.y <= r
275 -+ && distance(p, vec2(u_box_size.x - r, r)) > r) {
276 -+ discard;
277 -+ }
278 -+ }
279 -+ /* bottom-right */
280 -+ if (u_corners.z > 0.5) {
281 -+ if (p.x >= u_box_size.x - r && p.y >= u_box_size.y - r
282 -+ && distance(p, vec2(u_box_size.x - r, u_box_size.y - r)) > r) {
283 -+ discard;
284 -+ }
285 -+ }
286 -+ /* bottom-left */
287 -+ if (u_corners.w > 0.5) {
288 -+ if (p.x <= r && p.y >= u_box_size.y - r
289 -+ && distance(p, vec2(r, u_box_size.y - r)) > r) {
290 -+ discard;
291 -+ }
292 -+ }
293 -+}
294 -+
295 - void main() {
296 -+ rounded_clip();
297 - gl_FragColor = vec4(texture2D(tex, v_texcoord).rgb, 1.0) * alpha;
298 - }
299 -diff -ruN a/types/scene/wlr_scene.c b/types/scene/wlr_scene.c
300 -+++ b/types/scene/wlr_scene.c 2026-08-31 12:49:04.007960213 +0200
301 -@@ -1124,6 +1124,18 @@
302 - }
303 - }
304 -
305 -+void wlr_scene_buffer_set_rounded_clip(struct wlr_scene_buffer *scene_buffer,
306 -+ float radius, uint32_t corners) {
307 -+ if (scene_buffer->clip_radius == radius
308 -+ && scene_buffer->clip_corners == corners) {
309 -+ return;
310 -+ }
311 -+ assert(radius >= 0);
312 -+ scene_buffer->clip_radius = radius;
313 -+ scene_buffer->clip_corners = corners;
314 -+ scene_node_update(&scene_buffer->node, NULL);
315 -+}
316 -+
317 - void wlr_scene_buffer_set_opacity(struct wlr_scene_buffer *scene_buffer,
318 - float opacity) {
319 - if (scene_buffer->opacity == opacity) {
320 -@@ -1499,6 +1511,26 @@
321 - case WLR_SCENE_NODE_BUFFER:;
322 - struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
323 -
324 -+ bool rounded = scene_buffer->clip_radius > 0
325 -+ && scene_buffer->clip_corners != 0;
326 -+ if (rounded) {
327 -+ /* Corner areas are no longer opaque: exclude them from the
328 -+ * opaque region so occlusion and blending stay correct. */
329 -+ int r = (int)scene_buffer->clip_radius;
330 -+ pixman_region32_t corners;
331 -+ pixman_region32_init(&corners);
332 -+ pixman_region32_union_rect(&corners, &corners,
333 -+ x, y, r, r);
334 -+ pixman_region32_union_rect(&corners, &corners,
335 -+ x + dst_box.width - r, y, r, r);
336 -+ pixman_region32_union_rect(&corners, &corners,
337 -+ x + dst_box.width - r, y + dst_box.height - r, r, r);
338 -+ pixman_region32_union_rect(&corners, &corners,
339 -+ x, y + dst_box.height - r, r, r);
340 -+ pixman_region32_subtract(&opaque, &opaque, &corners);
341 -+ pixman_region32_fini(&corners);
342 -+ }
343 -+
344 - if (scene_buffer->is_single_pixel_buffer) {
345 - // Render the buffer as a rect, this is likely to be more efficient
346 - wlr_render_pass_add_rect(data->render_pass, &(struct wlr_render_rect_options){
347 -@@ -1544,9 +1576,11 @@
348 - .dst_box = dst_box,
349 - .transform = transform,
350 - .clip = &render_region,
351 -+ .corner_radius = scene_buffer->clip_radius,
352 -+ .rounded_corners = scene_buffer->clip_corners,
353 - .alpha = &scene_buffer->opacity,
354 - .filter_mode = scene_buffer->filter_mode,
355 -- .blend_mode = !data->output->scene->calculate_visibility ||
356 -+ .blend_mode = rounded || !data->output->scene->calculate_visibility ||
357 - !pixman_region32_empty(&opaque) ?
358 - WLR_RENDER_BLEND_MODE_PREMULTIPLIED : WLR_RENDER_BLEND_MODE_NONE,
359 - .transfer_function = scene_buffer->transfer_function,