Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package wmenu for openSUSE:Factory checked in at 2025-10-14 18:07:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/wmenu (Old) and /work/SRC/openSUSE:Factory/.wmenu.new.18484 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "wmenu" Tue Oct 14 18:07:53 2025 rev:6 rq:1311155 version:0.2.0 Changes: -------- --- /work/SRC/openSUSE:Factory/wmenu/wmenu.changes 2024-09-19 21:17:27.342752108 +0200 +++ /work/SRC/openSUSE:Factory/.wmenu.new.18484/wmenu.changes 2025-10-14 18:09:33.361925001 +0200 @@ -1,0 +2,7 @@ +Mon Oct 13 14:19:44 UTC 2025 - llyyr <[email protected]> + +- Update to version 0.2.0: + * Bug fix for rendering on fractional scaling factors + * Optimizations + +------------------------------------------------------------------- Old: ---- 0.1.9.tar.gz New: ---- 0.2.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ wmenu.spec ++++++ --- /var/tmp/diff_new_pack.n3T5MU/_old 2025-10-14 18:09:34.641979087 +0200 +++ /var/tmp/diff_new_pack.n3T5MU/_new 2025-10-14 18:09:34.645979256 +0200 @@ -1,7 +1,7 @@ # # spec file for package wmenu # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC and contributors # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,7 +17,7 @@ Name: wmenu -Version: 0.1.9 +Version: 0.2.0 Release: 0 Summary: A dynamic menu for Sway and wlroots-based Wayland compositors License: MIT ++++++ 0.1.9.tar.gz -> 0.2.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/README.md new/wmenu/README.md --- old/wmenu/README.md 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/README.md 2025-04-29 21:23:10.000000000 +0200 @@ -15,7 +15,7 @@ - scdoc (optional) ``` -$ meson build +$ meson setup build $ ninja -C build # ninja -C build install ``` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/menu.c new/wmenu/menu.c --- old/wmenu/menu.c 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/menu.c 2025-04-29 21:23:10.000000000 +0200 @@ -1,4 +1,5 @@ #define _POSIX_C_SOURCE 200809L +#include <assert.h> #include <ctype.h> #include <poll.h> #include <stdbool.h> @@ -33,6 +34,8 @@ menu->selectionbg = 0x005577ff; menu->selectionfg = 0xeeeeeeff; menu->callback = callback; + menu->test_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 1, 1); + menu->test_cairo = cairo_create(menu->test_surface); return menu; } @@ -45,24 +48,20 @@ } } -static void free_item(struct item *item) { - free(item->text); - free(item); -} - static void free_items(struct menu *menu) { - struct item *next = menu->items; - while (next) { - struct item *item = next; - next = item->next; - free_item(item); + for (size_t i = 0; i < menu->item_count; i++) { + struct item *item = &menu->items[i]; + free(item->text); } + free(menu->items); } // Destroys the menu, freeing memory associated with it. void menu_destroy(struct menu *menu) { free_pages(menu); free_items(menu); + cairo_destroy(menu->test_cairo); + cairo_surface_destroy(menu->test_surface); free(menu); } @@ -167,34 +166,44 @@ } // Add an item to the menu. -void menu_add_item(struct menu *menu, char *text, bool sort) { - struct item *new = calloc(1, sizeof(struct item)); - if (!new) { - return; +void menu_add_item(struct menu *menu, char *text) { + if ((menu->item_count & (menu->item_count - 1)) == 0) { + size_t alloc_size = menu->item_count ? 2 * menu->item_count : 1; + void *new_array = realloc(menu->items, sizeof(struct item) * alloc_size); + if (!new_array) { + fprintf(stderr, "could not realloc %zu bytes", sizeof(struct item) * alloc_size); + exit(EXIT_FAILURE); + } + menu->items = new_array; } + + struct item *new = &menu->items[menu->item_count]; new->text = text; - if (sort) { - for (struct item **item = &menu->items; *item; item = &(*item)->next) { - int result = strcmp(new->text, (*item)->text); - if (result == 0) { - free_item(new); - return; - } - if (result < 0) { - new->next = *item; - *item = new; - return; - } - } - } + menu->item_count++; +} - if (menu->lastitem) { - menu->lastitem->next = new; - } else { - menu->items = new; +static int compare_items(const void *a, const void *b) { + const struct item *item_a = a; + const struct item *item_b = b; + return strcmp(item_a->text, item_b->text); +} + +void menu_sort_and_deduplicate(struct menu *menu) { + size_t j = 1; + size_t i; + + qsort(menu->items, menu->item_count, sizeof(*menu->items), compare_items); + + for (i = 1; i < menu->item_count; i++) { + if (strcmp(menu->items[i].text, menu->items[j - 1].text) == 0) { + free(menu->items[i].text); + } else { + menu->items[j] = menu->items[i]; + j++; + } } - menu->lastitem = new; + menu->item_count = j; } static void append_page(struct page *page, struct page **first, struct page **last) { @@ -291,6 +300,7 @@ char buf[sizeof menu->input], *tok; char **tokv = NULL; int i, tokc = 0; + size_t k; size_t tok_len; menu->matches = NULL; menu->matches_end = NULL; @@ -314,8 +324,8 @@ } tok_len = tokc ? strlen(tokv[0]) : 0; - struct item *item; - for (item = menu->items; item; item = item->next) { + for (k = 0; k < menu->item_count; k++) { + struct item *item = &menu->items[k]; for (i = 0; i < tokc; i++) { if (!fstrstr(menu, item->text, tokv[i])) { /* token does not match */ @@ -366,9 +376,13 @@ } } +// Marks the menu as needing to be rendered again. +void menu_invalidate(struct menu *menu) { + menu->rendered = false; +} + // Render menu items. void menu_render_items(struct menu *menu) { - render_menu(menu); calc_widths(menu); match_items(menu); render_menu(menu); @@ -489,13 +503,13 @@ // Delete right menu->input[menu->cursor] = '\0'; match_items(menu); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_u: // Delete left insert(menu, NULL, 0 - menu->cursor); match_items(menu); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_w: // Delete word @@ -506,7 +520,7 @@ insert(menu, NULL, nextrune(menu, -1) - menu->cursor); } match_items(menu); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_Y: // Paste clipboard @@ -514,17 +528,17 @@ return; } match_items(menu); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_Left: case XKB_KEY_KP_Left: movewordedge(menu, -1); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_Right: case XKB_KEY_KP_Right: movewordedge(menu, +1); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_Return: @@ -538,11 +552,11 @@ switch (sym) { case XKB_KEY_b: movewordedge(menu, -1); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_f: movewordedge(menu, +1); - render_menu(menu); + menu_invalidate(menu); return; case XKB_KEY_g: sym = XKB_KEY_Home; @@ -584,10 +598,10 @@ case XKB_KEY_KP_Up: if (menu->sel && menu->sel->prev_match) { menu->sel = menu->sel->prev_match; - render_menu(menu); + menu_invalidate(menu); } else if (menu->cursor > 0) { menu->cursor = nextrune(menu, -1); - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_Right: @@ -596,51 +610,51 @@ case XKB_KEY_KP_Down: if (menu->cursor < len) { menu->cursor = nextrune(menu, +1); - render_menu(menu); + menu_invalidate(menu); } else if (menu->sel && menu->sel->next_match) { menu->sel = menu->sel->next_match; - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_Prior: case XKB_KEY_KP_Prior: if (menu->sel && menu->sel->page->prev) { menu->sel = menu->sel->page->prev->first; - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_Next: case XKB_KEY_KP_Next: if (menu->sel && menu->sel->page->next) { menu->sel = menu->sel->page->next->first; - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_Home: case XKB_KEY_KP_Home: if (menu->sel == menu->matches) { menu->cursor = 0; - render_menu(menu); + menu_invalidate(menu); } else { menu->sel = menu->matches; - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_End: case XKB_KEY_KP_End: if (menu->cursor < len) { menu->cursor = len; - render_menu(menu); + menu_invalidate(menu); } else { menu->sel = menu->matches_end; - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_BackSpace: if (menu->cursor > 0) { insert(menu, NULL, nextrune(menu, -1) - menu->cursor); match_items(menu); - render_menu(menu); + menu_invalidate(menu); } break; case XKB_KEY_Delete: @@ -651,7 +665,7 @@ menu->cursor = nextrune(menu, +1); insert(menu, NULL, nextrune(menu, -1) - menu->cursor); match_items(menu); - render_menu(menu); + menu_invalidate(menu); break; case XKB_KEY_Tab: if (!menu->sel) { @@ -661,7 +675,7 @@ memcpy(menu->input, menu->sel->text, menu->cursor); menu->input[menu->cursor] = '\0'; match_items(menu); - render_menu(menu); + menu_invalidate(menu); break; case XKB_KEY_Escape: menu->exit = true; @@ -671,7 +685,7 @@ if (xkb_keysym_to_utf8(sym, buf, 8)) { insert(menu, buf, strnlen(buf, 8)); match_items(menu); - render_menu(menu); + menu_invalidate(menu); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/menu.h new/wmenu/menu.h --- old/wmenu/menu.h 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/menu.h 2025-04-29 21:23:10.000000000 +0200 @@ -1,6 +1,7 @@ #ifndef WMENU_MENU_H #define WMENU_MENU_H +#include <cairo/cairo.h> #include <stdbool.h> #include <sys/types.h> #include <xkbcommon/xkbcommon.h> @@ -13,7 +14,6 @@ struct item { char *text; int width; - struct item *next; // traverses all items struct item *prev_match; // previous matching item struct item *next_match; // next matching item struct page *page; // the page holding this item @@ -52,6 +52,10 @@ struct wl_context *context; + // 1x1 surface used estimate text sizes with pango + cairo_surface_t *test_surface; + cairo_t *test_cairo; + int width; int height; int line_height; @@ -60,12 +64,13 @@ int promptw; int left_arrow; int right_arrow; + bool rendered; char input[BUFSIZ]; size_t cursor; - struct item *items; // list of all items - struct item *lastitem; // last item in the list + struct item *items; // array of all items + size_t item_count; struct item *matches; // list of matching items struct item *matches_end; // last matching item struct item *sel; // selected item @@ -79,7 +84,9 @@ struct menu *menu_create(menu_callback callback); void menu_destroy(struct menu *menu); void menu_getopts(struct menu *menu, int argc, char *argv[]); -void menu_add_item(struct menu *menu, char *text, bool sort); +void menu_add_item(struct menu *menu, char *text); +void menu_sort_and_deduplicate(struct menu *menu); +void menu_invalidate(struct menu *menu); void menu_render_items(struct menu *menu); void menu_paste(struct menu *menu, const char *text, ssize_t len); void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/meson.build new/wmenu/meson.build --- old/wmenu/meson.build 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/meson.build 2025-04-29 21:23:10.000000000 +0200 @@ -1,7 +1,7 @@ project( 'wmenu', 'c', - version: '0.1.9', + version: '0.2.0', license: 'MIT', default_options: [ 'c_std=c11', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/render.c new/wmenu/render.c --- old/wmenu/render.c 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/render.c 2025-04-29 21:23:10.000000000 +0200 @@ -13,8 +13,13 @@ // Calculate text widths. void calc_widths(struct menu *menu) { struct wl_context *context = menu->context; - struct pool_buffer *current = context_get_current_buffer(context); - cairo_t *cairo = current->cairo; + int scale = context_get_scale(context); + cairo_surface_set_device_scale(menu->test_surface, scale, scale); + cairo_set_antialias(menu->test_cairo, CAIRO_ANTIALIAS_BEST); + cairo_font_options_t *fo = cairo_font_options_create(); + cairo_set_font_options(menu->test_cairo, fo); + cairo_font_options_destroy(fo); + cairo_t *cairo = menu->test_cairo; // Calculate prompt width if (menu->prompt) { @@ -28,7 +33,8 @@ menu->right_arrow = text_width(cairo, menu->font, ">") + 2 * menu->padding; // Calculate item widths and input area width - for (struct item *item = menu->items; item; item = item->next) { + for (size_t i = 0; i < menu->item_count; i++) { + struct item *item = &menu->items[i]; item->width = text_width(cairo, menu->font, item->text); if (item->width > menu->inputw) { menu->inputw = item->width; @@ -183,33 +189,18 @@ void render_menu(struct menu *menu) { struct wl_context *context = menu->context; - cairo_surface_t *recorder = cairo_recording_surface_create( - CAIRO_CONTENT_COLOR_ALPHA, NULL); - cairo_t *cairo = cairo_create(recorder); - cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); - cairo_font_options_t *fo = cairo_font_options_create(); - cairo_set_font_options(cairo, fo); - cairo_font_options_destroy(fo); - cairo_save(cairo); - cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); - cairo_paint(cairo); - cairo_restore(cairo); - - render_to_cairo(menu, cairo); - int scale = context_get_scale(context); struct pool_buffer *buffer = context_get_next_buffer(context, scale); if (!buffer) { - goto cleanup; + return; } cairo_t *shm = buffer->cairo; - cairo_save(shm); - cairo_set_operator(shm, CAIRO_OPERATOR_CLEAR); - cairo_paint(shm); - cairo_restore(shm); - cairo_set_source_surface(shm, recorder, 0, 0); - cairo_paint(shm); + cairo_set_antialias(shm, CAIRO_ANTIALIAS_BEST); + cairo_font_options_t *fo = cairo_font_options_create(); + cairo_set_font_options(shm, fo); + cairo_font_options_destroy(fo); + render_to_cairo(menu, shm); struct wl_surface *surface = context_get_surface(context); wl_surface_set_buffer_scale(surface, scale); @@ -217,7 +208,5 @@ wl_surface_damage(surface, 0, 0, menu->width, menu->height); wl_surface_commit(surface); -cleanup: - cairo_destroy(cairo); - cairo_surface_destroy(recorder); + menu->rendered = true; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/wayland.c new/wmenu/wayland.c --- old/wmenu/wayland.c 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/wayland.c 2025-04-29 21:23:10.000000000 +0200 @@ -3,7 +3,6 @@ #include <errno.h> #include <poll.h> #include <stdbool.h> -#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -18,6 +17,7 @@ #include "menu.h" #include "pool-buffer.h" +#include "render.h" #include "wayland.h" #include "xdg-activation-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" @@ -208,6 +208,7 @@ static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *wl_output) { struct wl_context *context = data; context->output = wl_output_get_user_data(wl_output); + menu_invalidate(context->menu); } static const struct wl_surface_listener surface_listener = { @@ -439,7 +440,7 @@ context->layer_shell, context->surface, context->output ? context->output->output : NULL, - ZWLR_LAYER_SHELL_V1_LAYER_TOP, + ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "menu" ); assert(layer_surface != NULL); @@ -492,6 +493,11 @@ if (fds[1].revents & POLLIN) { keyboard_repeat(context->keyboard); } + + // Render the menu if necessary + if (!menu->rendered) { + render_menu(menu); + } } context_destroy(context); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/wmenu-run.c new/wmenu/wmenu-run.c --- old/wmenu/wmenu-run.c 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/wmenu-run.c 2025-04-29 21:23:10.000000000 +0200 @@ -20,10 +20,11 @@ if (ent->d_name[0] == '.') { continue; } - menu_add_item(menu, strdup(ent->d_name), true); + menu_add_item(menu, strdup(ent->d_name)); } closedir(dir); } + menu_sort_and_deduplicate(menu); free(path); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/wmenu/wmenu.c new/wmenu/wmenu.c --- old/wmenu/wmenu.c 2024-06-10 02:33:37.000000000 +0200 +++ new/wmenu/wmenu.c 2025-04-29 21:23:10.000000000 +0200 @@ -13,7 +13,7 @@ if (p) { *p = '\0'; } - menu_add_item(menu, strdup(buf), false); + menu_add_item(menu, strdup(buf)); } }
