*<theme><name>*
The name of the Openbox theme to use. It is not set by default.
+*<theme><icon>*
+ The name of the icon theme to use. It is not set by default.
+
*<theme><titlebar><layout>*
Selection and order of buttons in a window's titlebar.
The following identifiers can be used, each only once:
+ - 'icon': window icon
- 'menu': window menu
- 'iconify': iconify
- 'max': maximize toggle
buttons and the window title are shown.
- Title: The area of the titlebar (including blank space) between
the window buttons, where the window title is displayed.
+ - Icon: A window icon that, by default, displays a window menu.
- WindowMenu: A button that, by default, displays a window menu.
- Iconify: A button that, by default, iconifies a window.
- Maximize: A button that, by default, toggles maximization of a window.
<!-- <font><theme> can be defined without an attribute to set all places -->
<theme>
<name></name>
+ <icon></icon>
<titlebar>
- <layout>menu:iconify,max,close</layout>
+ <layout>icon:iconify,max,close</layout>
<showTitle>yes</showTitle>
</titlebar>
<cornerRadius>8</cornerRadius>
</mousebind>
</context>
+ <context name="Icon">
+ <mousebind button="Left" action="Click">
+ <action name="ShowMenu" menu="client-menu" atCursor="no" />
+ </mousebind>
+ <mousebind button="Right" action="Click">
+ <action name="ShowMenu" menu="client-menu" atCursor="no" />
+ </mousebind>
+ </context>
+
<context name="Shade">
<mousebind button="Left" action="Click">
<action name="ToggleShade" />
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef LABWC_BUTTON_PNG_H
-#define LABWC_BUTTON_PNG_H
-
-struct lab_data_buffer;
-
-void button_png_load(const char *button_name, struct lab_data_buffer **buffer);
-
-#endif /* LABWC_BUTTON_PNG_H */
+++ /dev/null
-/* 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 */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef LABWC_BUTTON_XBM_H
-#define LABWC_BUTTON_XBM_H
-
-struct lab_data_buffer;
-
-/**
- * button_xbm_from_bitmap() - create button from monochrome bitmap
- * @bitmap: bitmap data array in hexadecimal xbm format
- * @buffer: cairo-surface-buffer to create
- * @rgba: color
- *
- * Example bitmap: char button[6] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
- */
-void button_xbm_from_bitmap(const char *bitmap, struct lab_data_buffer **buffer,
- float *rgba);
-
-/* button_xbm_load - Convert xbm file to buffer with cairo surface */
-void button_xbm_load(const char *button_name, struct lab_data_buffer **buffer,
- float *rgba);
-
-#endif /* LABWC_BUTTON_XBM_H */
+++ /dev/null
-/* SPDX-License-Identifier: GPL-2.0-only */
-#ifndef LABWC_BUTTON_COMMON_H
-#define LABWC_BUTTON_COMMON_H
-
-#include <stddef.h>
-
-/**
- * button_filename() - Get full filename for button.
- * @name: The name of the button (for example 'iconify.xbm').
- * @buf: Buffer to fill with the full filename
- * @len: Length of buffer
- *
- * Example return value: /usr/share/themes/Numix/openbox-3/iconify.xbm
- */
-void button_filename(const char *name, char *buf, size_t len);
-
-#endif /* LABWC_BUTTON_COMMON_H */
.name = "atCursor",
.value = "no",
},
+ }, {
+ .context = "Icon",
+ .button = "Left",
+ .event = "Click",
+ .action = "ShowMenu",
+ .attributes[0] = {
+ .name = "menu",
+ .value = "client-menu",
+ },
+ .attributes[1] = {
+ .name = "atCursor",
+ .value = "no",
+ },
+ }, {
+ .context = "Icon",
+ .button = "Right",
+ .event = "Click",
+ .action = "ShowMenu",
+ .attributes[0] = {
+ .name = "menu",
+ .value = "client-menu",
+ },
+ .attributes[1] = {
+ .name = "atCursor",
+ .value = "no",
+ },
}, {
.context = "Root",
.button = "Left",
/* theme */
char *theme_name;
+ char *icon_theme_name;
struct wl_list title_buttons_left;
struct wl_list title_buttons_right;
int corner_radius;
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_ICON_LOADER_H
+#define LABWC_ICON_LOADER_H
+
+struct server;
+
+void icon_loader_init(struct server *server);
+void icon_loader_finish(struct server *server);
+struct lab_data_buffer *icon_loader_lookup(struct server *server,
+ const char *app_id, int size, int scale);
+
+#endif /* LABWC_ICON_LOADER_H */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_IMG_PNG_H
+#define LABWC_IMG_PNG_H
+
+struct lab_data_buffer;
+
+void img_png_load(const char *filename, struct lab_data_buffer **buffer);
+
+#endif /* LABWC_IMG_PNG_H */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_IMG_SVG_H
+#define LABWC_IMG_SVG_H
+
+struct lab_data_buffer;
+
+void img_svg_load(const char *filename, struct lab_data_buffer **buffer,
+ int size);
+
+#endif /* LABWC_IMG_SVG_H */
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LABWC_IMG_XBM_H
+#define LABWC_IMG_XBM_H
+
+struct lab_data_buffer;
+
+/**
+ * img_xbm_from_bitmap() - create button from monochrome bitmap
+ * @bitmap: bitmap data array in hexadecimal xbm format
+ * @buffer: cairo-surface-buffer to create
+ * @rgba: color
+ *
+ * Example bitmap: char button[6] = { 0x3f, 0x3f, 0x21, 0x21, 0x21, 0x3f };
+ */
+void img_xbm_from_bitmap(const char *bitmap, struct lab_data_buffer **buffer,
+ float *rgba);
+
+/* img_xbm_load - Convert xbm file to buffer with cairo surface */
+void img_xbm_load(const char *filename, struct lab_data_buffer **buffer,
+ float *rgba);
+
+#endif /* LABWC_IMG_XBM_H */
struct menu *menu_current;
struct wl_list menus;
+ struct icon_loader *icon_loader;
+
pid_t primary_client_pid;
};
struct ssd_state_title_width active;
struct ssd_state_title_width inactive;
} title;
+
+ char *app_id;
} state;
/* An invisible area around the view which allows resizing */
void add_toggled_icon(struct ssd_button *button, struct wl_list *part_list,
enum ssd_part_type type, struct wlr_buffer *icon_buffer,
struct wlr_buffer *hover_buffer);
+void update_window_icon_buffer(struct wlr_scene_node *button_node,
+ struct wlr_buffer *buffer);
/* SSD internal helpers */
struct ssd_part *ssd_get_part(
LAB_SSD_BUTTON_CLOSE,
LAB_SSD_BUTTON_MAXIMIZE,
LAB_SSD_BUTTON_ICONIFY,
+ LAB_SSD_BUTTON_WINDOW_ICON,
LAB_SSD_BUTTON_WINDOW_MENU,
LAB_SSD_BUTTON_SHADE,
LAB_SSD_BUTTON_OMNIPRESENT,
void ssd_update_geometry(struct ssd *ssd);
void ssd_destroy(struct ssd *ssd);
void ssd_set_titlebar(struct ssd *ssd, bool enabled);
+void ssd_update_window_icon(struct ssd *ssd);
void ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable);
void ssd_enable_shade(struct ssd *ssd, bool enable);
math = cc.find_library('m')
png = dependency('libpng')
svg = dependency('librsvg-2.0', version: '>=2.46', required: false)
+sfdo_basedir = dependency(
+ 'libsfdo-basedir',
+ default_options: ['default_library=static', 'examples=false', 'tests=false'],
+ version: '>=0.1.0',
+ required: not get_option('icon').disabled(),
+)
+sfdo_desktop = dependency(
+ 'libsfdo-desktop',
+ default_options: ['default_library=static', 'examples=false', 'tests=false'],
+ version: '>=0.1.0',
+ required: not get_option('icon').disabled(),
+)
+sfdo_icon = dependency(
+ 'libsfdo-icon',
+ default_options: ['default_library=static', 'examples=false', 'tests=false'],
+ version: '>=0.1.0',
+ required: not get_option('icon').disabled(),
+)
if get_option('xwayland').enabled() and not wlroots_has_xwayland
error('no wlroots Xwayland support')
endif
conf_data.set10('HAVE_RSVG', have_rsvg)
+have_libsfdo = sfdo_basedir.found() and sfdo_desktop.found() and sfdo_icon.found()
+conf_data.set10('HAVE_LIBSFDO', have_libsfdo)
+
if get_option('static_analyzer').enabled()
add_project_arguments(['-fanalyzer'], language: 'c')
endif
svg,
]
endif
+if have_libsfdo
+ labwc_deps += [
+ sfdo_basedir,
+ sfdo_desktop,
+ sfdo_icon,
+ ]
+endif
subdir('include')
subdir('src')
option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages')
option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
option('svg', type: 'feature', value: 'enabled', description: 'Enable svg window buttons')
+option('icon', type: 'feature', value: 'enabled', description: 'Enable window icons')
option('nls', type: 'feature', value: 'auto', description: 'Enable native language support')
option('static_analyzer', type: 'feature', value: 'disabled', description: 'Run gcc static analyzer')
option('test', type: 'feature', value: 'disabled', description: 'Run tests')
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-#include <stdio.h>
-#include <unistd.h>
-#include "button/common.h"
-#include "common/dir.h"
-#include "config/rcxml.h"
-#include "labwc.h"
-
-void
-button_filename(const char *name, char *buf, size_t len)
-{
- struct wl_list paths;
- paths_theme_create(&paths, rc.theme_name, name);
-
- /*
- * You can't really merge buttons, so let's just iterate forwards
- * and stop on the first hit
- */
- struct path *path;
- wl_list_for_each(path, &paths, link) {
- if (access(path->string, R_OK) == 0) {
- snprintf(buf, len, "%s", path->string);
- break;
- }
- }
- paths_destroy(&paths);
-}
return LAB_SSD_BUTTON_ICONIFY;
} else if (!strcasecmp(str, "WindowMenu")) {
return LAB_SSD_BUTTON_WINDOW_MENU;
+ } else if (!strcasecmp(str, "Icon")) {
+ return LAB_SSD_BUTTON_WINDOW_ICON;
} else if (!strcasecmp(str, "Shade")) {
return LAB_SSD_BUTTON_SHADE;
} else if (!strcasecmp(str, "AllDesktops")) {
continue;
}
enum ssd_part_type type = LAB_SSD_NONE;
- if (!strcmp(identifier, "menu")) {
+ if (!strcmp(identifier, "icon")) {
+ type = LAB_SSD_BUTTON_WINDOW_ICON;
+ } else if (!strcmp(identifier, "menu")) {
type = LAB_SSD_BUTTON_WINDOW_MENU;
} else if (!strcmp(identifier, "iconify")) {
type = LAB_SSD_BUTTON_ICONIFY;
rc.placement_cascade_offset_y = atoi(content);
} else if (!strcmp(nodename, "name.theme")) {
rc.theme_name = xstrdup(content);
+ } else if (!strcmp(nodename, "icon.theme")) {
+ rc.icon_theme_name = xstrdup(content);
} else if (!strcasecmp(nodename, "layout.titlebar.theme")) {
fill_title_layout(content);
} else if (!strcasecmp(nodename, "showTitle.titlebar.theme")) {
}
if (!rc.title_layout_loaded) {
- fill_title_layout("menu:iconify,max,close");
+ fill_title_layout("icon:iconify,max,close");
}
/*
zfree(rc.font_menuitem.name);
zfree(rc.font_osd.name);
zfree(rc.theme_name);
+ zfree(rc.icon_theme_name);
zfree(rc.workspace_config.prefix);
struct title_button *p, *p_tmp;
--- /dev/null
+// 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;
+}
#include <stdlib.h>
#include <wlr/util/log.h>
#include "buffer.h"
-#include "button/button-png.h"
-#include "button/common.h"
+#include "img/img-png.h"
#include "common/string-helpers.h"
#include "labwc.h"
#undef PNG_BYTES_TO_CHECK
void
-button_png_load(const char *button_name, struct lab_data_buffer **buffer)
+img_png_load(const char *filename, struct lab_data_buffer **buffer)
{
if (*buffer) {
wlr_buffer_drop(&(*buffer)->base);
*buffer = NULL;
}
- if (string_null_or_empty(button_name)) {
+ if (string_null_or_empty(filename)) {
return;
}
-
- char path[4096] = { 0 };
- button_filename(button_name, path, sizeof(path));
- if (!ispng(path)) {
+ if (!ispng(filename)) {
return;
}
- cairo_surface_t *image = cairo_image_surface_create_from_png(path);
+ cairo_surface_t *image = cairo_image_surface_create_from_png(filename);
if (cairo_surface_status(image)) {
- wlr_log(WLR_ERROR, "error reading png button '%s'", path);
+ wlr_log(WLR_ERROR, "error reading png button '%s'", filename);
cairo_surface_destroy(image);
return;
}
#include <stdlib.h>
#include <wlr/util/log.h>
#include "buffer.h"
-#include "button/button-svg.h"
-#include "button/common.h"
+#include "img/img-svg.h"
#include "common/string-helpers.h"
#include "labwc.h"
void
-button_svg_load(const char *button_name, struct lab_data_buffer **buffer,
+img_svg_load(const char *filename, struct lab_data_buffer **buffer,
int size)
{
if (*buffer) {
wlr_buffer_drop(&(*buffer)->base);
*buffer = NULL;
}
- if (string_null_or_empty(button_name)) {
- return;
- }
-
- char filename[4096] = { 0 };
- button_filename(button_name, filename, sizeof(filename));
if (string_null_or_empty(filename)) {
return;
}
#include <stdlib.h>
#include <string.h>
#include <drm_fourcc.h>
-#include "button/button-xbm.h"
-#include "button/common.h"
+#include "img/img-xbm.h"
#include "common/grab-file.h"
#include "common/mem.h"
#include "common/string-helpers.h"
}
void
-button_xbm_from_bitmap(const char *bitmap, struct lab_data_buffer **buffer,
+img_xbm_from_bitmap(const char *bitmap, struct lab_data_buffer **buffer,
float *rgba)
{
struct pixmap pixmap = {0};
}
void
-button_xbm_load(const char *button_name, struct lab_data_buffer **buffer,
+img_xbm_load(const char *filename, struct lab_data_buffer **buffer,
float *rgba)
{
struct pixmap pixmap = {0};
wlr_buffer_drop(&(*buffer)->base);
*buffer = NULL;
}
- if (string_null_or_empty(button_name)) {
+ if (string_null_or_empty(filename)) {
return;
}
color = argb32(rgba);
/* Read file into memory as it's easier to tokenize that way */
- char filename[4096] = { 0 };
- button_filename(button_name, filename, sizeof(filename));
struct buf token_buf = grab_file(filename);
if (token_buf.len) {
struct token *tokens = tokenize_xbm(token_buf.data);
labwc_sources += files(
- 'button-png.c',
- 'button-xbm.c',
- 'common.c',
+ 'img-png.c',
+ 'img-xbm.c',
)
if have_rsvg
labwc_sources += files(
- 'button-svg.c',
+ 'img-svg.c',
)
endif
)
endif
+if have_libsfdo
+ labwc_sources += files(
+ 'icon-loader.c',
+ )
+endif
-subdir('button')
+subdir('img')
subdir('common')
subdir('config')
subdir('decorations')
#include "config/rcxml.h"
#include "config/session.h"
#include "decorations.h"
+#if HAVE_LIBSFDO
+#include "icon-loader.h"
+#endif
#include "idle.h"
#include "labwc.h"
#include "layers.h"
theme_finish(server->theme);
theme_init(server->theme, server, rc.theme_name);
+#if HAVE_LIBSFDO
+ icon_loader_finish(server);
+ icon_loader_init(server);
+#endif
+
struct view *view;
wl_list_for_each(view, &server->views, link) {
view_reload_ssd(view);
layers_init(server);
+#if HAVE_LIBSFDO
+ icon_loader_init(server);
+#endif
+
#if HAVE_XWAYLAND
xwayland_server_init(server, compositor);
#endif
/* TODO: clean up various scene_tree nodes */
workspaces_destroy(server);
+
+#if HAVE_LIBSFDO
+ icon_loader_finish(server);
+#endif
}
return icon_geo;
}
+void
+update_window_icon_buffer(struct wlr_scene_node *button_node,
+ struct wlr_buffer *buffer)
+{
+ struct wlr_scene_buffer *scene_buffer =
+ wlr_scene_buffer_from_node(button_node);
+
+ struct wlr_box icon_geo = get_scale_box(buffer,
+ rc.theme->window_button_width,
+ rc.theme->title_height);
+
+ wlr_scene_buffer_set_buffer(scene_buffer, buffer);
+ wlr_scene_buffer_set_dest_size(scene_buffer,
+ icon_geo.width, icon_geo.height);
+ wlr_scene_node_set_position(button_node, icon_geo.x, icon_geo.y);
+}
+
struct ssd_part *
add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
struct wlr_scene_tree *parent, struct wlr_buffer *icon_buffer,
#include <assert.h>
#include <string.h>
#include "buffer.h"
+#include "config.h"
#include "common/mem.h"
#include "common/scaled-font-buffer.h"
#include "common/scene-helpers.h"
#include "common/string-helpers.h"
+#if HAVE_LIBSFDO
+#include "icon-loader.h"
+#endif
#include "labwc.h"
#include "node.h"
#include "ssd-internal.h"
struct ssd_button *btn;
switch (type) {
+ case LAB_SSD_BUTTON_WINDOW_ICON: /* fallthrough */
case LAB_SSD_BUTTON_WINDOW_MENU:
add_scene_button(&subtree->parts, type, parent,
active ? &theme->button_menu_active_unpressed->base
update_visible_buttons(ssd);
ssd_update_title(ssd);
+ ssd_update_window_icon(ssd);
bool maximized = view->maximized == VIEW_AXIS_BOTH;
if (maximized) {
wlr_scene_node_set_position(part->node, x, 0);
}
} FOR_EACH_END
+
ssd_update_title(ssd);
+ ssd_update_window_icon(ssd);
}
void
} FOR_EACH_END
if (ssd->state.title.text) {
- free(ssd->state.title.text);
- ssd->state.title.text = NULL;
+ zfree(ssd->state.title.text);
+ }
+ if (ssd->state.app_id) {
+ zfree(ssd->state.app_id);
}
wlr_scene_node_destroy(&ssd->titlebar.tree->node);
&& view->maximized != VIEW_AXIS_BOTH;
}
+void
+ssd_update_window_icon(struct ssd *ssd)
+{
+#if HAVE_LIBSFDO
+ const char *app_id = view_get_string_prop(ssd->view, "app_id");
+ if (string_null_or_empty(app_id)) {
+ return;
+ }
+ if (ssd->state.app_id && !strcmp(ssd->state.app_id, app_id)) {
+ return;
+ }
+
+ free(ssd->state.app_id);
+ ssd->state.app_id = xstrdup(app_id);
+
+ struct theme *theme = ssd->view->server->theme;
+
+ int icon_size = MIN(theme->window_button_width,
+ theme->title_height - 2 * theme->padding_height);
+ /* TODO: take into account output scales */
+ int icon_scale = 1;
+
+ struct lab_data_buffer *icon_buffer = icon_loader_lookup(
+ ssd->view->server, app_id, icon_size, icon_scale);
+ if (!icon_buffer) {
+ wlr_log(WLR_DEBUG, "icon could not be loaded for %s", app_id);
+ return;
+ }
+
+ struct ssd_sub_tree *subtree;
+ FOR_EACH_STATE(ssd, subtree) {
+ struct ssd_part *part =
+ ssd_get_part(&subtree->parts, LAB_SSD_BUTTON_WINDOW_ICON);
+ if (!part) {
+ break;
+ }
+
+ struct ssd_button *button = node_ssd_button_from_node(part->node);
+ update_window_icon_buffer(button->normal, &icon_buffer->base);
+ update_window_icon_buffer(button->hover, &icon_buffer->base);
+ } FOR_EACH_END
+
+ wlr_buffer_drop(&icon_buffer->base);
+#endif
+}
+
#undef FOR_EACH_STATE
#include "common/parse-double.h"
#include "common/string-helpers.h"
#include "config/rcxml.h"
-#include "button/button-png.h"
+#include "img/img-png.h"
#include "labwc.h"
#if HAVE_RSVG
-#include "button/button-svg.h"
+#include "img/img-svg.h"
#endif
-#include "button/button-xbm.h"
+#include "img/img-xbm.h"
#include "theme.h"
#include "buffer.h"
#include "ssd.h"
}
}
+/*
+ * Scan theme directories with button names (name + postfix) and write the full
+ * path of the found button file to @buf. An empty string is set if a button
+ * file is not found.
+ */
+static void
+get_button_filename(char *buf, size_t len, const char *name, const char *postfix)
+{
+ buf[0] = '\0';
+
+ char filename[4096];
+ snprintf(filename, sizeof(filename), "%s%s", name, postfix);
+
+ struct wl_list paths;
+ paths_theme_create(&paths, rc.theme_name, filename);
+
+ /*
+ * You can't really merge buttons, so let's just iterate forwards
+ * and stop on the first hit
+ */
+ struct path *path;
+ wl_list_for_each(path, &paths, link) {
+ if (access(path->string, R_OK) == 0) {
+ snprintf(buf, len, "%s", path->string);
+ break;
+ }
+ }
+ paths_destroy(&paths);
+}
+
/*
* We use the following button filename schema: "BUTTON [TOGGLED] [STATE]"
* with the words separated by underscore, and the following meaning:
zdrop(b->inactive.buffer);
/* PNG */
- snprintf(filename, sizeof(filename), "%s-active.png", b->name);
- button_png_load(filename, b->active.buffer);
- snprintf(filename, sizeof(filename), "%s-inactive.png", b->name);
- button_png_load(filename, b->inactive.buffer);
+ get_button_filename(filename, sizeof(filename), b->name, "-active.png");
+ img_png_load(filename, b->active.buffer);
+ get_button_filename(filename, sizeof(filename), b->name, "-inactive.png");
+ img_png_load(filename, b->inactive.buffer);
#if HAVE_RSVG
/* SVG */
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);
+ get_button_filename(filename, sizeof(filename), b->name, "-active.svg");
+ img_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);
+ get_button_filename(filename, sizeof(filename), b->name, "-inactive.svg");
+ img_svg_load(filename, b->inactive.buffer, size);
}
#endif
/* XBM */
- snprintf(filename, sizeof(filename), "%s.xbm", b->name);
+ get_button_filename(filename, sizeof(filename), b->name, ".xbm");
if (!*b->active.buffer) {
- button_xbm_load(filename, b->active.buffer, b->active.rgba);
+ img_xbm_load(filename, b->active.buffer, b->active.rgba);
}
if (!*b->inactive.buffer) {
- button_xbm_load(filename, b->inactive.buffer, b->inactive.rgba);
+ img_xbm_load(filename, b->inactive.buffer, b->inactive.rgba);
}
/*
* For example max_hover_toggled instead of max_toggled_hover
*/
if (b->alt_name) {
- snprintf(filename, sizeof(filename), "%s.xbm", b->alt_name);
+ get_button_filename(filename, sizeof(filename), b->alt_name, ".xbm");
} else {
filename[0] = '\0';
}
if (!*b->active.buffer) {
- button_xbm_load(filename, b->active.buffer, b->active.rgba);
+ img_xbm_load(filename, b->active.buffer, b->active.rgba);
}
if (!*b->inactive.buffer) {
- button_xbm_load(filename, b->inactive.buffer, b->inactive.rgba);
+ img_xbm_load(filename, b->inactive.buffer, b->inactive.rgba);
}
/*
continue;
}
if (!*b->active.buffer) {
- button_xbm_from_bitmap(b->fallback_button,
+ img_xbm_from_bitmap(b->fallback_button,
b->active.buffer, b->active.rgba);
}
if (!*b->inactive.buffer) {
- button_xbm_from_bitmap(b->fallback_button,
+ img_xbm_from_bitmap(b->fallback_button,
b->inactive.buffer, b->inactive.rgba);
}
}
}
wlr_foreign_toplevel_handle_v1_set_app_id(
view->toplevel.handle, app_id);
+
+ if (view->ssd_enabled) {
+ ssd_update_window_icon(view->ssd);
+ }
}
void
--- /dev/null
+[wrap-git]
+url = https://gitlab.freedesktop.org/vyivel/libsfdo.git
+revision = v0.1.3
+
+[provide]
+dependency_names = libsfdo-basedir, libsfdo-desktop, libsfdo-icon