2026-10-21 11:11:45 +03:00
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <dlfcn.h>
|
2026-10-21 17:37:51 +03:00
|
|
|
#include <errno.h>
|
2026-10-21 11:57:23 +03:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <signal.h>
|
2026-10-21 17:37:51 +03:00
|
|
|
#include <stdint.h>
|
2026-10-21 11:11:45 +03:00
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <strings.h>
|
2026-10-21 17:37:51 +03:00
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
2026-10-21 11:11:45 +03:00
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include "../sxmo-dwm/dwm_plugin.h"
|
|
|
|
|
|
2026-10-21 17:37:51 +03:00
|
|
|
static int write_all(int fd, const void *buf, size_t len) {
|
|
|
|
|
const char *p = (const char *)buf;
|
|
|
|
|
while (len > 0) {
|
|
|
|
|
ssize_t n = write(fd, p, len);
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
continue;
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
p += n;
|
|
|
|
|
len -= (size_t)n;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int is_dmenu_builtin_arg(const char *arg) {
|
|
|
|
|
if (!arg || !arg[0])
|
|
|
|
|
return 0;
|
|
|
|
|
return strcmp(arg, "sys") == 0 ||
|
|
|
|
|
strcmp(arg, "ctx") == 0 ||
|
|
|
|
|
strcmp(arg, "applications") == 0 ||
|
2026-10-24 18:59:48 +03:00
|
|
|
strcmp(arg, "games") == 0 ||
|
2026-10-21 17:37:51 +03:00
|
|
|
strcmp(arg, "scripts") == 0 ||
|
|
|
|
|
strcmp(arg, "modem") == 0 ||
|
2026-10-24 18:59:48 +03:00
|
|
|
strcmp(arg, "audio") == 0 ||
|
|
|
|
|
strcmp(arg, "notifications") == 0 ||
|
|
|
|
|
strcmp(arg, "wm") == 0 ||
|
|
|
|
|
strcmp(arg, "timezone") == 0 ||
|
2026-10-21 17:37:51 +03:00
|
|
|
strcmp(arg, "config") == 0 ||
|
|
|
|
|
strcmp(arg, "power") == 0 ||
|
|
|
|
|
strcmp(arg, "st") == 0 ||
|
|
|
|
|
strcmp(arg, "nano") == 0 ||
|
|
|
|
|
strcmp(arg, "sthotkeys") == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int try_dmenu_socket_client(int sub_argc, char **sub_argv, int *exit_code_out) {
|
|
|
|
|
FILE *pf = fopen("/tmp/dwm_plugin_dmenu.pid", "r");
|
|
|
|
|
if (!pf)
|
|
|
|
|
return 0;
|
|
|
|
|
int pid = 0;
|
|
|
|
|
int ok = (fscanf(pf, "%d", &pid) == 1 && pid > 1 && kill((pid_t)pid, 0) == 0);
|
|
|
|
|
fclose(pf);
|
|
|
|
|
if (!ok)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
int sock = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
|
|
|
|
|
if (sock < 0)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
|
strncpy(addr.sun_path, "/tmp/dwm_plugin_dmenu.sock", sizeof(addr.sun_path) - 1);
|
|
|
|
|
|
|
|
|
|
if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
|
|
|
|
|
close(sock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t c_argc = (uint32_t)sub_argc;
|
|
|
|
|
if (write_all(sock, &c_argc, sizeof(c_argc)) != 0) {
|
|
|
|
|
close(sock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
for (int i = 0; i < sub_argc; i++) {
|
|
|
|
|
const char *s = sub_argv[i] ? sub_argv[i] : "";
|
|
|
|
|
uint32_t slen = (uint32_t)strlen(s);
|
|
|
|
|
if (write_all(sock, &slen, sizeof(slen)) != 0 ||
|
|
|
|
|
(slen > 0 && write_all(sock, s, slen) != 0)) {
|
|
|
|
|
close(sock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char buf[4096];
|
|
|
|
|
for (;;) {
|
|
|
|
|
ssize_t n = read(STDIN_FILENO, buf, sizeof(buf));
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (n == 0)
|
|
|
|
|
break;
|
|
|
|
|
if (write_all(sock, buf, (size_t)n) != 0) {
|
|
|
|
|
close(sock);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
shutdown(sock, SHUT_WR);
|
|
|
|
|
|
|
|
|
|
uint8_t status_byte = 1;
|
|
|
|
|
ssize_t first = read(sock, &status_byte, 1);
|
|
|
|
|
if (first <= 0) {
|
|
|
|
|
close(sock);
|
|
|
|
|
*exit_code_out = 1;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
ssize_t n = read(sock, buf, sizeof(buf));
|
|
|
|
|
if (n < 0) {
|
|
|
|
|
if (errno == EINTR)
|
|
|
|
|
continue;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (n == 0)
|
|
|
|
|
break;
|
|
|
|
|
(void)write_all(STDOUT_FILENO, buf, (size_t)n);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(sock);
|
|
|
|
|
*exit_code_out = (int)status_byte;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-21 11:57:23 +03:00
|
|
|
static int try_send_plugin_fifo(const char *plugin_name, int sub_argc, char **sub_argv) {
|
2026-10-21 20:36:27 +03:00
|
|
|
if (sub_argc >= 2 && sub_argv[1] &&
|
|
|
|
|
(strcmp(sub_argv[1], "--preload") == 0 ||
|
|
|
|
|
strcmp(sub_argv[1], "--apply") == 0 ||
|
|
|
|
|
strcmp(sub_argv[1], "--export-default") == 0)) {
|
2026-10-21 11:57:23 +03:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
char pid_path[128];
|
|
|
|
|
snprintf(pid_path, sizeof(pid_path), "/tmp/dwm_plugin_%s.pid", plugin_name);
|
|
|
|
|
FILE *pf = fopen(pid_path, "r");
|
|
|
|
|
if (!pf) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
int pid = 0;
|
|
|
|
|
int ok = (fscanf(pf, "%d", &pid) == 1 && pid > 1 && kill((pid_t)pid, 0) == 0);
|
|
|
|
|
fclose(pf);
|
|
|
|
|
if (!ok) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char fifo_path[128];
|
|
|
|
|
snprintf(fifo_path, sizeof(fifo_path), "/tmp/dwm_plugin_%s.fifo", plugin_name);
|
|
|
|
|
int fd = open(fifo_path, O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char cmd[256];
|
|
|
|
|
int len = 0;
|
|
|
|
|
if (strcmp(plugin_name, "xdrawer") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "TOGGLE\n");
|
2026-10-21 17:37:51 +03:00
|
|
|
} else if (strcmp(plugin_name, "dmenu") == 0 && sub_argc >= 2 && sub_argv[1] &&
|
|
|
|
|
strcmp(sub_argv[1], "close") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "CLOSE\n");
|
2026-10-22 10:17:24 +03:00
|
|
|
} else if (strcmp(plugin_name, "callscreen") == 0) {
|
|
|
|
|
if (sub_argc >= 2 && sub_argv[1] && sub_argv[1][0]) {
|
|
|
|
|
const char *verb = sub_argv[1];
|
|
|
|
|
const char *a1 = (sub_argc >= 3 && sub_argv[2]) ? sub_argv[2] : "";
|
|
|
|
|
const char *a2 = (sub_argc >= 4 && sub_argv[3]) ? sub_argv[3] : "";
|
|
|
|
|
if (strcasecmp(verb, "incoming") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "INCOMING %s %s\n", a1[0] ? a1 : "-", a2);
|
|
|
|
|
} else if (strcasecmp(verb, "outgoing") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OUTGOING %s %s\n", a1[0] ? a1 : "-", a2);
|
|
|
|
|
} else if (strcasecmp(verb, "active") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "ACTIVE %s %s\n", a1[0] ? a1 : "-", a2);
|
|
|
|
|
} else if (strcasecmp(verb, "accept") == 0 || strcasecmp(verb, "pickup") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "ACCEPT\n");
|
|
|
|
|
} else if (strcasecmp(verb, "hangup") == 0 || strcasecmp(verb, "reject") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "HANGUP\n");
|
|
|
|
|
} else if (strcasecmp(verb, "mute") == 0 || strcasecmp(verb, "mute_ring") == 0 ||
|
|
|
|
|
strcasecmp(verb, "ignore") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "MUTE_RING\n");
|
|
|
|
|
} else if (strcasecmp(verb, "ended") == 0 || strcasecmp(verb, "end") == 0) {
|
|
|
|
|
len = a1[0] ? snprintf(cmd, sizeof(cmd), "ENDED %s\n", a1)
|
|
|
|
|
: snprintf(cmd, sizeof(cmd), "ENDED\n");
|
|
|
|
|
} else if (strcasecmp(verb, "close") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "CLOSE\n");
|
|
|
|
|
} else if (strcasecmp(verb, "record") == 0 || strcasecmp(verb, "toggle_rec") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "TOGGLE_REC\n");
|
|
|
|
|
} else if (strcasecmp(verb, "mic") == 0 || strcasecmp(verb, "toggle_mic") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "TOGGLE_MIC\n");
|
|
|
|
|
} else {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN %s\n", verb);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN\n");
|
|
|
|
|
}
|
2026-10-21 12:32:21 +03:00
|
|
|
} else if (sub_argc >= 2 && sub_argv[1] && strcmp(sub_argv[1], "newcontact") == 0) {
|
|
|
|
|
const char *num = (sub_argc >= 3 && sub_argv[2]) ? sub_argv[2] : "";
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN new:%s\n", num);
|
2026-10-21 14:46:11 +03:00
|
|
|
} else if (sub_argc >= 2 && sub_argv[1] && strcmp(sub_argv[1], "sendtextmenu") == 0) {
|
|
|
|
|
const char *num = (sub_argc >= 3 && sub_argv[2]) ? sub_argv[2] : "";
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN send:%s\n", num);
|
|
|
|
|
} else if (sub_argc >= 2 && sub_argv[1] &&
|
|
|
|
|
(strcmp(sub_argv[1], "tailtextlog") == 0 ||
|
|
|
|
|
strcmp(sub_argv[1], "conversationloop") == 0)) {
|
|
|
|
|
const char *num = (sub_argc >= 3 && sub_argv[2]) ? sub_argv[2] : "";
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN thread:%s\n", num);
|
2026-10-21 11:57:23 +03:00
|
|
|
} else if (sub_argc >= 2 && sub_argv[1] && sub_argv[1][0]) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN %s\n", sub_argv[1]);
|
2026-10-24 18:59:48 +03:00
|
|
|
} else if (sub_argc >= 1 && sub_argv[0]) {
|
|
|
|
|
const char *b0 = strrchr(sub_argv[0], '/');
|
|
|
|
|
b0 = b0 ? (b0 + 1) : sub_argv[0];
|
|
|
|
|
if (strcasecmp(b0, "xbluetooth") == 0 || strcasecmp(b0, "bluetooth") == 0) {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN bluetooth\n");
|
|
|
|
|
} else {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN\n");
|
|
|
|
|
}
|
2026-10-21 11:57:23 +03:00
|
|
|
} else {
|
|
|
|
|
len = snprintf(cmd, sizeof(cmd), "OPEN\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssize_t wr = (len > 0 && len < (int)sizeof(cmd)) ? write(fd, cmd, (size_t)len) : -1;
|
|
|
|
|
close(fd);
|
|
|
|
|
return wr > 0 ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-21 11:11:45 +03:00
|
|
|
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;
|
2026-10-21 17:37:51 +03:00
|
|
|
if (strcasecmp(base, "dmenu") == 0 || strcasecmp(base, "xdmenu") == 0) {
|
|
|
|
|
return "dmenu";
|
|
|
|
|
}
|
2026-10-21 11:11:45 +03:00
|
|
|
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";
|
|
|
|
|
}
|
2026-10-22 10:17:24 +03:00
|
|
|
if (strcasecmp(base, "xcallscreen") == 0 || strcasecmp(base, "callscreen") == 0) {
|
|
|
|
|
return "callscreen";
|
|
|
|
|
}
|
2026-10-21 12:32:21 +03:00
|
|
|
if (strcasecmp(base, "xcontacts") == 0 || strcasecmp(base, "contacts") == 0) {
|
|
|
|
|
return "contacts";
|
|
|
|
|
}
|
2026-10-21 14:46:11 +03:00
|
|
|
if (strcasecmp(base, "xsms") == 0 || strcasecmp(base, "sms") == 0) {
|
|
|
|
|
return "sms";
|
|
|
|
|
}
|
|
|
|
|
if (strcasecmp(base, "xfiles") == 0 || strcasecmp(base, "files") == 0) {
|
|
|
|
|
return "files";
|
|
|
|
|
}
|
|
|
|
|
if (strcasecmp(base, "xcamera") == 0 || strcasecmp(base, "camera") == 0) {
|
|
|
|
|
return "camera";
|
|
|
|
|
}
|
2026-10-21 20:36:27 +03:00
|
|
|
if (strcasecmp(base, "xthemes") == 0 || strcasecmp(base, "themes") == 0) {
|
|
|
|
|
return "themes";
|
|
|
|
|
}
|
2026-10-24 18:59:48 +03:00
|
|
|
if (strcasecmp(base, "xmodem") == 0 || strcasecmp(base, "modem") == 0) {
|
|
|
|
|
return "modem";
|
|
|
|
|
}
|
|
|
|
|
if (strcasecmp(base, "xnetworks") == 0 || strcasecmp(base, "networks") == 0 ||
|
|
|
|
|
strcasecmp(base, "xbluetooth") == 0 || strcasecmp(base, "bluetooth") == 0) {
|
|
|
|
|
return "networks";
|
|
|
|
|
}
|
2026-10-24 19:58:11 +03:00
|
|
|
if (strcasecmp(base, "xringtones") == 0 || strcasecmp(base, "ringtones") == 0) {
|
|
|
|
|
return "ringtones";
|
|
|
|
|
}
|
|
|
|
|
if (strcasecmp(base, "xwallpapers") == 0 || strcasecmp(base, "wallpapers") == 0 ||
|
|
|
|
|
strcasecmp(base, "xbackground") == 0 || strcasecmp(base, "background") == 0) {
|
|
|
|
|
return "wallpapers";
|
|
|
|
|
}
|
2026-10-25 17:31:54 +02:00
|
|
|
if (strcasecmp(base, "xmusic") == 0 || strcasecmp(base, "music") == 0 ||
|
|
|
|
|
strcasecmp(base, "xplayer") == 0) {
|
|
|
|
|
return "music";
|
|
|
|
|
}
|
2026-10-21 11:11:45 +03:00
|
|
|
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) {
|
2026-10-21 17:37:51 +03:00
|
|
|
signal(SIGPIPE, SIG_IGN);
|
2026-10-21 11:11:45 +03:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-21 17:37:51 +03:00
|
|
|
if (strcmp(plugin_name, "dmenu") == 0) {
|
|
|
|
|
if (sub_argc >= 2 && sub_argv[1]) {
|
|
|
|
|
if (strcmp(sub_argv[1], "-v") == 0) {
|
|
|
|
|
puts("dmenu-5.0.14-bananarchy");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(sub_argv[1], "isopen") == 0) {
|
|
|
|
|
return access("/tmp/dwm_plugin_dmenu.active", F_OK) == 0 ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
if (strcmp(sub_argv[1], "close") == 0) {
|
|
|
|
|
try_send_plugin_fifo("dmenu", sub_argc, sub_argv);
|
|
|
|
|
unlink("/tmp/dwm_plugin_dmenu.active");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (is_dmenu_builtin_arg(sub_argv[1])) {
|
|
|
|
|
if (try_send_plugin_fifo("dmenu", sub_argc, sub_argv)) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!(sub_argc >= 2 && sub_argv[1] &&
|
|
|
|
|
(strcmp(sub_argv[1], "--preload") == 0 || is_dmenu_builtin_arg(sub_argv[1])))) {
|
|
|
|
|
int exit_code = 1;
|
|
|
|
|
if (try_dmenu_socket_client(sub_argc, sub_argv, &exit_code)) {
|
|
|
|
|
return exit_code;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else if (try_send_plugin_fifo(plugin_name, sub_argc, sub_argv)) {
|
2026-10-21 11:57:23 +03:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-21 11:11:45 +03:00
|
|
|
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;
|
|
|
|
|
}
|