Support svg buttons

In the theme directory add close-{active,inactive}.svg instead of
close.xbm - and similarly for iconify, menu and max.
This commit is contained in:
Johan Malm 2023-08-21 21:26:08 +01:00 committed by Johan Malm
parent a386133068
commit c62df26c2a
10 changed files with 137 additions and 5 deletions

View file

@ -67,7 +67,7 @@ jobs:
pacman-key --init pacman-key --init
pacman -Syu --noconfirm pacman -Syu --noconfirm
pacman -S --noconfirm git meson clang wlroots libdrm libinput \ pacman -S --noconfirm git meson clang wlroots libdrm libinput \
wayland-protocols cairo pango libxml2 xorg-xwayland wayland-protocols cairo pango libxml2 xorg-xwayland librsvg
- name: Install Debian Testing dependencies - name: Install Debian Testing dependencies
if: matrix.name == 'Debian' if: matrix.name == 'Debian'
@ -77,7 +77,8 @@ jobs:
apt-get upgrade -y apt-get upgrade -y
apt-get install -y git clang \ apt-get install -y git clang \
hwdata \ hwdata \
libxml2-dev libcairo2-dev libpango1.0-dev libxml2-dev libcairo2-dev libpango1.0-dev \
librsvg2-dev
apt-get build-dep -y wlroots apt-get build-dep -y wlroots
- name: Install FreeBSD dependencies - name: Install FreeBSD dependencies
@ -108,6 +109,7 @@ jobs:
xcb-util-cursor-devel xcb-util-devel xcb-util-image-devel \ xcb-util-cursor-devel xcb-util-devel xcb-util-image-devel \
xcb-util-keysyms-devel xcb-util-xrm-devel xorg-server-xwayland \ xcb-util-keysyms-devel xcb-util-xrm-devel xorg-server-xwayland \
hwids \ hwids \
librsvg-devel \
libglib-devel cairo-devel pango-devel libglib-devel cairo-devel pango-devel
- name: Build with gcc - name: Build with gcc

View file

@ -151,6 +151,7 @@ Run-time dependencies include:
- wlroots, wayland, libinput, xkbcommon - wlroots, wayland, libinput, xkbcommon
- libxml2, cairo, pango, glib-2.0 - libxml2, cairo, pango, glib-2.0
- libpng, librsvg-2.0
- xwayland, xcb (optional) - xwayland, xcb (optional)
Build dependencies include: Build dependencies include:

View file

@ -182,6 +182,7 @@ The image formats listed below are supported. They are listed in order of
precedence, where the first format in the list is searched for first. precedence, where the first format in the list is searched for first.
- png - png
- svg
- xbm - xbm
By default, buttons are 1-bit xbm (X Bitmaps). These are masks where 0=clear and By default, buttons are 1-bit xbm (X Bitmaps). These are masks where 0=clear and

View file

@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef LABWC_BUTTON_SVG_H
#define LABWC_BUTTON_SVG_H
struct lab_data_buffer;
void button_svg_load(const char *button_name, struct lab_data_buffer **buffer,
int size);
#endif /* LABWC_BUTTON_SVG_H */

View file

@ -70,6 +70,7 @@ pangocairo = dependency('pangocairo')
input = dependency('libinput', version: '>=1.14') input = dependency('libinput', version: '>=1.14')
math = cc.find_library('m') math = cc.find_library('m')
png = dependency('libpng') png = dependency('libpng')
svg = dependency('librsvg-2.0', version: '>=2.46', required: false)
if get_option('xwayland').enabled() and not wlroots_has_xwayland if get_option('xwayland').enabled() and not wlroots_has_xwayland
error('no wlroots Xwayland support') error('no wlroots Xwayland support')
@ -78,6 +79,8 @@ have_xwayland = xcb.found() and wlroots_has_xwayland
conf_data = configuration_data() conf_data = configuration_data()
conf_data.set10('HAVE_XWAYLAND', have_xwayland) conf_data.set10('HAVE_XWAYLAND', have_xwayland)
conf_data.set10('HAVE_RSVG', svg.found())
msgfmt = find_program('msgfmt', required: get_option('nls')) msgfmt = find_program('msgfmt', required: get_option('nls'))
if msgfmt.found() if msgfmt.found()
source_root = meson.current_source_dir() source_root = meson.current_source_dir()
@ -106,6 +109,11 @@ labwc_deps = [
math, math,
png, png,
] ]
if svg.found()
labwc_deps += [
svg,
]
endif
subdir('include') subdir('include')
subdir('src') subdir('src')

View file

@ -5653,7 +5653,7 @@ sub process {
#Ignore Page<foo> variants #Ignore Page<foo> variants
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ && $var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
#Ignore some pango and libxml2 CamelCase variants #labwc-custom check to ignore some pango/libxml2/etc CamelCase variants
$var !~ /^(?:PangoLayout|PangoFontDescription)/ && $var !~ /^(?:PangoLayout|PangoFontDescription)/ &&
$var !~ /^(?:PangoTabArray|PangoRectangle)/ && $var !~ /^(?:PangoTabArray|PangoRectangle)/ &&
$var !~ /^(?:PangoWeight|_PangoFontDescription)/ && $var !~ /^(?:PangoWeight|_PangoFontDescription)/ &&
@ -5664,6 +5664,7 @@ sub process {
$var !~ /^(?:xmlParseMemory)/ && $var !~ /^(?:xmlParseMemory)/ &&
$var !~ /^(?:xmlFree)/ && $var !~ /^(?:xmlFree)/ &&
$var !~ /^(?:GString|GError)/ && $var !~ /^(?:GString|GError)/ &&
$var !~ /^(?:RsvgRectangle|RsvgHandle)/ &&
$var !~ /^(?:XKB_KEY_XF86Switch_VT_1)/ && $var !~ /^(?:XKB_KEY_XF86Switch_VT_1)/ &&
#Ignore SI style variants like nS, mV and dB #Ignore SI style variants like nS, mV and dB

View file

@ -54,7 +54,7 @@ png_load(const char *button_name, struct lab_data_buffer **buffer)
char path[4096] = { 0 }; char path[4096] = { 0 };
button_filename(button_name, path, sizeof(path)); button_filename(button_name, path, sizeof(path));
if (!file_exists(path) || !ispng(path)) { if (!ispng(path)) {
return; return;
} }

71
src/button/button-svg.c Normal file
View file

@ -0,0 +1,71 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) Johan Malm 2023
*/
#define _POSIX_C_SOURCE 200809L
#include <cairo.h>
#include <librsvg/rsvg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <wlr/util/log.h>
#include "buffer.h"
#include "button/button-svg.h"
#include "button/common.h"
#include "common/file-helpers.h"
#include "labwc.h"
#include "theme.h"
void
button_svg_load(const char *button_name, struct lab_data_buffer **buffer,
int size)
{
if (*buffer) {
wlr_buffer_drop(&(*buffer)->base);
*buffer = NULL;
}
char filename[4096] = { 0 };
button_filename(button_name, filename, sizeof(filename));
GError *err = NULL;
RsvgRectangle viewport = { .width = size, .height = size };
RsvgHandle *svg = rsvg_handle_new_from_file(filename, &err);
if (err) {
wlr_log(WLR_DEBUG, "error reading svg %s-%s\n", filename, err->message);
g_error_free(err);
/*
* rsvg_handle_new_from_file() returns NULL if an error occurs,
* so there is no need to free svg here.
*/
return;
}
cairo_surface_t *image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, size, size);
cairo_t *cr = cairo_create(image);
rsvg_handle_render_document(svg, cr, &viewport, &err);
if (err) {
wlr_log(WLR_ERROR, "error rendering svg %s-%s\n", filename, err->message);
g_error_free(err);
goto error;
}
if (cairo_surface_status(image)) {
wlr_log(WLR_ERROR, "error reading svg button '%s'", filename);
goto error;
}
cairo_surface_flush(image);
double w = cairo_image_surface_get_width(image);
double h = cairo_image_surface_get_height(image);
*buffer = buffer_create_cairo((int)w, (int)h, 1.0, /* free_on_destroy */ true);
cairo_t *cairo = (*buffer)->cairo;
cairo_set_source_surface(cairo, image, 0, 0);
cairo_paint_with_alpha(cairo, 1.0);
error:
cairo_destroy(cr);
cairo_surface_destroy(image);
g_object_unref(svg);
}

View file

@ -3,3 +3,10 @@ labwc_sources += files(
'button-xbm.c', 'button-xbm.c',
'common.c', 'common.c',
) )
if svg.found()
labwc_sources += files(
'button-svg.c',
)
endif

View file

@ -6,6 +6,7 @@
*/ */
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include "config.h"
#include <cairo.h> #include <cairo.h>
#include <ctype.h> #include <ctype.h>
#include <drm_fourcc.h> #include <drm_fourcc.h>
@ -25,6 +26,11 @@
#include "common/string-helpers.h" #include "common/string-helpers.h"
#include "config/rcxml.h" #include "config/rcxml.h"
#include "button/button-png.h" #include "button/button-png.h"
#if HAVE_RSVG
#include "button/button-svg.h"
#endif
#include "button/button-xbm.h" #include "button/button-xbm.h"
#include "theme.h" #include "theme.h"
#include "buffer.h" #include "buffer.h"
@ -39,6 +45,15 @@ struct button {
} active, inactive; } active, inactive;
}; };
static void
drop(struct lab_data_buffer **buffer)
{
if (*buffer) {
wlr_buffer_drop(&(*buffer)->base);
*buffer = NULL;
}
}
static void static void
load_buttons(struct theme *theme) load_buttons(struct theme *theme)
{ {
@ -97,13 +112,29 @@ load_buttons(struct theme *theme)
for (size_t i = 0; i < sizeof(buttons) / sizeof(buttons[0]); ++i) { for (size_t i = 0; i < sizeof(buttons) / sizeof(buttons[0]); ++i) {
struct button *b = &buttons[i]; struct button *b = &buttons[i];
drop(b->active.buffer);
drop(b->inactive.buffer);
/* Try png icon first */ /* Try png icon first */
snprintf(filename, sizeof(filename), "%s-active.png", b->name); snprintf(filename, sizeof(filename), "%s-active.png", b->name);
png_load(filename, b->active.buffer); png_load(filename, b->active.buffer);
snprintf(filename, sizeof(filename), "%s-inactive.png", b->name); snprintf(filename, sizeof(filename), "%s-inactive.png", b->name);
png_load(filename, b->inactive.buffer); png_load(filename, b->inactive.buffer);
/* If there were no png buttons, use xbm */ #if HAVE_RSVG
/* Then try svg icon */
int size = theme->title_height - 2 * theme->padding_height;
if (!*b->active.buffer) {
snprintf(filename, sizeof(filename), "%s-active.svg", b->name);
button_svg_load(filename, b->active.buffer, size);
}
if (!*b->inactive.buffer) {
snprintf(filename, sizeof(filename), "%s-inactive.svg", b->name);
button_svg_load(filename, b->inactive.buffer, size);
}
#endif
/* If there were no png/svg buttons, use xbm */
snprintf(filename, sizeof(filename), "%s.xbm", b->name); snprintf(filename, sizeof(filename), "%s.xbm", b->name);
if (!*b->active.buffer) { if (!*b->active.buffer) {
button_xbm_load(filename, b->active.buffer, button_xbm_load(filename, b->active.buffer,