mirror of
https://github.com/labwc/labwc.git
synced 2026-03-01 01:40:24 -05:00
ssd: allow arbitrary cairo pattern as titlebar background
The titlebar background is now first rendered to a 1px wide buffer, then stretched horizontally. This allows vertical gradients to be used.
This commit is contained in:
parent
54b236e027
commit
990706b081
3 changed files with 72 additions and 15 deletions
|
|
@ -8,7 +8,7 @@
|
||||||
#ifndef LABWC_THEME_H
|
#ifndef LABWC_THEME_H
|
||||||
#define LABWC_THEME_H
|
#define LABWC_THEME_H
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <cairo.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
#include "ssd.h"
|
#include "ssd.h"
|
||||||
|
|
||||||
|
|
@ -89,6 +89,18 @@ struct theme {
|
||||||
struct lab_img *button_imgs
|
struct lab_img *button_imgs
|
||||||
[LAB_SSD_BUTTON_LAST + 1][LAB_BS_ALL + 1];
|
[LAB_SSD_BUTTON_LAST + 1][LAB_BS_ALL + 1];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The titlebar background is specified as a cairo_pattern
|
||||||
|
* and then also rendered into a 1px wide buffer, which is
|
||||||
|
* stretched horizontally across the titlebar.
|
||||||
|
*
|
||||||
|
* This approach enables vertical gradients while saving
|
||||||
|
* some memory vs. rendering the entire titlebar into an
|
||||||
|
* image. It does not work for horizontal gradients.
|
||||||
|
*/
|
||||||
|
cairo_pattern_t *titlebar_pattern;
|
||||||
|
struct lab_data_buffer *titlebar_fill;
|
||||||
|
|
||||||
struct lab_data_buffer *corner_top_left_normal;
|
struct lab_data_buffer *corner_top_left_normal;
|
||||||
struct lab_data_buffer *corner_top_right_normal;
|
struct lab_data_buffer *corner_top_right_normal;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ ssd_titlebar_create(struct ssd *ssd)
|
||||||
int width = view->current.width;
|
int width = view->current.width;
|
||||||
int corner_width = ssd_get_corner_width();
|
int corner_width = ssd_get_corner_width();
|
||||||
|
|
||||||
float *color;
|
|
||||||
struct wlr_scene_tree *parent;
|
struct wlr_scene_tree *parent;
|
||||||
|
struct wlr_buffer *titlebar_fill;
|
||||||
struct wlr_buffer *corner_top_left;
|
struct wlr_buffer *corner_top_left;
|
||||||
struct wlr_buffer *corner_top_right;
|
struct wlr_buffer *corner_top_right;
|
||||||
int active;
|
int active;
|
||||||
|
|
@ -49,7 +49,7 @@ ssd_titlebar_create(struct ssd *ssd)
|
||||||
parent = subtree->tree;
|
parent = subtree->tree;
|
||||||
active = (subtree == &ssd->titlebar.active) ?
|
active = (subtree == &ssd->titlebar.active) ?
|
||||||
THEME_ACTIVE : THEME_INACTIVE;
|
THEME_ACTIVE : THEME_INACTIVE;
|
||||||
color = theme->window[active].title_bg_color;
|
titlebar_fill = &theme->window[active].titlebar_fill->base;
|
||||||
corner_top_left = &theme->window[active].corner_top_left_normal->base;
|
corner_top_left = &theme->window[active].corner_top_left_normal->base;
|
||||||
corner_top_right = &theme->window[active].corner_top_right_normal->base;
|
corner_top_right = &theme->window[active].corner_top_right_normal->base;
|
||||||
wlr_scene_node_set_enabled(&parent->node, active);
|
wlr_scene_node_set_enabled(&parent->node, active);
|
||||||
|
|
@ -57,9 +57,8 @@ ssd_titlebar_create(struct ssd *ssd)
|
||||||
wl_list_init(&subtree->parts);
|
wl_list_init(&subtree->parts);
|
||||||
|
|
||||||
/* Background */
|
/* Background */
|
||||||
add_scene_rect(&subtree->parts, LAB_SSD_PART_TITLEBAR, parent,
|
add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR, parent,
|
||||||
MAX(width - corner_width * 2, 0), theme->titlebar_height,
|
titlebar_fill, corner_width, 0);
|
||||||
corner_width, 0, color);
|
|
||||||
add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, parent,
|
add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, parent,
|
||||||
corner_top_left, -rc.theme->border_width, -rc.theme->border_width);
|
corner_top_left, -rc.theme->border_width, -rc.theme->border_width);
|
||||||
add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, parent,
|
add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, parent,
|
||||||
|
|
@ -151,7 +150,8 @@ set_squared_corners(struct ssd *ssd, bool enable)
|
||||||
FOR_EACH_STATE(ssd, subtree) {
|
FOR_EACH_STATE(ssd, subtree) {
|
||||||
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
|
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
|
||||||
wlr_scene_node_set_position(part->node, x, 0);
|
wlr_scene_node_set_position(part->node, x, 0);
|
||||||
wlr_scene_rect_set_size(wlr_scene_rect_from_node(part->node),
|
wlr_scene_buffer_set_dest_size(
|
||||||
|
wlr_scene_buffer_from_node(part->node),
|
||||||
MAX(width - 2 * x, 0), theme->titlebar_height);
|
MAX(width - 2 * x, 0), theme->titlebar_height);
|
||||||
|
|
||||||
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT);
|
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT);
|
||||||
|
|
@ -299,8 +299,8 @@ ssd_titlebar_update(struct ssd *ssd)
|
||||||
int bg_offset = maximized || squared ? 0 : corner_width;
|
int bg_offset = maximized || squared ? 0 : corner_width;
|
||||||
FOR_EACH_STATE(ssd, subtree) {
|
FOR_EACH_STATE(ssd, subtree) {
|
||||||
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
|
part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
|
||||||
wlr_scene_rect_set_size(
|
wlr_scene_buffer_set_dest_size(
|
||||||
wlr_scene_rect_from_node(part->node),
|
wlr_scene_buffer_from_node(part->node),
|
||||||
MAX(width - bg_offset * 2, 0), theme->titlebar_height);
|
MAX(width - bg_offset * 2, 0), theme->titlebar_height);
|
||||||
|
|
||||||
x = theme->window_titlebar_padding_width;
|
x = theme->window_titlebar_padding_width;
|
||||||
|
|
@ -458,7 +458,7 @@ ssd_update_title(struct ssd *ssd)
|
||||||
bool title_unchanged = state->text && !strcmp(title, state->text);
|
bool title_unchanged = state->text && !strcmp(title, state->text);
|
||||||
|
|
||||||
const float *text_color;
|
const float *text_color;
|
||||||
const float *bg_color;
|
const float bg_color[4] = {0, 0, 0, 0}; /* ignored */
|
||||||
struct font *font = NULL;
|
struct font *font = NULL;
|
||||||
struct ssd_part *part;
|
struct ssd_part *part;
|
||||||
struct ssd_sub_tree *subtree;
|
struct ssd_sub_tree *subtree;
|
||||||
|
|
@ -474,7 +474,6 @@ ssd_update_title(struct ssd *ssd)
|
||||||
THEME_ACTIVE : THEME_INACTIVE;
|
THEME_ACTIVE : THEME_INACTIVE;
|
||||||
dstate = active ? &state->active : &state->inactive;
|
dstate = active ? &state->active : &state->inactive;
|
||||||
text_color = theme->window[active].label_text_color;
|
text_color = theme->window[active].label_text_color;
|
||||||
bg_color = theme->window[active].title_bg_color;
|
|
||||||
font = active ? &rc.font_activewindow : &rc.font_inactivewindow;
|
font = active ? &rc.font_activewindow : &rc.font_inactivewindow;
|
||||||
|
|
||||||
if (title_bg_width <= 0) {
|
if (title_bg_width <= 0) {
|
||||||
|
|
@ -492,7 +491,9 @@ ssd_update_title(struct ssd *ssd)
|
||||||
if (!part) {
|
if (!part) {
|
||||||
/* Initialize part and wlr_scene_buffer without attaching a buffer */
|
/* Initialize part and wlr_scene_buffer without attaching a buffer */
|
||||||
part = add_scene_part(&subtree->parts, LAB_SSD_PART_TITLE);
|
part = add_scene_part(&subtree->parts, LAB_SSD_PART_TITLE);
|
||||||
part->buffer = scaled_font_buffer_create(subtree->tree);
|
part->buffer = scaled_font_buffer_create_for_titlebar(
|
||||||
|
subtree->tree, theme->titlebar_height,
|
||||||
|
theme->window[active].titlebar_pattern);
|
||||||
if (part->buffer) {
|
if (part->buffer) {
|
||||||
part->node = &part->buffer->scene_buffer->node;
|
part->node = &part->buffer->scene_buffer->node;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
50
src/theme.c
50
src/theme.c
|
|
@ -53,7 +53,7 @@ struct rounded_corner_ctx {
|
||||||
struct wlr_box *box;
|
struct wlr_box *box;
|
||||||
double radius;
|
double radius;
|
||||||
double line_width;
|
double line_width;
|
||||||
float *fill_color;
|
cairo_pattern_t *fill_pattern;
|
||||||
float *border_color;
|
float *border_color;
|
||||||
enum corner corner;
|
enum corner corner;
|
||||||
};
|
};
|
||||||
|
|
@ -1109,10 +1109,24 @@ rounded_rect(struct rounded_corner_ctx *ctx)
|
||||||
}
|
}
|
||||||
cairo_close_path(cairo);
|
cairo_close_path(cairo);
|
||||||
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
set_cairo_color(cairo, ctx->fill_color);
|
/*
|
||||||
|
* We need to offset the fill pattern vertically by the border
|
||||||
|
* width to line up with the rest of the titlebar. This is done
|
||||||
|
* by applying a transformation matrix to the pattern temporarily.
|
||||||
|
* It would be better to copy the pattern, but cairo does not
|
||||||
|
* provide a simple way to this.
|
||||||
|
*/
|
||||||
|
cairo_matrix_t matrix;
|
||||||
|
cairo_matrix_init_translate(&matrix, 0, -ctx->line_width);
|
||||||
|
cairo_pattern_set_matrix(ctx->fill_pattern, &matrix);
|
||||||
|
cairo_set_source(cairo, ctx->fill_pattern);
|
||||||
cairo_fill_preserve(cairo);
|
cairo_fill_preserve(cairo);
|
||||||
cairo_stroke(cairo);
|
cairo_stroke(cairo);
|
||||||
|
|
||||||
|
/* Reset the fill pattern transformation matrix afterward */
|
||||||
|
cairo_matrix_init_identity(&matrix);
|
||||||
|
cairo_pattern_set_matrix(ctx->fill_pattern, &matrix);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Stroke horizontal and vertical borders, shown by Xs and Ys
|
* Stroke horizontal and vertical borders, shown by Xs and Ys
|
||||||
* respectively in the figure below:
|
* respectively in the figure below:
|
||||||
|
|
@ -1215,6 +1229,33 @@ out:
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct lab_data_buffer *
|
||||||
|
create_titlebar_fill(cairo_pattern_t *pattern, int height)
|
||||||
|
{
|
||||||
|
/* create 1px wide buffer to be stretched horizontally */
|
||||||
|
struct lab_data_buffer *fill = buffer_create_cairo(1, height, 1);
|
||||||
|
|
||||||
|
cairo_t *cairo = cairo_create(fill->surface);
|
||||||
|
cairo_set_source(cairo, pattern);
|
||||||
|
cairo_paint(cairo);
|
||||||
|
cairo_surface_flush(fill->surface);
|
||||||
|
cairo_destroy(cairo);
|
||||||
|
|
||||||
|
return fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_backgrounds(struct theme *theme)
|
||||||
|
{
|
||||||
|
for (int active = THEME_INACTIVE; active <= THEME_ACTIVE; active++) {
|
||||||
|
theme->window[active].titlebar_pattern = color_to_pattern(
|
||||||
|
theme->window[active].title_bg_color);
|
||||||
|
theme->window[active].titlebar_fill = create_titlebar_fill(
|
||||||
|
theme->window[active].titlebar_pattern,
|
||||||
|
theme->titlebar_height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
create_corners(struct theme *theme)
|
create_corners(struct theme *theme)
|
||||||
{
|
{
|
||||||
|
|
@ -1232,7 +1273,7 @@ create_corners(struct theme *theme)
|
||||||
.box = &box,
|
.box = &box,
|
||||||
.radius = rc.corner_radius,
|
.radius = rc.corner_radius,
|
||||||
.line_width = theme->border_width,
|
.line_width = theme->border_width,
|
||||||
.fill_color = theme->window[active].title_bg_color,
|
.fill_pattern = theme->window[active].titlebar_pattern,
|
||||||
.border_color = theme->window[active].border_color,
|
.border_color = theme->window[active].border_color,
|
||||||
.corner = LAB_CORNER_TOP_LEFT,
|
.corner = LAB_CORNER_TOP_LEFT,
|
||||||
};
|
};
|
||||||
|
|
@ -1567,6 +1608,7 @@ theme_init(struct theme *theme, struct server *server, const char *theme_name)
|
||||||
paths_destroy(&paths);
|
paths_destroy(&paths);
|
||||||
|
|
||||||
post_processing(theme);
|
post_processing(theme);
|
||||||
|
create_backgrounds(theme);
|
||||||
create_corners(theme);
|
create_corners(theme);
|
||||||
load_buttons(theme);
|
load_buttons(theme);
|
||||||
create_shadows(theme);
|
create_shadows(theme);
|
||||||
|
|
@ -1593,6 +1635,8 @@ theme_finish(struct theme *theme)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int active = THEME_INACTIVE; active <= THEME_ACTIVE; active++) {
|
for (int active = THEME_INACTIVE; active <= THEME_ACTIVE; active++) {
|
||||||
|
zfree_pattern(theme->window[active].titlebar_pattern);
|
||||||
|
zdrop(&theme->window[active].titlebar_fill);
|
||||||
zdrop(&theme->window[active].corner_top_left_normal);
|
zdrop(&theme->window[active].corner_top_left_normal);
|
||||||
zdrop(&theme->window[active].corner_top_right_normal);
|
zdrop(&theme->window[active].corner_top_right_normal);
|
||||||
zdrop(&theme->window[active].shadow_corner_top);
|
zdrop(&theme->window[active].shadow_corner_top);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue