This commit is contained in:
Jack Zeal 2026-06-13 01:51:06 +00:00 committed by GitHub
commit dbecc2895d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 1605 additions and 58 deletions

View file

@ -67,7 +67,7 @@ labwc-config(5).
significant. The format is as follows: significant. The format is as follows:
``` ```
(Solid | Gradient <type>) (Solid | Gradient <type>) (Raised | Sunken | DoubleRaised | DoubleSunken)
``` ```
... where *|* stands for "or". ... where *|* stands for "or".
@ -107,12 +107,117 @@ window.*.title.bg.colorTo: #4d6982
window.*.title.bg.colorTo.splitTo: #557485 window.*.title.bg.colorTo.splitTo: #557485
``` ```
- *Raised* adds a bevel to the element, lighter on the top/left and darker on
the bottom/right
```
window.*.title.bg: Raised
```
- *Sunken* adds a similar bevel, but with darker hints on the top/left and lighter
on the bottom/right
```
window.active.title.bg: sunken gradient vertical
```
- *DoubleRaised* adds a raised bevel on the outer edge of the element, and a
second sunken bevel slightly inset to that.
```
window.*.title.bg: doubleraised
```
- *DoubleSunken* adds a sunken bevel to the outer edge, and a raised bevel
slightly inset.
```
window.*.title.bg: doublesunken
```
- *Flat* uses a solid color border for the element, even if it otherwise has a gradient.
```
window.*.title.bg: flat
```
- *None* draws no additional border for the element.
```
window.*.title.bg: none
```
*Bevel-Related Properties*
Beveled elements have paired properties *highlight* and *shadow* which indicate how much lighter
or darker than the base color the "highlighted" and "shadowed" edges will be. "256" represents
a 100% increase or decrease in brightness.
For *highlight*, the default is 128 - 50% more brightness.
For *shadow*, the default is 64 - 25% less brightness.
*DoubleRaised* and *DoubleSunken* bevels are paired with an additional *bevel-width* property
which controls how much of the space is devoted to the sub-bevels and how much remains in the
"base" colour.
```
window.active.title.bg.highlight: 256
window.active.title.bg.shadow: 256
window.active.title.bg.bevel-width: 2
window.active.border.highlight: 256
window.active.border.shadow: 128
window.active.border.bevel-width: 2
window.active.button.bg.highlight: 128
window.active.button.bg.shadow: 64
window.active.button.bg.bevel-width: 2
window.inactive.title.bg.highlight: 256
window.inactive.title.bg.shadow: 128
window.inactive.title.bg.bevel-width: 2
window.inactive.border.highlight: 256
window.inactive.border.shadow: 128
window.inactive.border.bevel-width: 2
window.inactive.button.bg.highlight: 128
window.inactive.button.bg.shadow: 64
window.inactive.button.bg.bevel-width: 2
menu.bg.highlight: 256
menu.bg.shadow: 128
menu.bg.bevel-width: 2
menu.items.bg.highlight: 256
menu.items.bg.shadow: 128
menu.items.bg.bevel-width: 3
menu.items.active.bg.highlight: 256
menu.items.active.bg.shadow: 128
menu.items.active.bg.bevel-width: 3
menu.title.bg.highlight: 256
menu.title.bg.shadow: 128
menu.title.bg.bevel-width: 3
osd.bg.highlight: 256
osd.bg.shadow: 128
osd.bg.bevel-width:2
```
# THEME ELEMENTS # THEME ELEMENTS
*border.width* *border.width*
Line width (integer) of border drawn around window frames. Line width (integer) of border drawn around window frames.
Default is 1. Default is 1.
*border.bevel-width*
Used with *window.active.border.type* and *window.inactive.border.type* *DoubleRaised* and *DoubleSunken*
The portion of *border.width* assigned to the inner and outer bevels.
Default is 0.
*window.titlebar.padding.width* *window.titlebar.padding.width*
Horizontal titlebar padding size, in pixels, between border and first Horizontal titlebar padding size, in pixels, between border and first
button on the left/right. button on the left/right.
@ -124,10 +229,16 @@ window.*.title.bg.colorTo.splitTo: #557485
*window.active.border.color* *window.active.border.color*
Border color of active window. Default is #aaaaaa. Border color of active window. Default is #aaaaaa.
*window.active.border.type*
Texture type for active window borders. Default is "None". Currently does not support gradients.
*window.inactive.border.color* *window.inactive.border.color*
Border color of inactive window. Default is #aaaaaa. Border color of inactive window. Default is #aaaaaa.
*window.inactive.border.type*
Texture type for inactive window borders. Default is "None". Currently does not support gradients.
*window.active.indicator.toggled-keybind.color* *window.active.indicator.toggled-keybind.color*
Status indicator for the ToggleKeybinds action. Can be set to the same Status indicator for the ToggleKeybinds action. Can be set to the same
value as set for window.active.border.color to disable the status value as set for window.active.border.color to disable the status
@ -137,6 +248,16 @@ window.*.title.bg.colorTo.splitTo: #557485
Texture for the focused window's titlebar. See texture section above. Texture for the focused window's titlebar. See texture section above.
Default is *Solid*. Default is *Solid*.
*window.active.title.bg.width*
Used with beveled textures.
The width of the beveled borders on the focused window titlebar.
Default is 0.
*window.active.title.bg.bevel-width*
Used with texture types *DoubleRaised* and *DoubleSunken*
The portion of the the focused window titlebar border width assigned to the inner and outer bevels.
Default is 0.
*window.active.title.bg.color* *window.active.title.bg.color*
Background color for the focused window's titlebar. See texture section Background color for the focused window's titlebar. See texture section
for additional color fields associated with gradients. for additional color fields associated with gradients.
@ -146,6 +267,16 @@ window.*.title.bg.colorTo.splitTo: #557485
Texture for non-focused windows' titlebars. See texture section above. Texture for non-focused windows' titlebars. See texture section above.
Default is *Solid*. Default is *Solid*.
*window.inactive.title.bg.width*
Used with beveled textures.
The width of the beveled borders on the non-focused window titlebar.
Default is 0.
*window.inactive.title.bg.bevel-width*
Used with texture types *DoubleRaised* and *DoubleSunken*
The portion of the the non-focused window titlebar border width assigned to the inner and outer bevels.
Default is 0.
*window.inactive.title.bg.color* *window.inactive.title.bg.color*
Background color for non-focused windows' titlebars. See texture section Background color for non-focused windows' titlebars. See texture section
for additional color fields associated with gradients. for additional color fields associated with gradients.
@ -203,6 +334,48 @@ here for comparison only.
*window.inactive.button.unpressed.image.color* *window.inactive.button.unpressed.image.color*
Color of the images in titlebar buttons in their default, unpressed, Color of the images in titlebar buttons in their default, unpressed,
state. This element is for non-focused windows. Default is #000000. state. This element is for non-focused windows. Default is #000000.
*window.active.button.bg.width*
Used with beveled textures.
The width of the beveled borders in titlebar buttons for focused windows.
Default is 0.
*window.active.button.bg.bevel-width*
Used with beveled textures of type *DoubleRaised* or *DoubleSunken*
The width of the sub-bevels within focused windows' titlebar buttons.
Default is 0.
*window.active.button.bg.border-color*
Used with beveled textures.
The color for the borders of focused windows' titlebar buttons.
Default is #000000.
*window.active.button.bg.border-hover-color*
Used with beveled textures.
The color for the buttons of focused windows' titlebar buttons when hovered over.
Default is #000000.
*window.inactive.button.bg.width*
Used with beveled textures.
The width of the beveled borders in titlebar buttons for non-focused windows.
Default is 0.
*window.inactive.button.bg.bevel-width*
Used with beveled textures of type *DoubleRaised* or *DoubleSunken*
The width of the sub-bevels within non-focused windows' titlebar buttons.
Default is 0.
*window.inactive.button.bg.border-color*
Used with beveled textures.
The color for the borders of non-focused windows' titlebar buttons.
Default is #000000.
*window.inactive.button.bg.border-hover-color*
Used with beveled textures.
The color for the buttons of non-focused windows' titlebar buttons when hovered over.
Default is #000000.
Note: Button elements (i.e. window.[in]active.button.\*) may be defined uniquely Note: Button elements (i.e. window.[in]active.button.\*) may be defined uniquely
for each type of button ("menu", "iconify", "max", "shade", "desk" or "close") for each type of button ("menu", "iconify", "max", "shade", "desk" or "close")
@ -234,6 +407,15 @@ all are supported.
Color of drop-shadows for non-focused windows, including opacity. Color of drop-shadows for non-focused windows, including opacity.
Default is #00000040 (black with 25% opacity). Default is #00000040 (black with 25% opacity).
*menu.bg*
Texture for the overall menu borders. Currently only supports bevels.
Default is "None"
*menu.bg.bevel-width*
Width of the sub-bevels on the outer edges of menu borders.
Used with texture types *DoubleRaised* and *DoubleSunken*
Default is 0.
*menu.overlap.x* *menu.overlap.x*
Horizontal overlap in pixels between submenus and their parents. A Horizontal overlap in pixels between submenus and their parents. A
positive value move submenus over the top of their parents, whereas a positive value move submenus over the top of their parents, whereas a
@ -267,13 +449,29 @@ all are supported.
*menu.items.padding.y* *menu.items.padding.y*
Vertical padding of menu text entries in pixels. Vertical padding of menu text entries in pixels.
Default is 4. Default is 4.
*menu.items.bg*
Texture for background of inactive menu items. Currently only supports bevels. Default is "None"
*menu.items.bg.bevel-width*
Width of the sub-bevels on inactive menu items.
Used with texture types *DoubleRaised* and *DoubleSunken*
Default is 0.
*menu.items.bg.color* *menu.items.bg.color*
Background color of inactive menu items. Default is #fcfbfa. Background color of inactive menu items. Default is #fcfbfa.
*menu.items.text.color* *menu.items.text.color*
Text color of inactive menu item. Default is #000000. Text color of inactive menu item. Default is #000000.
*menu.items.active.bg*
Texture for background of active menu items. Currently only supports bevels. Default is "None"
*menu.items.active.bg.bevel-width*
Width of the sub-bevels on highlighted menu items.
Used with texture types *DoubleRaised* and *DoubleSunken*
Default is 0.
*menu.items.active.bg.color* *menu.items.active.bg.color*
Background color of active menu items. Default is #e1dedb. Background color of active menu items. Default is #e1dedb.
@ -292,6 +490,14 @@ all are supported.
*menu.separator.color* *menu.separator.color*
Menu separator color. Default is #888888. Menu separator color. Default is #888888.
*menu.title.bg*
Texture for background of menu titles. Currently only supports bevels. Default is "None"
*menu.title.bg.bevel-width*
Width of the sub-bevels on menu titles.
Used with texture types *DoubleRaised* and *DoubleSunken*
Default is 0.
*menu.title.bg.color* *menu.title.bg.color*
Menu title color. Default is #589bda. Menu title color. Default is #589bda.
Note: A menu title is a separator with a label. Note: A menu title is a separator with a label.
@ -303,6 +509,15 @@ all are supported.
*menu.title.text.color* *menu.title.text.color*
Text color of separator label. Default is #ffffff. Text color of separator label. Default is #ffffff.
*osd.bg*
Texture used for on-screen display elements like the window-cycle dialog.
Currently only supports bevels. Default is "None"
*osd.bg.bevel-width*
Width of the sub-bevels on on-screen display borders.
Used with texture types *DoubleRaised* and *DoubleSunken*
Default is 0.
*osd.bg.color* *osd.bg.color*
Background color of on-screen-display. Inherits Background color of on-screen-display. Inherits
*window.active.title.bg.color* if not set. *window.active.title.bg.color* if not set.

View file

@ -0,0 +1,65 @@
/* 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;
int highlight;
int lowlight;
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,
int highlight, int lowlight);
struct borderset *create_buffer(uint32_t id, int size, enum border_type, int bevelSize,
int highlight, int lowlight);
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,10 @@ 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;
int highlight;
int shadow;
}; };
struct lab_scene_rect { struct lab_scene_rect {

View file

@ -69,4 +69,15 @@
#define LAB_WLR_VERSION_LOWER(major, minor, micro) (!LAB_WLR_VERSION_AT_LEAST(major, minor, micro)) #define LAB_WLR_VERSION_LOWER(major, minor, micro) (!LAB_WLR_VERSION_AT_LEAST(major, minor, 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,12 @@ 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;
int highlight;
int shadow;
bool exclusive;
}; };
struct theme { struct theme {
@ -92,10 +99,21 @@ 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];
int button_highlight;
int button_shadow;
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;
int highlight;
int shadow;
/* window drop-shadows */ /* window drop-shadows */
int shadow_size; int shadow_size;
@ -142,6 +160,10 @@ 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_highlight;
int menu_shadow;
int menu_items_padding_x; int menu_items_padding_x;
int menu_items_padding_y; int menu_items_padding_y;
@ -149,6 +171,18 @@ 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;
int menu_items_highlight;
int menu_items_shadow;
enum border_type menu_title_border_type;
int menu_title_bevel_width;
int menu_title_highlight;
int menu_title_shadow;
enum border_type menu_items_active_border_type;
int menu_items_active_bevel_width;
int menu_items_active_highlight;
int menu_items_active_shadow;
int menu_separator_line_thickness; int menu_separator_line_thickness;
int menu_separator_padding_width; int menu_separator_padding_width;
@ -164,6 +198,10 @@ 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;
int osd_highlight;
int osd_shadow;
struct window_switcher_classic_theme { struct window_switcher_classic_theme {
int width; int width;

View file

@ -251,6 +251,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;

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

@ -0,0 +1,491 @@
// 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,
int highlight, int lowlight)
{
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 &&
current->highlight == highlight && current->lowlight == lowlight) {
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, highlight, lowlight);
return border_cache;
} else {
last->next = create_buffer(id, size, type, bevelSize, highlight, lowlight);
return last->next;
}
return NULL;
}
struct borderset *create_buffer(uint32_t id, int size, enum border_type type,
int bevelSize, int highlight, int lowlight)
{
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;
new_borderset->highlight = highlight;
new_borderset->lowlight = lowlight;
// 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 * (256+highlight) / 256;
if (r1 > a) {
r1 = a;
}
uint32_t g1 = g * (256+highlight) / 256;
if (g1 > a) {
g1 = a;
}
uint32_t b1 = b * (256+highlight) / 256;
if (b1 > a) {
b1 = a;
}
/* darker outline */
uint32_t r0 = r * (256 - lowlight) / 256;
uint32_t g0 = g * (256 - lowlight) / 256;
uint32_t b0 = b * (256 - lowlight) / 256;
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)
{
// Bail early if you're being asked to generate buffers with negative size
if (width < 2 * bufferset->border_width || height < 2 * bufferset->border_width) {
return;
}
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,30 @@ 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,
opts->highlight, opts->shadow);
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 +106,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

@ -38,6 +38,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
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,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
lab_scene_rect_create(osd_output->tree, &bg_opts); lab_scene_rect_create(osd_output->tree, &bg_opts);
@ -202,6 +206,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
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,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
scroll->bar = lab_scene_rect_create(scroll->bar_tree, &scrollbar_opts); scroll->bar = lab_scene_rect_create(scroll->bar_tree, &scrollbar_opts);
} }

View file

@ -158,6 +158,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
item->active_bg = lab_scene_rect_create(tree, &opts); item->active_bg = lab_scene_rect_create(tree, &opts);
@ -290,6 +294,10 @@ 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,
.highlight = theme->osd_highlight,
.shadow = theme->osd_shadow
}; };
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

@ -16,6 +16,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
@ -44,6 +45,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

@ -34,6 +34,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 */
@ -252,10 +254,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);
@ -280,6 +283,41 @@ 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,
rc.theme->menu_items_active_highlight,
rc.theme->menu_items_active_shadow);
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,
rc.theme->menu_items_highlight,
rc.theme->menu_items_shadow);
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;
@ -308,6 +346,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;
} }
@ -341,10 +383,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);
@ -427,6 +469,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;
@ -446,6 +490,25 @@ 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,
rc.theme->menu_title_highlight,
rc.theme->menu_title_shadow);
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);
@ -474,6 +537,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);
@ -546,6 +613,10 @@ 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,
.highlight = theme->menu_highlight,
.shadow = theme->menu_shadow
}; };
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

@ -76,6 +76,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
@ -98,6 +99,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,24 @@ 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,
theme->osd_highlight, theme->osd_shadow);
indicator->textured_borders = generate_bufferset(indicator->tree,
renderedborders, bw);
}
} }
static void static void
@ -50,6 +70,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 +101,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 +140,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,50 @@ 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,
theme->window[active].highlight,
theme->window[active].shadow);
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 +160,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,32 @@ 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,
theme->window[active].title_bg.highlight,
theme->window[active].title_bg.shadow);
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 +101,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 +158,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 +170,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 +323,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 +354,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 +368,16 @@ 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); if (button->node->enabled) {
x += theme->window_button_width + theme->window_button_spacing; wlr_scene_node_set_position(button->node, x, y);
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,
@ -329,8 +385,27 @@ ssd_titlebar_update(struct ssd *ssd)
x = width - theme->window_titlebar_padding_width + theme->window_button_spacing; x = width - theme->window_titlebar_padding_width + theme->window_button_spacing;
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; if (button->node->enabled) {
wlr_scene_node_set_position(button->node, x, y); x -= theme->window_button_width + theme->window_button_spacing;
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 = titlebar_width -
(theme->window_button_width + theme->window_button_spacing)
* button_count;
}
if (titlebar_width > 0) {
renderBuffersetXY(subtree->textured_borders, titlebar_width,
theme->titlebar_height, titlebar_x, 0);
}
} }
} }

View file

@ -91,6 +91,91 @@ 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,
rc.theme->window[active].button_highlight,
rc.theme->window[active].button_shadow);
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 +307,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 +550,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 +672,40 @@ 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].highlight = 128;
theme->window[SSD_ACTIVE].shadow = 64;
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_ACTIVE].title_bg.highlight = 128;
theme->window[SSD_ACTIVE].title_bg.shadow = 64;
theme->window[SSD_INACTIVE].bevel_width = 0;
theme->window[SSD_INACTIVE].border_type = BORDER_NONE;
theme->window[SSD_INACTIVE].highlight = 128;
theme->window[SSD_INACTIVE].shadow = 64;
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_INACTIVE].title_bg.highlight = 128;
theme->window[SSD_INACTIVE].title_bg.shadow = 64;
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_highlight = 128;
theme->window[SSD_ACTIVE].button_shadow = 64;
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_highlight = 128;
theme->window[SSD_INACTIVE].button_shadow = 64;
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 +737,10 @@ 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_highlight = 128;
theme->menu_shadow = 64;
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 +748,18 @@ 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_items_highlight = 128;
theme->menu_items_shadow = 64;
theme->menu_title_border_type = BORDER_NONE;
theme->menu_title_bevel_width = 0;
theme->menu_title_highlight = 128;
theme->menu_title_shadow = 64;
theme->menu_items_active_border_type = BORDER_NONE;
theme->menu_items_active_bevel_width = 0;
theme->menu_items_active_highlight = 128;
theme->menu_items_active_shadow = 64;
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 +805,10 @@ 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;
theme->osd_highlight = 128;
theme->osd_shadow = 64;
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 +871,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 +887,70 @@ 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.highlight")) {
theme->window[SSD_ACTIVE].title_bg.highlight =
get_int_if_positive(value, "window.active.title.bg.highlight");
}
if (match_glob(key, "window.active.title.bg.shadow")) {
theme->window[SSD_ACTIVE].title_bg.shadow =
get_int_if_positive(value, "window.active.title.bg.shadow");
}
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.active.border.highlight")) {
theme->window[SSD_ACTIVE].highlight =
get_int_if_positive(value, "window.active.border.highlight");
}
if (match_glob(key, "window.active.border.shadow")) {
theme->window[SSD_ACTIVE].shadow =
get_int_if_positive(value, "window.active.border.shadow");
}
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);
}
if (match_glob(key, "window.inactive.border.highlight")) {
theme->window[SSD_INACTIVE].highlight =
get_int_if_positive(value, "window.inactive.border.highlight");
}
if (match_glob(key, "window.inactive.border.shadow")) {
theme->window[SSD_INACTIVE].shadow =
get_int_if_positive(value, "window.inactive.border.shadow");
}
/* 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 +964,30 @@ 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.highlight")) {
theme->window[SSD_INACTIVE].title_bg.highlight =
get_int_if_positive(value, "window.inactive.title.bg.highlight");
}
if (match_glob(key, "window.inactive.title.bg.shadow")) {
theme->window[SSD_INACTIVE].title_bg.shadow =
get_int_if_positive(value, "window.inactive.title.bg.shadow");
}
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 +1047,62 @@ 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.highlight")) {
theme->window[SSD_INACTIVE].button_highlight =
get_int_if_positive(value, "window.inactive.button.bg.highlight");
}
if (match_glob(key, "window.inactive.button.bg.shadow")) {
theme->window[SSD_INACTIVE].button_shadow =
get_int_if_positive(value, "window.inactive.button.bg.shadow");
}
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.highlight")) {
theme->window[SSD_ACTIVE].button_highlight =
get_int_if_positive(value, "window.active.button.bg.highlight");
}
if (match_glob(key, "window.active.button.bg.shadow")) {
theme->window[SSD_ACTIVE].button_shadow =
get_int_if_positive(value, "window.active.button.bg.shadow");
}
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);
}
/* button hover overlay */ /* button 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 +1220,22 @@ 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.bg.highlight")) {
theme->menu_highlight =
get_int_if_positive(value, "menu.bg.highlight");
}
if (match_glob(key, "menu.bg.shadow")) {
theme->menu_shadow =
get_int_if_positive(value, "menu.bg.shadow");
}
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 +1247,22 @@ 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.highlight")) {
theme->menu_items_highlight =
get_int_if_positive(value, "menu.items.bg.highlight");
}
if (match_glob(key, "menu.items.bg.shadow")) {
theme->menu_items_shadow =
get_int_if_positive(value, "menu.items.bg.shadow");
}
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 +1273,22 @@ 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.highlight")) {
theme->menu_items_active_highlight =
get_int_if_positive(value, "menu.items.active,bg.highlight");
}
if (match_glob(key, "menu.items.active.bg.shadow")) {
theme->menu_items_active_shadow =
get_int_if_positive(value, "menu.items.active.bg.shadow");
}
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 +1315,22 @@ 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.highlight")) {
theme->menu_title_highlight =
get_int_if_positive(value, "menu.title.bg.highlight");
}
if (match_glob(key, "menu.title.bg.shadow")) {
theme->menu_title_shadow =
get_int_if_positive(value, "menu.title.bg.shadow");
}
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 +1341,21 @@ 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.highlight")) {
theme->osd_highlight =
get_int_if_positive(value, "osd.bg.highlight");
}
if (match_glob(key, "osd.bg.shadow")) {
theme->osd_shadow =
get_int_if_positive(value, "osd.bg.shadow");
}
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 "show-desktop.h" #include "show-desktop.h"
@ -97,18 +98,74 @@ _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,
theme->osd_highlight, theme->osd_shadow);
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;