Spawn swaynag as a wayland client

This spawns swaynag as a wayland client similar to how swaybar and
swaybg are already done
This commit is contained in:
Brian Ashworth 2019-04-14 00:27:47 -04:00 committed by Simon Ser
parent 8c69da11bb
commit 6961bf2e4c
8 changed files with 147 additions and 71 deletions

View file

@ -1,16 +1,32 @@
#define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "log.h"
#include "sway/server.h"
#include "sway/swaynag.h"
#include "util.h"
static void handle_swaynag_client_destroy(struct wl_listener *listener,
void *data) {
struct swaynag_instance *swaynag =
wl_container_of(listener, swaynag, client_destroy);
wl_list_remove(&swaynag->client_destroy.link);
wl_list_init(&swaynag->client_destroy.link);
swaynag->client = NULL;
}
bool swaynag_spawn(const char *swaynag_command,
struct swaynag_instance *swaynag) {
if (swaynag->client != NULL) {
wl_client_destroy(swaynag->client);
}
if (!swaynag_command) {
return true;
}
@ -20,44 +36,94 @@ bool swaynag_spawn(const char *swaynag_command,
sway_log(SWAY_ERROR, "Failed to create pipe for swaynag");
return false;
}
fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC);
if (!set_cloexec(swaynag->fd[1], true)) {
goto failed;
}
}
pid_t pid;
if ((pid = fork()) == 0) {
if (swaynag->detailed) {
close(swaynag->fd[1]);
dup2(swaynag->fd[0], STDIN_FILENO);
close(swaynag->fd[0]);
}
int sockets[2];
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
sway_log_errno(SWAY_ERROR, "socketpair failed");
goto failed;
}
if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) {
goto failed;
}
size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
char *cmd = malloc(length);
snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
_exit(0);
} else if (pid < 0) {
swaynag->client = wl_client_create(server.wl_display, sockets[0]);
if (swaynag->client == NULL) {
sway_log_errno(SWAY_ERROR, "wl_client_create failed");
goto failed;
}
swaynag->client_destroy.notify = handle_swaynag_client_destroy;
wl_client_add_destroy_listener(swaynag->client, &swaynag->client_destroy);
pid_t pid = fork();
if (pid < 0) {
sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
if (swaynag->detailed) {
close(swaynag->fd[0]);
close(swaynag->fd[1]);
goto failed;
} else if (pid == 0) {
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
_exit(EXIT_FAILURE);
} else if (pid == 0) {
if (!set_cloexec(sockets[1], false)) {
_exit(EXIT_FAILURE);
}
if (swaynag->detailed) {
close(swaynag->fd[1]);
dup2(swaynag->fd[0], STDIN_FILENO);
close(swaynag->fd[0]);
}
char wayland_socket_str[16];
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
"%d", sockets[1]);
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
char *cmd = malloc(length);
snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
sway_log_errno(SWAY_ERROR, "execl failed");
_exit(EXIT_FAILURE);
}
return false;
_exit(EXIT_SUCCESS);
}
if (swaynag->detailed) {
close(swaynag->fd[0]);
if (close(swaynag->fd[0]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
return false;
}
}
swaynag->pid = pid;
if (close(sockets[1]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
return false;
}
if (waitpid(pid, NULL, 0) < 0) {
sway_log_errno(SWAY_ERROR, "waitpid failed");
return false;
}
return true;
}
void swaynag_kill(struct swaynag_instance *swaynag) {
if (swaynag->pid > 0) {
kill(swaynag->pid, SIGTERM);
swaynag->pid = -1;
failed:
if (swaynag->detailed) {
if (close(swaynag->fd[0]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
return false;
}
if (close(swaynag->fd[1]) != 0) {
sway_log_errno(SWAY_ERROR, "close failed");
}
}
return false;
}
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
@ -71,7 +137,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
return;
}
if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) {
if (swaynag->client == NULL && !swaynag_spawn(swaynag_command, swaynag)) {
return;
}
@ -96,7 +162,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
}
void swaynag_show(struct swaynag_instance *swaynag) {
if (swaynag->detailed && swaynag->pid > 0) {
if (swaynag->detailed && swaynag->client != NULL) {
close(swaynag->fd[1]);
}
}