commit 7956a271dc8cc8285f05034b747e0fd3171806ba
parent 02c3ac09a6bb555dff0c67fe42714d84ad16d1f4
Author: sewn <sewn@disroot.org>
Date: Thu, 5 Sep 2024 20:25:21 +0300
update drwl
Diffstat:
A | bufpool.h | | | 163 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | drwl.h | | | 61 | ++++++++++++++++++++++++++++++++----------------------------- |
M | mew.c | | | 26 | ++++++++++++++------------ |
D | poolbuf.h | | | 120 | ------------------------------------------------------------------------------- |
4 files changed, 209 insertions(+), 161 deletions(-)
diff --git a/bufpool.h b/bufpool.h
@@ -0,0 +1,163 @@
+/*
+ * bufpool - https://codeberg.org/sewn/drwl
+ *
+ * Copyright (c) 2023-2024 sewn <sewn@disroot.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <wayland-client.h>
+#ifdef __linux__
+#include <linux/memfd.h>
+#endif
+
+#include "drwl.h"
+
+typedef struct {
+ struct wl_buffer *wl_buf;
+ int32_t size;
+ int busy;
+ void *mmapped;
+ Img *image;
+} DrwBuf;
+
+typedef struct {
+ DrwBuf bufs[2];
+} BufPool;
+
+static void
+drwbuf_cleanup(DrwBuf *buf)
+{
+ if (buf->wl_buf)
+ wl_buffer_destroy(buf->wl_buf);
+ if (buf->mmapped)
+ munmap(buf->mmapped, buf->size);
+ if (buf->image)
+ drwl_image_destroy(buf->image);
+ *buf = (DrwBuf){0};
+}
+
+static void
+drwbuf_handle_release(void *data, struct wl_buffer *wl_buffer)
+{
+ DrwBuf *buf = data;
+ buf->busy = 0;
+}
+
+static struct wl_buffer_listener drwbuf_buffer_listener = {
+ .release = drwbuf_handle_release,
+};
+
+static DrwBuf *
+bufpool_getbuf(BufPool *pool, struct wl_shm *shm,
+ int32_t width, int32_t height)
+{
+ int i;
+ int fd;
+ void *mmapped;
+ struct wl_shm_pool *shm_pool;
+ struct wl_buffer *wl_buf;
+ int32_t size = width * 4 * height;
+ Img *image;
+ DrwBuf *buf = NULL;
+
+ for (i = 0; i < 2; i++) {
+ if (pool->bufs[i].busy)
+ continue;
+ if (pool->bufs[i].wl_buf && pool->bufs[i].size != size)
+ drwbuf_cleanup(&pool->bufs[i]);
+ buf = &pool->bufs[i];
+ }
+ if (!buf)
+ return NULL;
+ if (buf->wl_buf && buf->size == size)
+ return buf;
+
+#if defined(__linux__) || \
+ ((defined(__FreeBSD__) && (__FreeBSD_version >= 1300048)))
+ fd = memfd_create("drwbuf-shm-buffer-pool",
+ MFD_CLOEXEC | MFD_ALLOW_SEALING |
+#if defined(MFD_NOEXEC_SEAL)
+ MFD_NOEXEC_SEAL
+#else
+ 0
+#endif
+ );
+#else
+ char template[] = "/tmp/drwbuf-XXXXXX";
+#if defined(__OpenBSD__)
+ fd = shm_mkstemp(template);
+#else
+ fd = mkostemp(template, O_CLOEXEC);
+#endif
+ if (fd < 0)
+ return NULL;
+#if defined(__OpenBSD__)
+ shm_unlink(template);
+#else
+ unlink(template);
+#endif
+#endif
+
+ if ((ftruncate(fd, size)) < 0) {
+ close(fd);
+ return NULL;
+ }
+
+ mmapped = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (mmapped == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+#if defined(__linux__) || \
+ ((defined(__FreeBSD__) && (__FreeBSD_version >= 1300048)))
+ fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL);
+#endif
+
+ shm_pool = wl_shm_create_pool(shm, fd, size);
+ wl_buf = wl_shm_pool_create_buffer(shm_pool, 0,
+ width, height, width * 4, WL_SHM_FORMAT_ARGB8888);
+ wl_shm_pool_destroy(shm_pool);
+ close(fd);
+
+ buf->wl_buf = wl_buf;
+ buf->size = size;
+ buf->mmapped = mmapped;
+ buf->busy = 1;
+ if (!(image = drwl_image_create(NULL, width, height, buf->mmapped)))
+ drwbuf_cleanup(buf);
+ buf->image = image;
+ wl_buffer_add_listener(wl_buf, &drwbuf_buffer_listener, buf);
+ return buf;
+}
+
+static void
+bufpool_cleanup(BufPool *pool)
+{
+ int i;
+ for (i = 0; i < 2; i++)
+ drwbuf_cleanup(&pool->bufs[i]);
+}
diff --git a/drwl.h b/drwl.h
@@ -36,9 +36,10 @@
enum { ColFg, ColBg }; /* colorscheme index */
typedef struct fcft_font Fnt;
+typedef pixman_image_t Img;
typedef struct {
- pixman_image_t *pix;
+ Img *image;
Fnt *font;
uint32_t *scheme;
} Drwl;
@@ -102,6 +103,13 @@ drwl_setfont(Drwl *drwl, Fnt *font)
drwl->font = font;
}
+static void
+drwl_setimage(Drwl *drwl, Img *image)
+{
+ if (drwl)
+ drwl->image = image;
+}
+
static Fnt *
drwl_font_create(Drwl *drwl, size_t count,
const char *names[static count], const char *attributes)
@@ -136,26 +144,23 @@ drwl_setscheme(Drwl *drwl, uint32_t *scm)
drwl->scheme = scm;
}
-static inline int
-drwl_stride(unsigned int width)
-{
- return (((PIXMAN_FORMAT_BPP(PIXMAN_a8r8g8b8) * width + 7) / 8 + 4 - 1) & -4);
-}
-
-static void
-drwl_prepare_drawing(Drwl *drwl, unsigned int w, unsigned int h,
- uint32_t *bits, int stride)
+static Img *
+drwl_image_create(Drwl *drwl, unsigned int w, unsigned int h, uint32_t *bits)
{
+ Img *image;
pixman_region32_t clip;
- if (!drwl)
- return;
-
- drwl->pix = pixman_image_create_bits_no_clear(
- PIXMAN_a8r8g8b8, w, h, bits, stride);
+ image = pixman_image_create_bits_no_clear(
+ PIXMAN_a8r8g8b8, w, h, bits, w * 4);
+ if (!image)
+ return NULL;
pixman_region32_init_rect(&clip, 0, 0, w, h);
- pixman_image_set_clip_region32(drwl->pix, &clip);
+ pixman_image_set_clip_region32(image, &clip);
pixman_region32_fini(&clip);
+
+ if (drwl)
+ drwl_setimage(drwl, image);
+ return image;
}
static void
@@ -164,15 +169,15 @@ drwl_rect(Drwl *drwl,
int filled, int invert)
{
pixman_color_t clr;
- if (!drwl || !drwl->scheme || !drwl->pix)
+ if (!drwl || !drwl->scheme || !drwl->image)
return;
clr = convert_color(drwl->scheme[invert ? ColBg : ColFg]);
if (filled)
- pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->pix, &clr, 1,
+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 1,
&(pixman_rectangle16_t){x, y, w, h});
else
- pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->pix, &clr, 4,
+ pixman_image_fill_rectangles(PIXMAN_OP_SRC, drwl->image, &clr, 4,
(pixman_rectangle16_t[4]){
{ x, y, w, 1 },
{ x, y + h - 1, w, 1 },
@@ -195,7 +200,7 @@ drwl_text(Drwl *drwl,
const struct fcft_glyph *glyph, *eg = NULL;
int fcft_subpixel_mode = FCFT_SUBPIXEL_DEFAULT;
- if (!drwl || (render && (!drwl->scheme || !w || !drwl->pix)) || !text || !drwl->font)
+ if (!drwl || (render && (!drwl->scheme || !w || !drwl->image)) || !text || !drwl->font)
return 0;
if (!render) {
@@ -245,7 +250,7 @@ drwl_text(Drwl *drwl,
} else {
w -= eg->advance.x;
pixman_image_composite32(
- PIXMAN_OP_OVER, fg_pix, eg->pix, drwl->pix, 0, 0, 0, 0,
+ PIXMAN_OP_OVER, fg_pix, eg->pix, drwl->image, 0, 0, 0, 0,
x + eg->x, ty - eg->y, eg->width, eg->height);
}
}
@@ -258,11 +263,11 @@ drwl_text(Drwl *drwl,
if (render && pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)
/* pre-rendered glyphs (eg. emoji) */
pixman_image_composite32(
- PIXMAN_OP_OVER, glyph->pix, NULL, drwl->pix, 0, 0, 0, 0,
+ PIXMAN_OP_OVER, glyph->pix, NULL, drwl->image, 0, 0, 0, 0,
x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
else if (render)
pixman_image_composite32(
- PIXMAN_OP_OVER, fg_pix, glyph->pix, drwl->pix, 0, 0, 0, 0,
+ PIXMAN_OP_OVER, fg_pix, glyph->pix, drwl->image, 0, 0, 0, 0,
x + glyph->x, ty - glyph->y, glyph->width, glyph->height);
x += glyph->advance.x;
@@ -293,13 +298,9 @@ drwl_font_getwidth_clamp(Drwl *drwl, const char *text, unsigned int n)
}
static void
-drwl_finish_drawing(Drwl *drwl)
+drwl_image_destroy(Img *image)
{
- if (!drwl)
- return;
- if (drwl->pix)
- pixman_image_unref(drwl->pix);
- drwl->pix = NULL;
+ pixman_image_unref(image);
}
static void
@@ -307,6 +308,8 @@ drwl_destroy(Drwl *drwl)
{
if (drwl->font)
drwl_font_destroy(drwl->font);
+ if (drwl->image)
+ drwl_image_destroy(drwl->image);
free(drwl);
}
diff --git a/mew.c b/mew.c
@@ -1,4 +1,5 @@
/* See LICENSE file for copyright and license details. */
+#include <errno.h>
#include <ctype.h>
#include <locale.h>
#include <poll.h>
@@ -17,7 +18,7 @@
#define LENGTH(X) (sizeof (X) / sizeof (X)[0])
#include "drwl.h"
-#include "poolbuf.h"
+#include "bufpool.h"
#include "xdg-activation-v1-protocol.h"
#include "wlr-layer-shell-unstable-v1-protocol.h"
@@ -71,6 +72,7 @@ static struct xdg_activation_v1 *activation;
static struct wl_surface *surface;
static struct wl_registry *registry;
static Drwl *drw;
+static BufPool pool;
static struct wl_callback *frame_callback;
/* default output supplied by compositor */
static struct wl_output *output = NULL;
@@ -224,6 +226,8 @@ cleanup(void)
free(items[i].text);
free(items);
+ bufpool_cleanup(&pool);
+ drwl_setimage(drw, NULL);
drwl_destroy(drw);
drwl_fini();
@@ -272,14 +276,13 @@ drawmenu(void)
{
unsigned int curpos;
struct item *item;
- int x = 0, y = 0, w, stride;
- PoolBuf *buf;
+ int x = 0, y = 0, w;
+ DrwBuf *buf;
- stride = drwl_stride(mw);
- if (!(buf = poolbuf_create(shm, mw, mh, stride, 0)))
- die("poolbuf_create:");
-
- drwl_prepare_drawing(drw, mw, mh, buf->data, buf->stride);
+ errno = 0;
+ if (!(buf = bufpool_getbuf(&pool, shm, mw, mh)))
+ die("failed to find available buffer");
+ drwl_setimage(drw, buf->image);
drwl_setscheme(drw, colors[SchemeNorm]);
drwl_rect(drw, 0, 0, mw, mh, 1, 1);
@@ -322,7 +325,7 @@ drawmenu(void)
}
}
- drwl_finish_drawing(drw);
+ drwl_setimage(drw, NULL);
wl_surface_set_buffer_scale(surface, scale);
wl_surface_attach(surface, buf->wl_buf, 0, 0);
wl_surface_damage_buffer(surface, 0, 0, mw, mh);
@@ -728,13 +731,13 @@ static const struct wl_keyboard_listener keyboard_listener = {
};
static void
-layer_surface_handle_configure(void *data, struct zwlr_layer_surface_v1 *surface,
+layer_surface_handle_configure(void *data, struct zwlr_layer_surface_v1 *layer_surface,
uint32_t serial, uint32_t width, uint32_t height)
{
mw = width * scale;
mh = height * scale;
inputw = mw / 3; /* input width: ~33% of output width */
- zwlr_layer_surface_v1_ack_configure(surface, serial);
+ zwlr_layer_surface_v1_ack_configure(layer_surface, serial);
drawmenu();
}
@@ -882,7 +885,6 @@ run(void)
};
match();
- drawmenu();
while (running) {
if (wl_display_prepare_read(display) < 0)
diff --git a/poolbuf.h b/poolbuf.h
@@ -1,120 +0,0 @@
-/*
- * poolbuf - https://codeberg.org/sewn/drwl
- *
- * Copyright (c) 2023-2024 sewn <sewn@disroot.org>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdint.h>
-#include <sys/mman.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <wayland-client.h>
-#ifdef __linux__
-#include <linux/memfd.h>
-#endif
-
-typedef struct {
- struct wl_buffer *wl_buf;
- int32_t stride;
- int32_t size;
- void *data;
-} PoolBuf;
-
-static void
-poolbuf_destroy(PoolBuf *buf)
-{
- wl_buffer_destroy(buf->wl_buf);
- munmap(buf->data, buf->size);
- free(buf);
-}
-
-static void
-poolbuf_buffer_release(void *data, struct wl_buffer *wl_buffer)
-{
- PoolBuf *buf = data;
- poolbuf_destroy(buf);
-}
-
-static struct wl_buffer_listener poolbuf_buffer_listener = {
- .release = poolbuf_buffer_release,
-};
-
-static PoolBuf *
-poolbuf_create(struct wl_shm *shm,
- int32_t width, int32_t height, int32_t stride, int norelease)
-{
- int fd;
- void *data;
- struct wl_shm_pool *shm_pool;
- struct wl_buffer *wl_buf;
- int32_t size = stride * height;
- PoolBuf *buf;
-
-#if defined(__linux__) || \
- ((defined(__FreeBSD__) && (__FreeBSD_version >= 1300048)))
- fd = memfd_create("poolbuf-shm-buffer-pool",
- MFD_CLOEXEC | MFD_ALLOW_SEALING |
-#if defined(MFD_NOEXEC_SEAL)
- MFD_NOEXEC_SEAL
-#else
- 0
-#endif
- );
-#else
- char template[] = "/tmp/poolbuf-XXXXXX";
-#if defined(__OpenBSD__)
- fd = shm_mkstemp(template);
-#else
- fd = mkostemp(template, O_CLOEXEC);
-#endif
- unlink(template);
-#endif
- if (fd < 0)
- return NULL;
-
- if ((ftruncate(fd, size)) < 0) {
- close(fd);
- return NULL;
- }
-
- data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
- if (data == MAP_FAILED) {
- close(fd);
- return NULL;
- }
-
- shm_pool = wl_shm_create_pool(shm, fd, size);
- wl_buf = wl_shm_pool_create_buffer(shm_pool, 0,
- width, height, stride, WL_SHM_FORMAT_ARGB8888);
- wl_shm_pool_destroy(shm_pool);
- close(fd);
-
- buf = calloc(1, sizeof(PoolBuf));
- buf->wl_buf = wl_buf;
- buf->stride = stride;
- buf->size = size;
- buf->data = data;
- if (!norelease)
- wl_buffer_add_listener(wl_buf, &poolbuf_buffer_listener, buf);
- return buf;
-}