mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-19 19:25:41 +02:00
Introduce new module implementing the status notifier spec (https://www.freedesktop.org/wiki/Specifications/StatusNotifierItem/). The core dbus logic and spec implementation is from swaybar (https://github.com/swaywm/sway/tree/master/swaybar/tray), with rendering stripped out and a switch to tllist. The dbus loop is async and not re-entrant so the module lock is taken each time we process a message (and when we process content). To reduce memory usage the icon pixmaps are immutable and reference counted. So they can be passed between the module and the particles (through tags) without copying. Work to be done in future diffs: 1. Tray interactivity/menu support 2. Support KDE search paths for the tray. Can it be implemented with yml scripting?
327 lines
10 KiB
C
327 lines
10 KiB
C
#include "plugin.h"
|
|
|
|
#include <dlfcn.h>
|
|
#include <string.h>
|
|
|
|
#include <tllist.h>
|
|
|
|
#define LOG_MODULE "plugin"
|
|
#define LOG_ENABLE_DBG 0
|
|
#include "config.h"
|
|
#include "log.h"
|
|
|
|
#if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
|
|
|
|
#define EXTERN_MODULE(plug_name) \
|
|
extern const struct module_iface module_##plug_name##_iface; \
|
|
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
|
|
extern struct module *plug_name##_from_conf(const struct yml_node *node, struct conf_inherit inherited);
|
|
|
|
#define EXTERN_PARTICLE(plug_name) \
|
|
extern const struct particle_iface particle_##plug_name##_iface; \
|
|
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
|
|
extern struct particle *plug_name##_from_conf(const struct yml_node *node, struct particle *common);
|
|
|
|
#define EXTERN_DECORATION(plug_name) \
|
|
extern const struct deco_iface deco_##plug_name##_iface; \
|
|
extern bool plug_name##_verify_conf(keychain_t *chain, const struct yml_node *node); \
|
|
extern struct deco *plug_name##_from_conf(const struct yml_node *node);
|
|
|
|
#if defined(HAVE_PLUGIN_alsa)
|
|
EXTERN_MODULE(alsa);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_backlight)
|
|
EXTERN_MODULE(backlight);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_battery)
|
|
EXTERN_MODULE(battery);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_clock)
|
|
EXTERN_MODULE(clock);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_cpu)
|
|
EXTERN_MODULE(cpu);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_disk_io)
|
|
EXTERN_MODULE(disk_io);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_dwl)
|
|
EXTERN_MODULE(dwl);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_foreign_toplevel)
|
|
EXTERN_MODULE(foreign_toplevel);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_mem)
|
|
EXTERN_MODULE(mem);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_mpd)
|
|
EXTERN_MODULE(mpd);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_i3)
|
|
EXTERN_MODULE(i3);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_label)
|
|
EXTERN_MODULE(label);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_network)
|
|
EXTERN_MODULE(network);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_pipewire)
|
|
EXTERN_MODULE(pipewire);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_pulse)
|
|
EXTERN_MODULE(pulse);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_removables)
|
|
EXTERN_MODULE(removables);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_river)
|
|
EXTERN_MODULE(river);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_script)
|
|
EXTERN_MODULE(script);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_tray)
|
|
EXTERN_MODULE(tray);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_sway_xkb)
|
|
EXTERN_MODULE(sway_xkb);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_xkb)
|
|
EXTERN_MODULE(xkb);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_xwindow)
|
|
EXTERN_MODULE(xwindow);
|
|
#endif
|
|
|
|
EXTERN_PARTICLE(empty);
|
|
EXTERN_PARTICLE(list);
|
|
EXTERN_PARTICLE(map);
|
|
EXTERN_PARTICLE(progress_bar);
|
|
EXTERN_PARTICLE(ramp);
|
|
EXTERN_PARTICLE(string);
|
|
EXTERN_PARTICLE(icon);
|
|
|
|
EXTERN_DECORATION(background);
|
|
EXTERN_DECORATION(border);
|
|
EXTERN_DECORATION(stack);
|
|
EXTERN_DECORATION(underline);
|
|
EXTERN_DECORATION(overline);
|
|
|
|
#undef EXTERN_DECORATION
|
|
#undef EXTERN_PARTICLE
|
|
#undef EXTERN_MODULE
|
|
|
|
#endif
|
|
|
|
static tll(struct plugin) plugins = tll_init();
|
|
|
|
static const char *
|
|
type2str(enum plugin_type type)
|
|
{
|
|
switch (type) {
|
|
case PLUGIN_MODULE:
|
|
return "module";
|
|
case PLUGIN_PARTICLE:
|
|
return "particle";
|
|
case PLUGIN_DECORATION:
|
|
return "decoration";
|
|
}
|
|
|
|
assert(false && "invalid type");
|
|
return "";
|
|
}
|
|
|
|
static void __attribute__((constructor)) init(void)
|
|
{
|
|
#if !defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
|
|
|
|
#define REGISTER_CORE_PLUGIN(plug_name, func_prefix, plug_type) \
|
|
do { \
|
|
tll_push_back(plugins, ((struct plugin){ \
|
|
.name = strdup(#plug_name), \
|
|
.type = (plug_type), \
|
|
.lib = RTLD_DEFAULT, \
|
|
})); \
|
|
} while (0)
|
|
|
|
#define REGISTER_CORE_MODULE(plug_name, func_prefix) \
|
|
do { \
|
|
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_MODULE); \
|
|
tll_back(plugins).module = &module_##func_prefix##_iface; \
|
|
} while (0)
|
|
#define REGISTER_CORE_PARTICLE(plug_name, func_prefix) \
|
|
do { \
|
|
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_PARTICLE); \
|
|
tll_back(plugins).particle = &particle_##func_prefix##_iface; \
|
|
} while (0)
|
|
#define REGISTER_CORE_DECORATION(plug_name, func_prefix) \
|
|
do { \
|
|
REGISTER_CORE_PLUGIN(plug_name, func_prefix, PLUGIN_DECORATION); \
|
|
tll_back(plugins).decoration = &deco_##func_prefix##_iface; \
|
|
} while (0)
|
|
|
|
#if defined(HAVE_PLUGIN_alsa)
|
|
REGISTER_CORE_MODULE(alsa, alsa);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_backlight)
|
|
REGISTER_CORE_MODULE(backlight, backlight);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_battery)
|
|
REGISTER_CORE_MODULE(battery, battery);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_clock)
|
|
REGISTER_CORE_MODULE(clock, clock);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_cpu)
|
|
REGISTER_CORE_MODULE(cpu, cpu);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_disk_io)
|
|
REGISTER_CORE_MODULE(disk-io, disk_io);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_dwl)
|
|
REGISTER_CORE_MODULE(dwl, dwl);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_foreign_toplevel)
|
|
REGISTER_CORE_MODULE(foreign-toplevel, foreign_toplevel);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_mem)
|
|
REGISTER_CORE_MODULE(mem, mem);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_mpd)
|
|
REGISTER_CORE_MODULE(mpd, mpd);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_i3)
|
|
REGISTER_CORE_MODULE(i3, i3);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_label)
|
|
REGISTER_CORE_MODULE(label, label);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_network)
|
|
REGISTER_CORE_MODULE(network, network);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_pipewire)
|
|
REGISTER_CORE_MODULE(pipewire, pipewire);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_pulse)
|
|
REGISTER_CORE_MODULE(pulse, pulse);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_removables)
|
|
REGISTER_CORE_MODULE(removables, removables);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_river)
|
|
REGISTER_CORE_MODULE(river, river);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_script)
|
|
REGISTER_CORE_MODULE(script, script);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_sway_xkb)
|
|
REGISTER_CORE_MODULE(sway-xkb, sway_xkb);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_tray)
|
|
REGISTER_CORE_MODULE(tray, tray);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_xkb)
|
|
REGISTER_CORE_MODULE(xkb, xkb);
|
|
#endif
|
|
#if defined(HAVE_PLUGIN_xwindow)
|
|
REGISTER_CORE_MODULE(xwindow, xwindow);
|
|
#endif
|
|
|
|
REGISTER_CORE_PARTICLE(empty, empty);
|
|
REGISTER_CORE_PARTICLE(list, list);
|
|
REGISTER_CORE_PARTICLE(map, map);
|
|
REGISTER_CORE_PARTICLE(progress-bar, progress_bar);
|
|
REGISTER_CORE_PARTICLE(ramp, ramp);
|
|
REGISTER_CORE_PARTICLE(string, string);
|
|
REGISTER_CORE_PARTICLE(icon, icon);
|
|
|
|
REGISTER_CORE_DECORATION(background, background);
|
|
REGISTER_CORE_DECORATION(border, border);
|
|
REGISTER_CORE_DECORATION(stack, stack);
|
|
REGISTER_CORE_DECORATION(underline, underline);
|
|
REGISTER_CORE_DECORATION(overline, overline);
|
|
|
|
#undef REGISTER_CORE_DECORATION
|
|
#undef REGISTER_CORE_PARTICLE
|
|
#undef REGISTER_CORE_PLUGIN
|
|
|
|
#endif /* !CORE_PLUGINS_AS_SHARED_LIBRARIES */
|
|
}
|
|
|
|
static void
|
|
free_plugin(struct plugin plug)
|
|
{
|
|
dlerror();
|
|
|
|
if (plug.lib != NULL)
|
|
dlclose(plug.lib);
|
|
|
|
const char *dl_error = dlerror();
|
|
if (dl_error != NULL)
|
|
LOG_ERR("%s: %s: dlclose(): %s", type2str(plug.type), plug.name, dl_error);
|
|
|
|
free(plug.name);
|
|
}
|
|
|
|
static void __attribute__((destructor)) fini(void) { tll_free_and_free(plugins, free_plugin); }
|
|
|
|
const struct plugin *
|
|
plugin_load(const char *name, enum plugin_type type)
|
|
{
|
|
tll_foreach(plugins, plug)
|
|
{
|
|
if (plug->item.type == type && strcmp(plug->item.name, name) == 0) {
|
|
LOG_DBG("%s: %s already loaded: %p", type2str(type), name, plug->item.lib);
|
|
assert(plug->item.dummy != NULL);
|
|
return &plug->item;
|
|
}
|
|
}
|
|
|
|
char path[128];
|
|
snprintf(path, sizeof(path), "%s_%s.so", type2str(type), name);
|
|
|
|
/* Not loaded - do it now */
|
|
void *lib = dlopen(path, RTLD_LOCAL | RTLD_NOW);
|
|
LOG_DBG("%s: %s: dlopened to %p", type2str(type), name, lib);
|
|
|
|
if (lib == NULL) {
|
|
LOG_ERR("%s: %s: dlopen: %s", type2str(type), name, dlerror());
|
|
return NULL;
|
|
}
|
|
|
|
tll_push_back(plugins, ((struct plugin){strdup(name), type, lib, {NULL}}));
|
|
struct plugin *plug = &tll_back(plugins);
|
|
|
|
dlerror(); /* Clear previous error */
|
|
plug->dummy = dlsym(lib, "iface");
|
|
|
|
const char *dl_error = dlerror();
|
|
if (dl_error != NULL) {
|
|
LOG_ERR("%s: %s: dlsym: %s", type2str(type), name, dl_error);
|
|
return NULL;
|
|
}
|
|
|
|
return plug;
|
|
}
|
|
|
|
const struct module_iface *
|
|
plugin_load_module(const char *name)
|
|
{
|
|
const struct plugin *plug = plugin_load(name, PLUGIN_MODULE);
|
|
return plug != NULL ? plug->module : NULL;
|
|
}
|
|
|
|
const struct particle_iface *
|
|
plugin_load_particle(const char *name)
|
|
{
|
|
const struct plugin *plug = plugin_load(name, PLUGIN_PARTICLE);
|
|
return plug != NULL ? plug->particle : NULL;
|
|
}
|
|
|
|
const struct deco_iface *
|
|
plugin_load_deco(const char *name)
|
|
{
|
|
const struct plugin *plug = plugin_load(name, PLUGIN_DECORATION);
|
|
return plug != NULL ? plug->decoration : NULL;
|
|
}
|