From f3cca0d86fc079e0781217814576f170838cdf48 Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Wed, 16 Apr 2025 03:23:40 +0000 Subject: [PATCH 1/6] Add basic scaffolding for including libsfdo in builds --- meson.build | 30 ++++++++++++++++++++++++++++++ meson_options.txt | 1 + 2 files changed, 31 insertions(+) diff --git a/meson.build b/meson.build index eab1348ae..2c6397def 100644 --- a/meson.build +++ b/meson.build @@ -38,6 +38,34 @@ if is_freebsd add_project_arguments('-D_C11_SOURCE', language: 'c') endif +# Check for (currrently) optional libsfdo +sfdo_basedir = dependency( + 'libsfdo-basedir', + default_options: ['default_library=static', 'examples=false', 'tests=false'], + version: '>=0.1.3', + required: get_option('sfdo'), +) +sfdo_desktop = dependency( + 'libsfdo-desktop', + default_options: ['default_library=static', 'examples=false', 'tests=false'], + version: '>=0.1.3', + required: get_option('sfdo'), +) +sfdo_desktop_file = dependency( + 'libsfdo-desktop-file', + default_options: ['default_library=static', 'examples=false', 'tests=false'], + version: '>=0.1.3', + required: get_option('sfdo'), +) +sfdo_icon = dependency( + 'libsfdo-icon', + default_options: ['default_library=static', 'examples=false', 'tests=false'], + version: '>=0.1.3', + required: get_option('sfdo'), +) +have_libsfdo = sfdo_basedir.found() and sfdo_desktop.found() and sfdo_desktop_file.found() and sfdo_icon.found() + + # Execute the wlroots subproject, if any wlroots_version = ['>=0.20.0', '<0.21.0'] subproject( @@ -108,6 +136,7 @@ conf_data = configuration_data() conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd') conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind') +conf_data.set10('HAVE_LIBSFDO', have_libsfdo) conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu') conf_data.set10('HAVE_TRAY', have_tray) foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY'] @@ -244,5 +273,6 @@ subdir('completions') summary({ 'gdk-pixbuf': gdk_pixbuf.found(), 'tray': have_tray, + 'libsfdo': have_libsfdo, 'man-pages': scdoc.found(), }, bool_yn: true) diff --git a/meson_options.txt b/meson_options.txt index 506ecc9a6..6f776bab7 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,3 +8,4 @@ option('tray', type: 'feature', value: 'auto', description: 'Enable support for option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybar tray') option('man-pages', type: 'feature', value: 'auto', description: 'Generate and install man pages') option('sd-bus-provider', type: 'combo', choices: ['auto', 'libsystemd', 'libelogind', 'basu'], value: 'auto', description: 'Provider of the sd-bus library') +option('sfdo', type: 'feature', value: 'auto', description: 'Enable libsfdo integration') From 34d20200424330124a7a5226c6932847772c52d7 Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Wed, 16 Apr 2025 20:50:42 +0000 Subject: [PATCH 2/6] Clean up build scaffolding for libsfdo and add the creation and destruction of an sfdo data structure associated with a sway server with a view to future use of icon themes in places such as titlebars --- include/sway/server.h | 25 +- meson.build | 56 +-- sway/meson.build | 9 + sway/server.c | 894 +++++++++++++++++++++++------------------- 4 files changed, 559 insertions(+), 425 deletions(-) diff --git a/include/sway/server.h b/include/sway/server.h index 72bccd70c..13da0d605 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -8,7 +8,11 @@ #if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif - +#if HAVE_LIBSFDO +#include +#include +#include +#endif struct sway_transaction; struct sway_session_lock { @@ -24,6 +28,15 @@ struct sway_session_lock { struct wl_listener destroy; }; +#if HAVE_LIBSFDO +struct sfdo { + struct sfdo_desktop_ctx *desktop_ctx; + struct sfdo_icon_ctx *icon_ctx; + struct sfdo_desktop_db *desktop_db; + struct sfdo_icon_theme *icon_theme; +}; +#endif + struct sway_server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; @@ -146,6 +159,11 @@ struct sway_server { list_t *dirty_nodes; struct wl_event_source *delayed_modeset; + +#if HAVE_LIBSFDO + struct sfdo *sfdo; +#endif + }; extern struct sway_server server; @@ -192,4 +210,9 @@ void set_rr_scheduling(void); void handle_new_tearing_hint(struct wl_listener *listener, void *data); +#if HAVE_LIBSFDO +struct sfdo *sfdo_create(char *theme); +void sfdo_destroy(struct sfdo *sfdo); +#endif + #endif diff --git a/meson.build b/meson.build index 2c6397def..f22fa7be2 100644 --- a/meson.build +++ b/meson.build @@ -38,34 +38,6 @@ if is_freebsd add_project_arguments('-D_C11_SOURCE', language: 'c') endif -# Check for (currrently) optional libsfdo -sfdo_basedir = dependency( - 'libsfdo-basedir', - default_options: ['default_library=static', 'examples=false', 'tests=false'], - version: '>=0.1.3', - required: get_option('sfdo'), -) -sfdo_desktop = dependency( - 'libsfdo-desktop', - default_options: ['default_library=static', 'examples=false', 'tests=false'], - version: '>=0.1.3', - required: get_option('sfdo'), -) -sfdo_desktop_file = dependency( - 'libsfdo-desktop-file', - default_options: ['default_library=static', 'examples=false', 'tests=false'], - version: '>=0.1.3', - required: get_option('sfdo'), -) -sfdo_icon = dependency( - 'libsfdo-icon', - default_options: ['default_library=static', 'examples=false', 'tests=false'], - version: '>=0.1.3', - required: get_option('sfdo'), -) -have_libsfdo = sfdo_basedir.found() and sfdo_desktop.found() and sfdo_desktop_file.found() and sfdo_icon.found() - - # Execute the wlroots subproject, if any wlroots_version = ['>=0.20.0', '<0.21.0'] subproject( @@ -88,6 +60,34 @@ endforeach null_dep = dependency('', required: false) +# Check for (currrently) optional libsfdo +sfdo_basedir = dependency( + 'libsfdo-basedir', + version: '>=0.1.3', + required: get_option('sfdo') +) +sfdo_desktop = dependency( + 'libsfdo-desktop', + version: '>=0.1.3', + required: get_option('sfdo') +) +sfdo_desktop_file = dependency( + 'libsfdo-desktop-file', + version: '>=0.1.3', + required: get_option('sfdo') +) +sfdo_icon = dependency( + 'libsfdo-icon', + version: '>=0.1.3', + required: get_option('sfdo') +) +have_libsfdo = ( + sfdo_basedir.found() and + sfdo_desktop.found() and + sfdo_desktop_file.found() and + sfdo_icon.found() +) + jsonc = dependency('json-c', version: '>=0.13') pcre2 = dependency('libpcre2-8') wayland_server = dependency('wayland-server', version: '>=1.21.0') diff --git a/sway/meson.build b/sway/meson.build index 8042c89be..865049d82 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -244,6 +244,15 @@ if wlroots_features['libinput_backend'] sway_sources += 'input/libinput.c' endif +if have_libsfdo + sway_deps += [ + sfdo_basedir, + sfdo_desktop, + sfdo_desktop_file, + sfdo_icon + ] +endif + executable( 'sway', sway_sources + wl_protos_src, diff --git a/sway/server.c b/sway/server.c index 6ca5906df..4794f6f50 100644 --- a/sway/server.c +++ b/sway/server.c @@ -1,3 +1,13 @@ +#include "sway/server.h" +#include "config.h" +#include "list.h" +#include "log.h" +#include "sway/config.h" +#include "sway/desktop/idle_inhibit_v1.h" +#include "sway/input/cursor.h" +#include "sway/input/input-manager.h" +#include "sway/output.h" +#include "sway/tree/root.h" #include #include #include @@ -14,13 +24,13 @@ #include #include #include -#include #include #include +#include #include -#include #include #include +#include #include #include #include @@ -49,26 +59,22 @@ #include #include #include -#include "config.h" -#include "list.h" -#include "log.h" -#include "sway/config.h" -#include "sway/desktop/idle_inhibit_v1.h" -#include "sway/input/input-manager.h" -#include "sway/output.h" -#include "sway/server.h" -#include "sway/input/cursor.h" -#include "sway/tree/root.h" #if WLR_HAS_XWAYLAND -#include #include "sway/xwayland.h" +#include #endif #if WLR_HAS_DRM_BACKEND #include #endif +#if HAVE_LIBSFDO +#include +#include +#include +#endif + #define SWAY_XDG_SHELL_VERSION 5 #define SWAY_LAYER_SHELL_VERSION 4 #define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1 @@ -78,498 +84,594 @@ bool allow_unsupported_gpu = false; #if WLR_HAS_DRM_BACKEND static void handle_drm_lease_request(struct wl_listener *listener, void *data) { - /* We only offer non-desktop outputs, but in the future we might want to do - * more logic here. */ + /* We only offer non-desktop outputs, but in the future we might want to do + * more logic here. */ - struct wlr_drm_lease_request_v1 *req = data; - struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req); - if (!lease) { - sway_log(SWAY_ERROR, "Failed to grant lease request"); - wlr_drm_lease_request_v1_reject(req); - } + struct wlr_drm_lease_request_v1 *req = data; + struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req); + if (!lease) { + sway_log(SWAY_ERROR, "Failed to grant lease request"); + wlr_drm_lease_request_v1_reject(req); + } } #endif static bool is_privileged(const struct wl_global *global) { #if WLR_HAS_DRM_BACKEND - if (server.drm_lease_manager != NULL) { - struct wlr_drm_lease_device_v1 *drm_lease_dev; - wl_list_for_each(drm_lease_dev, &server.drm_lease_manager->devices, link) { - if (drm_lease_dev->global == global) { - return true; - } - } - } + if (server.drm_lease_manager != NULL) { + struct wlr_drm_lease_device_v1 *drm_lease_dev; + wl_list_for_each(drm_lease_dev, &server.drm_lease_manager->devices, link) { + if (drm_lease_dev->global == global) { + return true; + } + } + } #endif - return - global == server.output_manager_v1->global || - global == server.output_power_manager_v1->global || - global == server.input_method->global || - global == server.foreign_toplevel_list->global || - global == server.foreign_toplevel_manager->global || - global == server.wlr_data_control_manager_v1->global || - global == server.ext_data_control_manager_v1->global || - global == server.screencopy_manager_v1->global || - global == server.ext_image_copy_capture_manager_v1->global || - global == server.export_dmabuf_manager_v1->global || - global == server.security_context_manager_v1->global || - global == server.gamma_control_manager_v1->global || - global == server.layer_shell->global || - global == server.session_lock.manager->global || - global == server.input->keyboard_shortcuts_inhibit->global || - global == server.input->virtual_keyboard->global || - global == server.input->virtual_pointer->global || - global == server.input->transient_seat_manager->global || - global == server.xdg_output_manager_v1->global; + return global == server.output_manager_v1->global || + global == server.output_power_manager_v1->global || + global == server.input_method->global || + global == server.foreign_toplevel_list->global || + global == server.foreign_toplevel_manager->global || + global == server.wlr_data_control_manager_v1->global || + global == server.ext_data_control_manager_v1->global || + global == server.screencopy_manager_v1->global || + global == server.ext_image_copy_capture_manager_v1->global || + global == server.export_dmabuf_manager_v1->global || + global == server.security_context_manager_v1->global || + global == server.gamma_control_manager_v1->global || + global == server.layer_shell->global || + global == server.session_lock.manager->global || + global == server.input->keyboard_shortcuts_inhibit->global || + global == server.input->virtual_keyboard->global || + global == server.input->virtual_pointer->global || + global == server.input->transient_seat_manager->global || + global == server.xdg_output_manager_v1->global; } static bool filter_global(const struct wl_client *client, - const struct wl_global *global, void *data) { + const struct wl_global *global, void *data) { #if WLR_HAS_XWAYLAND - struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; - if (xwayland && global == xwayland->shell_v1->global) { - return xwayland->server != NULL && client == xwayland->server->client; - } + struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; + if (xwayland && global == xwayland->shell_v1->global) { + return xwayland->server != NULL && client == xwayland->server->client; + } #endif - // Restrict usage of privileged protocols to unsandboxed clients - // TODO: add a way for users to configure an allow-list - const struct wlr_security_context_v1_state *security_context = - wlr_security_context_manager_v1_lookup_client( - server.security_context_manager_v1, (struct wl_client *)client); - if (is_privileged(global)) { - return security_context == NULL; - } + // Restrict usage of privileged protocols to unsandboxed clients + // TODO: add a way for users to configure an allow-list + const struct wlr_security_context_v1_state *security_context = + wlr_security_context_manager_v1_lookup_client( + server.security_context_manager_v1, (struct wl_client *)client); + if (is_privileged(global)) { + return security_context == NULL; + } - return true; + return true; } static void detect_proprietary(struct wlr_backend *backend, void *data) { - int drm_fd = wlr_backend_get_drm_fd(backend); - if (drm_fd < 0) { - return; - } + int drm_fd = wlr_backend_get_drm_fd(backend); + if (drm_fd < 0) { + return; + } - drmVersion *version = drmGetVersion(drm_fd); - if (version == NULL) { - sway_log(SWAY_ERROR, "drmGetVersion() failed"); - return; - } + drmVersion *version = drmGetVersion(drm_fd); + if (version == NULL) { + sway_log(SWAY_ERROR, "drmGetVersion() failed"); + return; + } - bool is_unsupported = false; - if (strcmp(version->name, "nvidia-drm") == 0) { - is_unsupported = true; - sway_log(SWAY_ERROR, "!!! Proprietary Nvidia drivers are in use !!!"); - if (!allow_unsupported_gpu) { - sway_log(SWAY_ERROR, "Use Nouveau instead"); - } - } + bool is_unsupported = false; + if (strcmp(version->name, "nvidia-drm") == 0) { + is_unsupported = true; + sway_log(SWAY_ERROR, "!!! Proprietary Nvidia drivers are in use !!!"); + if (!allow_unsupported_gpu) { + sway_log(SWAY_ERROR, "Use Nouveau instead"); + } + } - if (strcmp(version->name, "evdi") == 0) { - is_unsupported = true; - sway_log(SWAY_ERROR, "!!! Proprietary DisplayLink drivers are in use !!!"); - } + if (strcmp(version->name, "evdi") == 0) { + is_unsupported = true; + sway_log(SWAY_ERROR, "!!! Proprietary DisplayLink drivers are in use !!!"); + } - if (!allow_unsupported_gpu && is_unsupported) { - sway_log(SWAY_ERROR, - "Proprietary drivers are NOT supported. To launch sway anyway, " - "launch with --unsupported-gpu and DO NOT report issues."); - exit(EXIT_FAILURE); - } + if (!allow_unsupported_gpu && is_unsupported) { + sway_log(SWAY_ERROR, + "Proprietary drivers are NOT supported. To launch sway anyway, " + "launch with --unsupported-gpu and DO NOT report issues."); + exit(EXIT_FAILURE); + } - drmFreeVersion(version); + drmFreeVersion(version); } static void do_renderer_recreate(void *data) { - struct sway_server *server = data; - server->recreating_renderer = NULL; + struct sway_server *server = data; + server->recreating_renderer = NULL; - sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); - struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); - if (renderer == NULL) { - sway_log(SWAY_ERROR, "Unable to create renderer"); - return; - } + sway_log(SWAY_INFO, "Re-creating renderer after GPU reset"); + struct wlr_renderer *renderer = wlr_renderer_autocreate(server->backend); + if (renderer == NULL) { + sway_log(SWAY_ERROR, "Unable to create renderer"); + return; + } - struct wlr_allocator *allocator = - wlr_allocator_autocreate(server->backend, renderer); - if (allocator == NULL) { - sway_log(SWAY_ERROR, "Unable to create allocator"); - wlr_renderer_destroy(renderer); - return; - } + struct wlr_allocator *allocator = + wlr_allocator_autocreate(server->backend, renderer); + if (allocator == NULL) { + sway_log(SWAY_ERROR, "Unable to create allocator"); + wlr_renderer_destroy(renderer); + return; + } - struct wlr_renderer *old_renderer = server->renderer; - struct wlr_allocator *old_allocator = server->allocator; - server->renderer = renderer; - server->allocator = allocator; + struct wlr_renderer *old_renderer = server->renderer; + struct wlr_allocator *old_allocator = server->allocator; + server->renderer = renderer; + server->allocator = allocator; - wl_list_remove(&server->renderer_lost.link); - wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + wl_list_remove(&server->renderer_lost.link); + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); - wlr_compositor_set_renderer(server->compositor, renderer); + wlr_compositor_set_renderer(server->compositor, renderer); - struct sway_output *output; - wl_list_for_each(output, &root->all_outputs, link) { - wlr_output_init_render(output->wlr_output, - server->allocator, server->renderer); - } + struct sway_output *output; + wl_list_for_each(output, &root->all_outputs, link) { + wlr_output_init_render(output->wlr_output, server->allocator, + server->renderer); + } - wlr_allocator_destroy(old_allocator); - wlr_renderer_destroy(old_renderer); + wlr_allocator_destroy(old_allocator); + wlr_renderer_destroy(old_renderer); } static void handle_renderer_lost(struct wl_listener *listener, void *data) { - struct sway_server *server = wl_container_of(listener, server, renderer_lost); + struct sway_server *server = wl_container_of(listener, server, renderer_lost); - if (server->recreating_renderer != NULL) { - sway_log(SWAY_DEBUG, "Re-creation of renderer already scheduled"); - return; - } + if (server->recreating_renderer != NULL) { + sway_log(SWAY_DEBUG, "Re-creation of renderer already scheduled"); + return; + } - sway_log(SWAY_INFO, "Scheduling re-creation of renderer after GPU reset"); - server->recreating_renderer = wl_event_loop_add_idle(server->wl_event_loop, do_renderer_recreate, server); + sway_log(SWAY_INFO, "Scheduling re-creation of renderer after GPU reset"); + server->recreating_renderer = wl_event_loop_add_idle( + server->wl_event_loop, do_renderer_recreate, server); } -static void handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, void *data) { - struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request *request = data; - struct sway_view *view = request->toplevel_handle->data; +static void +handle_new_foreign_toplevel_capture_request(struct wl_listener *listener, + void *data) { + struct wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request + *request = data; + struct sway_view *view = request->toplevel_handle->data; - if (view->image_capture_source == NULL) { - view->image_capture_source = wlr_ext_image_capture_source_v1_create_with_scene_node( - &view->image_capture_scene->tree.node, server.wl_event_loop, server.allocator, server.renderer); - if (view->image_capture_source == NULL) { - return; - } - } + if (view->image_capture_source == NULL) { + view->image_capture_source = + wlr_ext_image_capture_source_v1_create_with_scene_node( + &view->image_capture_scene->tree.node, server.wl_event_loop, + server.allocator, server.renderer); + if (view->image_capture_source == NULL) { + return; + } + } - wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept(request, view->image_capture_source); + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_request_accept( + request, view->image_capture_source); } bool server_init(struct sway_server *server) { - sway_log(SWAY_DEBUG, "Initializing Wayland server"); - server->wl_display = wl_display_create(); - server->wl_event_loop = wl_display_get_event_loop(server->wl_display); + sway_log(SWAY_DEBUG, "Initializing Wayland server"); + server->wl_display = wl_display_create(); + server->wl_event_loop = wl_display_get_event_loop(server->wl_display); - wl_display_set_global_filter(server->wl_display, filter_global, NULL); - wl_display_set_default_max_buffer_size(server->wl_display, 1024 * 1024); + wl_display_set_global_filter(server->wl_display, filter_global, NULL); + wl_display_set_default_max_buffer_size(server->wl_display, 1024 * 1024); - root = root_create(server->wl_display); + root = root_create(server->wl_display); - server->backend = wlr_backend_autocreate(server->wl_event_loop, &server->session); - if (!server->backend) { - sway_log(SWAY_ERROR, "Unable to create backend"); - return false; - } + server->backend = + wlr_backend_autocreate(server->wl_event_loop, &server->session); + if (!server->backend) { + sway_log(SWAY_ERROR, "Unable to create backend"); + return false; + } - wlr_multi_for_each_backend(server->backend, detect_proprietary, NULL); + wlr_multi_for_each_backend(server->backend, detect_proprietary, NULL); - server->renderer = wlr_renderer_autocreate(server->backend); - if (!server->renderer) { - sway_log(SWAY_ERROR, "Failed to create renderer"); - return false; - } + server->renderer = wlr_renderer_autocreate(server->backend); + if (!server->renderer) { + sway_log(SWAY_ERROR, "Failed to create renderer"); + return false; + } - server->renderer_lost.notify = handle_renderer_lost; - wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); + server->renderer_lost.notify = handle_renderer_lost; + wl_signal_add(&server->renderer->events.lost, &server->renderer_lost); - wlr_renderer_init_wl_shm(server->renderer, server->wl_display); + wlr_renderer_init_wl_shm(server->renderer, server->wl_display); - if (wlr_renderer_get_texture_formats(server->renderer, WLR_BUFFER_CAP_DMABUF) != NULL) { - server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( - server->wl_display, 4, server->renderer); - } - if (wlr_renderer_get_drm_fd(server->renderer) >= 0 && - server->renderer->features.timeline && - server->backend->features.timeline) { - wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1, - wlr_renderer_get_drm_fd(server->renderer)); - } + if (wlr_renderer_get_texture_formats(server->renderer, + WLR_BUFFER_CAP_DMABUF) != NULL) { + server->linux_dmabuf_v1 = wlr_linux_dmabuf_v1_create_with_renderer( + server->wl_display, 4, server->renderer); + } + if (wlr_renderer_get_drm_fd(server->renderer) >= 0 && + server->renderer->features.timeline && + server->backend->features.timeline) { + wlr_linux_drm_syncobj_manager_v1_create( + server->wl_display, 1, wlr_renderer_get_drm_fd(server->renderer)); + } - server->allocator = wlr_allocator_autocreate(server->backend, - server->renderer); - if (!server->allocator) { - sway_log(SWAY_ERROR, "Failed to create allocator"); - return false; - } + server->allocator = + wlr_allocator_autocreate(server->backend, server->renderer); + if (!server->allocator) { + sway_log(SWAY_ERROR, "Failed to create allocator"); + return false; + } - server->compositor = wlr_compositor_create(server->wl_display, 6, - server->renderer); + server->compositor = + wlr_compositor_create(server->wl_display, 6, server->renderer); - wlr_subcompositor_create(server->wl_display); + wlr_subcompositor_create(server->wl_display); - server->data_device_manager = - wlr_data_device_manager_create(server->wl_display); + server->data_device_manager = + wlr_data_device_manager_create(server->wl_display); - server->gamma_control_manager_v1 = - wlr_gamma_control_manager_v1_create(server->wl_display); - wlr_scene_set_gamma_control_manager_v1(root->root_scene, - server->gamma_control_manager_v1); + server->gamma_control_manager_v1 = + wlr_gamma_control_manager_v1_create(server->wl_display); + wlr_scene_set_gamma_control_manager_v1(root->root_scene, + server->gamma_control_manager_v1); - server->new_output.notify = handle_new_output; - wl_signal_add(&server->backend->events.new_output, &server->new_output); + server->new_output.notify = handle_new_output; + wl_signal_add(&server->backend->events.new_output, &server->new_output); - server->xdg_output_manager_v1 = - wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); + server->xdg_output_manager_v1 = + wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout); - server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); - sway_idle_inhibit_manager_v1_init(); + server->idle_notifier_v1 = wlr_idle_notifier_v1_create(server->wl_display); + sway_idle_inhibit_manager_v1_init(); - server->layer_shell = wlr_layer_shell_v1_create(server->wl_display, - SWAY_LAYER_SHELL_VERSION); - wl_signal_add(&server->layer_shell->events.new_surface, - &server->layer_shell_surface); - server->layer_shell_surface.notify = handle_layer_shell_surface; + server->layer_shell = + wlr_layer_shell_v1_create(server->wl_display, SWAY_LAYER_SHELL_VERSION); + wl_signal_add(&server->layer_shell->events.new_surface, + &server->layer_shell_surface); + server->layer_shell_surface.notify = handle_layer_shell_surface; - server->xdg_shell = wlr_xdg_shell_create(server->wl_display, - SWAY_XDG_SHELL_VERSION); - wl_signal_add(&server->xdg_shell->events.new_toplevel, - &server->xdg_shell_toplevel); - server->xdg_shell_toplevel.notify = handle_xdg_shell_toplevel; + server->xdg_shell = + wlr_xdg_shell_create(server->wl_display, SWAY_XDG_SHELL_VERSION); + wl_signal_add(&server->xdg_shell->events.new_toplevel, + &server->xdg_shell_toplevel); + server->xdg_shell_toplevel.notify = handle_xdg_shell_toplevel; - server->tablet_v2 = wlr_tablet_v2_create(server->wl_display); + server->tablet_v2 = wlr_tablet_v2_create(server->wl_display); - server->server_decoration_manager = - wlr_server_decoration_manager_create(server->wl_display); - wlr_server_decoration_manager_set_default_mode( - server->server_decoration_manager, - WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); - wl_signal_add(&server->server_decoration_manager->events.new_decoration, - &server->server_decoration); - server->server_decoration.notify = handle_server_decoration; - wl_list_init(&server->decorations); + server->server_decoration_manager = + wlr_server_decoration_manager_create(server->wl_display); + wlr_server_decoration_manager_set_default_mode( + server->server_decoration_manager, + WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + wl_signal_add(&server->server_decoration_manager->events.new_decoration, + &server->server_decoration); + server->server_decoration.notify = handle_server_decoration; + wl_list_init(&server->decorations); - server->xdg_decoration_manager = - wlr_xdg_decoration_manager_v1_create(server->wl_display); - wl_signal_add( - &server->xdg_decoration_manager->events.new_toplevel_decoration, - &server->xdg_decoration); - server->xdg_decoration.notify = handle_xdg_decoration; - wl_list_init(&server->xdg_decorations); + server->xdg_decoration_manager = + wlr_xdg_decoration_manager_v1_create(server->wl_display); + wl_signal_add(&server->xdg_decoration_manager->events.new_toplevel_decoration, + &server->xdg_decoration); + server->xdg_decoration.notify = handle_xdg_decoration; + wl_list_init(&server->xdg_decorations); - server->relative_pointer_manager = - wlr_relative_pointer_manager_v1_create(server->wl_display); + server->relative_pointer_manager = + wlr_relative_pointer_manager_v1_create(server->wl_display); - server->pointer_constraints = - wlr_pointer_constraints_v1_create(server->wl_display); - server->pointer_constraint.notify = handle_pointer_constraint; - wl_signal_add(&server->pointer_constraints->events.new_constraint, - &server->pointer_constraint); + server->pointer_constraints = + wlr_pointer_constraints_v1_create(server->wl_display); + server->pointer_constraint.notify = handle_pointer_constraint; + wl_signal_add(&server->pointer_constraints->events.new_constraint, + &server->pointer_constraint); - wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION); - wlr_alpha_modifier_v1_create(server->wl_display); + wlr_presentation_create(server->wl_display, server->backend, + SWAY_PRESENTATION_VERSION); + wlr_alpha_modifier_v1_create(server->wl_display); - server->output_manager_v1 = - wlr_output_manager_v1_create(server->wl_display); - server->output_manager_apply.notify = handle_output_manager_apply; - wl_signal_add(&server->output_manager_v1->events.apply, - &server->output_manager_apply); - server->output_manager_test.notify = handle_output_manager_test; - wl_signal_add(&server->output_manager_v1->events.test, - &server->output_manager_test); + server->output_manager_v1 = wlr_output_manager_v1_create(server->wl_display); + server->output_manager_apply.notify = handle_output_manager_apply; + wl_signal_add(&server->output_manager_v1->events.apply, + &server->output_manager_apply); + server->output_manager_test.notify = handle_output_manager_test; + wl_signal_add(&server->output_manager_v1->events.test, + &server->output_manager_test); - server->output_power_manager_v1 = - wlr_output_power_manager_v1_create(server->wl_display); - server->output_power_manager_set_mode.notify = - handle_output_power_manager_set_mode; - wl_signal_add(&server->output_power_manager_v1->events.set_mode, - &server->output_power_manager_set_mode); - server->input_method = wlr_input_method_manager_v2_create(server->wl_display); - server->text_input = wlr_text_input_manager_v3_create(server->wl_display); - server->foreign_toplevel_list = - wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION); - server->foreign_toplevel_manager = - wlr_foreign_toplevel_manager_v1_create(server->wl_display); + server->output_power_manager_v1 = + wlr_output_power_manager_v1_create(server->wl_display); + server->output_power_manager_set_mode.notify = + handle_output_power_manager_set_mode; + wl_signal_add(&server->output_power_manager_v1->events.set_mode, + &server->output_power_manager_set_mode); + server->input_method = wlr_input_method_manager_v2_create(server->wl_display); + server->text_input = wlr_text_input_manager_v3_create(server->wl_display); + server->foreign_toplevel_list = wlr_ext_foreign_toplevel_list_v1_create( + server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION); + server->foreign_toplevel_manager = + wlr_foreign_toplevel_manager_v1_create(server->wl_display); - sway_session_lock_init(); + sway_session_lock_init(); #if WLR_HAS_DRM_BACKEND - server->drm_lease_manager= - wlr_drm_lease_v1_manager_create(server->wl_display, server->backend); - if (server->drm_lease_manager) { - server->drm_lease_request.notify = handle_drm_lease_request; - wl_signal_add(&server->drm_lease_manager->events.request, - &server->drm_lease_request); - } else { - sway_log(SWAY_DEBUG, "Failed to create wlr_drm_lease_device_v1"); - sway_log(SWAY_INFO, "VR will not be available"); - } + server->drm_lease_manager = + wlr_drm_lease_v1_manager_create(server->wl_display, server->backend); + if (server->drm_lease_manager) { + server->drm_lease_request.notify = handle_drm_lease_request; + wl_signal_add(&server->drm_lease_manager->events.request, + &server->drm_lease_request); + } else { + sway_log(SWAY_DEBUG, "Failed to create wlr_drm_lease_device_v1"); + sway_log(SWAY_INFO, "VR will not be available"); + } #endif - server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display); - server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display); - server->ext_image_copy_capture_manager_v1 = wlr_ext_image_copy_capture_manager_v1_create(server->wl_display, 1); - wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1); - server->wlr_data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display); - server->ext_data_control_manager_v1 = wlr_ext_data_control_manager_v1_create(server->wl_display, 1); - server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display); - wlr_viewporter_create(server->wl_display); - wlr_single_pixel_buffer_manager_v1_create(server->wl_display); - server->content_type_manager_v1 = - wlr_content_type_manager_v1_create(server->wl_display, 1); - wlr_fractional_scale_manager_v1_create(server->wl_display, 1); + server->export_dmabuf_manager_v1 = + wlr_export_dmabuf_manager_v1_create(server->wl_display); + server->screencopy_manager_v1 = + wlr_screencopy_manager_v1_create(server->wl_display); + server->ext_image_copy_capture_manager_v1 = + wlr_ext_image_copy_capture_manager_v1_create(server->wl_display, 1); + wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1); + server->wlr_data_control_manager_v1 = + wlr_data_control_manager_v1_create(server->wl_display); + server->ext_data_control_manager_v1 = + wlr_ext_data_control_manager_v1_create(server->wl_display, 1); + server->security_context_manager_v1 = + wlr_security_context_manager_v1_create(server->wl_display); + wlr_viewporter_create(server->wl_display); + wlr_single_pixel_buffer_manager_v1_create(server->wl_display); + server->content_type_manager_v1 = + wlr_content_type_manager_v1_create(server->wl_display, 1); + wlr_fractional_scale_manager_v1_create(server->wl_display, 1); - server->ext_foreign_toplevel_image_capture_source_manager_v1 = - wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(server->wl_display, 1); - server->new_foreign_toplevel_capture_request.notify = handle_new_foreign_toplevel_capture_request; - wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1->events.new_request, - &server->new_foreign_toplevel_capture_request); + server->ext_foreign_toplevel_image_capture_source_manager_v1 = + wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create( + server->wl_display, 1); + server->new_foreign_toplevel_capture_request.notify = + handle_new_foreign_toplevel_capture_request; + wl_signal_add(&server->ext_foreign_toplevel_image_capture_source_manager_v1 + ->events.new_request, + &server->new_foreign_toplevel_capture_request); - server->tearing_control_v1 = - wlr_tearing_control_manager_v1_create(server->wl_display, 1); - server->tearing_control_new_object.notify = handle_new_tearing_hint; - wl_signal_add(&server->tearing_control_v1->events.new_object, - &server->tearing_control_new_object); - wl_list_init(&server->tearing_controllers); + server->tearing_control_v1 = + wlr_tearing_control_manager_v1_create(server->wl_display, 1); + server->tearing_control_new_object.notify = handle_new_tearing_hint; + wl_signal_add(&server->tearing_control_v1->events.new_object, + &server->tearing_control_new_object); + wl_list_init(&server->tearing_controllers); - struct wlr_xdg_foreign_registry *foreign_registry = - wlr_xdg_foreign_registry_create(server->wl_display); - wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry); - wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry); + struct wlr_xdg_foreign_registry *foreign_registry = + wlr_xdg_foreign_registry_create(server->wl_display); + wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry); + wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry); - server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display); - server->xdg_activation_v1_request_activate.notify = - xdg_activation_v1_handle_request_activate; - wl_signal_add(&server->xdg_activation_v1->events.request_activate, - &server->xdg_activation_v1_request_activate); - server->xdg_activation_v1_new_token.notify = - xdg_activation_v1_handle_new_token; - wl_signal_add(&server->xdg_activation_v1->events.new_token, - &server->xdg_activation_v1_new_token); + server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display); + server->xdg_activation_v1_request_activate.notify = + xdg_activation_v1_handle_request_activate; + wl_signal_add(&server->xdg_activation_v1->events.request_activate, + &server->xdg_activation_v1_request_activate); + server->xdg_activation_v1_new_token.notify = + xdg_activation_v1_handle_new_token; + wl_signal_add(&server->xdg_activation_v1->events.new_token, + &server->xdg_activation_v1_new_token); - struct wlr_cursor_shape_manager_v1 *cursor_shape_manager = - wlr_cursor_shape_manager_v1_create(server->wl_display, 1); - server->request_set_cursor_shape.notify = handle_request_set_cursor_shape; - wl_signal_add(&cursor_shape_manager->events.request_set_shape, &server->request_set_cursor_shape); + struct wlr_cursor_shape_manager_v1 *cursor_shape_manager = + wlr_cursor_shape_manager_v1_create(server->wl_display, 1); + server->request_set_cursor_shape.notify = handle_request_set_cursor_shape; + wl_signal_add(&cursor_shape_manager->events.request_set_shape, + &server->request_set_cursor_shape); - wl_list_init(&server->pending_launcher_ctxs); + wl_list_init(&server->pending_launcher_ctxs); - // Avoid using "wayland-0" as display socket - char name_candidate[16]; - for (unsigned int i = 1; i <= 32; ++i) { - snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i); - if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) { - server->socket = strdup(name_candidate); - break; - } - } + // Avoid using "wayland-0" as display socket + char name_candidate[16]; + for (unsigned int i = 1; i <= 32; ++i) { + snprintf(name_candidate, sizeof(name_candidate), "wayland-%u", i); + if (wl_display_add_socket(server->wl_display, name_candidate) >= 0) { + server->socket = strdup(name_candidate); + break; + } + } - if (!server->socket) { - sway_log(SWAY_ERROR, "Unable to open wayland socket"); - wlr_backend_destroy(server->backend); - return false; - } + if (!server->socket) { + sway_log(SWAY_ERROR, "Unable to open wayland socket"); + wlr_backend_destroy(server->backend); + return false; + } - server->headless_backend = wlr_headless_backend_create(server->wl_event_loop); - if (!server->headless_backend) { - sway_log(SWAY_ERROR, "Failed to create secondary headless backend"); - wlr_backend_destroy(server->backend); - return false; - } else { - wlr_multi_backend_add(server->backend, server->headless_backend); - } + server->headless_backend = wlr_headless_backend_create(server->wl_event_loop); + if (!server->headless_backend) { + sway_log(SWAY_ERROR, "Failed to create secondary headless backend"); + wlr_backend_destroy(server->backend); + return false; + } else { + wlr_multi_backend_add(server->backend, server->headless_backend); + } - struct wlr_output *wlr_output = - wlr_headless_add_output(server->headless_backend, 800, 600); - wlr_output_set_name(wlr_output, "FALLBACK"); - root->fallback_output = output_create(wlr_output); + struct wlr_output *wlr_output = + wlr_headless_add_output(server->headless_backend, 800, 600); + wlr_output_set_name(wlr_output, "FALLBACK"); + root->fallback_output = output_create(wlr_output); - // This may have been set already via -Dtxn-timeout - if (!server->txn_timeout_ms) { - server->txn_timeout_ms = 200; - } + // This may have been set already via -Dtxn-timeout + if (!server->txn_timeout_ms) { + server->txn_timeout_ms = 200; + } - server->dirty_nodes = create_list(); + server->dirty_nodes = create_list(); - server->input = input_manager_create(server); - input_manager_get_default_seat(); // create seat0 + server->input = input_manager_create(server); + input_manager_get_default_seat(); // create seat0 - return true; + return true; } void server_fini(struct sway_server *server) { - // remove listeners - wl_list_remove(&server->renderer_lost.link); - wl_list_remove(&server->new_output.link); - wl_list_remove(&server->layer_shell_surface.link); - wl_list_remove(&server->xdg_shell_toplevel.link); - wl_list_remove(&server->server_decoration.link); - wl_list_remove(&server->xdg_decoration.link); - wl_list_remove(&server->pointer_constraint.link); - wl_list_remove(&server->output_manager_apply.link); - wl_list_remove(&server->output_manager_test.link); - wl_list_remove(&server->output_power_manager_set_mode.link); + // remove listeners + wl_list_remove(&server->renderer_lost.link); + wl_list_remove(&server->new_output.link); + wl_list_remove(&server->layer_shell_surface.link); + wl_list_remove(&server->xdg_shell_toplevel.link); + wl_list_remove(&server->server_decoration.link); + wl_list_remove(&server->xdg_decoration.link); + wl_list_remove(&server->pointer_constraint.link); + wl_list_remove(&server->output_manager_apply.link); + wl_list_remove(&server->output_manager_test.link); + wl_list_remove(&server->output_power_manager_set_mode.link); #if WLR_HAS_DRM_BACKEND - if (server->drm_lease_manager) { - wl_list_remove(&server->drm_lease_request.link); - } + if (server->drm_lease_manager) { + wl_list_remove(&server->drm_lease_request.link); + } #endif - wl_list_remove(&server->tearing_control_new_object.link); - wl_list_remove(&server->xdg_activation_v1_request_activate.link); - wl_list_remove(&server->xdg_activation_v1_new_token.link); - wl_list_remove(&server->request_set_cursor_shape.link); - wl_list_remove(&server->new_foreign_toplevel_capture_request.link); - input_manager_finish(server->input); + wl_list_remove(&server->tearing_control_new_object.link); + wl_list_remove(&server->xdg_activation_v1_request_activate.link); + wl_list_remove(&server->xdg_activation_v1_new_token.link); + wl_list_remove(&server->request_set_cursor_shape.link); + wl_list_remove(&server->new_foreign_toplevel_capture_request.link); + input_manager_finish(server->input); - // TODO: free sway-specific resources + // TODO: free sway-specific resources #if WLR_HAS_XWAYLAND - if (server->xwayland.wlr_xwayland != NULL) { - wl_list_remove(&server->xwayland_surface.link); - wl_list_remove(&server->xwayland_ready.link); - wlr_xwayland_destroy(server->xwayland.wlr_xwayland); - } + if (server->xwayland.wlr_xwayland != NULL) { + wl_list_remove(&server->xwayland_surface.link); + wl_list_remove(&server->xwayland_ready.link); + wlr_xwayland_destroy(server->xwayland.wlr_xwayland); + } #endif - wl_display_destroy_clients(server->wl_display); - wlr_backend_destroy(server->backend); - wl_display_destroy(server->wl_display); - list_free(server->dirty_nodes); - free(server->socket); + wl_display_destroy_clients(server->wl_display); + wlr_backend_destroy(server->backend); + wl_display_destroy(server->wl_display); + list_free(server->dirty_nodes); +#if HAVE_LIBSFDO + sfdo_destroy(server->sfdo); +#endif + free(server->socket); } bool server_start(struct sway_server *server) { #if WLR_HAS_XWAYLAND - if (config->xwayland != XWAYLAND_MODE_DISABLED) { - sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", - config->xwayland == XWAYLAND_MODE_LAZY); - server->xwayland.wlr_xwayland = - wlr_xwayland_create(server->wl_display, server->compositor, - config->xwayland == XWAYLAND_MODE_LAZY); - if (!server->xwayland.wlr_xwayland) { - sway_log(SWAY_ERROR, "Failed to start Xwayland"); - unsetenv("DISPLAY"); - } else { - wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface, - &server->xwayland_surface); - server->xwayland_surface.notify = handle_xwayland_surface; - wl_signal_add(&server->xwayland.wlr_xwayland->events.ready, - &server->xwayland_ready); - server->xwayland_ready.notify = handle_xwayland_ready; + if (config->xwayland != XWAYLAND_MODE_DISABLED) { + sway_log(SWAY_DEBUG, "Initializing Xwayland (lazy=%d)", + config->xwayland == XWAYLAND_MODE_LAZY); + server->xwayland.wlr_xwayland = + wlr_xwayland_create(server->wl_display, server->compositor, + config->xwayland == XWAYLAND_MODE_LAZY); + if (!server->xwayland.wlr_xwayland) { + sway_log(SWAY_ERROR, "Failed to start Xwayland"); + unsetenv("DISPLAY"); + } else { + wl_signal_add(&server->xwayland.wlr_xwayland->events.new_surface, + &server->xwayland_surface); + server->xwayland_surface.notify = handle_xwayland_surface; + wl_signal_add(&server->xwayland.wlr_xwayland->events.ready, + &server->xwayland_ready); + server->xwayland_ready.notify = handle_xwayland_ready; - setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true); + setenv("DISPLAY", server->xwayland.wlr_xwayland->display_name, true); - /* xcursor configured by the default seat */ - } - } + /* xcursor configured by the default seat */ + } + } #endif - if (config->primary_selection) { - wlr_primary_selection_v1_device_manager_create(server->wl_display); - } + if (config->primary_selection) { + wlr_primary_selection_v1_device_manager_create(server->wl_display); + } - sway_log(SWAY_INFO, "Starting backend on wayland display '%s'", - server->socket); - if (!wlr_backend_start(server->backend)) { - sway_log(SWAY_ERROR, "Failed to start backend"); - wlr_backend_destroy(server->backend); - return false; - } + sway_log(SWAY_INFO, "Starting backend on wayland display '%s'", + server->socket); + if (!wlr_backend_start(server->backend)) { + sway_log(SWAY_ERROR, "Failed to start backend"); + wlr_backend_destroy(server->backend); + return false; + } - return true; +#if HAVE_LIBSFDO + // TODO: allow configurability of global sway icon theme if and when + // it is applicable (titlebar icons? ssd icons?) + server->sfdo = sfdo_create("Hicolor"); +#endif + + return true; } void server_run(struct sway_server *server) { - sway_log(SWAY_INFO, "Running compositor on wayland display '%s'", - server->socket); - wl_display_run(server->wl_display); + sway_log(SWAY_INFO, "Running compositor on wayland display '%s'", + server->socket); + wl_display_run(server->wl_display); } + +#if HAVE_LIBSFDO +struct sfdo *sfdo_create(char *theme) { + struct sfdo *sfdo = calloc(1, sizeof(struct sfdo)); + if (!sfdo) { + goto error_calloc; + } + + struct sfdo_basedir_ctx *basedir_ctx = sfdo_basedir_ctx_create(); + if (!basedir_ctx) { + goto error_basedir_ctx; + } + + sfdo->desktop_ctx = sfdo_desktop_ctx_create(basedir_ctx); + if (!sfdo->desktop_ctx) { + goto error_desktop_ctx; + } + + sfdo->icon_ctx = sfdo_icon_ctx_create(basedir_ctx); + if (!sfdo->icon_ctx) { + goto error_icon_ctx; + } + + sfdo->desktop_db = sfdo_desktop_db_load(sfdo->desktop_ctx, NULL); + if (!sfdo->desktop_db) { + goto error_desktop_db; + } + + int load_options = SFDO_ICON_THEME_LOAD_OPTIONS_DEFAULT | + SFDO_ICON_THEME_LOAD_OPTION_ALLOW_MISSING | + SFDO_ICON_THEME_LOAD_OPTION_RELAXED; + + sfdo->icon_theme = sfdo_icon_theme_load(sfdo->icon_ctx, theme, load_options); + if (!sfdo->icon_theme) { + goto error_icon_theme; + } + + sfdo_basedir_ctx_destroy(basedir_ctx); + + sway_log(SWAY_DEBUG, "Successfully setup sfdo"); + return sfdo; + +error_icon_theme: + sfdo_desktop_db_destroy(sfdo->desktop_db); +error_desktop_db: + sfdo_icon_ctx_destroy(sfdo->icon_ctx); +error_icon_ctx: + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); +error_desktop_ctx: + sfdo_basedir_ctx_destroy(basedir_ctx); +error_basedir_ctx: + free(sfdo); +error_calloc: + sway_log(SWAY_ERROR, "Failed to setup sfdo"); + return NULL; +} + +void sfdo_destroy(struct sfdo *sfdo) { + if (!sfdo) { + sway_log(SWAY_DEBUG, "Null sfdo passed in"); + return; + } + + sfdo_icon_theme_destroy(sfdo->icon_theme); + sfdo_desktop_db_destroy(sfdo->desktop_db); + sfdo_icon_ctx_destroy(sfdo->icon_ctx); + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); + sway_log(SWAY_DEBUG, "Successfully destroyed sfdo"); +} +#endif From 478c77a69bb978ca69a210d97bfc1e56d42d94ad Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Tue, 29 Apr 2025 17:37:58 +0000 Subject: [PATCH 3/6] Finds paths to icon files using libsfdo. Libsfdo is currently an optional compile time dependency. This means the former code paths are all retained and new ones are wrapped in #if HAVE_LIBSFDO. Behavior should be identical now between the two code paths. Later commits will add the handling of icons specified as absolute paths which both former swaybar code and libsfdo have thus far avoided. --- common/meson.build | 1 + common/sfdo.c | 95 ++++++++++++++++++++++++++++++++++++++++ include/sfdo.h | 19 ++++++++ include/sway/config.h | 5 ++- include/sway/server.h | 20 ++------- include/swaybar/bar.h | 8 ++++ include/swaybar/config.h | 13 +++++- sway/config/bar.c | 15 +++++++ sway/server.c | 4 +- swaybar/bar.c | 3 ++ swaybar/config.c | 14 ++++++ swaybar/ipc.c | 8 ++++ swaybar/meson.build | 9 ++++ swaybar/tray/item.c | 29 +++++++++++- 14 files changed, 220 insertions(+), 23 deletions(-) create mode 100644 common/sfdo.c create mode 100644 include/sfdo.h diff --git a/common/meson.build b/common/meson.build index c0ce1f681..c21aa9e45 100644 --- a/common/meson.build +++ b/common/meson.build @@ -8,6 +8,7 @@ lib_sway_common = static_library( 'loop.c', 'list.c', 'pango.c', + 'sfdo.c', 'stringop.c', 'util.c' ), diff --git a/common/sfdo.c b/common/sfdo.c new file mode 100644 index 000000000..a31c87698 --- /dev/null +++ b/common/sfdo.c @@ -0,0 +1,95 @@ +#include +#include +#include +#include + +#include "log.h" +#include "sfdo.h" + +char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale) { + int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; + struct sfdo_icon_file *icon_file = \ + sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ + target_size, scale, lookup_options); + char *icon_path = NULL; + if (icon_file && icon_file != SFDO_ICON_FILE_INVALID) { + icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + } + sfdo_icon_file_destroy(icon_file); + return icon_path; +} + +struct sfdo *sfdo_create(char *icon_theme) { + if (!icon_theme) { + goto error_null; + } + + struct sfdo *sfdo = calloc(1, sizeof(struct sfdo)); + if (!sfdo) { + goto error_calloc; + } + + struct sfdo_basedir_ctx *basedir_ctx = sfdo_basedir_ctx_create(); + if (!basedir_ctx) { + goto error_basedir_ctx; + } + + sfdo->desktop_ctx = sfdo_desktop_ctx_create(basedir_ctx); + if (!sfdo->desktop_ctx) { + goto error_desktop_ctx; + } + + sfdo->icon_ctx = sfdo_icon_ctx_create(basedir_ctx); + if (!sfdo->icon_ctx) { + goto error_icon_ctx; + } + + sfdo->desktop_db = sfdo_desktop_db_load(sfdo->desktop_ctx, NULL); + if (!sfdo->desktop_db) { + goto error_desktop_db; + } + + int load_options = SFDO_ICON_THEME_LOAD_OPTIONS_DEFAULT + | SFDO_ICON_THEME_LOAD_OPTION_ALLOW_MISSING + | SFDO_ICON_THEME_LOAD_OPTION_RELAXED; + + sfdo->icon_theme = sfdo_icon_theme_load(sfdo->icon_ctx, icon_theme, load_options); + if (!sfdo->icon_theme) { + goto error_icon_theme; + } + + sfdo_basedir_ctx_destroy(basedir_ctx); + + sway_log(SWAY_INFO, "Successfully setup sfdo with icon theme %s", icon_theme); + return sfdo; + +error_icon_theme: + sfdo_desktop_db_destroy(sfdo->desktop_db); +error_desktop_db: + sfdo_icon_ctx_destroy(sfdo->icon_ctx); +error_icon_ctx: + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); +error_desktop_ctx: + sfdo_basedir_ctx_destroy(basedir_ctx); +error_basedir_ctx: + free(sfdo); +error_calloc: +error_null: + // it's safe to call with null + sway_log(SWAY_ERROR, "Failed to setup sfdo with icon theme %s", icon_theme); + return NULL; +} + +void sfdo_destroy(struct sfdo *sfdo) { + if (!sfdo) { + sway_log(SWAY_DEBUG, "Null sfdo passed in"); + return; + } + + sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); + sfdo_icon_ctx_destroy(sfdo->icon_ctx); + sfdo_desktop_db_destroy(sfdo->desktop_db); + sfdo_icon_theme_destroy(sfdo->icon_theme); + free(sfdo); + sway_log(SWAY_DEBUG, "Successfully destroyed sfdo"); +} diff --git a/include/sfdo.h b/include/sfdo.h new file mode 100644 index 000000000..a009f3963 --- /dev/null +++ b/include/sfdo.h @@ -0,0 +1,19 @@ +#ifndef _SWAY_SFDO_H +#define _SWAY_SFDO_H + +#include +#include +#include + +struct sfdo { + struct sfdo_desktop_ctx *desktop_ctx; + struct sfdo_icon_ctx *icon_ctx; + struct sfdo_desktop_db *desktop_db; + struct sfdo_icon_theme *icon_theme; +}; + +char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale); +struct sfdo *sfdo_create(char *icon_theme); +void sfdo_destroy(struct sfdo *sfdo); + +#endif diff --git a/include/sway/config.h b/include/sway/config.h index bb770c6f7..75385b2dd 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -399,8 +399,11 @@ struct bar_config { char *binding_mode_text; } colors; -#if HAVE_TRAY +#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; +#endif + +#if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link list_t *tray_outputs; // char * int tray_padding; diff --git a/include/sway/server.h b/include/sway/server.h index 13da0d605..9202cb562 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -8,11 +8,11 @@ #if WLR_HAS_XWAYLAND #include "sway/xwayland.h" #endif + #if HAVE_LIBSFDO -#include -#include -#include +#include "sfdo.h" #endif + struct sway_transaction; struct sway_session_lock { @@ -28,15 +28,6 @@ struct sway_session_lock { struct wl_listener destroy; }; -#if HAVE_LIBSFDO -struct sfdo { - struct sfdo_desktop_ctx *desktop_ctx; - struct sfdo_icon_ctx *icon_ctx; - struct sfdo_desktop_db *desktop_db; - struct sfdo_icon_theme *icon_theme; -}; -#endif - struct sway_server { struct wl_display *wl_display; struct wl_event_loop *wl_event_loop; @@ -210,9 +201,4 @@ void set_rr_scheduling(void); void handle_new_tearing_hint(struct wl_listener *listener, void *data); -#if HAVE_LIBSFDO -struct sfdo *sfdo_create(char *theme); -void sfdo_destroy(struct sfdo *sfdo); -#endif - #endif diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 197d21901..311993372 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -16,6 +16,10 @@ struct swaybar_tray; struct swaybar_workspace; struct loop; +#if HAVE_LIBSFDO +struct sfdo; +#endif + struct swaybar { char *id; char *mode; @@ -50,6 +54,10 @@ struct swaybar { struct swaybar_tray *tray; #endif +#if HAVE_LIBSFDO + struct sfdo *sfdo; +#endif + bool running; }; diff --git a/include/swaybar/config.h b/include/swaybar/config.h index ad58b3c3c..8433b8c78 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -8,6 +8,10 @@ #include "util.h" #include +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + struct box_colors { uint32_t border; uint32_t background; @@ -73,13 +77,20 @@ struct swaybar_config { struct box_colors binding_mode; } colors; -#if HAVE_TRAY +#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; +#endif + +#if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link bool tray_hidden; list_t *tray_outputs; // char * int tray_padding; #endif + +#if HAVE_LIBSFDO + struct sfdo *sfdo; +#endif }; #if HAVE_TRAY diff --git a/sway/config/bar.c b/sway/config/bar.c index f4efb276c..58734a11e 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -70,6 +70,14 @@ void free_bar_config(struct bar_config *bar) { free(bar->colors.binding_mode_border); free(bar->colors.binding_mode_bg); free(bar->colors.binding_mode_text); + + // this is to cover the case where tray support is not compiled in + // but we have libsfdo support which implies at least a default + // icon_theme string was allocated +#if HAVE_LIBSFDO && !HAVE_TRAY + free(bar->icone_theme); +#endif + #if HAVE_TRAY list_free_items_and_destroy(bar->tray_outputs); free(bar->icon_theme); @@ -170,6 +178,13 @@ struct bar_config *default_bar_config(void) { bar->colors.binding_mode_bg = NULL; bar->colors.binding_mode_text = NULL; + // we need some default when we initialize sfdo +#if HAVE_LIBSFDO + if (!(bar->icon_theme = strdup("Hicolor"))) { + goto cleanup; + } +#endif + #if HAVE_TRAY bar->tray_padding = 2; wl_list_init(&bar->tray_bindings); diff --git a/sway/server.c b/sway/server.c index 4794f6f50..841c61cce 100644 --- a/sway/server.c +++ b/sway/server.c @@ -70,9 +70,7 @@ #endif #if HAVE_LIBSFDO -#include -#include -#include +#include "sfdo.h" #endif #define SWAY_XDG_SHELL_VERSION 5 diff --git a/swaybar/bar.c b/swaybar/bar.c index 4d20f20f0..5d7854b3c 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -537,6 +537,9 @@ static void free_seats(struct wl_list *list) { void bar_teardown(struct swaybar *bar) { #if HAVE_TRAY destroy_tray(bar->tray); +#endif +#if HAVE_LIBSFDO + sfdo_destroy(bar->config->sfdo); #endif free_outputs(&bar->outputs); free_outputs(&bar->unused_outputs); diff --git a/swaybar/config.c b/swaybar/config.c index 55bfcb722..9e17a7128 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -7,6 +7,10 @@ #include "list.h" #include "log.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + uint32_t parse_position(const char *position) { uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; @@ -131,5 +135,15 @@ void free_config(struct swaybar_config *config) { free(config->icon_theme); #endif + +#if HAVE_LIBSFDO && !HAVE_TRAY + free(config->icon_theme); +#endif + +#if HAVE_LIBSFDO + sfdo_destroy(config->sfdo); + sway_log(SWAY_DEBUG, "Destroyed swaybar sfdo"); +#endif + free(config); } diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 68d8dd32d..e1a6283da 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -18,6 +18,10 @@ #include "stringop.h" #include "util.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { uint32_t size = strlen("workspace \"\"") + strlen(ws); for (size_t i = 0; i < strlen(ws); ++i) { @@ -330,6 +334,10 @@ static bool ipc_parse_config( if ((json_object_object_get_ex(bar_config, "icon_theme", &icon_theme))) { config->icon_theme = strdup(json_object_get_string(icon_theme)); +#if HAVE_LIBSFDO + sfdo_destroy(config->sfdo); + config->sfdo = sfdo_create(config->icon_theme); +#endif } #endif diff --git a/swaybar/meson.build b/swaybar/meson.build index 34bbdeea9..6a1d17461 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build @@ -21,6 +21,15 @@ if have_tray swaybar_deps += sdbus endif +if have_libsfdo + swaybar_deps += [ + sfdo_basedir, + sfdo_desktop, + sfdo_desktop_file, + sfdo_icon + ] +endif + executable( 'swaybar', [ 'bar.c', diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 12929743b..455feda4a 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,6 +20,10 @@ #include "stringop.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" +#if HAVE_LIBSFDO +#include "sfdo.h" +#endif + // TODO menu static bool sni_ready(struct swaybar_sni *sni) { @@ -420,15 +426,36 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, char *icon_name = sni->status[0] == 'N' ? sni->attention_icon_name : sni->icon_name; if (icon_name) { + char *icon_path = NULL; +#if !HAVE_LIBSFDO list_t *icon_search_paths = create_list(); list_cat(icon_search_paths, sni->tray->basedirs); if (sni->icon_theme_path) { list_add(icon_search_paths, sni->icon_theme_path); } - char *icon_path = find_icon(sni->tray->themes, icon_search_paths, + icon_path = find_icon(sni->tray->themes, icon_search_paths, icon_name, target_size, icon_theme, &sni->min_size, &sni->max_size); +#else + struct sfdo *sfdo = sni->tray->bar->config->sfdo; + if (sfdo) { + int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; + int scale = 1; + struct sfdo_icon_file *icon_file = \ + sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ + target_size, scale, lookup_options); + if (!icon_file || icon_file == SFDO_ICON_FILE_INVALID) { + sway_log(SWAY_ERROR, "sfdo: icon %s invalid or not found in theme %s at size %d", \ + icon_name, icon_theme, target_size); + } else { + icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + } + sfdo_icon_file_destroy(icon_file); + } +#endif +#if !HAVE_LIBSFDO list_free(icon_search_paths); +#endif if (icon_path) { cairo_surface_destroy(sni->icon); sni->icon = load_image(icon_path); From c8cc27c49ef4a78834b2aebaee399e8b154605af Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Wed, 30 Apr 2025 02:32:07 +0000 Subject: [PATCH 4/6] Extends former behavior to include loading of icons if they are specified as an absolute path. Fixes size selection for SVG (scalable) icons relying on whose nominal size read via gdk-pixbuf loader may not correctly indicate that they can be scaled to neatly fill the available scale e.g., symbolic icons from Adwaita specify a nominal size of 16x16. --- common/sfdo.c | 23 ++++++++++++++++------- include/swaybar/image.h | 2 +- swaybar/image.c | 20 ++++++++++++++++++-- swaybar/tray/item.c | 28 +++++++++++++++------------- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/common/sfdo.c b/common/sfdo.c index a31c87698..e2e685650 100644 --- a/common/sfdo.c +++ b/common/sfdo.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,16 +7,24 @@ #include "log.h" #include "sfdo.h" +// this extends libsfdo's behavior to also handle icons specified as absolute paths char *sfdo_icon_lookup_extended(struct sfdo *sfdo, char *icon_name, int target_size, int scale) { - int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; - struct sfdo_icon_file *icon_file = \ - sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ - target_size, scale, lookup_options); char *icon_path = NULL; - if (icon_file && icon_file != SFDO_ICON_FILE_INVALID) { - icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + if (icon_name[0] == '/') { + struct stat sb; + if (!stat(icon_name, &sb)) { + icon_path = strdup(icon_name); + } + } else { + int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; + struct sfdo_icon_file *icon_file = \ + sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ + target_size, scale, lookup_options); + if (icon_file && icon_file != SFDO_ICON_FILE_INVALID) { + icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); + } + sfdo_icon_file_destroy(icon_file); } - sfdo_icon_file_destroy(icon_file); return icon_path; } diff --git a/include/swaybar/image.h b/include/swaybar/image.h index 53a210dd7..332e81152 100644 --- a/include/swaybar/image.h +++ b/include/swaybar/image.h @@ -2,6 +2,6 @@ #define _SWAYBAR_IMAGE_H #include -cairo_surface_t *load_image(const char *path); +cairo_surface_t *load_image(const char *path, int target_size, int scale); #endif diff --git a/swaybar/image.c b/swaybar/image.c index ed24b9f99..f3ba2082d 100644 --- a/swaybar/image.c +++ b/swaybar/image.c @@ -104,11 +104,27 @@ static cairo_surface_t* gdk_cairo_image_surface_create_from_pixbuf( } #endif // HAVE_GDK_PIXBUF -cairo_surface_t *load_image(const char *path) { +cairo_surface_t *load_image(const char *path, int target_size, int scale) { cairo_surface_t *image; #if HAVE_GDK_PIXBUF GError *err = NULL; - GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(path, &err); + GdkPixbuf *pixbuf = NULL; + // svg images should be loaded at target size. the size read from an svg + // file is only nominal and can lead to an image too small for the avaialble + // space compared to bitmap icons selected at the nearest available size + int i = strlen(path) - 1; + // this is naive and assumes ascii, utf-8, or another encoding + // that encodes these letters as single bytes + if ((i > 2) && + (path[i] == 'g' || path[i] == 'G') && \ + (path[i - 1] == 'v' || path[i - 1] == 'V') && \ + (path[i - 2] == 's' || path[i - 2] == 'S') && \ + (path[i - 3] == '.' )) { + pixbuf = gdk_pixbuf_new_from_file_at_scale(path, -1, target_size, \ + true, &err); + } else { + pixbuf = gdk_pixbuf_new_from_file(path, &err); + } if (!pixbuf) { sway_log(SWAY_ERROR, "Failed to load background image (%s).", err->message); diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index 455feda4a..e7b8d4231 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -421,8 +421,7 @@ static enum hotspot_event_handling icon_hotspot_callback( return HOTSPOT_PROCESS; } -static void reload_sni(struct swaybar_sni *sni, char *icon_theme, - int target_size) { +static void reload_sni(struct swaybar_sni *sni, char *icon_theme, int target_size) { char *icon_name = sni->status[0] == 'N' ? sni->attention_icon_name : sni->icon_name; if (icon_name) { @@ -437,20 +436,15 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, icon_name, target_size, icon_theme, &sni->min_size, &sni->max_size); #else + // TODO: at some point we will need to make this scaling-aware + int scale = 1; struct sfdo *sfdo = sni->tray->bar->config->sfdo; if (sfdo) { - int lookup_options = SFDO_ICON_THEME_LOOKUP_OPTIONS_DEFAULT; - int scale = 1; - struct sfdo_icon_file *icon_file = \ - sfdo_icon_theme_lookup(sfdo->icon_theme, icon_name, SFDO_NT, \ - target_size, scale, lookup_options); - if (!icon_file || icon_file == SFDO_ICON_FILE_INVALID) { - sway_log(SWAY_ERROR, "sfdo: icon %s invalid or not found in theme %s at size %d", \ + icon_path = sfdo_icon_lookup_extended(sfdo, icon_name, target_size, scale); + if (!icon_path) { + sway_log(SWAY_DEBUG, "sfdo: icon %s invalid or not found in theme %s at size %d", \ icon_name, icon_theme, target_size); - } else { - icon_path = strdup(sfdo_icon_file_get_path(icon_file, NULL)); } - sfdo_icon_file_destroy(icon_file); } #endif #if !HAVE_LIBSFDO @@ -458,9 +452,17 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, #endif if (icon_path) { cairo_surface_destroy(sni->icon); - sni->icon = load_image(icon_path); + sni->icon = load_image(icon_path, target_size, scale); free(icon_path); return; + } else { + // the :( icon won't be drawn for a missing icon and whichever old icon was + // loaded will persist if this is not done. one might not have noticed this + // for tray items that have only one icon loaded only once, successfully or + // unsuccessfully. items with multiple icons, such as fcitx5 or other input + // method frameworks make the problem apparent + free(sni->icon); + sni->icon = NULL; } } From 087267347269c6b94dda431051c151c1cadf6ae8 Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:10:01 +0000 Subject: [PATCH 5/6] Make libsfdo a hard dependency. --- meson.build | 34 ++++------------------------------ sway/meson.build | 13 ++++--------- swaybar/meson.build | 13 ++++--------- 3 files changed, 12 insertions(+), 48 deletions(-) diff --git a/meson.build b/meson.build index f22fa7be2..a8f3f6ad6 100644 --- a/meson.build +++ b/meson.build @@ -60,34 +60,10 @@ endforeach null_dep = dependency('', required: false) -# Check for (currrently) optional libsfdo -sfdo_basedir = dependency( - 'libsfdo-basedir', - version: '>=0.1.3', - required: get_option('sfdo') -) -sfdo_desktop = dependency( - 'libsfdo-desktop', - version: '>=0.1.3', - required: get_option('sfdo') -) -sfdo_desktop_file = dependency( - 'libsfdo-desktop-file', - version: '>=0.1.3', - required: get_option('sfdo') -) -sfdo_icon = dependency( - 'libsfdo-icon', - version: '>=0.1.3', - required: get_option('sfdo') -) -have_libsfdo = ( - sfdo_basedir.found() and - sfdo_desktop.found() and - sfdo_desktop_file.found() and - sfdo_icon.found() -) - +libsfdo_basedir = dependency('libsfdo-basedir', version: '>=0.1.3') +libsfdo_desktop = dependency('libsfdo-desktop', version: '>=0.1.3') +libsfdo_desktop_file = dependency('libsfdo-desktop-file', version: '>=0.1.3') +libsfdo_icon = dependency('libsfdo-icon', version: '>=0.1.3') jsonc = dependency('json-c', version: '>=0.13') pcre2 = dependency('libpcre2-8') wayland_server = dependency('wayland-server', version: '>=1.21.0') @@ -136,7 +112,6 @@ conf_data = configuration_data() conf_data.set10('HAVE_GDK_PIXBUF', gdk_pixbuf.found()) conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd') conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind') -conf_data.set10('HAVE_LIBSFDO', have_libsfdo) conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu') conf_data.set10('HAVE_TRAY', have_tray) foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY'] @@ -273,6 +248,5 @@ subdir('completions') summary({ 'gdk-pixbuf': gdk_pixbuf.found(), 'tray': have_tray, - 'libsfdo': have_libsfdo, 'man-pages': scdoc.found(), }, bool_yn: true) diff --git a/sway/meson.build b/sway/meson.build index 865049d82..9bc83e460 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -218,6 +218,10 @@ sway_sources = files( ) sway_deps = [ + libsfdo_basedir, + libsfdo_desktop, + libsfdo_desktop_file, + libsfdo_icon, cairo, drm, jsonc, @@ -244,15 +248,6 @@ if wlroots_features['libinput_backend'] sway_sources += 'input/libinput.c' endif -if have_libsfdo - sway_deps += [ - sfdo_basedir, - sfdo_desktop, - sfdo_desktop_file, - sfdo_icon - ] -endif - executable( 'sway', sway_sources + wl_protos_src, diff --git a/swaybar/meson.build b/swaybar/meson.build index 6a1d17461..f7b54ba7c 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build @@ -7,6 +7,10 @@ tray_files = have_tray ? [ ] : [] swaybar_deps = [ + libsfdo_basedir, + libsfdo_desktop, + libsfdo_desktop_file, + libsfdo_icon, cairo, gdk_pixbuf, jsonc, @@ -21,15 +25,6 @@ if have_tray swaybar_deps += sdbus endif -if have_libsfdo - swaybar_deps += [ - sfdo_basedir, - sfdo_desktop, - sfdo_desktop_file, - sfdo_icon - ] -endif - executable( 'swaybar', [ 'bar.c', From 6d7c0d52d64d5faa75aaf498d9599114a9d4c2d8 Mon Sep 17 00:00:00 2001 From: myrslint <206005528+myrslint@users.noreply.github.com> Date: Wed, 2 Jul 2025 21:59:38 +0000 Subject: [PATCH 6/6] Remove conditionals and old code for locating and loading icons With libsfdo a hard dependency we can locate and load icons always, regardless of whether we have tray or not. Old locating and loading code can also be removed. --- include/sway/config.h | 2 -- include/sway/server.h | 5 --- include/swaybar/bar.h | 4 --- include/swaybar/config.h | 6 ---- sway/config/bar.c | 13 +++---- sway/server.c | 76 ---------------------------------------- swaybar/bar.c | 2 -- swaybar/config.c | 9 ----- swaybar/ipc.c | 8 ++--- swaybar/tray/item.c | 16 --------- 10 files changed, 7 insertions(+), 134 deletions(-) diff --git a/include/sway/config.h b/include/sway/config.h index 75385b2dd..aa151d985 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -399,9 +399,7 @@ struct bar_config { char *binding_mode_text; } colors; -#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; -#endif #if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link diff --git a/include/sway/server.h b/include/sway/server.h index 9202cb562..b1053d25f 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -9,9 +9,7 @@ #include "sway/xwayland.h" #endif -#if HAVE_LIBSFDO #include "sfdo.h" -#endif struct sway_transaction; @@ -151,10 +149,7 @@ struct sway_server { struct wl_event_source *delayed_modeset; -#if HAVE_LIBSFDO struct sfdo *sfdo; -#endif - }; extern struct sway_server server; diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index 311993372..cbfa3df04 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h @@ -16,9 +16,7 @@ struct swaybar_tray; struct swaybar_workspace; struct loop; -#if HAVE_LIBSFDO struct sfdo; -#endif struct swaybar { char *id; @@ -54,9 +52,7 @@ struct swaybar { struct swaybar_tray *tray; #endif -#if HAVE_LIBSFDO struct sfdo *sfdo; -#endif bool running; }; diff --git a/include/swaybar/config.h b/include/swaybar/config.h index 8433b8c78..b360dbf0e 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h @@ -8,9 +8,7 @@ #include "util.h" #include -#if HAVE_LIBSFDO #include "sfdo.h" -#endif struct box_colors { uint32_t border; @@ -77,9 +75,7 @@ struct swaybar_config { struct box_colors binding_mode; } colors; -#if HAVE_TRAY || HAVE_LIBSFDO char *icon_theme; -#endif #if HAVE_TRAY struct wl_list tray_bindings; // struct tray_binding::link @@ -88,9 +84,7 @@ struct swaybar_config { int tray_padding; #endif -#if HAVE_LIBSFDO struct sfdo *sfdo; -#endif }; #if HAVE_TRAY diff --git a/sway/config/bar.c b/sway/config/bar.c index 58734a11e..93b217dff 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c @@ -71,16 +71,13 @@ void free_bar_config(struct bar_config *bar) { free(bar->colors.binding_mode_bg); free(bar->colors.binding_mode_text); - // this is to cover the case where tray support is not compiled in - // but we have libsfdo support which implies at least a default - // icon_theme string was allocated -#if HAVE_LIBSFDO && !HAVE_TRAY - free(bar->icone_theme); -#endif + // since libsfdo is a hard depedency now we always have at least + // a default icon theme and need to free the string that contains + // its name + free(bar->icon_theme); #if HAVE_TRAY list_free_items_and_destroy(bar->tray_outputs); - free(bar->icon_theme); struct tray_binding *tray_bind = NULL, *tmp_tray_bind = NULL; wl_list_for_each_safe(tray_bind, tmp_tray_bind, &bar->tray_bindings, link) { @@ -179,11 +176,9 @@ struct bar_config *default_bar_config(void) { bar->colors.binding_mode_text = NULL; // we need some default when we initialize sfdo -#if HAVE_LIBSFDO if (!(bar->icon_theme = strdup("Hicolor"))) { goto cleanup; } -#endif #if HAVE_TRAY bar->tray_padding = 2; diff --git a/sway/server.c b/sway/server.c index 841c61cce..e4fe3944a 100644 --- a/sway/server.c +++ b/sway/server.c @@ -69,9 +69,7 @@ #include #endif -#if HAVE_LIBSFDO #include "sfdo.h" -#endif #define SWAY_XDG_SHELL_VERSION 5 #define SWAY_LAYER_SHELL_VERSION 4 @@ -545,9 +543,7 @@ void server_fini(struct sway_server *server) { wlr_backend_destroy(server->backend); wl_display_destroy(server->wl_display); list_free(server->dirty_nodes); -#if HAVE_LIBSFDO sfdo_destroy(server->sfdo); -#endif free(server->socket); } @@ -589,11 +585,9 @@ bool server_start(struct sway_server *server) { return false; } -#if HAVE_LIBSFDO // TODO: allow configurability of global sway icon theme if and when // it is applicable (titlebar icons? ssd icons?) server->sfdo = sfdo_create("Hicolor"); -#endif return true; } @@ -603,73 +597,3 @@ void server_run(struct sway_server *server) { server->socket); wl_display_run(server->wl_display); } - -#if HAVE_LIBSFDO -struct sfdo *sfdo_create(char *theme) { - struct sfdo *sfdo = calloc(1, sizeof(struct sfdo)); - if (!sfdo) { - goto error_calloc; - } - - struct sfdo_basedir_ctx *basedir_ctx = sfdo_basedir_ctx_create(); - if (!basedir_ctx) { - goto error_basedir_ctx; - } - - sfdo->desktop_ctx = sfdo_desktop_ctx_create(basedir_ctx); - if (!sfdo->desktop_ctx) { - goto error_desktop_ctx; - } - - sfdo->icon_ctx = sfdo_icon_ctx_create(basedir_ctx); - if (!sfdo->icon_ctx) { - goto error_icon_ctx; - } - - sfdo->desktop_db = sfdo_desktop_db_load(sfdo->desktop_ctx, NULL); - if (!sfdo->desktop_db) { - goto error_desktop_db; - } - - int load_options = SFDO_ICON_THEME_LOAD_OPTIONS_DEFAULT | - SFDO_ICON_THEME_LOAD_OPTION_ALLOW_MISSING | - SFDO_ICON_THEME_LOAD_OPTION_RELAXED; - - sfdo->icon_theme = sfdo_icon_theme_load(sfdo->icon_ctx, theme, load_options); - if (!sfdo->icon_theme) { - goto error_icon_theme; - } - - sfdo_basedir_ctx_destroy(basedir_ctx); - - sway_log(SWAY_DEBUG, "Successfully setup sfdo"); - return sfdo; - -error_icon_theme: - sfdo_desktop_db_destroy(sfdo->desktop_db); -error_desktop_db: - sfdo_icon_ctx_destroy(sfdo->icon_ctx); -error_icon_ctx: - sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); -error_desktop_ctx: - sfdo_basedir_ctx_destroy(basedir_ctx); -error_basedir_ctx: - free(sfdo); -error_calloc: - sway_log(SWAY_ERROR, "Failed to setup sfdo"); - return NULL; -} - -void sfdo_destroy(struct sfdo *sfdo) { - if (!sfdo) { - sway_log(SWAY_DEBUG, "Null sfdo passed in"); - return; - } - - sfdo_icon_theme_destroy(sfdo->icon_theme); - sfdo_desktop_db_destroy(sfdo->desktop_db); - sfdo_icon_ctx_destroy(sfdo->icon_ctx); - sfdo_desktop_ctx_destroy(sfdo->desktop_ctx); - sway_log(SWAY_DEBUG, "Successfully destroyed sfdo"); -} -#endif diff --git a/swaybar/bar.c b/swaybar/bar.c index 5d7854b3c..8f808fa93 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c @@ -538,9 +538,7 @@ void bar_teardown(struct swaybar *bar) { #if HAVE_TRAY destroy_tray(bar->tray); #endif -#if HAVE_LIBSFDO sfdo_destroy(bar->config->sfdo); -#endif free_outputs(&bar->outputs); free_outputs(&bar->unused_outputs); free_seats(&bar->seats); diff --git a/swaybar/config.c b/swaybar/config.c index 9e17a7128..eb8b1a064 100644 --- a/swaybar/config.c +++ b/swaybar/config.c @@ -7,9 +7,7 @@ #include "list.h" #include "log.h" -#if HAVE_LIBSFDO #include "sfdo.h" -#endif uint32_t parse_position(const char *position) { uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | @@ -132,18 +130,11 @@ void free_config(struct swaybar_config *config) { wl_list_remove(&tray_bind->link); free_tray_binding(tray_bind); } - - free(config->icon_theme); #endif -#if HAVE_LIBSFDO && !HAVE_TRAY free(config->icon_theme); -#endif - -#if HAVE_LIBSFDO sfdo_destroy(config->sfdo); sway_log(SWAY_DEBUG, "Destroyed swaybar sfdo"); -#endif free(config); } diff --git a/swaybar/ipc.c b/swaybar/ipc.c index e1a6283da..2e38775a5 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c @@ -18,9 +18,7 @@ #include "stringop.h" #include "util.h" -#if HAVE_LIBSFDO #include "sfdo.h" -#endif void ipc_send_workspace_command(struct swaybar *bar, const char *ws) { uint32_t size = strlen("workspace \"\"") + strlen(ws); @@ -332,14 +330,14 @@ static bool ipc_parse_config( } } +#endif + + // whether or not there is a tray, we now always have an icon theme if ((json_object_object_get_ex(bar_config, "icon_theme", &icon_theme))) { config->icon_theme = strdup(json_object_get_string(icon_theme)); -#if HAVE_LIBSFDO sfdo_destroy(config->sfdo); config->sfdo = sfdo_create(config->icon_theme); -#endif } -#endif json_object_put(bar_config); return true; diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index e7b8d4231..6ee5bf505 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c @@ -20,9 +20,7 @@ #include "stringop.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h" -#if HAVE_LIBSFDO #include "sfdo.h" -#endif // TODO menu @@ -426,16 +424,6 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, int target_siz sni->attention_icon_name : sni->icon_name; if (icon_name) { char *icon_path = NULL; -#if !HAVE_LIBSFDO - list_t *icon_search_paths = create_list(); - list_cat(icon_search_paths, sni->tray->basedirs); - if (sni->icon_theme_path) { - list_add(icon_search_paths, sni->icon_theme_path); - } - icon_path = find_icon(sni->tray->themes, icon_search_paths, - icon_name, target_size, icon_theme, - &sni->min_size, &sni->max_size); -#else // TODO: at some point we will need to make this scaling-aware int scale = 1; struct sfdo *sfdo = sni->tray->bar->config->sfdo; @@ -446,10 +434,6 @@ static void reload_sni(struct swaybar_sni *sni, char *icon_theme, int target_siz icon_name, icon_theme, target_size); } } -#endif -#if !HAVE_LIBSFDO - list_free(icon_search_paths); -#endif if (icon_path) { cairo_surface_destroy(sni->icon); sni->icon = load_image(icon_path, target_size, scale);