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)
{
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
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);
}
}
+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)
{
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
}
}
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
}
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)
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;
}
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);
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 {
}
}
-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);
}
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);
}
/*
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:
{
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);
}
}
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;
/* 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 */
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);