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;
|
||||
}
|
||||
|
||||
|
||||
@@ -971,6 +971,9 @@ inline void closeOtherPlugins(const char* selfPluginName) {
|
||||
sendPluginCommand(p.name, "CLOSE");
|
||||
}
|
||||
}
|
||||
if (::access("/tmp/dwm_plugin_dmenu.active", F_OK) == 0) {
|
||||
sendPluginCommand("dmenu", "CLOSE");
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string getModemLogDirPath() {
|
||||
|
||||
+2630
-1216
File diff suppressed because it is too large
Load Diff
+18
-2
@@ -1649,7 +1649,7 @@ host_spawn_plugin(const char *plugin_name, const char *arg)
|
||||
if (arg && strcmp(arg, "--preload") == 0) {
|
||||
if (is_plugin_daemon_alive(plugin_name))
|
||||
return;
|
||||
int stagger_ms = 600 + (preload_stagger_idx++ * 220);
|
||||
int stagger_ms = (strcmp(plugin_name, "dmenu") == 0) ? 150 : (600 + (preload_stagger_idx++ * 220));
|
||||
if (fork() == 0) {
|
||||
if (dpy)
|
||||
close(ConnectionNumber(dpy));
|
||||
@@ -1670,6 +1670,8 @@ host_spawn_plugin(const char *plugin_name, const char *arg)
|
||||
int len;
|
||||
if (strcmp(plugin_name, "xdrawer") == 0)
|
||||
len = snprintf(msg, sizeof(msg), "TOGGLE\n");
|
||||
else if (strcmp(plugin_name, "dmenu") == 0 && arg && strcmp(arg, "close") == 0)
|
||||
len = snprintf(msg, sizeof(msg), "CLOSE\n");
|
||||
else if (arg && arg[0])
|
||||
len = snprintf(msg, sizeof(msg), "OPEN %s\n", arg);
|
||||
else
|
||||
@@ -1843,6 +1845,8 @@ trigger_softkey_chord(long long now)
|
||||
kill(-last_menu_pgid, SIGKILL);
|
||||
last_menu_pgid = 0;
|
||||
}
|
||||
if (is_plugin_loaded("dmenu"))
|
||||
host_spawn_plugin("dmenu", "close");
|
||||
softkey_pending = 0;
|
||||
softkey_first_ms = 0;
|
||||
softkey_deadline_ms = 0;
|
||||
@@ -1868,6 +1872,10 @@ flush_pending_softkey(void)
|
||||
XUngrabKeyboard(dpy, CurrentTime);
|
||||
XFlush(dpy);
|
||||
if (pending == SOFTKEY_LEFT) {
|
||||
if (is_plugin_loaded("dmenu")) {
|
||||
host_spawn_plugin("dmenu", "sys");
|
||||
return;
|
||||
}
|
||||
const Arg syscmd = { .v = (const char*[]){ "sxmo_appmenu.sh", "sys", NULL } };
|
||||
last_menu_pgid = spawn_pgid(&syscmd);
|
||||
} else if (pending == SOFTKEY_RIGHT) {
|
||||
@@ -1875,6 +1883,10 @@ flush_pending_softkey(void)
|
||||
dispatch_plugin_idle_key(XF86XK_Back, 166, 0)) {
|
||||
return;
|
||||
}
|
||||
if (is_plugin_loaded("dmenu")) {
|
||||
host_spawn_plugin("dmenu", "ctx");
|
||||
return;
|
||||
}
|
||||
const Arg ctxcmd = { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } };
|
||||
last_menu_pgid = spawn_pgid(&ctxcmd);
|
||||
}
|
||||
@@ -1953,9 +1965,13 @@ keypress(XEvent *e)
|
||||
|
||||
if (!selmon->sel && CLEANMASK(ev->state) == 0) {
|
||||
if (keysym == XK_Return) {
|
||||
const Arg entercmd = { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } };
|
||||
XUngrabKeyboard(dpy, CurrentTime);
|
||||
XFlush(dpy);
|
||||
if (is_plugin_loaded("dmenu")) {
|
||||
host_spawn_plugin("dmenu", "sys");
|
||||
return;
|
||||
}
|
||||
const Arg entercmd = { .v = (const char*[]){ "sxmo_appmenu.sh", NULL } };
|
||||
spawn(&entercmd);
|
||||
return;
|
||||
} else if (keysym == XK_Left) {
|
||||
|
||||
@@ -744,7 +744,13 @@ static int xdrawer_run_main(int argc, char** argv) {
|
||||
writeIntFile(pidPath, static_cast<int>(::getpid()));
|
||||
controller.refreshAll();
|
||||
render();
|
||||
runAsyncCmd("pkill -x dmenu >/dev/null 2>&1");
|
||||
if (::access("/tmp/dwm_plugin_dmenu.active", F_OK) == 0) {
|
||||
int dfd = ::open("/tmp/dwm_plugin_dmenu.fifo", O_WRONLY | O_NONBLOCK | O_CLOEXEC);
|
||||
if (dfd >= 0) {
|
||||
(void)::write(dfd, "CLOSE\n", 6);
|
||||
::close(dfd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto hideWindow = [&](bool drainSoftkeys) {
|
||||
|
||||
Reference in New Issue
Block a user