mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
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.
This commit is contained in:
parent
c413e65a20
commit
c2a3a354db
6 changed files with 417 additions and 637 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#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;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <assert.h>
|
||||
#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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
667
src/theme.c
667
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)
|
||||
static struct lab_data_buffer *
|
||||
copy_icon_buffer(struct theme *theme, struct lab_data_buffer *icon_buffer)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
/* Overlay (pre-multiplied alpha) */
|
||||
float overlay_color[4] = { 0.15f, 0.15f, 0.15f, 0.3f};
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
switch (theme->window_button_hover_bg_shape) {
|
||||
case LAB_CIRCLE:
|
||||
cairo_arc(cairo, width / 2, height / 2, radius, 0 * deg, 360 * deg);
|
||||
break;
|
||||
case LAB_RECTANGLE:
|
||||
cairo_rectangle(cairo, 0, 0, width, height);
|
||||
break;
|
||||
}
|
||||
|
||||
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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue