feat(dwm): add dynamic plugin system with xdrawer, dialer, and calllog plugins
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../sxmo-dwm/dwm_plugin.h"
|
||||
|
||||
static const char *const kPluginDirs[] = {
|
||||
"/home/user/.local/lib/dwm/plugins",
|
||||
"/usr/lib/dwm/plugins",
|
||||
NULL
|
||||
};
|
||||
|
||||
static const char *resolve_plugin_name_from_argv0(const char *argv0) {
|
||||
const char *base = strrchr(argv0, '/');
|
||||
base = base ? (base + 1) : argv0;
|
||||
if (strcasecmp(base, "xdrawer") == 0) {
|
||||
return "xdrawer";
|
||||
}
|
||||
if (strcasecmp(base, "xdialer") == 0 || strcasecmp(base, "dialer") == 0) {
|
||||
return "dialer";
|
||||
}
|
||||
if (strcasecmp(base, "xcalllog") == 0 || strcasecmp(base, "calllog") == 0) {
|
||||
return "calllog";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int list_plugins(void) {
|
||||
for (int i = 0; kPluginDirs[i]; ++i) {
|
||||
DIR *dir = opendir(kPluginDirs[i]);
|
||||
if (!dir) {
|
||||
continue;
|
||||
}
|
||||
struct dirent *ent;
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
size_t len = strlen(ent->d_name);
|
||||
if (len <= 3 || strcmp(ent->d_name + len - 3, ".so") != 0) {
|
||||
continue;
|
||||
}
|
||||
char path[512];
|
||||
snprintf(path, sizeof(path), "%s/%s", kPluginDirs[i], ent->d_name);
|
||||
void *h = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
if (!h) {
|
||||
continue;
|
||||
}
|
||||
const DwmPlugin *plug = (const DwmPlugin *)dlsym(h, DWM_PLUGIN_ENTRY_SYMBOL);
|
||||
if (plug && plug->api_version == DWM_PLUGIN_API_VERSION && plug->name) {
|
||||
printf("%-12s %s (%s)\n",
|
||||
plug->name,
|
||||
plug->description ? plug->description : "",
|
||||
path);
|
||||
}
|
||||
dlclose(h);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *plugin_name = resolve_plugin_name_from_argv0(argv[0]);
|
||||
int sub_argc = argc;
|
||||
char **sub_argv = argv;
|
||||
|
||||
if (!plugin_name) {
|
||||
if (argc < 2 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) {
|
||||
fprintf(stderr, "Usage: %s <plugin-name|--list> [args...]\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[1], "--list") == 0 || strcmp(argv[1], "-l") == 0) {
|
||||
return list_plugins();
|
||||
}
|
||||
plugin_name = argv[1];
|
||||
sub_argc = argc - 1;
|
||||
sub_argv = argv + 1;
|
||||
}
|
||||
|
||||
const char *env_dir = getenv("DWM_PLUGIN_PATH");
|
||||
char path[512];
|
||||
void *handle = NULL;
|
||||
|
||||
if (env_dir && env_dir[0]) {
|
||||
snprintf(path, sizeof(path), "%s/%s.so", env_dir, plugin_name);
|
||||
if (access(path, R_OK) == 0) {
|
||||
handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; !handle && kPluginDirs[i]; ++i) {
|
||||
snprintf(path, sizeof(path), "%s/%s.so", kPluginDirs[i], plugin_name);
|
||||
if (access(path, R_OK) == 0) {
|
||||
handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!handle) {
|
||||
fprintf(stderr, "dwm-plugin: failed to load plugin '%s': %s\n",
|
||||
plugin_name, dlerror());
|
||||
return 1;
|
||||
}
|
||||
|
||||
const DwmPlugin *plug = (const DwmPlugin *)dlsym(handle, DWM_PLUGIN_ENTRY_SYMBOL);
|
||||
if (!plug || plug->api_version != DWM_PLUGIN_API_VERSION || !plug->run_main) {
|
||||
fprintf(stderr, "dwm-plugin: invalid plugin '%s'\n", plugin_name);
|
||||
dlclose(handle);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = plug->run_main(sub_argc, sub_argv);
|
||||
dlclose(handle);
|
||||
return rc;
|
||||
}
|
||||
Reference in New Issue
Block a user