Integrate dmenu as a preloaded zero-lag DWM plugin (dmenu.so)
This commit is contained in:
@@ -1,15 +1,131 @@
|
||||
#include <dirent.h>
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "../sxmo-dwm/dwm_plugin.h"
|
||||
|
||||
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 ||
|
||||
strcmp(arg, "scripts") == 0 ||
|
||||
strcmp(arg, "modem") == 0 ||
|
||||
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;
|
||||
}
|
||||
|
||||
static int try_send_plugin_fifo(const char *plugin_name, int sub_argc, char **sub_argv) {
|
||||
if (sub_argc >= 2 && sub_argv[1] && strcmp(sub_argv[1], "--preload") == 0) {
|
||||
return 0;
|
||||
@@ -38,6 +154,9 @@ static int try_send_plugin_fifo(const char *plugin_name, int sub_argc, char **su
|
||||
int len = 0;
|
||||
if (strcmp(plugin_name, "xdrawer") == 0) {
|
||||
len = snprintf(cmd, sizeof(cmd), "TOGGLE\n");
|
||||
} 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");
|
||||
} 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);
|
||||
@@ -69,6 +188,9 @@ static const char *const kPluginDirs[] = {
|
||||
static const char *resolve_plugin_name_from_argv0(const char *argv0) {
|
||||
const char *base = strrchr(argv0, '/');
|
||||
base = base ? (base + 1) : argv0;
|
||||
if (strcasecmp(base, "dmenu") == 0 || strcasecmp(base, "xdmenu") == 0) {
|
||||
return "dmenu";
|
||||
}
|
||||
if (strcasecmp(base, "xdrawer") == 0) {
|
||||
return "xdrawer";
|
||||
}
|
||||
@@ -126,6 +248,7 @@ static int list_plugins(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
const char *plugin_name = resolve_plugin_name_from_argv0(argv[0]);
|
||||
int sub_argc = argc;
|
||||
char **sub_argv = argv;
|
||||
@@ -143,7 +266,34 @@ int main(int argc, char **argv) {
|
||||
sub_argv = argv + 1;
|
||||
}
|
||||
|
||||
if (try_send_plugin_fifo(plugin_name, sub_argc, sub_argv)) {
|
||||
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)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user