Compare commits

...

4 commits

Author SHA1 Message Date
John Lindgren
da96513e70 menu: remove redundant cast
Some checks are pending
labwc.github.io / notify (push) Waiting to run
2025-10-12 14:15:19 -04:00
John Lindgren
40eed3915a osd,ssd: don't cast away const 2025-10-12 14:15:19 -04:00
John Lindgren
e6f54a0fc8 menu: use xmlFree() for return value of xmlGetProp() 2025-10-12 14:15:19 -04:00
tokyo4j
5e8df27f84 osd-classic: add theme options for selected window item
This commit adds new theme options:
- osd.window-switcher.style-classic.item.active.border.color
- osd.window-switcher.style-classic.item.active.bg.color

These theme options configures the border/background of selected window
item in the `classic` style window switcher. Their default values are
identical to `thumbnail` style window switcher, which means the default
border color is now `osd.label.text.color` with 50% opacity and the
default background color is now `osd.label.text.color` with 15% opacity.
2025-10-13 01:46:43 +09:00
8 changed files with 106 additions and 56 deletions

View file

@ -327,6 +327,14 @@ all are supported.
Border width of the selection box in the window switcher in pixels. Border width of the selection box in the window switcher in pixels.
Default is 2. Default is 2.
*osd.window-switcher.style-classic.item.active.border.color*
Border color around the selected window switcher item.
Default is *osd.label.text.color* with 50% opacity.
*osd.window-switcher.style-classic.item.active.bg.color*
Background color of the selected window switcher item.
Default is *osd.label.text.color* with 15% opacity.
*osd.window-switcher.style-classic.item.icon.size* *osd.window-switcher.style-classic.item.icon.size*
Size of the icon in window switcher, in pixels. Size of the icon in window switcher, in pixels.
If not set, the font size derived from <theme><font place="OnScreenDisplay"> If not set, the font size derived from <theme><font place="OnScreenDisplay">

View file

@ -97,6 +97,8 @@ osd.window-switcher.style-classic.padding: 4
osd.window-switcher.style-classic.item.padding.x: 10 osd.window-switcher.style-classic.item.padding.x: 10
osd.window-switcher.style-classic.item.padding.y: 1 osd.window-switcher.style-classic.item.padding.y: 1
osd.window-switcher.style-classic.item.active.border.width: 2 osd.window-switcher.style-classic.item.active.border.width: 2
osd.window-switcher.style-classic.item.active.border.color: #706f6d
osd.window-switcher.style-classic.item.active.bg.color: #bfbcba
# The icon size the same as the font size by default # The icon size the same as the font size by default
# osd.window-switcher.style-classic.item.icon.size: 50 # osd.window-switcher.style-classic.item.icon.size: 50

View file

@ -170,6 +170,8 @@ struct theme {
int item_padding_x; int item_padding_x;
int item_padding_y; int item_padding_y;
int item_active_border_width; int item_active_border_width;
float item_active_border_color[4];
float item_active_bg_color[4];
int item_icon_size; int item_icon_size;
bool width_is_percent; bool width_is_percent;

View file

@ -482,13 +482,13 @@ fill_item(struct menu *menu, xmlNode *node)
goto out; goto out;
} }
struct menuitem *item = item_create(menu, (char *)label, icon_name, false); struct menuitem *item = item_create(menu, label, icon_name, false);
lab_xml_expand_dotted_attributes(node); lab_xml_expand_dotted_attributes(node);
append_parsed_actions(node, &item->actions); append_parsed_actions(node, &item->actions);
out: out:
free(label); xmlFree(label);
free(icon_name); xmlFree(icon_name);
} }
static void static void
@ -619,10 +619,10 @@ fill_menu(struct server *server, struct menu *parent, xmlNode *n)
item->submenu = menu; item->submenu = menu;
} }
error: error:
free(label); xmlFree(label);
free(icon_name); xmlFree(icon_name);
free(execute); xmlFree(execute);
free(id); xmlFree(id);
} }
/* This can be one of <separator> and <separator label=""> */ /* This can be one of <separator> and <separator label=""> */
@ -631,7 +631,7 @@ fill_separator(struct menu *menu, xmlNode *n)
{ {
char *label = (char *)xmlGetProp(n, (const xmlChar *)"label"); char *label = (char *)xmlGetProp(n, (const xmlChar *)"label");
separator_create(menu, label); separator_create(menu, label);
free(label); xmlFree(label);
} }
/* parent==NULL when processing toplevel menus in menu.xml */ /* parent==NULL when processing toplevel menus in menu.xml */

View file

@ -19,9 +19,59 @@
struct osd_classic_scene_item { struct osd_classic_scene_item {
struct view *view; struct view *view;
struct wlr_scene_node *highlight_outline; struct wlr_scene_tree *normal_tree, *active_tree;
}; };
static void
create_fields_scene(struct server *server, struct view *view,
struct wlr_scene_tree *parent, const float *text_color,
const float *bg_color, int field_widths_sum, int x, int y)
{
struct theme *theme = server->theme;
struct window_switcher_classic_theme *switcher_theme =
&theme->osd_window_switcher_classic;
struct window_switcher_field *field;
wl_list_for_each(field, &rc.window_switcher.fields, link) {
int field_width = field_widths_sum * field->width / 100.0;
struct wlr_scene_node *node = NULL;
int height = -1;
if (field->content == LAB_FIELD_ICON) {
int icon_size = MIN(field_width,
switcher_theme->item_icon_size);
struct scaled_icon_buffer *icon_buffer =
scaled_icon_buffer_create(parent,
server, icon_size, icon_size);
scaled_icon_buffer_set_view(icon_buffer, view);
node = &icon_buffer->scene_buffer->node;
height = icon_size;
} else {
struct buf buf = BUF_INIT;
osd_field_get_content(field, &buf, view);
if (!string_null_or_empty(buf.data)) {
struct scaled_font_buffer *font_buffer =
scaled_font_buffer_create(parent);
scaled_font_buffer_update(font_buffer,
buf.data, field_width,
&rc.font_osd, text_color, bg_color);
node = &font_buffer->scene_buffer->node;
height = font_height(&rc.font_osd);
}
buf_reset(&buf);
}
if (node) {
int item_height = switcher_theme->item_height;
wlr_scene_node_set_position(node,
x, y + (item_height - height) / 2);
}
x += field_width + switcher_theme->item_padding_x;
}
}
static void static void
osd_classic_create(struct output *output, struct wl_array *views) osd_classic_create(struct output *output, struct wl_array *views)
{ {
@ -126,62 +176,33 @@ osd_classic_create(struct output *output, struct wl_array *views)
+ switcher_theme->item_padding_x; + switcher_theme->item_padding_x;
struct wlr_scene_tree *item_root = struct wlr_scene_tree *item_root =
wlr_scene_tree_create(output->osd_scene.tree); wlr_scene_tree_create(output->osd_scene.tree);
item->normal_tree = wlr_scene_tree_create(item_root);
item->active_tree = wlr_scene_tree_create(item_root);
wlr_scene_node_set_enabled(&item->active_tree->node, false);
struct window_switcher_field *field; float *active_bg_color = switcher_theme->item_active_bg_color;
wl_list_for_each(field, &rc.window_switcher.fields, link) { float *active_border_color = switcher_theme->item_active_border_color;
int field_width = field_widths_sum * field->width / 100.0;
struct wlr_scene_node *node = NULL;
int height = -1;
if (field->content == LAB_FIELD_ICON) {
int icon_size = MIN(field_width,
switcher_theme->item_icon_size);
struct scaled_icon_buffer *icon_buffer =
scaled_icon_buffer_create(item_root,
server, icon_size, icon_size);
scaled_icon_buffer_set_view(icon_buffer, *view);
node = &icon_buffer->scene_buffer->node;
height = icon_size;
} else {
buf_clear(&buf);
osd_field_get_content(field, &buf, *view);
if (!string_null_or_empty(buf.data)) {
struct scaled_font_buffer *font_buffer =
scaled_font_buffer_create(item_root);
scaled_font_buffer_update(font_buffer,
buf.data, field_width,
&rc.font_osd, text_color, bg_color);
node = &font_buffer->scene_buffer->node;
height = font_height(&rc.font_osd);
}
}
if (node) {
int item_height = switcher_theme->item_height;
wlr_scene_node_set_position(node,
x, y + (item_height - height) / 2);
}
x += field_width + switcher_theme->item_padding_x;
}
/* Highlight around selected window's item */ /* Highlight around selected window's item */
int highlight_x = theme->osd_border_width int highlight_x = theme->osd_border_width
+ switcher_theme->padding; + switcher_theme->padding;
struct lab_scene_rect_options highlight_opts = { struct lab_scene_rect_options highlight_opts = {
.border_colors = (float *[1]) {text_color}, .border_colors = (float *[1]) {active_border_color},
.bg_color = active_bg_color,
.nr_borders = 1, .nr_borders = 1,
.border_width = switcher_theme->item_active_border_width, .border_width = switcher_theme->item_active_border_width,
.width = w - 2 * theme->osd_border_width .width = w - 2 * theme->osd_border_width
- 2 * switcher_theme->padding, - 2 * switcher_theme->padding,
.height = switcher_theme->item_height, .height = switcher_theme->item_height,
}; };
struct lab_scene_rect *highlight_rect = lab_scene_rect_create( struct lab_scene_rect *highlight_rect = lab_scene_rect_create(
output->osd_scene.tree, &highlight_opts); item->active_tree, &highlight_opts);
item->highlight_outline = &highlight_rect->tree->node; wlr_scene_node_set_position(&highlight_rect->tree->node, highlight_x, y);
wlr_scene_node_set_position(item->highlight_outline, highlight_x, y);
wlr_scene_node_set_enabled(item->highlight_outline, false); create_fields_scene(server, *view, item->normal_tree,
text_color, bg_color, field_widths_sum, x, y);
create_fields_scene(server, *view, item->active_tree,
text_color, active_bg_color, field_widths_sum, x, y);
y += switcher_theme->item_height; y += switcher_theme->item_height;
} }
@ -200,8 +221,9 @@ osd_classic_update(struct output *output)
{ {
struct osd_classic_scene_item *item; struct osd_classic_scene_item *item;
wl_array_for_each(item, &output->osd_scene.items) { wl_array_for_each(item, &output->osd_scene.items) {
wlr_scene_node_set_enabled(item->highlight_outline, bool active = item->view == output->server->osd_state.cycle_view;
item->view == output->server->osd_state.cycle_view); wlr_scene_node_set_enabled(&item->normal_tree->node, !active);
wlr_scene_node_set_enabled(&item->active_tree->node, active);
} }
} }

View file

@ -36,7 +36,7 @@ get_app_id_or_class(struct view *view, bool trim)
/* remove the first two nodes of 'org.' strings */ /* remove the first two nodes of 'org.' strings */
if (trim && !strncmp(identifier, "org.", 4)) { if (trim && !strncmp(identifier, "org.", 4)) {
char *p = (char *)identifier + 4; const char *p = identifier + 4;
p = strchr(p, '.'); p = strchr(p, '.');
if (p) { if (p) {
return ++p; return ++p;

View file

@ -440,7 +440,7 @@ ssd_update_title(struct ssd *ssd)
} }
struct view *view = ssd->view; struct view *view = ssd->view;
char *title = (char *)view_get_string_prop(view, "title"); const char *title = view_get_string_prop(view, "title");
if (string_null_or_empty(title)) { if (string_null_or_empty(title)) {
return; return;
} }

View file

@ -604,6 +604,8 @@ theme_builtin(struct theme *theme, struct server *server)
theme->osd_window_switcher_classic.item_padding_x = 10; theme->osd_window_switcher_classic.item_padding_x = 10;
theme->osd_window_switcher_classic.item_padding_y = 1; theme->osd_window_switcher_classic.item_padding_y = 1;
theme->osd_window_switcher_classic.item_active_border_width = 2; theme->osd_window_switcher_classic.item_active_border_width = 2;
theme->osd_window_switcher_classic.item_active_border_color[0] = FLT_MIN;
theme->osd_window_switcher_classic.item_active_bg_color[0] = FLT_MIN;
theme->osd_window_switcher_classic.item_icon_size = -1; theme->osd_window_switcher_classic.item_icon_size = -1;
theme->osd_window_switcher_thumbnail.max_width = 80; theme->osd_window_switcher_thumbnail.max_width = 80;
@ -989,6 +991,12 @@ entry(struct theme *theme, const char *key, const char *value)
get_int_if_positive(value, get_int_if_positive(value,
"osd.window-switcher.style-classic.item.active.border.width"); "osd.window-switcher.style-classic.item.active.border.width");
} }
if (match_glob(key, "osd.window-switcher.style-classic.item.active.border.color")) {
parse_color(value, switcher_classic_theme->item_active_border_color);
}
if (match_glob(key, "osd.window-switcher.style-classic.item.active.bg.color")) {
parse_color(value, switcher_classic_theme->item_active_bg_color);
}
if (match_glob(key, "osd.window-switcher.style-classic.item.icon.size") if (match_glob(key, "osd.window-switcher.style-classic.item.icon.size")
|| match_glob(key, "osd.window-switcher.item.icon.size")) { || match_glob(key, "osd.window-switcher.item.icon.size")) {
switcher_classic_theme->item_icon_size = switcher_classic_theme->item_icon_size =
@ -1746,6 +1754,14 @@ post_processing(struct theme *theme)
memcpy(theme->osd_border_color, theme->osd_label_text_color, memcpy(theme->osd_border_color, theme->osd_label_text_color,
sizeof(theme->osd_border_color)); sizeof(theme->osd_border_color));
} }
if (switcher_classic_theme->item_active_border_color[0] == FLT_MIN) {
blend_color_with_bg(switcher_classic_theme->item_active_border_color,
theme->osd_label_text_color, 0.50, theme->osd_bg_color);
}
if (switcher_classic_theme->item_active_bg_color[0] == FLT_MIN) {
blend_color_with_bg(switcher_classic_theme->item_active_bg_color,
theme->osd_label_text_color, 0.15, theme->osd_bg_color);
}
if (switcher_thumb_theme->item_active_border_color[0] == FLT_MIN) { if (switcher_thumb_theme->item_active_border_color[0] == FLT_MIN) {
blend_color_with_bg(switcher_thumb_theme->item_active_border_color, blend_color_with_bg(switcher_thumb_theme->item_active_border_color,
theme->osd_label_text_color, 0.50, theme->osd_bg_color); theme->osd_label_text_color, 0.50, theme->osd_bg_color);