diff --git a/LICENSE b/LICENSE index 26ff2da..921ddb0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -Copyright (c) 2023-2025 sewn +Copyright (c) 2023-2024 sewn Copyright (c) 2015 Eric Pruitt Copyright (c) 2024 Forrest Bushstone Copyright (c) 2018-2019 Henrik Nyman diff --git a/drwl.h b/drwl.h index 5b36f34..a506247 100644 --- a/drwl.h +++ b/drwl.h @@ -1,7 +1,7 @@ /* * drwl - https://codeberg.org/sewn/drwl * - * Copyright (c) 2023-2025 sewn + * Copyright (c) 2023-2024 sewn * Copyright (c) 2024 notchoc * * Permission is hereby granted, free of charge, to any person obtaining @@ -81,6 +81,7 @@ utf8decode(uint32_t *state, uint32_t *codep, uint8_t byte) static int drwl_init(void) { + fcft_set_scaling_filter(FCFT_SCALING_FILTER_LANCZOS3); return fcft_init(FCFT_LOG_COLORIZE_AUTO, 0, FCFT_LOG_CLASS_ERROR); } diff --git a/mew.c b/mew.c index 44aaf89..b6ee87d 100644 --- a/mew.c +++ b/mew.c @@ -284,7 +284,7 @@ drawmenu(void) errno = 0; if (!(buf = bufpool_getbuf(&pool, shm, mw, mh))) - die(errno ? "bufpool_getbuf:" : "no buffer available"); + die("failed to find available buffer"); drwl_setimage(drw, buf->image); drwl_setscheme(drw, colors[SchemeNorm]); @@ -419,7 +419,7 @@ insert(const char *str, ssize_t n) return; /* move existing text out of the way, insert new text, and update cursor */ memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0)); - if (str) + if (n > 0) memcpy(&text[cursor], str, n); cursor += n; match(); @@ -694,20 +694,6 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *wl_keyboard, kbd.xkb_state = xkb_state_new(kbd.xkb_keymap); } -static void -keyboard_handle_leave(void *data, struct wl_keyboard *wl_keyboard, - uint32_t serial, struct wl_surface *surface) -{ - /* - * In dmenu(1), if the keyboard cannot be grabbed, it will - * immediately exit. This is done before dmenu is initialized, - * but can't be the same for Wayland. If a new layer surface - * wants keyboard, it will get keyboard, set_exclusivity doesn't - * seem to work. - */ - die("lost keyboard"); -} - static void keyboard_handle_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t _key_state) @@ -768,7 +754,7 @@ keyboard_handle_repeat_info(void *data, struct wl_keyboard *wl_keyboard, static const struct wl_keyboard_listener keyboard_listener = { .keymap = keyboard_handle_keymap, .enter = noop, - .leave = keyboard_handle_leave, + .leave = noop, .key = keyboard_handle_key, .modifiers = keyboard_handle_modifiers, .repeat_info = keyboard_handle_repeat_info, @@ -784,7 +770,6 @@ layer_surface_handle_configure(void *data, struct zwlr_layer_surface_v1 *layer_s mw = width * scale; mh = height * scale; inputw = mw / 3; /* input width: ~33% of output width */ - match(); zwlr_layer_surface_v1_ack_configure(layer_surface, serial); drawmenu(); } @@ -804,12 +789,14 @@ static void surface_handle_preferred_scale(void *data, struct wl_surface *wl_surface, int32_t factor) { - if (scale == factor) - return; scale = factor; loadfonts(); - /* the scale of the surface is only known after an initial draw, not before :( */ + /* FIXME: + * Use a callback to ensure the 'configure' event + * is sent before the draw, which changes the dimensions + * properly for the update in scale. + */ zwlr_layer_surface_v1_set_size(layer_surface, 0, mh / scale); redraw(); } @@ -936,19 +923,33 @@ run(void) { kbd.repeat.timer, POLLIN }, }; - running = 1; + match(); + while (running) { - wl_display_flush(display); + if (wl_display_prepare_read(display) < 0) + if (wl_display_dispatch_pending(display) < 0) + die("wl_display_dispatch_pending:"); - if (poll(pfds, LENGTH(pfds), -1) < 0) + if (wl_display_flush(display) < 0) + die("wl_display_flush:"); + + if (poll(pfds, LENGTH(pfds), -1) < 0) { + wl_display_cancel_read(display); die("poll:"); - - if (pfds[0].revents & POLLIN) - if (wl_display_dispatch(display) < 0) - die("display dispatch failed"); + } if (pfds[1].revents & POLLIN) keyboard_repeat(); + + if (!(pfds[0].revents & POLLIN)) { + wl_display_cancel_read(display); + continue; + } + + if (wl_display_read_events(display) < 0) + die("wl_display_read_events:"); + if (wl_display_dispatch_pending(display) < 0) + die("wl_display_dispatch_pending:"); } } @@ -994,10 +995,11 @@ setup(void) (top ? ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP : ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM ) | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT); zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, -1); - zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, 1); + zwlr_layer_surface_v1_set_keyboard_interactivity(layer_surface, true); zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, NULL); wl_surface_commit(surface); + running = 1; } static void diff --git a/poolbuf.h b/poolbuf.h new file mode 100644 index 0000000..b22d37f --- /dev/null +++ b/poolbuf.h @@ -0,0 +1,143 @@ +/* + * poolbuf - https://codeberg.org/sewn/drwl + * + * Copyright (c) 2023-2024 sewn + * + * 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 +#include +#include +#include +#include +#include + +typedef struct { + struct wl_buffer *wl_buf; + int32_t stride; + int32_t size; + void *data; +} PoolBuf; + +#if defined(__linux__) || defined(___FreeBSD__) +#ifdef __linux__ +#include +#endif +#define __POOLBUF_HAS_MEMFD_CREATE +int memfd_create(const char *, unsigned); +#else +static void +randname(char *buf) +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + long r = ts.tv_nsec; + for (int i = 0; i < 6; ++i) { + buf[i] = 'A'+(r&15)+(r&16)*2; + r >>= 5; + } +} + +static int +create_shm(void) +{ + char name[] = "/poolbuf-XXXXXX"; + int retries = 100; + + do { + randname(name + sizeof(name) - 7); + --retries; + int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600); + if (fd >= 0) { + shm_unlink(name); + return fd; + } + } while (retries > 0 && errno == EEXIST); + return -1; +} +#endif + +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, +}; + +/* Caller must call poolbuf_destroy after finalizing usage if norelease is passed */ +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; + +#ifdef __POOLBUF_HAS_MEMFD_CREATE + fd = memfd_create("poolbuf-shm-buffer-pool", + MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL); +#else + fd = create_shm(); +#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; +}