labwc/src/icon-loader.c
tokyo4j a745f91169 ssd: support window icons
The default `titleLayout` is updated to `icon:iconify,max,close` which
replaces the window menu button with the window icon.

When the icon file is not found or could not be loaded, the window menu
icon as before is shown.

The icon theme can be selected with `<theme><icon>`.

This commit adds libsfdo as an optional dependency. `-Dicon=disabled` can
be passsed to `meson setup` command in order to disable window icon, in
which case the window icon is always replaced with a window menu button.
2024-09-25 18:04:09 +09:00

137 lines
3.3 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
#include <sfdo-desktop.h>
#include <sfdo-icon.h>
#include <sfdo-basedir.h>
#include <wlr/util/log.h>
#include "common/mem.h"
#include "config.h"
#include "icon-loader.h"
#include "img/img-png.h"
#if HAVE_RSVG
#include "img/img-svg.h"
#endif
#include "labwc.h"
struct icon_loader {
struct sfdo_desktop_ctx *desktop_ctx;
struct sfdo_icon_ctx *icon_ctx;
struct sfdo_desktop_db *desktop_db;
struct sfdo_icon_theme *icon_theme;
};
void
icon_loader_init(struct server *server)
{
struct icon_loader *loader = znew(*loader);
struct sfdo_basedir_ctx *basedir_ctx = sfdo_basedir_ctx_create();
if (!basedir_ctx) {
goto err_basedir_ctx;
}
loader->desktop_ctx = sfdo_desktop_ctx_create(basedir_ctx);
if (!loader->desktop_ctx) {
goto err_desktop_ctx;
}
loader->icon_ctx = sfdo_icon_ctx_create(basedir_ctx);
if (!loader->icon_ctx) {
goto err_icon_ctx;
}
loader->desktop_db = sfdo_desktop_db_load(loader->desktop_ctx, NULL);
if (!loader->desktop_db) {
goto err_desktop_db;
}
loader->icon_theme = sfdo_icon_theme_load(loader->icon_ctx,
rc.icon_theme_name, SFDO_ICON_THEME_LOAD_OPTIONS_DEFAULT);
if (!loader->icon_theme) {
goto err_icon_theme;
}
/* basedir_ctx is not referenced by other objects */
sfdo_basedir_ctx_destroy(basedir_ctx);
server->icon_loader = loader;
return;
err_icon_theme:
sfdo_desktop_db_destroy(loader->desktop_db);
err_desktop_db:
sfdo_icon_ctx_destroy(loader->icon_ctx);
err_icon_ctx:
sfdo_desktop_ctx_destroy(loader->desktop_ctx);
err_desktop_ctx:
sfdo_basedir_ctx_destroy(basedir_ctx);
err_basedir_ctx:
free(loader);
wlr_log(WLR_ERROR, "Failed to initialize icon loader");
}
void
icon_loader_finish(struct server *server)
{
struct icon_loader *loader = server->icon_loader;
if (!loader) {
return;
}
sfdo_desktop_db_destroy(loader->desktop_db);
sfdo_icon_ctx_destroy(loader->icon_ctx);
sfdo_desktop_ctx_destroy(loader->desktop_ctx);
free(loader);
server->icon_loader = NULL;
}
struct lab_data_buffer *
icon_loader_lookup(struct server *server, const char *app_id, int size, int scale)
{
struct icon_loader *loader = server->icon_loader;
if (!loader) {
return NULL;
}
const char *icon_name = NULL;
struct sfdo_desktop_entry *entry = sfdo_desktop_db_get_entry_by_id(
loader->desktop_db, app_id, SFDO_NT);
if (entry) {
icon_name = sfdo_desktop_entry_get_icon(entry, NULL);
}
if (!icon_name) {
/* fall back to app id */
icon_name = app_id;
}
int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT;
#if !HAVE_RSVG
lookup_options |= SFDO_ICON_THEME_LOOKUP_OPTION_NO_SVG;
#endif
struct sfdo_icon_file *icon_file = sfdo_icon_theme_lookup(
loader->icon_theme, icon_name, SFDO_NT, size, scale,
lookup_options);
if (!icon_file || icon_file == SFDO_ICON_FILE_INVALID) {
return NULL;
}
struct lab_data_buffer *icon_buffer = NULL;
const char *icon_path = sfdo_icon_file_get_path(icon_file, NULL);
wlr_log(WLR_DEBUG, "loading icon file %s", icon_path);
switch (sfdo_icon_file_get_format(icon_file)) {
case SFDO_ICON_FILE_FORMAT_PNG:
img_png_load(icon_path, &icon_buffer);
break;
case SFDO_ICON_FILE_FORMAT_SVG:
#if HAVE_RSVG
img_svg_load(icon_path, &icon_buffer, size * scale);
#endif
break;
case SFDO_ICON_FILE_FORMAT_XPM:
/* XPM is not supported */
break;
}
sfdo_icon_file_destroy(icon_file);
return icon_buffer;
}