This commit is contained in:
Jack Zeal 2026-04-06 01:10:21 +00:00 committed by GitHub
commit 7cd2f4184d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 1215 additions and 54 deletions

View file

@ -6,7 +6,9 @@
# make sure all other lines are commented out or deleted. # make sure all other lines are commented out or deleted.
# general # general
border.width: 1 border.width: 6
border.beveled: yes
border.bevel_width:2
# #
# The global padding.{width,height} of openbox are not supported because # The global padding.{width,height} of openbox are not supported because

View file

@ -0,0 +1,61 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <stdint.h>
#include <wlr/types/wlr_scene.h>
#ifndef LABWC_BORDERSET_H
#define LABWC_BORDERSET_H
enum border_type {
BORDER_NONE, BORDER_SINGLE, BORDER_DOUBLE, BORDER_INSET, BORDER_DOUBLE_INSET, BORDER_FLAT
};
struct borderset {
// Base colour, but could be used as a tracking hash for images or whatever in the future
uint32_t id;
// width (since I suspect a 2px border scaled up to 20px might look weird)
int size;
// Single or double bevel, etc.
enum border_type type;
// So we can disambiguate multiple possible designs cached together
int bevelSize;
struct lab_data_buffer *top;
struct lab_data_buffer *left;
struct lab_data_buffer *right;
struct lab_data_buffer *bottom;
struct lab_data_buffer *tl;
struct lab_data_buffer *tr;
struct lab_data_buffer *bl;
struct lab_data_buffer *br;
struct borderset *next;
};
struct bufferset {
enum border_type type;
int border_width;
struct wlr_scene_buffer *top;
struct wlr_scene_buffer *left;
struct wlr_scene_buffer *right;
struct wlr_scene_buffer *bottom;
struct wlr_scene_buffer *tl;
struct wlr_scene_buffer *tr;
struct wlr_scene_buffer *bl;
struct wlr_scene_buffer *br;
};
extern struct borderset *border_cache;
struct borderset *get_borders(uint32_t id, int size, enum border_type, int bevelSize);
struct borderset *create_buffer(uint32_t id, int size, enum border_type, int bevelSize);
struct bufferset *generate_bufferset(struct wlr_scene_tree *tree,
struct borderset *borderset, int bw);
void renderBufferset(struct bufferset *bufferset, int width, int height, int y);
void renderBuffersetXY(struct bufferset *bufferset, int width, int height, int x, int y);
void clearborder_cache(struct borderset *borderset);
#endif /* LABWC_BORDERSET_H */

View file

@ -2,6 +2,7 @@
#ifndef LABWC_LAB_SCENE_RECT_H #ifndef LABWC_LAB_SCENE_RECT_H
#define LABWC_LAB_SCENE_RECT_H #define LABWC_LAB_SCENE_RECT_H
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include "common/borderset.h"
struct wlr_scene_tree; struct wlr_scene_tree;
@ -12,6 +13,8 @@ struct lab_scene_rect_options {
float *bg_color; /* can be NULL */ float *bg_color; /* can be NULL */
int width; int width;
int height; int height;
enum border_type border_type;
int bevel_width;
}; };
struct lab_scene_rect { struct lab_scene_rect {

View file

@ -65,4 +65,15 @@
#define LAB_WLR_VERSION_AT_LEAST(major, minor, micro) \ #define LAB_WLR_VERSION_AT_LEAST(major, minor, micro) \
(WLR_VERSION_NUM >= (((major) << 16) | ((minor) << 8) | (micro))) (WLR_VERSION_NUM >= (((major) << 16) | ((minor) << 8) | (micro)))
/**
* PIXEL () - calculate pixel offset in an array
*
* @param x x-coordinate
* @param y y-coordinate
* @param size width of the buffer in pixes
* Assumes "bw" was defined externally
*/
#define PIXEL(x, y, size) (size * y + x)
#endif /* LABWC_MACROS_H */ #endif /* LABWC_MACROS_H */

View file

@ -106,6 +106,7 @@ struct ssd {
struct scaled_font_buffer *title; struct scaled_font_buffer *title;
struct wl_list buttons_left; /* ssd_button.link */ struct wl_list buttons_left; /* ssd_button.link */
struct wl_list buttons_right; /* ssd_button.link */ struct wl_list buttons_right; /* ssd_button.link */
struct bufferset *textured_borders;
} subtrees[2]; /* indexed by enum ssd_active_state */ } subtrees[2]; /* indexed by enum ssd_active_state */
} titlebar; } titlebar;
@ -115,6 +116,7 @@ struct ssd {
struct ssd_border_subtree { struct ssd_border_subtree {
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_scene_rect *top, *bottom, *left, *right; struct wlr_scene_rect *top, *bottom, *left, *right;
struct bufferset *textured_borders;
} subtrees[2]; /* indexed by enum ssd_active_state */ } subtrees[2]; /* indexed by enum ssd_active_state */
} border; } border;

View file

@ -11,6 +11,7 @@
#include <cairo.h> #include <cairo.h>
#include <stdbool.h> #include <stdbool.h>
#include "common/node-type.h" #include "common/node-type.h"
#include "common/borderset.h"
struct lab_img; struct lab_img;
@ -56,6 +57,10 @@ struct theme_background {
float color_split_to[4]; float color_split_to[4];
float color_to[4]; float color_to[4];
float color_to_split_to[4]; float color_to_split_to[4];
enum border_type border_type;
int border_width;
int bevel_width;
bool exclusive;
}; };
struct theme { struct theme {
@ -92,10 +97,17 @@ struct theme {
/* TODO: add toggled/hover/pressed/disabled colors for buttons */ /* TODO: add toggled/hover/pressed/disabled colors for buttons */
float button_colors[LAB_NODE_BUTTON_LAST + 1][4]; float button_colors[LAB_NODE_BUTTON_LAST + 1][4];
enum border_type button_border_type;
int button_border_width;
int button_bevel_width;
float button_border_color[4];
float button_hover_border_color[4];
float border_color[4]; float border_color[4];
float toggled_keybinds_color[4]; float toggled_keybinds_color[4];
float label_text_color[4]; float label_text_color[4];
enum border_type border_type;
int bevel_width;
/* window drop-shadows */ /* window drop-shadows */
int shadow_size; int shadow_size;
@ -142,6 +154,8 @@ struct theme {
int menu_max_width; int menu_max_width;
int menu_border_width; int menu_border_width;
float menu_border_color[4]; float menu_border_color[4];
enum border_type menu_border_type;
int menu_bevel_width;
int menu_items_padding_x; int menu_items_padding_x;
int menu_items_padding_y; int menu_items_padding_y;
@ -149,6 +163,12 @@ struct theme {
float menu_items_text_color[4]; float menu_items_text_color[4];
float menu_items_active_bg_color[4]; float menu_items_active_bg_color[4];
float menu_items_active_text_color[4]; float menu_items_active_text_color[4];
enum border_type menu_items_border_type;
int menu_items_bevel_width;
enum border_type menu_title_border_type;
int menu_title_bevel_width;
enum border_type menu_items_active_border_type;
int menu_items_active_bevel_width;
int menu_separator_line_thickness; int menu_separator_line_thickness;
int menu_separator_padding_width; int menu_separator_padding_width;
@ -164,6 +184,8 @@ struct theme {
float osd_bg_color[4]; float osd_bg_color[4];
float osd_border_color[4]; float osd_border_color[4];
float osd_label_text_color[4]; float osd_label_text_color[4];
enum border_type osd_border_type;
int osd_border_bevel_width;
struct window_switcher_classic_theme { struct window_switcher_classic_theme {
int width; int width;

View file

@ -244,6 +244,7 @@ struct view {
int width, height; int width, height;
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_scene_rect *border; struct wlr_scene_rect *border;
struct bufferset *textured_borders;
struct wlr_scene_rect *background; struct wlr_scene_rect *background;
struct scaled_font_buffer *text; struct scaled_font_buffer *text;
} resize_indicator; } resize_indicator;

482
src/common/borderset.c Normal file
View file

@ -0,0 +1,482 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <assert.h>
#include <wlr/types/wlr_scene.h>
#include "common/borderset.h"
#include "common/mem.h"
#include "common/macros.h"
#include "buffer.h"
struct borderset *get_borders(uint32_t id, int size, enum border_type type, int bevelSize)
{
struct borderset *current = border_cache;
struct borderset *last;
// Preventing building nonsense borders:
// If you try for a double bevel but it's so deep they would overlap,
// convert to a single bevel
if (type == BORDER_DOUBLE && (bevelSize > size/2)) {
type = BORDER_SINGLE;
}
if (type == BORDER_DOUBLE_INSET && (bevelSize > size/2)) {
type = BORDER_INSET;
}
// Anything with a size of 0 is converted to a 1-pixel flat border so as to
// prevent empty allocations
if (size < 1) {
type = BORDER_FLAT;
size = 1;
}
while (current) {
if (current->size == size && current->id == id &&
current->type == type && current->bevelSize == bevelSize) {
return current;
}
last = current;
current = current->next;
}
// Fall through, we need to create a buffer.
if (!border_cache) {
border_cache = create_buffer(id, size, type, bevelSize);
return border_cache;
} else {
last->next = create_buffer(id, size, type, bevelSize);
return last->next;
}
return NULL;
}
struct borderset *create_buffer(uint32_t id, int size, enum border_type type, int bevelSize)
{
struct borderset *new_borderset = znew(*new_borderset);
new_borderset->next = NULL;
new_borderset->id = id;
new_borderset->size = size;
new_borderset->type = type;
new_borderset->bevelSize = bevelSize;
// Use ID as a AARRGGBB colour
uint8_t a = id >> 24 & 255;
uint8_t r = id >> 16 & 255;
uint8_t g = id >> 8 & 255;
uint8_t b = id & 255;
uint32_t r1 = r * 5 / 4;
if (r1 > a) {
r1 = a;
}
uint32_t g1 = g * 5 / 4;
if (g1 > a) {
g1 = a;
}
uint32_t b1 = b * 5 / 4;
if (b1 > a) {
b1 = a;
}
/* darker outline */
uint32_t r0 = r / 2;
uint32_t g0 = g / 2;
uint32_t b0 = b / 2;
uint32_t hl32 = ((uint32_t)a << 24) | ((uint32_t)r1 << 16)
| ((uint32_t)g1 << 8) | (uint32_t)b1;
uint32_t ll32 = ((uint32_t)a << 24) | ((uint32_t)r0 << 16)
| ((uint32_t)g0 << 8) | (uint32_t)b0;
uint32_t temp;
// All borders have NxN corners
uint32_t *tl = znew_n(uint32_t, size*size);
uint32_t *tr = znew_n(uint32_t, size*size);
uint32_t *bl = znew_n(uint32_t, size*size);
uint32_t *br = znew_n(uint32_t, size*size);
uint32_t *top = NULL;
uint32_t *left = NULL;
uint32_t *right = NULL;
uint32_t *bottom = NULL;
size_t side_size = 0;
switch (type) {
case BORDER_INSET:
temp = ll32;
ll32 = hl32;
hl32 = temp;
top = znew(uint32_t);
left = znew(uint32_t);
right = znew(uint32_t);
bottom = znew(uint32_t);
side_size = 1;
*top = hl32;
*left = hl32;
*right = ll32;
*bottom = ll32;
// Fill with solid
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
tl[PIXEL(j, k, size)] = hl32;
tr[PIXEL(size - 1 - j, k, size)] = (j > k) ? hl32 : ll32;
bl[PIXEL(size - 1 -j, k, size)] = (j > k) ? hl32 : ll32;
br[PIXEL(j, k, size)] = ll32;
}
}
break;
case BORDER_SINGLE: // Single bevel borders have 1x1 sides
top = znew(uint32_t);
left = znew(uint32_t);
right = znew(uint32_t);
bottom = znew(uint32_t);
side_size = 1;
*top = hl32;
*left = hl32;
*right = ll32;
*bottom = ll32;
// Fill with solid
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
tl[PIXEL(j, k, size)] = hl32;
tr[PIXEL(size - 1 - j, k, size)] = (j > k) ? hl32 : ll32;
bl[PIXEL(size - 1 -j, k, size)] = (j > k) ? hl32 : ll32;
br[PIXEL(j, k, size)] = ll32;
}
}
break;
case BORDER_DOUBLE_INSET:
temp = ll32;
ll32 = hl32;
hl32 = temp;
top = znew_n(uint32_t, size);
left = znew_n(uint32_t, size);
right = znew_n(uint32_t, size);
bottom = znew_n(uint32_t, size);
side_size = size;
for (int i = 0; i < size; i++) {
if (i < bevelSize) {
left[i] = hl32;
top[i] = hl32;
right[i] = hl32;
bottom[i] = hl32;
} else if (i > (size-bevelSize-1)) {
left[i] = ll32;
top[i] = ll32;
right[i] = ll32;
bottom[i] = ll32;
} else {
left[i] = id;
top[i] = id;
right[i] = id;
bottom[i] = id;
}
}
// Blank corners...
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
tl[PIXEL(i, j, size)] = id;
tr[PIXEL(i, j, size)] = id;
bl[PIXEL(i, j, size)] = id;
br[PIXEL(i, j, size)] = id;
}
}
// Main Corners
for (int i = 0; i < bevelSize; i++) {
// Solid bar parts
for (int j = 0; j < size; j++) {
// Top left corner: Entire "bevel size" top rows are highlighted
tl[PIXEL(j, i, size)] = hl32;
// First "bevel size" top columns are highlighted
tl[PIXEL(i, j, size)] = hl32;
// Bottom Right corner: Entire "bevel size" last rows are lowlight
br[PIXEL(j, (size-1-i), size)] = ll32;
// Last "bevel size" columns are lowlight
br[PIXEL((size-1-i), j, size)] = ll32;
// Bottom left corner: Entire "bevel size" last rows are lowlight
bl[PIXEL(j, (size-1-i), size)] = ll32;
// First "bevel size" columns are highlight, except for
// the bottom right corner
bl[PIXEL(i, j, size)] = hl32;
// Top Right corner: Entire "bevel size" first rows are highlight
tr[PIXEL(j, i, size)] = hl32;
// Last "bevel size" columns are lowlight, except for the top left
tr[PIXEL((size-1-i), j, size)] = ll32;
}
}
// Beveled Corner Parts
for (int i = 0; i < bevelSize; i++) {
for (int j = 0; j < bevelSize; j++) {
// Outer Corners
// Bottom left corner:
// First "bevel size" columns are highlight, except
// for the bottom right corner
bl[PIXEL(i, (size - 1 - j), size)] = (j >= i) ? hl32 : ll32;
// Top Right corner:
// Last "bevel size" columns are lowlight, except for the top left
tr[PIXEL((size-1-i), j, size)] = (j > i) ? ll32 : hl32;
// Inner Corners
// Top left corner: Bottom right is all dark
tl[PIXEL((size-1-i), (size - 1 - j), size)] = ll32;
// Bottom Right corner: Top left is all light
br[PIXEL(i, j, size)] = hl32;
// Top Right corner:
// Interior bottom left is dark on top, light on bottom
tr[PIXEL(i, (size-1-j), size)] = (i > j) ? hl32 : ll32;
// Bottom Left corner:
// Interior top right is dark on top, light on bottom
bl[PIXEL((size-1-i), j, size)] = (i > j) ? ll32 : hl32;
}
}
break;
case BORDER_DOUBLE:
top = znew_n(uint32_t, size);
left = znew_n(uint32_t, size);
right = znew_n(uint32_t, size);
bottom = znew_n(uint32_t, size);
side_size = size;
for (int i = 0; i < size; i++) {
if (i < bevelSize) {
left[i] = hl32;
top[i] = hl32;
right[i] = hl32;
bottom[i] = hl32;
} else if (i > (size-bevelSize-1)) {
left[i] = ll32;
top[i] = ll32;
right[i] = ll32;
bottom[i] = ll32;
} else {
left[i] = id;
top[i] = id;
right[i] = id;
bottom[i] = id;
}
}
// Blank corners...
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
tl[PIXEL(i, j, size)] = id;
tr[PIXEL(i, j, size)] = id;
bl[PIXEL(i, j, size)] = id;
br[PIXEL(i, j, size)] = id;
}
}
// Main Corners
for (int i = 0; i < bevelSize; i++) {
// Solid bar parts
for (int j = 0; j < size; j++) {
// Top left corner: Entire "bevel size" top rows are highlighted
tl[PIXEL(j, i, size)] = hl32;
// First "bevel size" top columns are highlighted
tl[PIXEL(i, j, size)] = hl32;
// Bottom Right corner: Entire "bevel size" last rows are lowlight
br[PIXEL(j, (size-1-i), size)] = ll32;
// Last "bevel size" columns are lowlight
br[PIXEL((size-1-i), j, size)] = ll32;
// Bottom left corner: Entire "bevel size" last rows are lowlight
bl[PIXEL(j, (size-1-i), size)] = ll32;
// First "bevel size" columns are highlight, except for
// the bottom right corner
bl[PIXEL(i, j, size)] = hl32;
// Top Right corner: Entire "bevel size" first rows are highlight
tr[PIXEL(j, i, size)] = hl32;
// Last "bevel size" columns are lowlight, except for the top left
tr[PIXEL((size-1-i), j, size)] = ll32;
}
}
// Beveled Corner Parts
for (int i = 0; i < bevelSize; i++) {
for (int j = 0; j < bevelSize; j++) {
// Outer Corners
// Bottom left corner:
// First "bevel size" columns are highlight, except
// for the bottom right corner
bl[PIXEL(i, (size - 1 - j), size)] = (j >= i) ? hl32 : ll32;
// Top Right corner:
// Last "bevel size" columns are lowlight, except for the top left
tr[PIXEL((size-1-i), j, size)] = (j > i) ? ll32 : hl32;
// Inner Corners
// Top left corner: Bottom right is all dark
tl[PIXEL((size-1-i), (size - 1 - j), size)] = ll32;
// Bottom Right corner: Top left is all light
br[PIXEL(i, j, size)] = hl32;
// Top Right corner:
// Interior bottom left is dark on top, light on bottom
tr[PIXEL(i, (size-1-j), size)] = (i > j) ? hl32 : ll32;
// Bottom Left corner:
// Interior top right is dark on top, light on bottom
bl[PIXEL((size-1-i), j, size)] = (i > j) ? ll32 : hl32;
}
}
break;
case BORDER_FLAT: // Placeholder that uses buffers but for a flat colour
case BORDER_NONE: // Provided as a fallback but should not be actually requested/rendered
top = znew(uint32_t);
left = znew(uint32_t);
right = znew(uint32_t);
bottom = znew(uint32_t);
side_size = 1;
*top = id;
*left = id;
*right = id;
*bottom = id;
// Fill with solid
for (int j = 0; j < size; j++) {
for (int k = 0; k < size; k++) {
tl[PIXEL(j, k, size)] = id;
tr[PIXEL(size - 1 - j, k, size)] = id;
bl[PIXEL(size - 1 -j, k, size)] = id;
br[PIXEL(j, k, size)] = id;
}
}
break;
}
assert(side_size > 0);
new_borderset->top = buffer_create_from_data(top, 1, side_size, 4);
new_borderset->left = buffer_create_from_data(left, side_size, 1, side_size * 4);
new_borderset->right = buffer_create_from_data(right, side_size, 1, side_size * 4);
new_borderset->bottom = buffer_create_from_data(bottom, 1, side_size, 4);
new_borderset->tl = buffer_create_from_data(tl, size, size, size * 4);
new_borderset->tr = buffer_create_from_data(tr, size, size, size * 4);
new_borderset->bl = buffer_create_from_data(bl, size, size, size * 4);
new_borderset->br = buffer_create_from_data(br, size, size, size * 4);
return new_borderset;
}
struct bufferset *generate_bufferset(struct wlr_scene_tree *tree,
struct borderset *borderset, int bw)
{
struct bufferset *bufferset = znew(struct bufferset);
bufferset->top = wlr_scene_buffer_create(tree, &borderset->top->base);
bufferset->left = wlr_scene_buffer_create(tree, &borderset->left->base);
bufferset->right = wlr_scene_buffer_create(tree, &borderset->right->base);
bufferset->bottom = wlr_scene_buffer_create(tree, &borderset->bottom->base);
bufferset->tl = wlr_scene_buffer_create(tree, &borderset->tl->base);
bufferset->tr = wlr_scene_buffer_create(tree, &borderset->tr->base);
bufferset->bl = wlr_scene_buffer_create(tree, &borderset->bl->base);
bufferset->br = wlr_scene_buffer_create(tree, &borderset->br->base);
bufferset->border_width = bw;
wlr_scene_buffer_set_filter_mode(bufferset->top, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->left, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->right, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->bottom, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->tl, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->tr, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->bl, WLR_SCALE_FILTER_NEAREST);
wlr_scene_buffer_set_filter_mode(bufferset->br, WLR_SCALE_FILTER_NEAREST);
return bufferset;
}
void renderBufferset(struct bufferset *bufferset, int width, int height, int y)
{
renderBuffersetXY(bufferset, width, height, 0, y);
}
void renderBuffersetXY(struct bufferset *bufferset, int width, int height, int x, int y)
{
wlr_scene_buffer_set_dest_size(bufferset->top,
width - 2 * bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->top->node,
x+bufferset->border_width, y);
wlr_scene_buffer_set_dest_size(bufferset->bottom,
width - 2 * bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->bottom->node,
x+bufferset->border_width, y+height - bufferset->border_width);
wlr_scene_buffer_set_dest_size(bufferset->left,
bufferset->border_width, height - bufferset->border_width * 2);
wlr_scene_node_set_position(&bufferset->left->node,
x, bufferset->border_width+y);
wlr_scene_buffer_set_dest_size(bufferset->right,
bufferset->border_width, height - bufferset->border_width * 2);
wlr_scene_node_set_position(&bufferset->right->node,
x+width - bufferset->border_width, y+bufferset->border_width);
wlr_scene_buffer_set_dest_size(bufferset->tl,
bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->tl->node,
x, y);
wlr_scene_buffer_set_dest_size(bufferset->tr,
bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->tr->node,
x+width-bufferset->border_width, y);
wlr_scene_buffer_set_dest_size(bufferset->br,
bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->br->node,
x+width-bufferset->border_width, y+height-bufferset->border_width);
wlr_scene_buffer_set_dest_size(bufferset->bl,
bufferset->border_width, bufferset->border_width);
wlr_scene_node_set_position(&bufferset->bl->node,
x, height-bufferset->border_width+y);
}
void clearborder_cache(struct borderset *borderset)
{
if (!borderset) {
return;
}
if (borderset->next) {
clearborder_cache(borderset->next);
}
wlr_buffer_drop(&borderset->top->base);
wlr_buffer_drop(&borderset->left->base);
wlr_buffer_drop(&borderset->right->base);
wlr_buffer_drop(&borderset->bottom->base);
wlr_buffer_drop(&borderset->tl->base);
wlr_buffer_drop(&borderset->tr->base);
wlr_buffer_drop(&borderset->bl->base);
wlr_buffer_drop(&borderset->br->base);
free(borderset);
}

View file

@ -4,10 +4,15 @@
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include "common/mem.h" #include "common/mem.h"
#include "common/scene-helpers.h" #include "common/scene-helpers.h"
#include "common/macros.h"
#include "common/borderset.h"
#include "theme.h"
#include "buffer.h"
struct border_scene { struct border_scene {
struct wlr_scene_tree *tree; struct wlr_scene_tree *tree;
struct wlr_scene_rect *top, *bottom, *left, *right; struct wlr_scene_rect *top, *bottom, *left, *right;
struct bufferset *textured_borders;
}; };
static void static void
@ -37,10 +42,29 @@ lab_scene_rect_create(struct wlr_scene_tree *parent,
struct border_scene *border = &rect->borders[i]; struct border_scene *border = &rect->borders[i];
float *color = opts->border_colors[i]; float *color = opts->border_colors[i];
border->tree = lab_wlr_scene_tree_create(rect->tree); border->tree = lab_wlr_scene_tree_create(rect->tree);
border->top = lab_wlr_scene_rect_create(border->tree, 0, 0, color); border->top = lab_wlr_scene_rect_create(border->tree, 0, 0, color);
border->right = lab_wlr_scene_rect_create(border->tree, 0, 0, color); border->right = lab_wlr_scene_rect_create(border->tree, 0, 0, color);
border->bottom = lab_wlr_scene_rect_create(border->tree, 0, 0, color); border->bottom = lab_wlr_scene_rect_create(border->tree, 0, 0, color);
border->left = lab_wlr_scene_rect_create(border->tree, 0, 0, color); border->left = lab_wlr_scene_rect_create(border->tree, 0, 0, color);
if (opts->border_type) {
float r = color[0];
float g = color[1];
float b = color[2];
float a = color[3];
int bw = rect->border_width;
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
opts->border_type, opts->bevel_width);
border->textured_borders = generate_bufferset(border->tree,
renderedborders, bw);
} else {
border->textured_borders = NULL;
}
} }
rect->node_destroy.notify = handle_node_destroy; rect->node_destroy.notify = handle_node_destroy;
@ -81,6 +105,9 @@ resize_border(struct border_scene *border, int border_width, int width, int heig
wlr_scene_rect_set_size(border->bottom, width, border_width); wlr_scene_rect_set_size(border->bottom, width, border_width);
wlr_scene_rect_set_size(border->left, border_width, height - border_width * 2); wlr_scene_rect_set_size(border->left, border_width, height - border_width * 2);
wlr_scene_rect_set_size(border->right, border_width, height - border_width * 2); wlr_scene_rect_set_size(border->right, border_width, height - border_width * 2);
if (border->textured_borders) {
renderBufferset(border->textured_borders, width, height, 0);
}
} }
void void

View file

@ -1,4 +1,5 @@
labwc_sources += files( labwc_sources += files(
'borderset.c',
'box.c', 'box.c',
'buf.c', 'buf.c',
'dir.c', 'dir.c',

View file

@ -37,6 +37,8 @@ update_preview_outlines(struct view *view)
}, },
.nr_borders = 3, .nr_borders = 3,
.border_width = theme->osd_window_switcher_preview_border_width, .border_width = theme->osd_window_switcher_preview_border_width,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
rect = lab_scene_rect_create(&server.scene->tree, &opts); rect = lab_scene_rect_create(&server.scene->tree, &opts);
wlr_scene_node_place_above(&rect->tree->node, wlr_scene_node_place_above(&rect->tree->node,

View file

@ -120,6 +120,8 @@ cycle_osd_classic_init(struct cycle_osd_output *osd_output)
.bg_color = bg_color, .bg_color = bg_color,
.width = w, .width = w,
.height = h, .height = h,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
lab_scene_rect_create(osd_output->tree, &bg_opts); lab_scene_rect_create(osd_output->tree, &bg_opts);
@ -202,6 +204,8 @@ cycle_osd_classic_init(struct cycle_osd_output *osd_output)
.bg_color = active_bg_color, .bg_color = active_bg_color,
.width = w - 2 * padding, .width = w - 2 * padding,
.height = switcher_theme->item_height, .height = switcher_theme->item_height,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
struct lab_scene_rect *highlight_rect = lab_scene_rect_create( struct lab_scene_rect *highlight_rect = lab_scene_rect_create(
item->active_tree, &highlight_opts); item->active_tree, &highlight_opts);

View file

@ -3,7 +3,9 @@
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include "common/lab-scene-rect.h" #include "common/lab-scene-rect.h"
#include "common/scene-helpers.h" #include "common/scene-helpers.h"
#include "config/rcxml.h"
#include "labwc.h" #include "labwc.h"
#include "theme.h"
#include "cycle.h" #include "cycle.h"
#include "output.h" #include "output.h"
@ -12,6 +14,8 @@ cycle_osd_scroll_init(struct cycle_osd_output *osd_output, struct wlr_box bar_ar
int delta_y, int nr_cols, int nr_rows, int nr_visible_rows, int delta_y, int nr_cols, int nr_rows, int nr_visible_rows,
float *border_color, float *bg_color) float *border_color, float *bg_color)
{ {
struct theme *theme = rc.theme;
if (nr_visible_rows >= nr_rows) { if (nr_visible_rows >= nr_rows) {
/* OSD doesn't have so many windows to scroll through */ /* OSD doesn't have so many windows to scroll through */
return; return;
@ -35,6 +39,8 @@ cycle_osd_scroll_init(struct cycle_osd_output *osd_output, struct wlr_box bar_ar
.bg_color = bg_color, .bg_color = bg_color,
.width = bar_area.width, .width = bar_area.width,
.height = bar_area.height * nr_visible_rows / nr_rows, .height = bar_area.height * nr_visible_rows / nr_rows,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
scroll->bar = lab_scene_rect_create(scroll->bar_tree, &scrollbar_opts); scroll->bar = lab_scene_rect_create(scroll->bar_tree, &scrollbar_opts);
} }

View file

@ -154,6 +154,8 @@ create_item_scene(struct wlr_scene_tree *parent, struct view *view,
.bg_color = switcher_theme->item_active_bg_color, .bg_color = switcher_theme->item_active_bg_color,
.width = switcher_theme->item_width, .width = switcher_theme->item_width,
.height = switcher_theme->item_height, .height = switcher_theme->item_height,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
item->active_bg = lab_scene_rect_create(tree, &opts); item->active_bg = lab_scene_rect_create(tree, &opts);
@ -286,6 +288,8 @@ cycle_osd_thumbnail_init(struct cycle_osd_output *osd_output)
.bg_color = theme->osd_bg_color, .bg_color = theme->osd_bg_color,
.width = items_width + 2 * padding, .width = items_width + 2 * padding,
.height = items_height + 2 * padding, .height = items_height + 2 * padding,
.border_type = theme->osd_border_type,
.bevel_width = theme->osd_border_bevel_width
}; };
struct lab_scene_rect *bg = struct lab_scene_rect *bg =
lab_scene_rect_create(osd_output->tree, &bg_opts); lab_scene_rect_create(osd_output->tree, &bg_opts);

View file

@ -13,6 +13,7 @@
#include "theme.h" #include "theme.h"
#include "translate.h" #include "translate.h"
#include "menu/menu.h" #include "menu/menu.h"
#include "common/borderset.h"
/* /*
* Globals * Globals
@ -40,6 +41,8 @@ static const struct option long_options[] = {
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
struct borderset *border_cache;
static const char labwc_usage[] = static const char labwc_usage[] =
"Usage: labwc [options...]\n" "Usage: labwc [options...]\n"
" -c, --config <file> Specify config file (with path)\n" " -c, --config <file> Specify config file (with path)\n"

View file

@ -32,6 +32,8 @@
#include "translate.h" #include "translate.h"
#include "view.h" #include "view.h"
#include "workspaces.h" #include "workspaces.h"
#include "common/borderset.h"
#include "buffer.h"
#define PIPEMENU_MAX_BUF_SIZE 1048576 /* 1 MiB */ #define PIPEMENU_MAX_BUF_SIZE 1048576 /* 1 MiB */
#define PIPEMENU_TIMEOUT_IN_MS 4000 /* 4 seconds */ #define PIPEMENU_TIMEOUT_IN_MS 4000 /* 4 seconds */
@ -163,10 +165,11 @@ item_create(struct menu *menu, const char *text, const char *icon_name, bool sho
static struct wlr_scene_tree * static struct wlr_scene_tree *
item_create_scene_for_state(struct menuitem *item, float *text_color, item_create_scene_for_state(struct menuitem *item, float *text_color,
float *bg_color) float *bg_color, int state)
{ {
struct menu *menu = item->parent; struct menu *menu = item->parent;
struct theme *theme = rc.theme; struct theme *theme = rc.theme;
struct bufferset *bufferset = NULL;
/* Tree to hold background and label buffers */ /* Tree to hold background and label buffers */
struct wlr_scene_tree *tree = lab_wlr_scene_tree_create(item->tree); struct wlr_scene_tree *tree = lab_wlr_scene_tree_create(item->tree);
@ -191,6 +194,37 @@ item_create_scene_for_state(struct menuitem *item, float *text_color,
/* Create background */ /* Create background */
lab_wlr_scene_rect_create(tree, bg_width, theme->menu_item_height, bg_color); lab_wlr_scene_rect_create(tree, bg_width, theme->menu_item_height, bg_color);
int bw = theme->menu_border_width;
if (rc.theme->menu_items_active_border_type && state) {
float r = bg_color[0];
float g = bg_color[1];
float b = bg_color[2];
float a = bg_color[3];
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
rc.theme->menu_items_active_border_type,
rc.theme->menu_items_active_bevel_width);
bufferset = generate_bufferset(tree, renderedborders, bw);
} else if (rc.theme->menu_items_border_type && !state) {
float r = bg_color[0];
float g = bg_color[1];
float b = bg_color[2];
float a = bg_color[3];
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
rc.theme->menu_items_border_type,
rc.theme->menu_items_bevel_width);
bufferset = generate_bufferset(tree, renderedborders, bw);
}
/* Create icon */ /* Create icon */
bool show_app_icon = !strcmp(item->parent->id, "client-list-combined-menu") bool show_app_icon = !strcmp(item->parent->id, "client-list-combined-menu")
&& item->client_list_view; && item->client_list_view;
@ -219,6 +253,10 @@ item_create_scene_for_state(struct menuitem *item, float *text_color,
int y = (theme->menu_item_height - label_buffer->height) / 2; int y = (theme->menu_item_height - label_buffer->height) / 2;
wlr_scene_node_set_position(&label_buffer->scene_buffer->node, x, y); wlr_scene_node_set_position(&label_buffer->scene_buffer->node, x, y);
if (bufferset) {
renderBufferset(bufferset, bg_width, theme->menu_item_height, 0);
}
if (!item->arrow) { if (!item->arrow) {
return tree; return tree;
} }
@ -252,10 +290,10 @@ item_create_scene(struct menuitem *menuitem, int *item_y)
/* Create scenes for unselected/selected states */ /* Create scenes for unselected/selected states */
menuitem->normal_tree = item_create_scene_for_state(menuitem, menuitem->normal_tree = item_create_scene_for_state(menuitem,
theme->menu_items_text_color, theme->menu_items_text_color,
theme->menu_items_bg_color); theme->menu_items_bg_color, 0);
menuitem->selected_tree = item_create_scene_for_state(menuitem, menuitem->selected_tree = item_create_scene_for_state(menuitem,
theme->menu_items_active_text_color, theme->menu_items_active_text_color,
theme->menu_items_active_bg_color); theme->menu_items_active_bg_color, 1);
/* Hide selected state */ /* Hide selected state */
wlr_scene_node_set_enabled(&menuitem->selected_tree->node, false); wlr_scene_node_set_enabled(&menuitem->selected_tree->node, false);
@ -338,6 +376,8 @@ title_create_scene(struct menuitem *menuitem, int *item_y)
assert(menuitem->type == LAB_MENU_TITLE); assert(menuitem->type == LAB_MENU_TITLE);
struct menu *menu = menuitem->parent; struct menu *menu = menuitem->parent;
struct theme *theme = rc.theme; struct theme *theme = rc.theme;
struct bufferset *bufferset = NULL;
float *bg_color = theme->menu_title_bg_color; float *bg_color = theme->menu_title_bg_color;
float *text_color = theme->menu_title_text_color; float *text_color = theme->menu_title_text_color;
@ -357,6 +397,23 @@ title_create_scene(struct menuitem *menuitem, int *item_y)
goto error; goto error;
} }
int bw = theme->menu_border_width;
if (rc.theme->menu_title_border_type) {
float r = bg_color[0];
float g = bg_color[1];
float b = bg_color[2];
float a = bg_color[3];
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
rc.theme->menu_title_border_type,
rc.theme->menu_title_bevel_width);
bufferset = generate_bufferset(menuitem->tree, renderedborders, bw);
}
/* Background */ /* Background */
lab_wlr_scene_rect_create(menuitem->normal_tree, lab_wlr_scene_rect_create(menuitem->normal_tree,
bg_width, theme->menu_header_height, bg_color); bg_width, theme->menu_header_height, bg_color);
@ -385,6 +442,10 @@ title_create_scene(struct menuitem *menuitem, int *item_y)
int title_y = (theme->menu_header_height - title_font_buffer->height) / 2; int title_y = (theme->menu_header_height - title_font_buffer->height) / 2;
wlr_scene_node_set_position(&title_font_buffer->scene_buffer->node, wlr_scene_node_set_position(&title_font_buffer->scene_buffer->node,
title_x, title_y); title_x, title_y);
if (bufferset && rc.theme->menu_title_border_type) {
renderBufferset(bufferset, bg_width, theme->menu_item_height, 0);
}
error: error:
wlr_scene_node_set_position(&menuitem->tree->node, wlr_scene_node_set_position(&menuitem->tree->node,
theme->menu_border_width, *item_y); theme->menu_border_width, *item_y);
@ -457,6 +518,8 @@ menu_create_scene(struct menu *menu)
.border_width = theme->menu_border_width, .border_width = theme->menu_border_width,
.width = menu->size.width, .width = menu->size.width,
.height = menu->size.height, .height = menu->size.height,
.border_type = theme->menu_border_type,
.bevel_width = theme->menu_bevel_width
}; };
struct lab_scene_rect *bg_rect = struct lab_scene_rect *bg_rect =
lab_scene_rect_create(menu->scene_tree, &opts); lab_scene_rect_create(menu->scene_tree, &opts);

View file

@ -73,6 +73,7 @@
#include "view.h" #include "view.h"
#include "workspaces.h" #include "workspaces.h"
#include "xwayland.h" #include "xwayland.h"
#include "common/borderset.h"
#define LAB_EXT_DATA_CONTROL_VERSION 1 #define LAB_EXT_DATA_CONTROL_VERSION 1
#define LAB_EXT_FOREIGN_TOPLEVEL_LIST_VERSION 1 #define LAB_EXT_FOREIGN_TOPLEVEL_LIST_VERSION 1
@ -89,6 +90,9 @@ reload_config_and_theme(void)
scaled_buffer_invalidate_sharing(); scaled_buffer_invalidate_sharing();
rcxml_finish(); rcxml_finish();
clearborder_cache(border_cache);
border_cache = NULL;
rcxml_read(rc.config_file); rcxml_read(rc.config_file);
theme_finish(rc.theme); theme_finish(rc.theme);
theme_init(rc.theme, rc.theme_name); theme_init(rc.theme, rc.theme_name);

View file

@ -12,6 +12,8 @@
#include "ssd.h" #include "ssd.h"
#include "theme.h" #include "theme.h"
#include "view.h" #include "view.h"
#include "common/borderset.h"
#include "buffer.h"
#define PADDING rc.theme->osd_window_switcher_classic.padding #define PADDING rc.theme->osd_window_switcher_classic.padding
@ -36,6 +38,23 @@ resize_indicator_reconfigure_view(struct resize_indicator *indicator)
/* Colors */ /* Colors */
wlr_scene_rect_set_color(indicator->border, theme->osd_border_color); wlr_scene_rect_set_color(indicator->border, theme->osd_border_color);
wlr_scene_rect_set_color(indicator->background, theme->osd_bg_color); wlr_scene_rect_set_color(indicator->background, theme->osd_bg_color);
if (rc.theme->osd_border_type) {
float r = theme->osd_border_color[0];
float g = theme->osd_border_color[1];
float b = theme->osd_border_color[2];
float a = theme->osd_border_color[3];
int bw = theme->osd_border_width;
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
theme->osd_border_type, theme->osd_border_bevel_width);
indicator->textured_borders = generate_bufferset(indicator->tree,
renderedborders, bw);
}
} }
static void static void
@ -50,6 +69,7 @@ resize_indicator_init(struct view *view)
indicator->tree, 0, 0, rc.theme->osd_border_color); indicator->tree, 0, 0, rc.theme->osd_border_color);
indicator->background = lab_wlr_scene_rect_create( indicator->background = lab_wlr_scene_rect_create(
indicator->tree, 0, 0, rc.theme->osd_bg_color); indicator->tree, 0, 0, rc.theme->osd_bg_color);
indicator->text = scaled_font_buffer_create(indicator->tree); indicator->text = scaled_font_buffer_create(indicator->tree);
wlr_scene_node_set_enabled(&indicator->tree->node, false); wlr_scene_node_set_enabled(&indicator->tree->node, false);
@ -80,7 +100,9 @@ resize_indicator_reconfigure(void)
wl_list_for_each(view, &server.views, link) { wl_list_for_each(view, &server.views, link) {
struct resize_indicator *indicator = &view->resize_indicator; struct resize_indicator *indicator = &view->resize_indicator;
if (indicator->tree) { if (indicator->tree) {
resize_indicator_reconfigure_view(indicator); // Destroy the old tree so it doesn't have the leftover styling/sizing.
wlr_scene_node_destroy(&indicator->tree->node);
indicator->tree = NULL;
} }
if (view != server.grabbed_view) { if (view != server.grabbed_view) {
continue; continue;
@ -117,6 +139,11 @@ resize_indicator_set_size(struct resize_indicator *indicator, int width)
wlr_scene_rect_set_size(indicator->background, wlr_scene_rect_set_size(indicator->background,
indicator->width - 2 * rc.theme->osd_border_width, indicator->width - 2 * rc.theme->osd_border_width,
indicator->height - 2 * rc.theme->osd_border_width); indicator->height - 2 * rc.theme->osd_border_width);
if (rc.theme->osd_border_type) {
renderBufferset(indicator->textured_borders, indicator->width,
indicator->height, 0);
}
} }
void void

View file

@ -2,13 +2,16 @@
#include <assert.h> #include <assert.h>
#include <wlr/types/wlr_scene.h> #include <wlr/types/wlr_scene.h>
#include "buffer.h"
#include "common/macros.h" #include "common/macros.h"
#include "common/mem.h"
#include "common/scene-helpers.h" #include "common/scene-helpers.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "ssd.h" #include "ssd.h"
#include "ssd-internal.h" #include "ssd-internal.h"
#include "theme.h" #include "theme.h"
#include "view.h" #include "view.h"
#include "common/borderset.h"
void void
ssd_border_create(struct ssd *ssd) ssd_border_create(struct ssd *ssd)
@ -18,6 +21,7 @@ ssd_border_create(struct ssd *ssd)
struct view *view = ssd->view; struct view *view = ssd->view;
struct theme *theme = rc.theme; struct theme *theme = rc.theme;
int bw = theme->border_width;
int width = view->current.width; int width = view->current.width;
int height = view_effective_height(view, /* use_pending */ false); int height = view_effective_height(view, /* use_pending */ false);
int full_width = width + 2 * theme->border_width; int full_width = width + 2 * theme->border_width;
@ -33,26 +37,48 @@ ssd_border_create(struct ssd *ssd)
struct wlr_scene_tree *parent = subtree->tree; struct wlr_scene_tree *parent = subtree->tree;
wlr_scene_node_set_enabled(&parent->node, active); wlr_scene_node_set_enabled(&parent->node, active);
float *color = theme->window[active].border_color; float *color = theme->window[active].border_color;
if (theme->window[active].border_type) {
// These will otherwise get left under the window when we reload
subtree->left = lab_wlr_scene_rect_create(parent, subtree->left = lab_wlr_scene_rect_create(parent, 1, 1, color);
theme->border_width, height, color); subtree->right = lab_wlr_scene_rect_create(parent, 1, 1, color);
wlr_scene_node_set_position(&subtree->left->node, 0, 0); subtree->bottom = lab_wlr_scene_rect_create(parent, 1, 1, color);
subtree->top = lab_wlr_scene_rect_create(parent, 1, 1, color);
subtree->right = lab_wlr_scene_rect_create(parent, /* From Pull request 3382 */
theme->border_width, height, color); float r = color[0];
wlr_scene_node_set_position(&subtree->right->node, float g = color[1];
theme->border_width + width, 0); float b = color[2];
float a = color[3];
subtree->bottom = lab_wlr_scene_rect_create(parent, uint32_t colour32 = (uint32_t)(a*255) << 24 |
full_width, theme->border_width, color); (uint32_t)(r*255) << 16 |
wlr_scene_node_set_position(&subtree->bottom->node, (uint32_t)(g*255) << 8 |
0, height); (uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
theme->window[active].border_type,
theme->window[active].bevel_width);
subtree->textured_borders = generate_bufferset(subtree->tree,
renderedborders, bw);
} else {
subtree->left = lab_wlr_scene_rect_create(parent,
theme->border_width, height, color);
subtree->right = lab_wlr_scene_rect_create(parent,
theme->border_width, height, color);
subtree->bottom = lab_wlr_scene_rect_create(parent,
full_width, theme->border_width, color);
subtree->top = lab_wlr_scene_rect_create(parent,
MAX(width - 2 * corner_width, 0), theme->border_width, color);
subtree->top = lab_wlr_scene_rect_create(parent, wlr_scene_node_set_position(&subtree->left->node, 0, 0);
MAX(width - 2 * corner_width, 0), theme->border_width, color); wlr_scene_node_set_position(&subtree->right->node,
wlr_scene_node_set_position(&subtree->top->node, theme->border_width + width, 0);
theme->border_width + corner_width, wlr_scene_node_set_position(&subtree->bottom->node,
-(ssd->titlebar.height + theme->border_width)); 0, height);
wlr_scene_node_set_position(&subtree->top->node,
theme->border_width + corner_width,
-(ssd->titlebar.height + theme->border_width));
}
} }
if (view->maximized == VIEW_AXIS_BOTH) { if (view->maximized == VIEW_AXIS_BOTH) {
@ -132,26 +158,28 @@ ssd_border_update(struct ssd *ssd)
enum ssd_active_state active; enum ssd_active_state active;
FOR_EACH_ACTIVE_STATE(active) { FOR_EACH_ACTIVE_STATE(active) {
struct ssd_border_subtree *subtree = &ssd->border.subtrees[active]; struct ssd_border_subtree *subtree = &ssd->border.subtrees[active];
if (theme->window[active].border_type) {
wlr_scene_rect_set_size(subtree->left, renderBufferset(subtree->textured_borders, full_width,
theme->border_width, side_height); side_height+(ssd->titlebar.height + 2*theme->border_width),
wlr_scene_node_set_position(&subtree->left->node, -ssd->titlebar.height-theme->border_width);
0, side_y); } else {
wlr_scene_rect_set_size(subtree->left,
wlr_scene_rect_set_size(subtree->right, theme->border_width, side_height);
theme->border_width, side_height); wlr_scene_node_set_position(&subtree->left->node,
wlr_scene_node_set_position(&subtree->right->node, 0, side_y);
theme->border_width + width, side_y); wlr_scene_rect_set_size(subtree->right,
theme->border_width, side_height);
wlr_scene_rect_set_size(subtree->bottom, wlr_scene_node_set_position(&subtree->right->node,
full_width, theme->border_width); theme->border_width + width, side_y);
wlr_scene_node_set_position(&subtree->bottom->node, wlr_scene_rect_set_size(subtree->bottom,
0, height); full_width, theme->border_width);
wlr_scene_node_set_position(&subtree->bottom->node,
wlr_scene_rect_set_size(subtree->top, 0, height);
top_width, theme->border_width); wlr_scene_rect_set_size(subtree->top,
wlr_scene_node_set_position(&subtree->top->node, top_width, theme->border_width);
top_x, -(ssd->titlebar.height + theme->border_width)); wlr_scene_node_set_position(&subtree->top->node,
top_x, -(ssd->titlebar.height + theme->border_width));
}
} }
} }

View file

@ -18,6 +18,7 @@
#include "ssd-internal.h" #include "ssd-internal.h"
#include "theme.h" #include "theme.h"
#include "view.h" #include "view.h"
#include "common/borderset.h"
static void set_squared_corners(struct ssd *ssd, bool enable); static void set_squared_corners(struct ssd *ssd, bool enable);
static void set_alt_button_icon(struct ssd *ssd, enum lab_node_type type, bool enable); static void set_alt_button_icon(struct ssd *ssd, enum lab_node_type type, bool enable);
@ -36,6 +37,7 @@ ssd_titlebar_create(struct ssd *ssd)
LAB_NODE_TITLEBAR, view, /*data*/ NULL); LAB_NODE_TITLEBAR, view, /*data*/ NULL);
enum ssd_active_state active; enum ssd_active_state active;
bool should_force_update = FALSE;
FOR_EACH_ACTIVE_STATE(active) { FOR_EACH_ACTIVE_STATE(active) {
struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active]; struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
subtree->tree = lab_wlr_scene_tree_create(ssd->titlebar.tree); subtree->tree = lab_wlr_scene_tree_create(ssd->titlebar.tree);
@ -52,6 +54,30 @@ ssd_titlebar_create(struct ssd *ssd)
/* Background */ /* Background */
subtree->bar = lab_wlr_scene_buffer_create(parent, titlebar_fill); subtree->bar = lab_wlr_scene_buffer_create(parent, titlebar_fill);
if (theme->window[active].title_bg.border_type) {
/* Beveled Titlebar */
float *color = theme->window[active].title_bg.color;
float r = color[0];
float g = color[1];
float b = color[2];
float a = color[3];
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32,
theme->window[active].title_bg.border_width,
theme->window[active].title_bg.border_type,
theme->window[active].title_bg.bevel_width);
subtree->textured_borders = generate_bufferset(subtree->tree,
renderedborders, theme->window[active].title_bg.border_width);
// If we have the beveled borders, we actually have to run
// ssd_titlebar_update() to make sure we render the updated borders.
// Otherwise they disappear on reconfigure
should_force_update = true;
}
/* /*
* Work around the wlroots/pixman bug that widened 1px buffer * Work around the wlroots/pixman bug that widened 1px buffer
* becomes translucent when bilinear filtering is used. * becomes translucent when bilinear filtering is used.
@ -73,9 +99,17 @@ ssd_titlebar_create(struct ssd *ssd)
width - corner_width, -rc.theme->border_width); width - corner_width, -rc.theme->border_width);
/* Title */ /* Title */
subtree->title = scaled_font_buffer_create_for_titlebar( if (theme->window[active].title_bg.border_type) {
subtree->tree, theme->titlebar_height, // Use a blank background pattern so it doesn't overlay
theme->window[active].titlebar_pattern); // a pattern on the order.
subtree->title = scaled_font_buffer_create_for_titlebar(
subtree->tree, theme->titlebar_height,
NULL);
} else {
subtree->title = scaled_font_buffer_create_for_titlebar(
subtree->tree, theme->titlebar_height,
theme->window[active].titlebar_pattern);
}
assert(subtree->title); assert(subtree->title);
node_descriptor_create(&subtree->title->scene_buffer->node, node_descriptor_create(&subtree->title->scene_buffer->node,
LAB_NODE_TITLE, view, /*data*/ NULL); LAB_NODE_TITLE, view, /*data*/ NULL);
@ -122,7 +156,10 @@ ssd_titlebar_create(struct ssd *ssd)
if (squared) { if (squared) {
ssd->state.was_squared = true; ssd->state.was_squared = true;
} }
set_squared_corners(ssd, maximized || squared); set_squared_corners(ssd, maximized ||
squared ||
theme->window[SSD_ACTIVE].title_bg.border_type ||
theme->window[SSD_INACTIVE].title_bg.border_type);
if (view->shaded) { if (view->shaded) {
set_alt_button_icon(ssd, LAB_NODE_BUTTON_SHADE, true); set_alt_button_icon(ssd, LAB_NODE_BUTTON_SHADE, true);
@ -131,6 +168,10 @@ ssd_titlebar_create(struct ssd *ssd)
if (view->visible_on_all_workspaces) { if (view->visible_on_all_workspaces) {
set_alt_button_icon(ssd, LAB_NODE_BUTTON_OMNIPRESENT, true); set_alt_button_icon(ssd, LAB_NODE_BUTTON_OMNIPRESENT, true);
} }
if (should_force_update) {
ssd_titlebar_update(ssd);
}
} }
static void static void
@ -280,7 +321,10 @@ ssd_titlebar_update(struct ssd *ssd)
if (ssd->state.was_maximized != maximized if (ssd->state.was_maximized != maximized
|| ssd->state.was_squared != squared) { || ssd->state.was_squared != squared) {
set_squared_corners(ssd, maximized || squared); set_squared_corners(ssd, maximized ||
squared ||
theme->window[SSD_ACTIVE].title_bg.border_type ||
theme->window[SSD_INACTIVE].title_bg.border_type);
if (ssd->state.was_maximized != maximized) { if (ssd->state.was_maximized != maximized) {
set_alt_button_icon(ssd, LAB_NODE_BUTTON_MAXIMIZE, maximized); set_alt_button_icon(ssd, LAB_NODE_BUTTON_MAXIMIZE, maximized);
} }
@ -308,7 +352,11 @@ ssd_titlebar_update(struct ssd *ssd)
/* Center buttons vertically within titlebar */ /* Center buttons vertically within titlebar */
int y = (theme->titlebar_height - theme->window_button_height) / 2; int y = (theme->titlebar_height - theme->window_button_height) / 2;
int x; int x;
int bg_offset = maximized || squared ? 0 : corner_width; int bg_offset = (maximized ||
squared ||
theme->window[SSD_INACTIVE].title_bg.border_type ||
theme->window[SSD_ACTIVE].title_bg.border_type)
? 0 : corner_width;
enum ssd_active_state active; enum ssd_active_state active;
FOR_EACH_ACTIVE_STATE(active) { FOR_EACH_ACTIVE_STATE(active) {
@ -318,10 +366,14 @@ ssd_titlebar_update(struct ssd *ssd)
x = theme->window_titlebar_padding_width; x = theme->window_titlebar_padding_width;
struct ssd_button *button; struct ssd_button *button;
int button_count = 0;
wl_list_for_each(button, &subtree->buttons_left, link) { wl_list_for_each(button, &subtree->buttons_left, link) {
wlr_scene_node_set_position(button->node, x, y); wlr_scene_node_set_position(button->node, x, y);
x += theme->window_button_width + theme->window_button_spacing; x += theme->window_button_width + theme->window_button_spacing;
button_count++;
} }
int exclusive_x = x;
x = width - corner_width; x = width - corner_width;
wlr_scene_node_set_position(&subtree->corner_right->node, wlr_scene_node_set_position(&subtree->corner_right->node,
@ -331,6 +383,25 @@ ssd_titlebar_update(struct ssd *ssd)
wl_list_for_each(button, &subtree->buttons_right, link) { wl_list_for_each(button, &subtree->buttons_right, link) {
x -= theme->window_button_width + theme->window_button_spacing; x -= theme->window_button_width + theme->window_button_spacing;
wlr_scene_node_set_position(button->node, x, y); wlr_scene_node_set_position(button->node, x, y);
button_count++;
}
if (theme->window[active].title_bg.border_type) {
int titlebar_x = 0;
int titlebar_width = MAX(view->current.width, 0);
if (theme->window[active].title_bg.exclusive) {
titlebar_x = exclusive_x+theme->window_titlebar_padding_width;
titlebar_width = MAX(
(theme->window_button_width + theme->window_button_spacing)
* button_count,
titlebar_width -
(theme->window_button_width + theme->window_button_spacing)
* button_count
);
}
renderBuffersetXY(subtree->textured_borders, titlebar_width,
theme->titlebar_height, titlebar_x, 0);
} }
} }

View file

@ -91,6 +91,89 @@ draw_hover_overlay_on_button(cairo_t *cairo, int w, int h)
cairo_fill(cairo); cairo_fill(cairo);
} }
static void draw_beveled_border_on_button(cairo_t *cairo, int w, int h, int active, int hover)
{
if (rc.theme->window[active].button_border_type) {
int bw = rc.theme->window[active].button_border_width;
float r, g, b, a;
if (!hover) {
r = rc.theme->window[active].button_border_color[0];
g = rc.theme->window[active].button_border_color[1];
b = rc.theme->window[active].button_border_color[2];
a = rc.theme->window[active].button_border_color[3];
} else {
r = rc.theme->window[active].button_hover_border_color[0];
g = rc.theme->window[active].button_hover_border_color[1];
b = rc.theme->window[active].button_hover_border_color[2];
a = rc.theme->window[active].button_hover_border_color[3];
}
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
rc.theme->window[active].button_border_type,
rc.theme->window[active].button_bevel_width);
cairo_set_source_surface(cairo, renderedborders->top->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, bw, 0, w-bw*2, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->bottom->surface, bw, h-bw);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, bw, h-bw, w-bw*2, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->left->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, 0, bw, bw, h-bw*2);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->right->surface, w-bw, bw);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, w-bw, bw, bw, h-bw*2);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->tl->surface, 0, 0);
cairo_rectangle(cairo, 0, 0, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->tr->surface, w-bw, 0);
cairo_rectangle(cairo, w - bw, 0, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->bl->surface, 0, h - bw);
cairo_rectangle(cairo, 0, h - bw, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->br->surface, w - bw, h -bw);
cairo_rectangle(cairo, w - bw, h - bw, bw, bw);
cairo_fill(cairo);
}
}
static void draw_hover_active_border_on_button(cairo_t *cairo, int w, int h)
{
draw_beveled_border_on_button(cairo, w, h, SSD_ACTIVE, 1);
}
static void draw_hover_inactive_border_on_button(cairo_t *cairo, int w, int h)
{
draw_beveled_border_on_button(cairo, w, h, SSD_INACTIVE, 1);
}
static void draw_nonhover_active_border_on_button(cairo_t *cairo, int w, int h)
{
draw_beveled_border_on_button(cairo, w, h, SSD_ACTIVE, 0);
}
static void draw_nonhover_inactive_border_on_button(cairo_t *cairo, int w, int h)
{
draw_beveled_border_on_button(cairo, w, h, SSD_INACTIVE, 0);
}
/* Round the buffer for the leftmost button in the titlebar */ /* Round the buffer for the leftmost button in the titlebar */
static void static void
round_left_corner_button(cairo_t *cairo, int w, int h) round_left_corner_button(cairo_t *cairo, int w, int h)
@ -222,6 +305,21 @@ load_button(struct theme *theme, struct button *b, enum ssd_active_state active)
draw_hover_overlay_on_button); draw_hover_overlay_on_button);
} }
if (theme->window[active].button_border_type) {
if (active) {
if (b->state_set & LAB_BS_HOVERED) {
lab_img_add_modifier(*img, draw_hover_active_border_on_button);
} else {
lab_img_add_modifier(*img, draw_nonhover_active_border_on_button);
}
} else {
if (b->state_set & LAB_BS_HOVERED) {
lab_img_add_modifier(*img, draw_hover_inactive_border_on_button);
} else {
lab_img_add_modifier(*img, draw_nonhover_inactive_border_on_button);
}
}
}
/* /*
* If the loaded button is at the corner of the titlebar, also create * If the loaded button is at the corner of the titlebar, also create
* rounded variants. * rounded variants.
@ -450,6 +548,28 @@ parse_hexstrs(const char *hexes, float colors[3][4])
g_strfreev(elements); g_strfreev(elements);
} }
static enum border_type parse_border_type(const char *str)
{
char *lower = g_ascii_strdown(str, -1);
enum border_type border_type;
if (strstr(lower, "doublesunken")) {
border_type = BORDER_DOUBLE_INSET;
} else if (strstr(lower, "sunken")) {
border_type = BORDER_INSET;
} else if (strstr(lower, "doubleraised")) {
border_type = BORDER_DOUBLE;
} else if (strstr(lower, "raised")) {
border_type = BORDER_SINGLE;
} else if (strstr(lower, "flat")) {
border_type = BORDER_FLAT;
} else {
border_type = BORDER_NONE;
}
g_free(lower);
return border_type;
}
static void static void
parse_color(const char *str, float *rgba) parse_color(const char *str, float *rgba)
{ {
@ -550,6 +670,28 @@ theme_builtin(struct theme *theme)
theme->window[SSD_INACTIVE].title_bg.color_to[0] = FLT_MIN; theme->window[SSD_INACTIVE].title_bg.color_to[0] = FLT_MIN;
theme->window[SSD_ACTIVE].title_bg.color_to_split_to[0] = FLT_MIN; theme->window[SSD_ACTIVE].title_bg.color_to_split_to[0] = FLT_MIN;
theme->window[SSD_INACTIVE].title_bg.color_to_split_to[0] = FLT_MIN; theme->window[SSD_INACTIVE].title_bg.color_to_split_to[0] = FLT_MIN;
theme->window[SSD_ACTIVE].bevel_width = 0;
theme->window[SSD_ACTIVE].border_type = BORDER_NONE;
theme->window[SSD_ACTIVE].title_bg.bevel_width = 0;
theme->window[SSD_ACTIVE].title_bg.border_width = 0;
theme->window[SSD_ACTIVE].title_bg.exclusive = FALSE;
theme->window[SSD_ACTIVE].title_bg.border_type = BORDER_NONE;
theme->window[SSD_INACTIVE].bevel_width = 0;
theme->window[SSD_INACTIVE].border_type = BORDER_NONE;
theme->window[SSD_INACTIVE].title_bg.bevel_width = 0;
theme->window[SSD_INACTIVE].title_bg.border_width = 0;
theme->window[SSD_INACTIVE].title_bg.exclusive = FALSE;
theme->window[SSD_INACTIVE].title_bg.border_type = BORDER_NONE;
theme->window[SSD_ACTIVE].button_border_type = BORDER_NONE;
theme->window[SSD_ACTIVE].button_border_width = 0;
theme->window[SSD_ACTIVE].button_bevel_width = 0;
theme->window[SSD_ACTIVE].button_border_color[0] = FLT_MIN;
theme->window[SSD_ACTIVE].button_hover_border_color[0] = FLT_MIN;
theme->window[SSD_INACTIVE].button_border_type = BORDER_NONE;
theme->window[SSD_INACTIVE].button_border_width = 0;
theme->window[SSD_INACTIVE].button_bevel_width = 0;
theme->window[SSD_INACTIVE].button_border_color[0] = FLT_MIN;
theme->window[SSD_INACTIVE].button_hover_border_color[0] = FLT_MIN;
parse_hexstr("#000000", theme->window[SSD_ACTIVE].label_text_color); parse_hexstr("#000000", theme->window[SSD_ACTIVE].label_text_color);
parse_hexstr("#000000", theme->window[SSD_INACTIVE].label_text_color); parse_hexstr("#000000", theme->window[SSD_INACTIVE].label_text_color);
@ -581,6 +723,8 @@ theme_builtin(struct theme *theme)
theme->menu_max_width = 200; theme->menu_max_width = 200;
theme->menu_border_width = INT_MIN; theme->menu_border_width = INT_MIN;
theme->menu_border_color[0] = FLT_MIN; theme->menu_border_color[0] = FLT_MIN;
theme->menu_border_type = BORDER_NONE;
theme->menu_bevel_width = 0;
theme->menu_items_padding_x = 7; theme->menu_items_padding_x = 7;
theme->menu_items_padding_y = 4; theme->menu_items_padding_y = 4;
@ -588,6 +732,12 @@ theme_builtin(struct theme *theme)
parse_hexstr("#000000", theme->menu_items_text_color); parse_hexstr("#000000", theme->menu_items_text_color);
parse_hexstr("#e1dedb", theme->menu_items_active_bg_color); parse_hexstr("#e1dedb", theme->menu_items_active_bg_color);
parse_hexstr("#000000", theme->menu_items_active_text_color); parse_hexstr("#000000", theme->menu_items_active_text_color);
theme->menu_items_border_type = BORDER_NONE;
theme->menu_items_bevel_width = 0;
theme->menu_title_border_type = BORDER_NONE;
theme->menu_title_bevel_width = 0;
theme->menu_items_active_border_type = BORDER_NONE;
theme->menu_items_active_bevel_width = 0;
theme->menu_separator_line_thickness = 1; theme->menu_separator_line_thickness = 1;
theme->menu_separator_padding_width = 6; theme->menu_separator_padding_width = 6;
@ -633,6 +783,8 @@ theme_builtin(struct theme *theme)
theme->osd_border_width = INT_MIN; theme->osd_border_width = INT_MIN;
theme->osd_border_color[0] = FLT_MIN; theme->osd_border_color[0] = FLT_MIN;
theme->osd_label_text_color[0] = FLT_MIN; theme->osd_label_text_color[0] = FLT_MIN;
theme->osd_border_type = BORDER_NONE;
theme->osd_border_bevel_width = 0;
if (wlr_renderer_is_pixman(server.renderer)) { if (wlr_renderer_is_pixman(server.renderer)) {
/* Draw only outlined overlay by default to save CPU resource */ /* Draw only outlined overlay by default to save CPU resource */
@ -695,6 +847,7 @@ entry(struct theme *theme, const char *key, const char *value)
theme->border_width = get_int_if_positive( theme->border_width = get_int_if_positive(
value, "border.width"); value, "border.width");
} }
if (match_glob(key, "window.titlebar.padding.width")) { if (match_glob(key, "window.titlebar.padding.width")) {
theme->window_titlebar_padding_width = get_int_if_positive( theme->window_titlebar_padding_width = get_int_if_positive(
value, "window.titlebar.padding.width"); value, "window.titlebar.padding.width");
@ -710,12 +863,45 @@ entry(struct theme *theme, const char *key, const char *value)
wlr_log(WLR_INFO, "padding.height is no longer supported"); wlr_log(WLR_INFO, "padding.height is no longer supported");
} }
if (match_glob(key, "window.active.title.bg") && parse_border_type(value)) {
theme->window[SSD_ACTIVE].title_bg.border_type = parse_border_type(value);
}
if (match_glob(key, "window.active.title.bg.width")) {
theme->window[SSD_ACTIVE].title_bg.border_width =
get_int_if_positive(value, "window.active.title.bg.width");
}
if (match_glob(key, "window.active.title.bg.exclusive")) {
set_bool(value, &theme->window[SSD_ACTIVE].title_bg.exclusive);
}
if (match_glob(key, "window.active.title.bg.bevel-width")) {
theme->window[SSD_ACTIVE].title_bg.bevel_width =
get_int_if_positive(value, "window.active.title.bg.bevel-width");
}
if (match_glob(key, "window.active.border.color")) { if (match_glob(key, "window.active.border.color")) {
parse_color(value, theme->window[SSD_ACTIVE].border_color); parse_color(value, theme->window[SSD_ACTIVE].border_color);
} }
if (match_glob(key, "window.active.border.type")) {
theme->window[SSD_ACTIVE].border_type = parse_border_type(value);
}
if (match_glob(key, "window.active.border.bevel-width")) {
theme->window[SSD_ACTIVE].bevel_width =
get_int_if_positive(value, "window.active.border.bevel-width");
}
if (match_glob(key, "window.inactive.border.color")) { if (match_glob(key, "window.inactive.border.color")) {
parse_color(value, theme->window[SSD_INACTIVE].border_color); parse_color(value, theme->window[SSD_INACTIVE].border_color);
} }
if (match_glob(key, "window.inactive.border.bevel-width")) {
theme->window[SSD_INACTIVE].bevel_width =
get_int_if_positive(value, "window.inactive.border.bevel-width");
}
if (match_glob(key, "window.inactive.border.type")) {
theme->window[SSD_INACTIVE].border_type = parse_border_type(value);
}
/* border.color is obsolete, but handled for backward compatibility */ /* border.color is obsolete, but handled for backward compatibility */
if (match_glob(key, "border.color")) { if (match_glob(key, "border.color")) {
parse_color(value, theme->window[SSD_ACTIVE].border_color); parse_color(value, theme->window[SSD_ACTIVE].border_color);
@ -729,6 +915,22 @@ entry(struct theme *theme, const char *key, const char *value)
if (match_glob(key, "window.active.title.bg")) { if (match_glob(key, "window.active.title.bg")) {
theme->window[SSD_ACTIVE].title_bg.gradient = parse_gradient(value); theme->window[SSD_ACTIVE].title_bg.gradient = parse_gradient(value);
} }
if (match_glob(key, "window.inactive.title.bg") && parse_border_type(value)) {
theme->window[SSD_INACTIVE].title_bg.border_type = parse_border_type(value);
}
if (match_glob(key, "window.inactive.title.bg.width")) {
theme->window[SSD_INACTIVE].title_bg.border_width =
get_int_if_positive(value, "window.inactive.title.bg.width");
}
if (match_glob(key, "window.inactive.title.bg.bevel-width")) {
theme->window[SSD_INACTIVE].title_bg.bevel_width =
get_int_if_positive(value, "window.inactive.title.bg.bevel-width");
}
if (match_glob(key, "window.inactive.title.bg.exclusive")) {
set_bool(value, &theme->window[SSD_INACTIVE].title_bg.exclusive);
}
if (match_glob(key, "window.inactive.title.bg")) { if (match_glob(key, "window.inactive.title.bg")) {
theme->window[SSD_INACTIVE].title_bg.gradient = parse_gradient(value); theme->window[SSD_INACTIVE].title_bg.gradient = parse_gradient(value);
} }
@ -788,6 +990,46 @@ entry(struct theme *theme, const char *key, const char *value)
value, "window.button.spacing"); value, "window.button.spacing");
} }
if (match_glob(key, "window.inactive.button.bg") && parse_border_type(value)) {
theme->window[SSD_INACTIVE].button_border_type = parse_border_type(value);
}
if (match_glob(key, "window.inactive.button.bg.width")) {
theme->window[SSD_INACTIVE].button_border_width =
get_int_if_positive(value, "window.inactive.button.bg.width");
}
if (match_glob(key, "window.inactive.button.bg.bevel-width")) {
theme->window[SSD_INACTIVE].button_bevel_width =
get_int_if_positive(value, "window.inactive.button.bg.bevel-width");
}
if (match_glob(key, "window.inactive.button.bg.border-color")) {
parse_color(value, theme->window[SSD_INACTIVE].button_border_color);
}
if (match_glob(key, "window.inactive.button.bg.border-hover-color")) {
parse_color(value, theme->window[SSD_INACTIVE].button_hover_border_color);
}
if (match_glob(key, "window.active.button.bg") && parse_border_type(value)) {
theme->window[SSD_ACTIVE].button_border_type = parse_border_type(value);
}
if (match_glob(key, "window.active.button.bg.width")) {
theme->window[SSD_ACTIVE].button_border_width =
get_int_if_positive(value, "window.active.button.bg.width");
}
if (match_glob(key, "window.inactive.button.bg.bevel-width")) {
theme->window[SSD_ACTIVE].button_bevel_width =
get_int_if_positive(value, "window.active.button.bg.bevel-width");
}
if (match_glob(key, "window.active.button.bg.border-color")) {
parse_color(value, theme->window[SSD_ACTIVE].button_border_color);
}
if (match_glob(key, "window.active.button.bg.border-hover-color")) {
parse_color(value, theme->window[SSD_ACTIVE].button_hover_border_color);
}
/* botton hover overlay */ /* botton hover overlay */
if (match_glob(key, "window.button.hover.bg.color")) { if (match_glob(key, "window.button.hover.bg.color")) {
parse_color(value, theme->window_button_hover_bg_color); parse_color(value, theme->window_button_hover_bg_color);
@ -905,6 +1147,14 @@ entry(struct theme *theme, const char *key, const char *value)
parse_color(value, theme->menu_border_color); parse_color(value, theme->menu_border_color);
} }
if (match_glob(key, "menu.bg")) {
theme->menu_border_type = parse_border_type(value);
}
if (match_glob(key, "menu.bg.bevel-width")) {
theme->menu_bevel_width =
get_int_if_positive(value, "menu.bg.bevel-width");
}
if (match_glob(key, "menu.items.padding.x")) { if (match_glob(key, "menu.items.padding.x")) {
theme->menu_items_padding_x = get_int_if_positive( theme->menu_items_padding_x = get_int_if_positive(
value, "menu.items.padding.x"); value, "menu.items.padding.x");
@ -916,6 +1166,14 @@ entry(struct theme *theme, const char *key, const char *value)
if (match_glob(key, "menu.items.bg.color")) { if (match_glob(key, "menu.items.bg.color")) {
parse_color(value, theme->menu_items_bg_color); parse_color(value, theme->menu_items_bg_color);
} }
if (match_glob(key, "menu.items.bg")) {
theme->menu_items_border_type = parse_border_type(value);
}
if (match_glob(key, "menu.items.bg.bevel-width")) {
theme->menu_items_bevel_width =
get_int_if_positive(value, "menu.items.bg.bevel-width");
}
if (match_glob(key, "menu.items.text.color")) { if (match_glob(key, "menu.items.text.color")) {
parse_color(value, theme->menu_items_text_color); parse_color(value, theme->menu_items_text_color);
} }
@ -926,6 +1184,14 @@ entry(struct theme *theme, const char *key, const char *value)
parse_color(value, theme->menu_items_active_text_color); parse_color(value, theme->menu_items_active_text_color);
} }
if (match_glob(key, "menu.items.active.bg")) {
theme->menu_items_active_border_type = parse_border_type(value);
}
if (match_glob(key, "menu.items.active.bg.bevel-width")) {
theme->menu_items_active_bevel_width =
get_int_if_positive(value, "menu.items.active.bg.bevel-width");
}
if (match_glob(key, "menu.separator.width")) { if (match_glob(key, "menu.separator.width")) {
theme->menu_separator_line_thickness = get_int_if_positive( theme->menu_separator_line_thickness = get_int_if_positive(
value, "menu.separator.width"); value, "menu.separator.width");
@ -952,6 +1218,14 @@ entry(struct theme *theme, const char *key, const char *value)
parse_color(value, theme->menu_title_text_color); parse_color(value, theme->menu_title_text_color);
} }
if (match_glob(key, "menu.title.bg")) {
theme->menu_title_border_type = parse_border_type(value);
}
if (match_glob(key, "menu.title.bg.bevel-width")) {
theme->menu_title_bevel_width =
get_int_if_positive(value, "menu.title.bg.bevel-width");
}
if (match_glob(key, "osd.bg.color")) { if (match_glob(key, "osd.bg.color")) {
parse_color(value, theme->osd_bg_color); parse_color(value, theme->osd_bg_color);
} }
@ -962,6 +1236,13 @@ entry(struct theme *theme, const char *key, const char *value)
if (match_glob(key, "osd.border.color")) { if (match_glob(key, "osd.border.color")) {
parse_color(value, theme->osd_border_color); parse_color(value, theme->osd_border_color);
} }
if (match_glob(key, "osd.bg")) {
theme->osd_border_type = parse_border_type(value);
}
if (match_glob(key, "osd.bg.bevel-width")) {
theme->osd_border_bevel_width = get_int_if_positive(value, "osd.bg.bevel-width");
}
/* classic window switcher */ /* classic window switcher */
if (match_glob(key, "osd.window-switcher.style-classic.width") if (match_glob(key, "osd.window-switcher.style-classic.width")
|| match_glob(key, "osd.window-switcher.width")) { || match_glob(key, "osd.window-switcher.width")) {

View file

@ -19,6 +19,7 @@
#include "common/scene-helpers.h" #include "common/scene-helpers.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "input/keyboard.h" #include "input/keyboard.h"
#include "common/borderset.h"
#include "labwc.h" #include "labwc.h"
#include "output.h" #include "output.h"
#include "theme.h" #include "theme.h"
@ -96,18 +97,73 @@ _osd_update(void)
cairo = cairo_create(buffer->surface); cairo = cairo_create(buffer->surface);
int bw = theme->osd_border_width;
/* Background */ /* Background */
set_cairo_color(cairo, theme->osd_bg_color); set_cairo_color(cairo, theme->osd_bg_color);
cairo_rectangle(cairo, 0, 0, width, height); cairo_rectangle(cairo, bw, bw, width-bw*2, height-bw*2);
cairo_fill(cairo); cairo_fill(cairo);
/* Border */ /* Border */
set_cairo_color(cairo, theme->osd_border_color); if (theme->osd_border_type) {
struct wlr_fbox border_fbox = { float r = theme->osd_border_color[0];
.width = width, float g = theme->osd_border_color[1];
.height = height, float b = theme->osd_border_color[2];
}; float a = theme->osd_border_color[3];
draw_cairo_border(cairo, border_fbox, theme->osd_border_width);
uint32_t colour32 = (uint32_t)(a*255) << 24 |
(uint32_t)(r*255) << 16 |
(uint32_t)(g*255) << 8 |
(uint32_t)(b*255);
struct borderset *renderedborders = get_borders(colour32, bw,
theme->osd_border_type, theme->osd_border_bevel_width);
cairo_set_source_surface(cairo, renderedborders->top->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, bw, 0, width-bw*2, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->bottom->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, bw, height-bw, width-bw*2, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->left->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, 0, bw, bw, height-bw*2);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->right->surface, 0, 0);
cairo_pattern_set_extend(cairo_get_source(cairo), CAIRO_EXTEND_REPEAT);
cairo_rectangle(cairo, width-bw, bw, bw, height-bw*2);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->tl->surface, 0, 0);
cairo_rectangle(cairo, 0, 0, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->tr->surface, width-bw, 0);
cairo_rectangle(cairo, width - bw, 0, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->bl->surface,
0, height - bw);
cairo_rectangle(cairo, 0, height - bw, bw, bw);
cairo_fill(cairo);
cairo_set_source_surface(cairo, renderedborders->br->surface,
width - bw, height -bw);
cairo_rectangle(cairo, width - bw, height - bw, bw, bw);
cairo_fill(cairo);
set_cairo_color(cairo, theme->osd_border_color);
} else {
set_cairo_color(cairo, theme->osd_border_color);
struct wlr_fbox border_fbox = {
.width = width,
.height = height,
};
draw_cairo_border(cairo, border_fbox, theme->osd_border_width);
}
/* Boxes */ /* Boxes */
uint16_t x; uint16_t x;