Free memory associated with the menu on exit - wmenu - 🔧 fork of wmenu
 (HTM) git clone git@git.drkhsh.at/wmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit f7e6e0b4bf3bca6dbc2b6c7e81cb013be43c6c06
 (DIR) parent b247119ab3ad46760ac85428309230200d9f6c61
 (HTM) Author: adnano <me@adnano.co>
       Date:   Sat,  2 Mar 2024 11:31:13 -0500
       
       Free memory associated with the menu on exit
       
       Diffstat:
         M main.c                              |      89 +++++++++++++------------------
         M menu.c                              |     149 ++++++++++++++++++++++++++-----
         M menu.h                              |      60 +++++++++++++++++++++-----------
         M pango.c                             |       8 ++++++--
         M render.c                            |      13 +++++++------
       
       5 files changed, 220 insertions(+), 99 deletions(-)
       ---
 (DIR) diff --git a/main.c b/main.c
       @@ -24,11 +24,9 @@ static void noop() {
                // Do nothing
        }
        
       -static void surface_enter(void *data, struct wl_surface *surface,
       -                struct wl_output *wl_output) {
       +static void surface_enter(void *data, struct wl_surface *surface, struct wl_output *wl_output) {
                struct menu *menu = data;
       -        struct output *output = wl_output_get_user_data(wl_output);
       -        menu->output = output;
       +        menu->output = wl_output_get_user_data(wl_output);
        }
        
        static const struct wl_surface_listener surface_listener = {
       @@ -45,8 +43,7 @@ static void layer_surface_configure(void *data,
                zwlr_layer_surface_v1_ack_configure(surface, serial);
        }
        
       -static void layer_surface_closed(void *data,
       -                struct zwlr_layer_surface_v1 *surface) {
       +static void layer_surface_closed(void *data, struct zwlr_layer_surface_v1 *surface) {
                struct menu *menu = data;
                menu->exit = true;
        }
       @@ -82,18 +79,18 @@ static const struct wl_output_listener output_listener = {
        
        static void keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
                        uint32_t format, int32_t fd, uint32_t size) {
       -        assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
                struct keyboard *keyboard = data;
       +        assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
        
                char *map_shm = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
       -        assert (map_shm != MAP_FAILED);
       +        assert(map_shm != MAP_FAILED);
        
       -        struct xkb_keymap *keymap = xkb_keymap_new_from_string(keyboard->xkb_context,
       +        keyboard->keymap = xkb_keymap_new_from_string(keyboard->context,
                        map_shm, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
                munmap(map_shm, size);
                close(fd);
        
       -        keyboard->xkb_state = xkb_state_new(keymap);
       +        keyboard->state = xkb_state_new(keyboard->keymap);
        }
        
        static void keyboard_repeat(struct keyboard *keyboard) {
       @@ -109,7 +106,7 @@ static void keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
                struct keyboard *keyboard = data;
        
                enum wl_keyboard_key_state key_state = _key_state;
       -        xkb_keysym_t sym = xkb_state_key_get_one_sym(keyboard->xkb_state, key + 8);
       +        xkb_keysym_t sym = xkb_state_key_get_one_sym(keyboard->state, key + 8);
                menu_keypress(keyboard->menu, key_state, sym);
        
                if (key_state == WL_KEYBOARD_KEY_STATE_PRESSED && keyboard->repeat_period >= 0) {
       @@ -142,7 +139,7 @@ static void keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
                        uint32_t mods_latched, uint32_t mods_locked,
                        uint32_t group) {
                struct keyboard *keyboard = data;
       -        xkb_state_update_mask(keyboard->xkb_state, mods_depressed, mods_latched,
       +        xkb_state_update_mask(keyboard->state, mods_depressed, mods_latched,
                                mods_locked, 0, 0, group);
        }
        
       @@ -159,8 +156,10 @@ static void seat_capabilities(void *data, struct wl_seat *seat,
                        enum wl_seat_capability caps) {
                struct menu *menu = data;
                if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
       -                struct wl_keyboard *keyboard = wl_seat_get_keyboard(seat);
       -                wl_keyboard_add_listener(keyboard, &keyboard_listener, menu->keyboard);
       +                struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(seat);
       +                struct keyboard *keyboard = keyboard_create(menu, wl_keyboard);
       +                wl_keyboard_add_listener(wl_keyboard, &keyboard_listener, keyboard);
       +                menu_set_keyboard(menu, keyboard);
                }
        }
        
       @@ -170,9 +169,9 @@ static const struct wl_seat_listener seat_listener = {
        };
        
        static void data_device_selection(void *data, struct wl_data_device *data_device,
       -                struct wl_data_offer *offer) {
       +                struct wl_data_offer *data_offer) {
                struct menu *menu = data;
       -        menu->offer = offer;
       +        menu->data_offer = data_offer;
        }
        
        static const struct wl_data_device_listener data_device_listener = {
       @@ -188,27 +187,22 @@ static void handle_global(void *data, struct wl_registry *registry,
                        uint32_t name, const char *interface, uint32_t version) {
                struct menu *menu = data;
                if (strcmp(interface, wl_compositor_interface.name) == 0) {
       -                menu->compositor = wl_registry_bind(registry, name,
       -                                &wl_compositor_interface, 4);
       +                menu->compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 4);
                } else if (strcmp(interface, wl_shm_interface.name) == 0) {
                        menu->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
                } else if (strcmp(interface, wl_seat_interface.name) == 0) {
                        menu->seat = wl_registry_bind(registry, name, &wl_seat_interface, 4);
                        wl_seat_add_listener(menu->seat, &seat_listener, menu);
                } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
       -                menu->data_device_manager = wl_registry_bind(registry, name,
       -                                &wl_data_device_manager_interface, 3);
       +                menu->data_device_manager = wl_registry_bind(registry, name, &wl_data_device_manager_interface, 3);
                } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
       -                menu->layer_shell = wl_registry_bind(registry, name,
       -                                &zwlr_layer_shell_v1_interface, 1);
       +                menu->layer_shell = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, 1);
                } else if (strcmp(interface, wl_output_interface.name) == 0) {
       -                struct output *output = calloc(1, sizeof(struct output));
       -                output->output = wl_registry_bind(registry, name,
       -                                &wl_output_interface, 4);
       -                output->menu = menu;
       -                output->scale = 1;
       -                wl_output_set_user_data(output->output, output);
       -                wl_output_add_listener(output->output, &output_listener, output);
       +                struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, 4);
       +                struct output *output = output_create(menu, wl_output);
       +                wl_output_set_user_data(wl_output, output);
       +                wl_output_add_listener(wl_output, &output_listener, output);
       +                menu_add_output(menu, output);
                }
        }
        
       @@ -217,15 +211,8 @@ static const struct wl_registry_listener registry_listener = {
                .global_remove = noop,
        };
        
       -static void keyboard_init(struct keyboard *keyboard, struct menu *menu) {
       -        keyboard->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
       -        assert(keyboard->xkb_context != NULL);
       -        keyboard->repeat_timer = timerfd_create(CLOCK_MONOTONIC, 0);
       -        assert(keyboard->repeat_timer >= 0);
       -        keyboard->menu = menu;
       -}
       -
       -static void create_surface(struct menu *menu) {
       +// Connect to the Wayland display.
       +static void menu_connect(struct menu *menu) {
                menu->display = wl_display_connect(NULL);
                if (!menu->display) {
                        fprintf(stderr, "Failed to connect to display.\n");
       @@ -240,14 +227,17 @@ static void create_surface(struct menu *menu) {
                assert(menu->seat != NULL);
                assert(menu->data_device_manager != NULL);
                assert(menu->layer_shell != NULL);
       +        menu->registry = registry;
        
                // Get data device for seat
                struct wl_data_device *data_device = wl_data_device_manager_get_data_device(
                                menu->data_device_manager, menu->seat);
                wl_data_device_add_listener(data_device, &data_device_listener, menu);
       +        menu->data_device = data_device;
        
       -        // Second roundtrip for xdg-output
       +        // Second roundtrip for seat and output listeners
                wl_display_roundtrip(menu->display);
       +        assert(menu->keyboard != NULL);
        
                if (menu->output_name && !menu->output) {
                        fprintf(stderr, "Output %s not found\n", menu->output_name);
       @@ -265,6 +255,7 @@ static void create_surface(struct menu *menu) {
                        "menu"
                );
                assert(layer_surface != NULL);
       +        menu->layer_surface = layer_surface;
        
                uint32_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
                        ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
       @@ -285,14 +276,9 @@ static void create_surface(struct menu *menu) {
        }
        
        int main(int argc, char *argv[]) {
       -        struct menu *menu = calloc(1, sizeof(struct menu));
       -        menu_init(menu, argc, argv);
       -
       -        struct keyboard *keyboard = calloc(1, sizeof(struct keyboard));
       -        keyboard_init(keyboard, menu);
       -        menu->keyboard = keyboard;
       -
       -        create_surface(menu);
       +        struct menu *menu = menu_create();
       +        menu_getopts(menu, argc, argv);
       +        menu_connect(menu);
                render_menu(menu);
        
                read_menu_items(menu);
       @@ -300,7 +286,7 @@ int main(int argc, char *argv[]) {
        
                struct pollfd fds[] = {
                        { wl_display_get_fd(menu->display), POLLIN },
       -                { keyboard->repeat_timer, POLLIN },
       +                { menu->keyboard->repeat_timer, POLLIN },
                };
                const size_t nfds = sizeof(fds) / sizeof(*fds);
        
       @@ -325,13 +311,14 @@ int main(int argc, char *argv[]) {
                        }
        
                        if (fds[1].revents & POLLIN) {
       -                        keyboard_repeat(keyboard);
       +                        keyboard_repeat(menu->keyboard);
                        }
                }
        
       -        wl_display_disconnect(menu->display);
       +        bool failure = menu->failure;
       +        menu_destroy(menu);
        
       -        if (menu->failure) {
       +        if (failure) {
                        return EXIT_FAILURE;
                }
                return EXIT_SUCCESS;
 (DIR) diff --git a/menu.c b/menu.c
       @@ -1,4 +1,5 @@
        #define _POSIX_C_SOURCE 200809L
       +#include <assert.h>
        #include <ctype.h>
        #include <poll.h>
        #include <stdbool.h>
       @@ -18,7 +19,55 @@
        #include "menu.h"
        
        #include "pango.h"
       +#include "pool-buffer.h"
        #include "render.h"
       +#include "wlr-layer-shell-unstable-v1-client-protocol.h"
       +
       +// Creates and returns a new menu.
       +struct menu *menu_create() {
       +        struct menu *menu = calloc(1, sizeof(struct menu));
       +        menu->strncmp = strncmp;
       +        menu->font = "monospace 10";
       +        menu->normalbg = 0x222222ff;
       +        menu->normalfg = 0xbbbbbbff;
       +        menu->promptbg = 0x005577ff;
       +        menu->promptfg = 0xeeeeeeff;
       +        menu->selectionbg = 0x005577ff;
       +        menu->selectionfg = 0xeeeeeeff;
       +        return menu;
       +}
       +
       +// Creates and returns a new keyboard.
       +struct keyboard *keyboard_create(struct menu *menu, struct wl_keyboard *wl_keyboard) {
       +        struct keyboard *keyboard = calloc(1, sizeof(struct keyboard));
       +        keyboard->menu = menu;
       +        keyboard->keyboard = wl_keyboard;
       +        keyboard->context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
       +        assert(keyboard->context != NULL);
       +        keyboard->repeat_timer = timerfd_create(CLOCK_MONOTONIC, 0);
       +        assert(keyboard->repeat_timer != -1);
       +        return keyboard;
       +}
       +
       +// Sets the current keyboard.
       +void menu_set_keyboard(struct menu *menu, struct keyboard *keyboard) {
       +        menu->keyboard = keyboard;
       +}
       +
       +// Creates and returns a new output.
       +struct output *output_create(struct menu *menu, struct wl_output *wl_output) {
       +        struct output *output = calloc(1, sizeof(struct output));
       +        output->menu = menu;
       +        output->output = wl_output;
       +        output->scale = 1;
       +        return output;
       +}
       +
       +// Adds an output to the output list.
       +void menu_add_output(struct menu *menu, struct output *output) {
       +        output->next = menu->output_list;
       +        menu->output_list = output;
       +}
        
        static bool parse_color(const char *color, uint32_t *result) {
                if (color[0] == '#') {
       @@ -37,17 +86,8 @@ static bool parse_color(const char *color, uint32_t *result) {
                return true;
        }
        
       -// Initialize the menu.
       -void menu_init(struct menu *menu, int argc, char *argv[]) {
       -        menu->strncmp = strncmp;
       -        menu->font = "monospace 10";
       -        menu->background = 0x222222ff;
       -        menu->foreground = 0xbbbbbbff;
       -        menu->promptbg = 0x005577ff;
       -        menu->promptfg = 0xeeeeeeff;
       -        menu->selectionbg = 0x005577ff;
       -        menu->selectionfg = 0xeeeeeeff;
       -
       +// Parse menu options from command line arguments.
       +void menu_getopts(struct menu *menu, int argc, char *argv[]) {
                const char *usage =
                        "Usage: wmenu [-biv] [-f font] [-l lines] [-o output] [-p prompt]\n"
                        "\t[-N color] [-n color] [-M color] [-m color] [-S color] [-s color]\n";
       @@ -77,12 +117,12 @@ void menu_init(struct menu *menu, int argc, char *argv[]) {
                                menu->prompt = optarg;
                                break;
                        case 'N':
       -                        if (!parse_color(optarg, &menu->background)) {
       +                        if (!parse_color(optarg, &menu->normalbg)) {
                                        fprintf(stderr, "Invalid background color: %s", optarg);
                                }
                                break;
                        case 'n':
       -                        if (!parse_color(optarg, &menu->foreground)) {
       +                        if (!parse_color(optarg, &menu->normalfg)) {
                                        fprintf(stderr, "Invalid foreground color: %s", optarg);
                                }
                                break;
       @@ -262,6 +302,8 @@ static void match_items(struct menu *menu) {
                        }
                }
        
       +        free(tokv);
       +
                if (lexact) {
                        menu->matches = lexact;
                        menu->matches_end = exactend;
       @@ -364,13 +406,13 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                        return;
                }
        
       -        bool ctrl = xkb_state_mod_name_is_active(menu->keyboard->xkb_state,
       +        bool ctrl = xkb_state_mod_name_is_active(menu->keyboard->state,
                                XKB_MOD_NAME_CTRL,
                                XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
       -        bool meta = xkb_state_mod_name_is_active(menu->keyboard->xkb_state,
       +        bool meta = xkb_state_mod_name_is_active(menu->keyboard->state,
                                XKB_MOD_NAME_ALT,
                                XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
       -        bool shift = xkb_state_mod_name_is_active(menu->keyboard->xkb_state,
       +        bool shift = xkb_state_mod_name_is_active(menu->keyboard->state,
                                XKB_MOD_NAME_SHIFT,
                                XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
        
       @@ -448,7 +490,7 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                return;
                        case XKB_KEY_Y:
                                // Paste clipboard
       -                        if (!menu->offer) {
       +                        if (!menu->data_offer) {
                                        return;
                                }
        
       @@ -457,7 +499,7 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                        // Pipe failed
                                        return;
                                }
       -                        wl_data_offer_receive(menu->offer, "text/plain", fds[1]);
       +                        wl_data_offer_receive(menu->data_offer, "text/plain", fds[1]);
                                close(fds[1]);
        
                                wl_display_roundtrip(menu->display);
       @@ -472,8 +514,8 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                }
                                close(fds[0]);
        
       -                        wl_data_offer_destroy(menu->offer);
       -                        menu->offer = NULL;
       +                        wl_data_offer_destroy(menu->data_offer);
       +                        menu->data_offer = NULL;
                                match_items(menu);
                                render_menu(menu);
                                return;
       @@ -642,3 +684,70 @@ void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                        }
                }
        }
       +
       +// Frees the keyboard.
       +static void free_keyboard(struct keyboard *keyboard) {
       +        wl_keyboard_release(keyboard->keyboard);
       +        xkb_state_unref(keyboard->state);
       +        xkb_keymap_unref(keyboard->keymap);
       +        xkb_context_unref(keyboard->context);
       +        free(keyboard);
       +}
       +
       +// Frees the outputs.
       +static void free_outputs(struct menu *menu) {
       +        struct output *next = menu->output_list;
       +        while (next) {
       +                struct output *output = next;
       +                next = output->next;
       +                wl_output_destroy(output->output);
       +                free(output);
       +        }
       +}
       +
       +// Frees menu pages.
       +static void free_pages(struct menu *menu) {
       +        struct page *next = menu->pages;
       +        while (next) {
       +                struct page *page = next;
       +                next = page->next;
       +                free(page);
       +        }
       +}
       +
       +// Frees menu items.
       +static void free_items(struct menu *menu) {
       +        struct item *next = menu->items;
       +        while (next) {
       +                struct item *item = next;
       +                next = item->next;
       +                free(item->text);
       +                free(item);
       +        }
       +}
       +
       +// Destroys the menu, freeing memory associated with it.
       +void menu_destroy(struct menu *menu) {
       +        wl_registry_destroy(menu->registry);
       +        wl_compositor_destroy(menu->compositor);
       +        wl_shm_destroy(menu->shm);
       +        wl_seat_destroy(menu->seat);
       +        wl_data_device_manager_destroy(menu->data_device_manager);
       +        zwlr_layer_shell_v1_destroy(menu->layer_shell);
       +        free_outputs(menu);
       +
       +        free_keyboard(menu->keyboard);
       +        wl_data_device_destroy(menu->data_device);
       +        wl_surface_destroy(menu->surface);
       +        zwlr_layer_surface_v1_destroy(menu->layer_surface);
       +        wl_data_offer_destroy(menu->data_offer);
       +
       +        free_pages(menu);
       +        free_items(menu);
       +
       +        destroy_buffer(&menu->buffers[0]);
       +        destroy_buffer(&menu->buffers[1]);
       +
       +        wl_display_disconnect(menu->display);
       +        free(menu);
       +}
 (DIR) diff --git a/menu.h b/menu.h
       @@ -27,16 +27,18 @@ struct page {
        struct output {
                struct menu *menu;
                struct wl_output *output;
       -        const char *name;
       -        int32_t scale;
       +        const char *name;    // output name
       +        int32_t scale;       // output scale
       +        struct output *next; // next output
        };
        
        // Keyboard state.
        struct keyboard {
                struct menu *menu;
       -
       -        struct xkb_context *xkb_context;
       -        struct xkb_state *xkb_state;
       +        struct wl_keyboard *keyboard;
       +        struct xkb_context *context;
       +        struct xkb_keymap *keymap;
       +        struct xkb_state *state;
        
                int repeat_timer;
                int repeat_delay;
       @@ -47,19 +49,40 @@ struct keyboard {
        
        // Menu state.
        struct menu {
       +        // Whether the menu appears at the bottom of the screen
       +        bool bottom;
       +        // The function used to match menu items
       +        int (*strncmp)(const char *, const char *, size_t);
       +        // The font used to display the menu
       +        char *font;
       +        // The number of lines to list items vertically
       +        int lines;
       +        // The name of the output to display on
       +        char *output_name;
       +        // The prompt displayed to the left of the input field
       +        char *prompt;
       +        // Normal colors
       +        uint32_t normalbg, normalfg;
       +        // Prompt colors
       +        uint32_t promptbg, promptfg;
       +        // Selection colors
       +        uint32_t selectionbg, selectionfg;
       +
       +        struct wl_display *display;
       +        struct wl_registry *registry;
                struct wl_compositor *compositor;
                struct wl_shm *shm;
                struct wl_seat *seat;
                struct wl_data_device_manager *data_device_manager;
                struct zwlr_layer_shell_v1 *layer_shell;
       -
       -        struct wl_display *display;
       -        struct wl_surface *surface;
       -        struct wl_data_offer *offer;
       +        struct output *output_list;
        
                struct keyboard *keyboard;
       +        struct wl_data_device *data_device;
       +        struct wl_surface *surface;
       +        struct zwlr_layer_surface_v1 *layer_surface;
       +        struct wl_data_offer *data_offer;
                struct output *output;
       -        char *output_name;
        
                struct pool_buffer buffers[2];
                struct pool_buffer *current;
       @@ -73,15 +96,6 @@ struct menu {
                int left_arrow;
                int right_arrow;
        
       -        bool bottom;
       -        int (*strncmp)(const char *, const char *, size_t);
       -        char *font;
       -        int lines;
       -        char *prompt;
       -        uint32_t background, foreground;
       -        uint32_t promptbg, promptfg;
       -        uint32_t selectionbg, selectionfg;
       -
                char input[BUFSIZ];
                size_t cursor;
        
       @@ -95,9 +109,15 @@ struct menu {
                bool failure;
        };
        
       -void menu_init(struct menu *menu, int argc, char *argv[]);
       +struct menu *menu_create();
       +struct keyboard *keyboard_create(struct menu *menu, struct wl_keyboard *wl_keyboard);
       +void menu_set_keyboard(struct menu *menu, struct keyboard *keyboard);
       +struct output *output_create(struct menu *menu, struct wl_output *wl_output);
       +void menu_add_output(struct menu *menu, struct output *output);
       +void menu_getopts(struct menu *menu, int argc, char *argv[]);
        void read_menu_items(struct menu *menu);
        void menu_keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                        xkb_keysym_t sym);
       +void menu_destroy(struct menu *menu);
        
        #endif
 (DIR) diff --git a/pango.c b/pango.c
       @@ -13,12 +13,16 @@ int get_font_height(const char *fontstr) {
                PangoFontDescription *desc = pango_font_description_from_string(fontstr);
                PangoFont *font = pango_font_map_load_font(fontmap, context, desc);
                if (font == NULL) {
       +                pango_font_description_free(desc);
       +                g_object_unref(context);
                        return -1;
                }
                PangoFontMetrics *metrics = pango_font_get_metrics(font, NULL);
                int height = pango_font_metrics_get_height(metrics) / PANGO_SCALE;
       -        pango_font_description_free(desc);
                pango_font_metrics_unref(metrics);
       +        g_object_unref(font);
       +        pango_font_description_free(desc);
       +        g_object_unref(context);
                return height;
        }
        
       @@ -32,8 +36,8 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
                pango_layout_set_font_description(layout, desc);
                pango_layout_set_single_paragraph_mode(layout, 1);
                pango_layout_set_attributes(layout, attrs);
       -        pango_attr_list_unref(attrs);
                pango_font_description_free(desc);
       +        pango_attr_list_unref(attrs);
                return layout;
        }
        
 (DIR) diff --git a/render.c b/render.c
       @@ -73,7 +73,7 @@ static void render_prompt(struct menu *menu, cairo_t *cairo) {
        // Renders the input text.
        static void render_input(struct menu *menu, cairo_t *cairo) {
                render_text(menu, cairo, menu->input, menu->promptw, 0, 0,
       -                0, menu->foreground, menu->padding, menu->padding);
       +                0, menu->normalfg, menu->padding, menu->padding);
        }
        
        // Renders a cursor for the input field.
       @@ -91,8 +91,8 @@ static void render_cursor(struct menu *menu, cairo_t *cairo) {
        
        // Renders a single menu item horizontally.
        static int render_horizontal_item(struct menu *menu, cairo_t *cairo, struct item *item, int x) {
       -        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       -        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
       +        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->normalbg;
       +        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->normalfg;
        
                return render_text(menu, cairo, item->text, x, 0, 0,
                        bg_color, fg_color, menu->padding, menu->padding);
       @@ -100,8 +100,8 @@ static int render_horizontal_item(struct menu *menu, cairo_t *cairo, struct item
        
        // Renders a single menu item vertically.
        static int render_vertical_item(struct menu *menu, cairo_t *cairo, struct item *item, int x, int y) {
       -        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->background;
       -        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->foreground;
       +        uint32_t bg_color = menu->sel == item ? menu->selectionbg : menu->normalbg;
       +        uint32_t fg_color = menu->sel == item ? menu->selectionfg : menu->normalfg;
        
                render_text(menu, cairo, item->text, x, y, menu->width - x,
                        bg_color, fg_color, menu->padding, 0);
       @@ -139,7 +139,7 @@ static void render_vertical_page(struct menu *menu, cairo_t *cairo, struct page 
        static void render_to_cairo(struct menu *menu, cairo_t *cairo) {
                // Render background
                cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
       -        cairo_set_source_u32(cairo, menu->background);
       +        cairo_set_source_u32(cairo, menu->normalbg);
                cairo_paint(cairo);
        
                // Render prompt and input
       @@ -196,4 +196,5 @@ void render_menu(struct menu *menu) {
        
        cleanup:
                cairo_destroy(cairo);
       +        cairo_surface_destroy(recorder);
        }