From: tokyo4j Date: Fri, 4 Oct 2024 06:27:25 +0000 (+0900) Subject: theme: refine the management of corner buttons X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=c2a3a354db31041eb766d85badee1ec02db3d1e0;p=proto%2Flabwc.git theme: refine the management of corner buttons - The builtin hover effect is now unrounded when the window is tiled. - All the corner button icons including ones provided by the user are now rounded when the window is not tiled. - Fixed the bug that the window menu button as a fallback of the window icon is not correctly rounded. --- diff --git a/include/ssd-internal.h b/include/ssd-internal.h index 14bd3265..a0786dfc 100644 --- a/include/ssd-internal.h +++ b/include/ssd-internal.h @@ -18,12 +18,16 @@ struct ssd_button { struct view *view; enum ssd_part_type type; - struct wlr_scene_node *normal; - struct wlr_scene_node *hover; - struct wlr_scene_node *toggled; - struct wlr_scene_node *toggled_hover; - struct wlr_scene_tree *icon_tree; - struct wlr_scene_tree *hover_tree; + /* + * Bitmap of lab_button_state that represents a combination of + * hover/toggled/rounded states. + */ + uint8_t state_set; + /* + * Button nodes for each combination of hover/toggled/rounded states. + * nodes[state_set] should be displayed. + */ + struct wlr_scene_node *nodes[LAB_BS_ALL + 1]; struct wl_listener destroy; }; @@ -140,13 +144,10 @@ struct ssd_part *add_scene_rect( struct ssd_part *add_scene_buffer( struct wl_list *list, enum ssd_part_type type, struct wlr_scene_tree *parent, struct wlr_buffer *buffer, int x, int y); -struct ssd_part *add_scene_button( - struct wl_list *part_list, enum ssd_part_type type, - struct wlr_scene_tree *parent, struct wlr_buffer *icon_buffer, - struct wlr_buffer *hover_buffer, int x, struct view *view); -void add_toggled_icon(struct ssd_button *button, struct wl_list *part_list, - enum ssd_part_type type, struct wlr_buffer *icon_buffer, - struct wlr_buffer *hover_buffer); +struct ssd_part *add_scene_button(struct wl_list *part_list, + enum ssd_part_type type, struct wlr_scene_tree *parent, + struct lab_data_buffer *buffers[LAB_BS_ALL + 1], int x, + struct view *view); void update_window_icon_buffer(struct wlr_scene_node *button_node, struct wlr_buffer *buffer); diff --git a/include/ssd.h b/include/ssd.h index daad81a5..d5b66c08 100644 --- a/include/ssd.h +++ b/include/ssd.h @@ -21,14 +21,19 @@ */ enum ssd_part_type { LAB_SSD_NONE = 0, - LAB_SSD_BUTTON_CLOSE, + + LAB_SSD_BUTTON_CLOSE = 1, LAB_SSD_BUTTON_MAXIMIZE, LAB_SSD_BUTTON_ICONIFY, LAB_SSD_BUTTON_WINDOW_ICON, LAB_SSD_BUTTON_WINDOW_MENU, LAB_SSD_BUTTON_SHADE, LAB_SSD_BUTTON_OMNIPRESENT, - LAB_SSD_BUTTON, /* only for internal use */ + /* only for internal use */ + LAB_SSD_BUTTON_FIRST = LAB_SSD_BUTTON_CLOSE, + LAB_SSD_BUTTON_LAST = LAB_SSD_BUTTON_OMNIPRESENT, + LAB_SSD_BUTTON, + LAB_SSD_PART_TITLEBAR, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, diff --git a/include/theme.h b/include/theme.h index 7f3eac90..3fbe4404 100644 --- a/include/theme.h +++ b/include/theme.h @@ -10,6 +10,7 @@ #include #include +#include "ssd.h" enum lab_justification { LAB_JUSTIFY_LEFT, @@ -30,6 +31,14 @@ struct theme_snapping_overlay { float border_color[3][4]; }; +enum lab_button_state { + LAB_BS_HOVERD = 1 << 0, + LAB_BS_TOGGLED = 1 << 1, + LAB_BS_ROUNDED = 1 << 2, + + LAB_BS_ALL = LAB_BS_HOVERD | LAB_BS_TOGGLED | LAB_BS_ROUNDED, +}; + struct theme { int border_width; @@ -65,21 +74,6 @@ struct theme { /* the shape of the hover effect */ enum lab_shape window_button_hover_bg_shape; - /* button colors */ - float window_active_button_menu_unpressed_image_color[4]; - float window_active_button_iconify_unpressed_image_color[4]; - float window_active_button_max_unpressed_image_color[4]; - float window_active_button_close_unpressed_image_color[4]; - float window_active_button_shade_unpressed_image_color[4]; - float window_active_button_omnipresent_unpressed_image_color[4]; - float window_inactive_button_menu_unpressed_image_color[4]; - float window_inactive_button_iconify_unpressed_image_color[4]; - float window_inactive_button_max_unpressed_image_color[4]; - float window_inactive_button_close_unpressed_image_color[4]; - float window_inactive_button_shade_unpressed_image_color[4]; - float window_inactive_button_omnipresent_unpressed_image_color[4]; - /* TODO: add pressed and hover colors for buttons */ - int menu_item_padding_x; int menu_item_padding_y; int menu_item_height; @@ -128,47 +122,26 @@ struct theme { float window_active_shadow_color[4]; float window_inactive_shadow_color[4]; + struct { + /* + * The texture of a window buttons for each hover/toggled/rounded + * state. This can be accessed like: + * + * buttons[LAB_SSD_BUTTON_ICONIFY][LAB_BS_HOVERD | LAB_BS_TOGGLED] + * + * Elements in buttons[0] are all NULL since LAB_SSD_BUTTON_FIRST is 1. + */ + struct lab_data_buffer *buttons + [LAB_SSD_BUTTON_LAST + 1][LAB_BS_ALL + 1]; + + /* TODO: add toggled/hover/pressed/disabled colors for buttons */ + float button_colors[LAB_SSD_BUTTON_LAST + 1][4]; + + /* TODO: move other window.(in)active.* entries to here */ + + } window[2]; /* indexed by THEME_INACTIVE and THEME_ACTIVE */ + /* textures */ - struct lab_data_buffer *button_close_active_unpressed; - struct lab_data_buffer *button_maximize_active_unpressed; - struct lab_data_buffer *button_restore_active_unpressed; - struct lab_data_buffer *button_iconify_active_unpressed; - struct lab_data_buffer *button_menu_active_unpressed; - struct lab_data_buffer *button_shade_active_unpressed; - struct lab_data_buffer *button_unshade_active_unpressed; - struct lab_data_buffer *button_omnipresent_active_unpressed; - struct lab_data_buffer *button_exclusive_active_unpressed; - - struct lab_data_buffer *button_close_inactive_unpressed; - struct lab_data_buffer *button_maximize_inactive_unpressed; - struct lab_data_buffer *button_restore_inactive_unpressed; - struct lab_data_buffer *button_iconify_inactive_unpressed; - struct lab_data_buffer *button_menu_inactive_unpressed; - struct lab_data_buffer *button_shade_inactive_unpressed; - struct lab_data_buffer *button_unshade_inactive_unpressed; - struct lab_data_buffer *button_omnipresent_inactive_unpressed; - struct lab_data_buffer *button_exclusive_inactive_unpressed; - - /* hover variants are optional and may be NULL */ - struct lab_data_buffer *button_close_active_hover; - struct lab_data_buffer *button_maximize_active_hover; - struct lab_data_buffer *button_restore_active_hover; - struct lab_data_buffer *button_iconify_active_hover; - struct lab_data_buffer *button_menu_active_hover; - struct lab_data_buffer *button_shade_active_hover; - struct lab_data_buffer *button_unshade_active_hover; - struct lab_data_buffer *button_omnipresent_active_hover; - struct lab_data_buffer *button_exclusive_active_hover; - - struct lab_data_buffer *button_close_inactive_hover; - struct lab_data_buffer *button_maximize_inactive_hover; - struct lab_data_buffer *button_restore_inactive_hover; - struct lab_data_buffer *button_iconify_inactive_hover; - struct lab_data_buffer *button_menu_inactive_hover; - struct lab_data_buffer *button_shade_inactive_hover; - struct lab_data_buffer *button_unshade_inactive_hover; - struct lab_data_buffer *button_omnipresent_inactive_hover; - struct lab_data_buffer *button_exclusive_inactive_hover; struct lab_data_buffer *corner_top_left_active_normal; struct lab_data_buffer *corner_top_right_active_normal; @@ -190,6 +163,9 @@ struct theme { int mag_border_width; }; +#define THEME_INACTIVE 0 +#define THEME_ACTIVE 1 + struct server; /** diff --git a/src/ssd/ssd-part.c b/src/ssd/ssd-part.c index d647a272..57b2e63f 100644 --- a/src/ssd/ssd-part.c +++ b/src/ssd/ssd-part.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include "buffer.h" #include "common/list.h" #include "common/mem.h" #include "labwc.h" @@ -123,8 +124,9 @@ update_window_icon_buffer(struct wlr_scene_node *button_node, struct ssd_part * add_scene_button(struct wl_list *part_list, enum ssd_part_type type, - struct wlr_scene_tree *parent, struct wlr_buffer *icon_buffer, - struct wlr_buffer *hover_buffer, int x, struct view *view) + struct wlr_scene_tree *parent, + struct lab_data_buffer *buffers[LAB_BS_ALL + 1], + int x, struct view *view) { struct ssd_part *button_root = add_scene_part(part_list, type); parent = wlr_scene_tree_create(parent); @@ -137,76 +139,35 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type, rc.theme->window_button_width, rc.theme->title_height, 0, 0, invisible); - /* Icon */ - struct wlr_scene_tree *icon_tree = wlr_scene_tree_create(parent); - struct wlr_box icon_geo = get_scale_box(icon_buffer, - rc.theme->window_button_width, rc.theme->title_height); - struct ssd_part *icon_part = add_scene_buffer(part_list, type, - icon_tree, icon_buffer, icon_geo.x, icon_geo.y); - - /* Make sure big icons are scaled down if necessary */ - wlr_scene_buffer_set_dest_size( - wlr_scene_buffer_from_node(icon_part->node), - icon_geo.width, icon_geo.height); - - /* Hover icon */ - struct wlr_scene_tree *hover_tree = wlr_scene_tree_create(parent); - wlr_scene_node_set_enabled(&hover_tree->node, false); - struct wlr_box hover_geo = get_scale_box(hover_buffer, - rc.theme->window_button_width, rc.theme->title_height); - struct ssd_part *hover_part = add_scene_buffer(part_list, type, - hover_tree, hover_buffer, hover_geo.x, hover_geo.y); - - /* Make sure big icons are scaled down if necessary */ - wlr_scene_buffer_set_dest_size( - wlr_scene_buffer_from_node(hover_part->node), - hover_geo.width, hover_geo.height); + /* Icons */ + struct wlr_scene_node *nodes[LAB_BS_ALL + 1] = {0}; + for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; state_set++) { + if (!buffers[state_set]) { + continue; + } + struct wlr_buffer *icon_buffer = &buffers[state_set]->base; + struct wlr_box icon_geo = get_scale_box(icon_buffer, + rc.theme->window_button_width, rc.theme->title_height); + struct ssd_part *icon_part = add_scene_buffer(part_list, type, + parent, icon_buffer, icon_geo.x, icon_geo.y); + /* Make sure big icons are scaled down if necessary */ + wlr_scene_buffer_set_dest_size( + wlr_scene_buffer_from_node(icon_part->node), + icon_geo.width, icon_geo.height); + wlr_scene_node_set_enabled(icon_part->node, false); + nodes[state_set] = icon_part->node; + } + /* Initially show non-hover, non-toggled, unrounded variant */ + wlr_scene_node_set_enabled(nodes[0], true); struct ssd_button *button = ssd_button_descriptor_create(button_root->node); button->type = type; button->view = view; - button->normal = icon_part->node; - button->hover = hover_part->node; - button->toggled = NULL; - button->toggled_hover = NULL; - button->icon_tree = icon_tree; - button->hover_tree = hover_tree; + button->state_set = 0; + memcpy(button->nodes, nodes, sizeof(nodes)); return button_root; } -void -add_toggled_icon(struct ssd_button *button, struct wl_list *part_list, - enum ssd_part_type type, struct wlr_buffer *icon_buffer, - struct wlr_buffer *hover_buffer) -{ - /* Alternate icon */ - struct wlr_box icon_geo = get_scale_box(icon_buffer, - rc.theme->window_button_width, rc.theme->title_height); - - struct ssd_part *alticon_part = add_scene_buffer(part_list, type, - button->icon_tree, icon_buffer, icon_geo.x, icon_geo.y); - - wlr_scene_buffer_set_dest_size( - wlr_scene_buffer_from_node(alticon_part->node), - icon_geo.width, icon_geo.height); - - wlr_scene_node_set_enabled(alticon_part->node, false); - - struct wlr_box hover_geo = get_scale_box(hover_buffer, - rc.theme->window_button_width, rc.theme->title_height); - struct ssd_part *althover_part = add_scene_buffer(part_list, type, - button->hover_tree, hover_buffer, hover_geo.x, hover_geo.y); - - wlr_scene_buffer_set_dest_size( - wlr_scene_buffer_from_node(althover_part->node), - hover_geo.width, hover_geo.height); - - wlr_scene_node_set_enabled(althover_part->node, false); - - button->toggled = alticon_part->node; - button->toggled_hover = althover_part->node; -} - struct ssd_part * ssd_get_part(struct wl_list *part_list, enum ssd_part_type type) { diff --git a/src/ssd/ssd-titlebar.c b/src/ssd/ssd-titlebar.c index c63bd5f9..ca5a8dde 100644 --- a/src/ssd/ssd-titlebar.c +++ b/src/ssd/ssd-titlebar.c @@ -26,95 +26,6 @@ static void set_squared_corners(struct ssd *ssd, bool enable); static void set_alt_button_icon(struct ssd *ssd, enum ssd_part_type type, bool enable); static void update_visible_buttons(struct ssd *ssd); -static void -add_button(struct ssd *ssd, struct ssd_sub_tree *subtree, enum ssd_part_type type, int x) -{ - struct view *view = ssd->view; - struct theme *theme = view->server->theme; - struct wlr_scene_tree *parent = subtree->tree; - bool active = subtree == &ssd->titlebar.active; - - struct ssd_part *btn_root; - struct ssd_button *btn; - - switch (type) { - case LAB_SSD_BUTTON_WINDOW_ICON: /* fallthrough */ - case LAB_SSD_BUTTON_WINDOW_MENU: - add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_menu_active_unpressed->base - : &theme->button_menu_inactive_unpressed->base, - active ? &theme->button_menu_active_hover->base - : &theme->button_menu_inactive_hover->base, - x, view); - break; - case LAB_SSD_BUTTON_ICONIFY: - add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_iconify_active_unpressed->base - : &theme->button_iconify_inactive_unpressed->base, - active ? &theme->button_iconify_active_hover->base - : &theme->button_iconify_inactive_hover->base, - x, view); - break; - case LAB_SSD_BUTTON_MAXIMIZE: - /* Maximize button has an alternate state when maximized */ - btn_root = add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_maximize_active_unpressed->base - : &theme->button_maximize_inactive_unpressed->base, - active ? &theme->button_maximize_active_hover->base - : &theme->button_maximize_inactive_hover->base, - x, view); - btn = node_ssd_button_from_node(btn_root->node); - add_toggled_icon(btn, &subtree->parts, LAB_SSD_BUTTON_MAXIMIZE, - active ? &theme->button_restore_active_unpressed->base - : &theme->button_restore_inactive_unpressed->base, - active ? &theme->button_restore_active_hover->base - : &theme->button_restore_inactive_hover->base); - break; - case LAB_SSD_BUTTON_SHADE: - /* Shade button has an alternate state when shaded */ - btn_root = add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_shade_active_unpressed->base - : &theme->button_shade_inactive_unpressed->base, - active ? &theme->button_shade_active_hover->base - : &theme->button_shade_inactive_hover->base, - x, view); - btn = node_ssd_button_from_node(btn_root->node); - add_toggled_icon(btn, &subtree->parts, LAB_SSD_BUTTON_SHADE, - active ? &theme->button_unshade_active_unpressed->base - : &theme->button_unshade_inactive_unpressed->base, - active ? &theme->button_unshade_active_hover->base - : &theme->button_unshade_inactive_hover->base); - break; - case LAB_SSD_BUTTON_OMNIPRESENT: - /* Omnipresent button has an alternate state when enabled */ - btn_root = add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_omnipresent_active_unpressed->base - : &theme->button_omnipresent_inactive_unpressed->base, - active ? &theme->button_omnipresent_active_hover->base - : &theme->button_omnipresent_inactive_hover->base, - x, view); - btn = node_ssd_button_from_node(btn_root->node); - add_toggled_icon(btn, &subtree->parts, LAB_SSD_BUTTON_OMNIPRESENT, - active ? &theme->button_exclusive_active_unpressed->base - : &theme->button_exclusive_inactive_unpressed->base, - active ? &theme->button_exclusive_active_hover->base - : &theme->button_exclusive_inactive_hover->base); - break; - case LAB_SSD_BUTTON_CLOSE: - add_scene_button(&subtree->parts, type, parent, - active ? &theme->button_close_active_unpressed->base - : &theme->button_close_inactive_unpressed->base, - active ? &theme->button_close_active_hover->base - : &theme->button_close_inactive_hover->base, - x, view); - break; - default: - assert(false && "invalid titlebar part"); - wlr_log(WLR_ERROR, "invalid titlebar type"); - abort(); - } -} - void ssd_titlebar_create(struct ssd *ssd) { @@ -158,18 +69,27 @@ ssd_titlebar_create(struct ssd *ssd) corner_top_right, width - corner_width, -rc.theme->border_width); + int active = (subtree == &ssd->titlebar.active) ? + THEME_ACTIVE : THEME_INACTIVE; + /* Buttons */ struct title_button *b; int x = theme->padding_width; wl_list_for_each(b, &rc.title_buttons_left, link) { - add_button(ssd, subtree, b->type, x); + struct lab_data_buffer **buffers = + theme->window[active].buttons[b->type]; + add_scene_button(&subtree->parts, b->type, parent, + buffers, x, view); x += theme->window_button_width + theme->window_button_spacing; } x = width - theme->padding_width + theme->window_button_spacing; wl_list_for_each_reverse(b, &rc.title_buttons_right, link) { x -= theme->window_button_width + theme->window_button_spacing; - add_button(ssd, subtree, b->type, x); + struct lab_data_buffer **buffers = + theme->window[active].buttons[b->type]; + add_scene_button(&subtree->parts, b->type, parent, + buffers, x, view); } } FOR_EACH_END @@ -178,6 +98,8 @@ ssd_titlebar_create(struct ssd *ssd) ssd_update_title(ssd); ssd_update_window_icon(ssd); + set_squared_corners(ssd, false); + bool maximized = view->maximized == VIEW_AXIS_BOTH; if (maximized) { set_squared_corners(ssd, true); @@ -199,6 +121,25 @@ ssd_titlebar_create(struct ssd *ssd) } } +static void +update_button_state(struct ssd_button *button, enum lab_button_state state, + bool enable) +{ + if (enable) { + button->state_set |= state; + } else { + button->state_set &= ~state; + } + /* Switch the displayed icon buffer to the new one */ + for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; state_set++) { + if (!button->nodes[state_set]) { + continue; + } + wlr_scene_node_set_enabled( + button->nodes[state_set], button->state_set == state_set); + } +} + static void set_squared_corners(struct ssd *ssd, bool enable) { @@ -222,6 +163,21 @@ set_squared_corners(struct ssd *ssd, bool enable) part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT); wlr_scene_node_set_enabled(part->node, !enable); + + /* (Un)round the corner buttons */ + struct title_button *title_button; + wl_list_for_each(title_button, &rc.title_buttons_left, link) { + part = ssd_get_part(&subtree->parts, title_button->type); + struct ssd_button *button = node_ssd_button_from_node(part->node); + update_button_state(button, LAB_BS_ROUNDED, !enable); + break; + } + wl_list_for_each_reverse(title_button, &rc.title_buttons_right, link) { + part = ssd_get_part(&subtree->parts, title_button->type); + struct ssd_button *button = node_ssd_button_from_node(part->node); + update_button_state(button, LAB_BS_ROUNDED, !enable); + break; + } } FOR_EACH_END } @@ -239,16 +195,7 @@ set_alt_button_icon(struct ssd *ssd, enum ssd_part_type type, bool enable) } button = node_ssd_button_from_node(part->node); - - if (button->toggled) { - wlr_scene_node_set_enabled(button->toggled, enable); - wlr_scene_node_set_enabled(button->normal, !enable); - } - - if (button->toggled_hover) { - wlr_scene_node_set_enabled(button->toggled_hover, enable); - wlr_scene_node_set_enabled(button->hover, !enable); - } + update_button_state(button, LAB_BS_TOGGLED, enable); } FOR_EACH_END } @@ -583,14 +530,6 @@ ssd_update_title(struct ssd *ssd) ssd_update_title_positions(ssd, offset_left, offset_right); } -static void -ssd_button_set_hover(struct ssd_button *button, bool enabled) -{ - assert(button); - wlr_scene_node_set_enabled(&button->hover_tree->node, enabled); - wlr_scene_node_set_enabled(&button->icon_tree->node, !enabled); -} - void ssd_update_button_hover(struct wlr_scene_node *node, struct ssd_hover_state *hover_state) @@ -611,12 +550,12 @@ ssd_update_button_hover(struct wlr_scene_node *node, disable_old_hover: if (hover_state->button) { - ssd_button_set_hover(hover_state->button, false); + update_button_state(hover_state->button, LAB_BS_HOVERD, false); hover_state->view = NULL; hover_state->button = NULL; } if (button) { - ssd_button_set_hover(button, true); + update_button_state(button, LAB_BS_HOVERD, true); hover_state->view = button->view; hover_state->button = button; } @@ -677,15 +616,20 @@ ssd_update_window_icon(struct ssd *ssd) struct ssd_sub_tree *subtree; FOR_EACH_STATE(ssd, subtree) { - struct ssd_part *part = - ssd_get_part(&subtree->parts, LAB_SSD_BUTTON_WINDOW_ICON); + struct ssd_part *part = ssd_get_part( + &subtree->parts, LAB_SSD_BUTTON_WINDOW_ICON); if (!part) { break; } + /* Replace all the buffers in the button with the window icon */ struct ssd_button *button = node_ssd_button_from_node(part->node); - update_window_icon_buffer(button->normal, &icon_buffer->base); - update_window_icon_buffer(button->hover, &icon_buffer->base); + for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; state_set++) { + if (button->nodes[state_set]) { + update_window_icon_buffer(button->nodes[state_set], + &icon_buffer->base); + } + } } FOR_EACH_END wlr_buffer_drop(&icon_buffer->base); diff --git a/src/theme.c b/src/theme.c index f3b328b0..bfcaa3dc 100644 --- a/src/theme.c +++ b/src/theme.c @@ -45,10 +45,8 @@ struct button { const char *name; const char *alt_name; const char *fallback_button; /* built-in 6x6 button */ - struct { - struct lab_data_buffer **buffer; - float *rgba; - } active, inactive; + enum ssd_part_type type; + uint8_t state_set; }; enum corner { @@ -82,50 +80,10 @@ zdrop(struct lab_data_buffer **buffer) } } -static bool -match_button_by_name(struct title_button *b, const char *icon_name) -{ - assert(icon_name); - return (b->type == LAB_SSD_BUTTON_WINDOW_MENU && !strcmp(icon_name, "menu")) - || (b->type == LAB_SSD_BUTTON_MAXIMIZE && !strcmp(icon_name, "max")) - || (b->type == LAB_SSD_BUTTON_MAXIMIZE && !strcmp(icon_name, "max_toggled")) - || (b->type == LAB_SSD_BUTTON_ICONIFY && !strcmp(icon_name, "iconify")) - || (b->type == LAB_SSD_BUTTON_CLOSE && !strcmp(icon_name, "close")) - || (b->type == LAB_SSD_BUTTON_SHADE && !strcmp(icon_name, "shade")) - || (b->type == LAB_SSD_BUTTON_SHADE && !strcmp(icon_name, "shade_toggled")) - || (b->type == LAB_SSD_BUTTON_OMNIPRESENT && !strcmp(icon_name, "desk")) - || (b->type == LAB_SSD_BUTTON_OMNIPRESENT && !strcmp(icon_name, "desk_toggled")); -} - -static enum corner -corner_from_icon_name(const char *icon_name) -{ - assert(icon_name); - - struct title_button *b; - wl_list_for_each(b, &rc.title_buttons_left, link) { - if (match_button_by_name(b, icon_name)) { - return LAB_CORNER_TOP_LEFT; - } - break; - } - wl_list_for_each_reverse(b, &rc.title_buttons_right, link) { - if (match_button_by_name(b, icon_name)) { - return LAB_CORNER_TOP_RIGHT; - } - break; - } - return LAB_CORNER_UNKNOWN; -} - -static void -create_hover_fallback(struct theme *theme, const char *icon_name, - struct lab_data_buffer **hover_buffer, - struct lab_data_buffer *icon_buffer) +static struct lab_data_buffer * +copy_icon_buffer(struct theme *theme, struct lab_data_buffer *icon_buffer) { - assert(icon_name); assert(icon_buffer); - assert(!*hover_buffer); struct surface_context icon = get_cairo_surface_from_lab_data_buffer(icon_buffer); @@ -151,75 +109,100 @@ create_hover_fallback(struct theme *theme, const char *icon_name, } int buffer_width = (double)width * scale; int buffer_height = (double)height * scale; + struct lab_data_buffer *buffer = buffer_create_cairo( + buffer_width, buffer_height, 1.0, true); + cairo_t *cairo = buffer->cairo; - *hover_buffer = buffer_create_cairo(buffer_width, buffer_height, 1.0, true); - - cairo_t *cairo = (*hover_buffer)->cairo; - cairo_surface_t *surf = cairo_get_target(cairo); - - /* Background */ cairo_set_source_surface(cairo, icon.surface, (buffer_width - icon_width) / 2, (buffer_height - icon_height) / 2); cairo_paint(cairo); - /* Switch from buffer scale to theme scale */ - cairo_save(cairo); + /* + * Scale cairo context so that we can draw hover overlay or rounded + * corner on this buffer in the scene coordinates. + */ cairo_scale(cairo, scale, scale); + if (icon.is_duplicate) { + cairo_surface_destroy(icon.surface); + } + + return buffer; +} + +static void +create_hover_fallback(struct theme *theme, + struct lab_data_buffer **hover_buffer, + struct lab_data_buffer *icon_buffer) +{ + assert(icon_buffer); + assert(!*hover_buffer); + + int width = theme->window_button_width; + int height = theme->title_height; + + *hover_buffer = copy_icon_buffer(theme, icon_buffer); + cairo_t *cairo = (*hover_buffer)->cairo; + /* Overlay (pre-multiplied alpha) */ float overlay_color[4] = { 0.15f, 0.15f, 0.15f, 0.3f}; + set_cairo_color(cairo, overlay_color); int radius = MIN(width, height) / 2; - enum corner corner = corner_from_icon_name(icon_name); switch (theme->window_button_hover_bg_shape) { case LAB_CIRCLE: - set_cairo_color(cairo, overlay_color); cairo_arc(cairo, width / 2, height / 2, radius, 0 * deg, 360 * deg); - cairo_fill(cairo); break; case LAB_RECTANGLE: - set_cairo_color(cairo, overlay_color); cairo_rectangle(cairo, 0, 0, width, height); - if (corner == LAB_CORNER_UNKNOWN) { - cairo_fill(cairo); - } else { - /* - * Round the hover overlay of corner buttons by - * cropping the region within the window border. - */ - float white[4] = {1, 1, 1, 1}; - struct rounded_corner_ctx rounded_ctx = { - .box = &(struct wlr_box){ - .width = theme->padding_width + width, - .height = height, - }, - .radius = rc.corner_radius, - .line_width = theme->border_width, - .fill_color = white, - .border_color = white, - .corner = corner, - }; - struct lab_data_buffer *mask_buffer = - rounded_rect(&rounded_ctx); - int mask_offset; - if (corner == LAB_CORNER_TOP_LEFT) { - mask_offset = -theme->padding_width; - } else { - mask_offset = 0; - } - cairo_mask_surface(cairo, - cairo_get_target(mask_buffer->cairo), - mask_offset, 0); - wlr_buffer_drop(&mask_buffer->base); - } break; } - cairo_surface_flush(surf); - cairo_restore(cairo); - if (icon.is_duplicate) { - cairo_surface_destroy(icon.surface); + cairo_fill(cairo); + cairo_surface_flush(cairo_get_target(cairo)); +} + +static void +create_rounded_buffer(struct theme *theme, enum corner corner, + struct lab_data_buffer **rounded_buffer, + struct lab_data_buffer *icon_buffer) +{ + *rounded_buffer = copy_icon_buffer(theme, icon_buffer); + cairo_t *cairo = (*rounded_buffer)->cairo; + + int width = theme->window_button_width; + int height = theme->title_height; + + /* + * Round the hover overlay of corner buttons by + * cropping the region within the window border. + */ + float white[4] = {1, 1, 1, 1}; + struct rounded_corner_ctx rounded_ctx = { + .box = &(struct wlr_box){ + .width = theme->padding_width + width, + .height = height, + }, + .radius = rc.corner_radius, + .line_width = theme->border_width, + .fill_color = white, + .border_color = white, + .corner = corner, + }; + int mask_offset; + if (corner == LAB_CORNER_TOP_LEFT) { + mask_offset = -theme->padding_width; + } else { + mask_offset = 0; } + struct lab_data_buffer *mask_buffer = rounded_rect(&rounded_ctx); + cairo_set_operator(cairo, CAIRO_OPERATOR_DEST_IN); + cairo_set_source_surface(cairo, + cairo_get_target(mask_buffer->cairo), mask_offset, 0); + cairo_paint(cairo); + + cairo_surface_flush(cairo_get_target(cairo)); + wlr_buffer_drop(&mask_buffer->base); } /* @@ -252,6 +235,93 @@ get_button_filename(char *buf, size_t len, const char *name, const char *postfix paths_destroy(&paths); } +static void +load_button(struct theme *theme, struct button *b, int active) +{ + struct lab_data_buffer *(*buttons)[LAB_BS_ALL + 1] = + theme->window[active].buttons; + struct lab_data_buffer **buffer = &buttons[b->type][b->state_set]; + float *rgba = theme->window[active].button_colors[b->type]; + char filename[4096]; + + zdrop(buffer); + + /* PNG */ + get_button_filename(filename, sizeof(filename), b->name, + active ? "-active.png" : "-inactive.png"); + img_png_load(filename, buffer); + +#if HAVE_RSVG + /* SVG */ + if (!*buffer) { + int size = theme->title_height - 2 * theme->padding_height; + get_button_filename(filename, sizeof(filename), b->name, + active ? "-active.svg" : "-inactive.png"); + img_svg_load(filename, buffer, size); + } +#endif + + /* XBM */ + if (!*buffer) { + get_button_filename(filename, sizeof(filename), b->name, ".xbm"); + img_xbm_load(filename, buffer, rgba); + } + + /* + * XBM (alternative name) + * For example max_hover_toggled instead of max_toggled_hover + */ + if (!*buffer && b->alt_name) { + get_button_filename(filename, sizeof(filename), + b->alt_name, ".xbm"); + img_xbm_load(filename, buffer, rgba); + } + + /* + * Builtin bitmap + * + * Applicable to basic buttons such as max, max_toggled and iconify. + * There are no bitmap fallbacks for *_hover icons. + */ + if (!*buffer && b->fallback_button) { + img_xbm_from_bitmap(b->fallback_button, buffer, rgba); + } + + /* + * If hover-icons do not exist, add fallbacks by copying the non-hover + * variant and then adding an overlay. + */ + if (!*buffer && (b->state_set & LAB_BS_HOVERD)) { + uint8_t non_hover_state_set = b->state_set & ~LAB_BS_HOVERD; + create_hover_fallback(theme, buffer, + buttons[b->type][non_hover_state_set]); + } + + struct title_button *leftmost_button = NULL; + wl_list_for_each(leftmost_button, + &rc.title_buttons_left, link) { + break; + } + struct title_button *rightmost_button = NULL; + wl_list_for_each_reverse(rightmost_button, + &rc.title_buttons_right, link) { + break; + } + + /* + * If the loaded button is at the corner of the titlebar, also create + * rounded variants. + */ + uint8_t rounded_state_set = b->state_set | LAB_BS_ROUNDED; + if (leftmost_button && leftmost_button->type == b->type) { + create_rounded_buffer(theme, LAB_CORNER_TOP_LEFT, + &buttons[b->type][rounded_state_set], *buffer); + } else if (rightmost_button && rightmost_button->type == b->type) { + create_rounded_buffer(theme, LAB_CORNER_TOP_RIGHT, + &buttons[b->type][rounded_state_set], *buffer); + } +} + /* * We use the following button filename schema: "BUTTON [TOGGLED] [STATE]" * with the words separated by underscore, and the following meaning: @@ -287,236 +357,115 @@ load_buttons(struct theme *theme) { struct button buttons[] = { { .name = "menu", + .type = LAB_SSD_BUTTON_WINDOW_MENU, + .state_set = 0, + .fallback_button = (const char[]){ 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 }, + }, { + /* menu icon is loaded again as a fallback of window icon */ + .name = "menu", + .type = LAB_SSD_BUTTON_WINDOW_ICON, + .state_set = 0, .fallback_button = (const char[]){ 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00 }, - .active.buffer = &theme->button_menu_active_unpressed, - .active.rgba = theme->window_active_button_menu_unpressed_image_color, - .inactive.buffer = &theme->button_menu_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_menu_unpressed_image_color, }, { .name = "iconify", + .type = LAB_SSD_BUTTON_ICONIFY, + .state_set = 0, .fallback_button = (const char[]){ 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f }, - .active.buffer = &theme->button_iconify_active_unpressed, - .active.rgba = theme->window_active_button_iconify_unpressed_image_color, - .inactive.buffer = &theme->button_iconify_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_iconify_unpressed_image_color, }, { .name = "max", + .type = LAB_SSD_BUTTON_MAXIMIZE, + .state_set = 0, .fallback_button = (const char[]){ 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f }, - .active.buffer = &theme->button_maximize_active_unpressed, - .active.rgba = theme->window_active_button_max_unpressed_image_color, - .inactive.buffer = &theme->button_maximize_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_max_unpressed_image_color, }, { .name = "max_toggled", + .type = LAB_SSD_BUTTON_MAXIMIZE, + .state_set = LAB_BS_TOGGLED, .fallback_button = (const char[]){ 0x3e, 0x22, 0x2f, 0x29, 0x39, 0x0f }, - .active.buffer = &theme->button_restore_active_unpressed, - .active.rgba = theme->window_active_button_max_unpressed_image_color, - .inactive.buffer = &theme->button_restore_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_max_unpressed_image_color, }, { .name = "shade", + .type = LAB_SSD_BUTTON_SHADE, + .state_set = 0, .fallback_button = (const char[]){ 0x3f, 0x3f, 0x00, 0x0c, 0x1e, 0x3f }, - .active.buffer = &theme->button_shade_active_unpressed, - .active.rgba = theme->window_active_button_shade_unpressed_image_color, - .inactive.buffer = &theme->button_shade_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_shade_unpressed_image_color, }, { .name = "shade_toggled", + .type = LAB_SSD_BUTTON_SHADE, + .state_set = LAB_BS_TOGGLED, .fallback_button = (const char[]){ 0x3f, 0x3f, 0x00, 0x3f, 0x1e, 0x0c }, - .active.buffer = &theme->button_unshade_active_unpressed, - .active.rgba = theme->window_active_button_shade_unpressed_image_color, - .inactive.buffer = &theme->button_unshade_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_shade_unpressed_image_color, }, { .name = "desk", + .type = LAB_SSD_BUTTON_OMNIPRESENT, + .state_set = 0, .fallback_button = (const char[]){ 0x33, 0x33, 0x00, 0x00, 0x33, 0x33 }, - .active.buffer = &theme->button_omnipresent_active_unpressed, - .active.rgba = theme->window_active_button_omnipresent_unpressed_image_color, - .inactive.buffer = &theme->button_omnipresent_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_omnipresent_unpressed_image_color, }, { .name = "desk_toggled", + .type = LAB_SSD_BUTTON_OMNIPRESENT, + .state_set = LAB_BS_TOGGLED, .fallback_button = (const char[]){ 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 }, - .active.buffer = &theme->button_exclusive_active_unpressed, - .active.rgba = theme->window_active_button_omnipresent_unpressed_image_color, - .inactive.buffer = &theme->button_exclusive_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_omnipresent_unpressed_image_color, }, { .name = "close", + .type = LAB_SSD_BUTTON_CLOSE, + .state_set = 0, .fallback_button = (const char[]){ 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 }, - .active.buffer = &theme->button_close_active_unpressed, - .active.rgba = theme->window_active_button_close_unpressed_image_color, - .inactive.buffer = &theme->button_close_inactive_unpressed, - .inactive.rgba = theme->window_inactive_button_close_unpressed_image_color, }, { .name = "menu_hover", + .type = LAB_SSD_BUTTON_WINDOW_MENU, + .state_set = LAB_BS_HOVERD, + /* no fallback (non-hover variant is used instead) */ + }, { + /* menu_hover icon is loaded again as a fallback of window icon */ + .name = "menu_hover", + .type = LAB_SSD_BUTTON_WINDOW_ICON, + .state_set = LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_menu_active_hover, - .active.rgba = theme->window_active_button_menu_unpressed_image_color, - .inactive.buffer = &theme->button_menu_inactive_hover, - .inactive.rgba = theme->window_inactive_button_menu_unpressed_image_color, }, { .name = "iconify_hover", + .type = LAB_SSD_BUTTON_ICONIFY, + .state_set = LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_iconify_active_hover, - .active.rgba = theme->window_active_button_iconify_unpressed_image_color, - .inactive.buffer = &theme->button_iconify_inactive_hover, - .inactive.rgba = theme->window_inactive_button_iconify_unpressed_image_color, }, { .name = "max_hover", + .type = LAB_SSD_BUTTON_MAXIMIZE, + .state_set = LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_maximize_active_hover, - .active.rgba = theme->window_active_button_max_unpressed_image_color, - .inactive.buffer = &theme->button_maximize_inactive_hover, - .inactive.rgba = theme->window_inactive_button_max_unpressed_image_color, }, { .name = "max_toggled_hover", .alt_name = "max_hover_toggled", + .type = LAB_SSD_BUTTON_MAXIMIZE, + .state_set = LAB_BS_TOGGLED | LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_restore_active_hover, - .active.rgba = theme->window_active_button_max_unpressed_image_color, - .inactive.buffer = &theme->button_restore_inactive_hover, - .inactive.rgba = theme->window_inactive_button_max_unpressed_image_color, }, { .name = "shade_hover", + .type = LAB_SSD_BUTTON_SHADE, + .state_set = LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_shade_active_hover, - .active.rgba = theme->window_active_button_shade_unpressed_image_color, - .inactive.buffer = &theme->button_shade_inactive_hover, - .inactive.rgba = theme->window_inactive_button_shade_unpressed_image_color, }, { .name = "shade_toggled_hover", .alt_name = "shade_hover_toggled", + .type = LAB_SSD_BUTTON_SHADE, + .state_set = LAB_BS_TOGGLED | LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_unshade_active_hover, - .active.rgba = theme->window_active_button_shade_unpressed_image_color, - .inactive.buffer = &theme->button_unshade_inactive_hover, - .inactive.rgba = theme->window_inactive_button_shade_unpressed_image_color, }, { .name = "desk_hover", /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_omnipresent_active_hover, - .active.rgba = theme->window_active_button_omnipresent_unpressed_image_color, - .inactive.buffer = &theme->button_omnipresent_inactive_hover, - .inactive.rgba = theme->window_inactive_button_omnipresent_unpressed_image_color, + .type = LAB_SSD_BUTTON_OMNIPRESENT, + .state_set = LAB_BS_HOVERD, }, { .name = "desk_toggled_hover", .alt_name = "desk_hover_toggled", + .type = LAB_SSD_BUTTON_OMNIPRESENT, + .state_set = LAB_BS_TOGGLED | LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_exclusive_active_hover, - .active.rgba = theme->window_active_button_omnipresent_unpressed_image_color, - .inactive.buffer = &theme->button_exclusive_inactive_hover, - .inactive.rgba = theme->window_inactive_button_omnipresent_unpressed_image_color, }, { .name = "close_hover", + .type = LAB_SSD_BUTTON_CLOSE, + .state_set = LAB_BS_HOVERD, /* no fallback (non-hover variant is used instead) */ - .active.buffer = &theme->button_close_active_hover, - .active.rgba = theme->window_active_button_close_unpressed_image_color, - .inactive.buffer = &theme->button_close_inactive_hover, - .inactive.rgba = theme->window_inactive_button_close_unpressed_image_color, }, }; - char filename[4096] = {0}; for (size_t i = 0; i < ARRAY_SIZE(buttons); ++i) { struct button *b = &buttons[i]; - - zdrop(b->active.buffer); - zdrop(b->inactive.buffer); - - /* PNG */ - get_button_filename(filename, sizeof(filename), b->name, "-active.png"); - img_png_load(filename, b->active.buffer); - get_button_filename(filename, sizeof(filename), b->name, "-inactive.png"); - img_png_load(filename, b->inactive.buffer); - -#if HAVE_RSVG - /* SVG */ - int size = theme->title_height - 2 * theme->padding_height; - if (!*b->active.buffer) { - get_button_filename(filename, sizeof(filename), b->name, "-active.svg"); - img_svg_load(filename, b->active.buffer, size); - } - if (!*b->inactive.buffer) { - get_button_filename(filename, sizeof(filename), b->name, "-inactive.svg"); - img_svg_load(filename, b->inactive.buffer, size); - } -#endif - - /* XBM */ - get_button_filename(filename, sizeof(filename), b->name, ".xbm"); - if (!*b->active.buffer) { - img_xbm_load(filename, b->active.buffer, b->active.rgba); - } - if (!*b->inactive.buffer) { - img_xbm_load(filename, b->inactive.buffer, b->inactive.rgba); - } - - /* - * XBM (alternative name) - * For example max_hover_toggled instead of max_toggled_hover - */ - if (b->alt_name) { - get_button_filename(filename, sizeof(filename), b->alt_name, ".xbm"); - } else { - filename[0] = '\0'; - } - if (!*b->active.buffer) { - img_xbm_load(filename, b->active.buffer, b->active.rgba); - } - if (!*b->inactive.buffer) { - img_xbm_load(filename, b->inactive.buffer, b->inactive.rgba); - } - - /* - * Builtin bitmap - * - * Applicable to basic buttons such as max, max_toggled and - * iconify. There are no bitmap fallbacks for *_hover icons. - */ - if (!b->fallback_button) { - continue; - } - if (!*b->active.buffer) { - img_xbm_from_bitmap(b->fallback_button, - b->active.buffer, b->active.rgba); - } - if (!*b->inactive.buffer) { - img_xbm_from_bitmap(b->fallback_button, - b->inactive.buffer, b->inactive.rgba); - } - } - - /* - * If hover-icons do not exist, add fallbacks by copying the non-hover - * variant (base) and then adding an overlay. - */ - for (size_t i = 0; i < ARRAY_SIZE(buttons); i++) { - struct button *hover_button = &buttons[i]; - - if (!strstr(hover_button->name, "_hover")) { - continue; - } - - /* If name=='foo_hover', basename='foo' */ - char basename[64] = {0}; - snprintf(basename, sizeof(basename), "%s", hover_button->name); - trim_last_field(basename, '_'); - for (size_t j = 0; j < ARRAY_SIZE(buttons); j++) { - struct button *base = &buttons[j]; - if (!strcmp(basename, base->name)) { - if (!*hover_button->active.buffer) { - create_hover_fallback(theme, basename, - hover_button->active.buffer, - *base->active.buffer); - } - if (!*hover_button->inactive.buffer) { - create_hover_fallback(theme, basename, - hover_button->inactive.buffer, - *base->inactive.buffer); - } - break; - } - } + load_button(theme, b, THEME_INACTIVE); + load_button(theme, b, THEME_ACTIVE); } } @@ -645,30 +594,13 @@ theme_builtin(struct theme *theme, struct server *server) theme->window_button_spacing = 0; theme->window_button_hover_bg_shape = LAB_RECTANGLE; - parse_hexstr("#000000", - theme->window_active_button_menu_unpressed_image_color); - parse_hexstr("#000000", - theme->window_active_button_iconify_unpressed_image_color); - parse_hexstr("#000000", - theme->window_active_button_max_unpressed_image_color); - parse_hexstr("#000000", - theme->window_active_button_shade_unpressed_image_color); - parse_hexstr("#000000", - theme->window_active_button_omnipresent_unpressed_image_color); - parse_hexstr("#000000", - theme->window_active_button_close_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_menu_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_iconify_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_max_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_shade_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_omnipresent_unpressed_image_color); - parse_hexstr("#000000", - theme->window_inactive_button_close_unpressed_image_color); + for (enum ssd_part_type type = LAB_SSD_BUTTON_FIRST; + type <= LAB_SSD_BUTTON_LAST; type++) { + parse_hexstr("#000000", + theme->window[THEME_INACTIVE].button_colors[type]); + parse_hexstr("#000000", + theme->window[THEME_ACTIVE].button_colors[type]); + } theme->window_active_shadow_size = 60; theme->window_inactive_shadow_size = 40; @@ -855,82 +787,72 @@ entry(struct theme *theme, const char *key, const char *value) /* universal button */ if (match_glob(key, "window.active.button.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_menu_unpressed_image_color); - parse_hexstr(value, - theme->window_active_button_iconify_unpressed_image_color); - parse_hexstr(value, - theme->window_active_button_max_unpressed_image_color); - parse_hexstr(value, - theme->window_active_button_shade_unpressed_image_color); - parse_hexstr(value, - theme->window_active_button_omnipresent_unpressed_image_color); - parse_hexstr(value, - theme->window_active_button_close_unpressed_image_color); + for (enum ssd_part_type type = LAB_SSD_BUTTON_FIRST; + type <= LAB_SSD_BUTTON_LAST; type++) { + parse_hexstr(value, + theme->window[THEME_ACTIVE].button_colors[type]); + } } if (match_glob(key, "window.inactive.button.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_menu_unpressed_image_color); - parse_hexstr(value, - theme->window_inactive_button_iconify_unpressed_image_color); - parse_hexstr(value, - theme->window_inactive_button_max_unpressed_image_color); - parse_hexstr(value, - theme->window_inactive_button_shade_unpressed_image_color); - parse_hexstr(value, - theme->window_inactive_button_omnipresent_unpressed_image_color); - parse_hexstr(value, - theme->window_inactive_button_close_unpressed_image_color); + for (enum ssd_part_type type = LAB_SSD_BUTTON_FIRST; + type <= LAB_SSD_BUTTON_LAST; type++) { + parse_hexstr(value, + theme->window[THEME_INACTIVE].button_colors[type]); + } } /* individual buttons */ if (match_glob(key, "window.active.button.menu.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_menu_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_WINDOW_MENU]); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_WINDOW_ICON]); } if (match_glob(key, "window.active.button.iconify.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_iconify_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_ICONIFY]); } if (match_glob(key, "window.active.button.max.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_max_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_MAXIMIZE]); } if (match_glob(key, "window.active.button.shade.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_shade_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_SHADE]); } if (match_glob(key, "window.active.button.desk.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_omnipresent_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_OMNIPRESENT]); } if (match_glob(key, "window.active.button.close.unpressed.image.color")) { - parse_hexstr(value, - theme->window_active_button_close_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_ACTIVE] + .button_colors[LAB_SSD_BUTTON_CLOSE]); } if (match_glob(key, "window.inactive.button.menu.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_menu_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_WINDOW_MENU]); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_WINDOW_ICON]); } if (match_glob(key, "window.inactive.button.iconify.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_iconify_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_ICONIFY]); } if (match_glob(key, "window.inactive.button.max.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_max_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_MAXIMIZE]); } if (match_glob(key, "window.inactive.button.shade.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_shade_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_SHADE]); } if (match_glob(key, "window.inactive.button.desk.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_omnipresent_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_OMNIPRESENT]); } if (match_glob(key, "window.inactive.button.close.unpressed.image.color")) { - parse_hexstr(value, - theme->window_inactive_button_close_unpressed_image_color); + parse_hexstr(value, theme->window[THEME_INACTIVE] + .button_colors[LAB_SSD_BUTTON_CLOSE]); } /* window drop-shadows */ @@ -1657,45 +1579,16 @@ theme_init(struct theme *theme, struct server *server, const char *theme_name) void theme_finish(struct theme *theme) { - zdrop(&theme->button_close_active_unpressed); - zdrop(&theme->button_maximize_active_unpressed); - zdrop(&theme->button_restore_active_unpressed); - zdrop(&theme->button_shade_active_unpressed); - zdrop(&theme->button_unshade_active_unpressed); - zdrop(&theme->button_omnipresent_active_unpressed); - zdrop(&theme->button_exclusive_active_unpressed); - zdrop(&theme->button_iconify_active_unpressed); - zdrop(&theme->button_menu_active_unpressed); - - zdrop(&theme->button_close_inactive_unpressed); - zdrop(&theme->button_maximize_inactive_unpressed); - zdrop(&theme->button_restore_inactive_unpressed); - zdrop(&theme->button_shade_inactive_unpressed); - zdrop(&theme->button_unshade_inactive_unpressed); - zdrop(&theme->button_omnipresent_inactive_unpressed); - zdrop(&theme->button_exclusive_inactive_unpressed); - zdrop(&theme->button_iconify_inactive_unpressed); - zdrop(&theme->button_menu_inactive_unpressed); - - zdrop(&theme->button_close_active_hover); - zdrop(&theme->button_maximize_active_hover); - zdrop(&theme->button_restore_active_hover); - zdrop(&theme->button_shade_active_hover); - zdrop(&theme->button_unshade_active_hover); - zdrop(&theme->button_omnipresent_active_hover); - zdrop(&theme->button_exclusive_active_hover); - zdrop(&theme->button_iconify_active_hover); - zdrop(&theme->button_menu_active_hover); - - zdrop(&theme->button_close_inactive_hover); - zdrop(&theme->button_maximize_inactive_hover); - zdrop(&theme->button_restore_inactive_hover); - zdrop(&theme->button_shade_inactive_hover); - zdrop(&theme->button_unshade_inactive_hover); - zdrop(&theme->button_omnipresent_inactive_hover); - zdrop(&theme->button_exclusive_inactive_hover); - zdrop(&theme->button_iconify_inactive_hover); - zdrop(&theme->button_menu_inactive_hover); + for (enum ssd_part_type type = LAB_SSD_BUTTON_FIRST; + type <= LAB_SSD_BUTTON_LAST; type++) { + for (uint8_t state_set = 0; state_set <= LAB_BS_ALL; + state_set++) { + zdrop(&theme->window[THEME_INACTIVE] + .buttons[type][state_set]); + zdrop(&theme->window[THEME_ACTIVE] + .buttons[type][state_set]); + } + } zdrop(&theme->corner_top_left_active_normal); zdrop(&theme->corner_top_left_inactive_normal);