mirror of
https://github.com/swaywm/sway.git
synced 2024-11-25 17:31:28 +00:00
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:
parent
8c69da11bb
commit
6961bf2e4c
|
@ -1,5 +1,6 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -75,3 +76,21 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel)
|
||||||
sway_assert(false, "Unknown value for wl_output_subpixel.");
|
sway_assert(false, "Unknown value for wl_output_subpixel.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool set_cloexec(int fd, bool cloexec) {
|
||||||
|
int flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags == -1) {
|
||||||
|
sway_log_errno(SWAY_ERROR, "fcntl failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cloexec) {
|
||||||
|
flags = flags | FD_CLOEXEC;
|
||||||
|
} else {
|
||||||
|
flags = flags & ~FD_CLOEXEC;
|
||||||
|
}
|
||||||
|
if (fcntl(fd, F_SETFD, flags) == -1) {
|
||||||
|
sway_log_errno(SWAY_ERROR, "fcntl failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef _SWAY_SWAYNAG_H
|
#ifndef _SWAY_SWAYNAG_H
|
||||||
#define _SWAY_SWAYNAG_H
|
#define _SWAY_SWAYNAG_H
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
struct swaynag_instance {
|
struct swaynag_instance {
|
||||||
|
struct wl_client *client;
|
||||||
|
struct wl_listener client_destroy;
|
||||||
|
|
||||||
const char *args;
|
const char *args;
|
||||||
pid_t pid;
|
|
||||||
int fd[2];
|
int fd[2];
|
||||||
bool detailed;
|
bool detailed;
|
||||||
};
|
};
|
||||||
|
@ -15,9 +18,6 @@ struct swaynag_instance {
|
||||||
bool swaynag_spawn(const char *swaynag_command,
|
bool swaynag_spawn(const char *swaynag_command,
|
||||||
struct swaynag_instance *swaynag);
|
struct swaynag_instance *swaynag);
|
||||||
|
|
||||||
// Kill the swaynag instance
|
|
||||||
void swaynag_kill(struct swaynag_instance *swaynag);
|
|
||||||
|
|
||||||
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
|
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
|
||||||
// is false.
|
// is false.
|
||||||
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
|
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
|
||||||
|
|
|
@ -32,4 +32,6 @@ float parse_float(const char *value);
|
||||||
|
|
||||||
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
|
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
|
||||||
|
|
||||||
|
bool set_cloexec(int fd, bool cloexec);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -175,15 +175,13 @@ static void set_color(float dest[static 4], uint32_t color) {
|
||||||
|
|
||||||
static void config_defaults(struct sway_config *config) {
|
static void config_defaults(struct sway_config *config) {
|
||||||
if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup;
|
if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup;
|
||||||
config->swaynag_config_errors = (struct swaynag_instance){
|
config->swaynag_config_errors = (struct swaynag_instance){0};
|
||||||
.args = "--type error "
|
config->swaynag_config_errors.args = "--type error "
|
||||||
"--message 'There are errors in your config file' "
|
"--message 'There are errors in your config file' "
|
||||||
"--detailed-message "
|
"--detailed-message "
|
||||||
"--button 'Exit sway' 'swaymsg exit' "
|
"--button-no-terminal 'Exit sway' 'swaymsg exit' "
|
||||||
"--button 'Reload sway' 'swaymsg reload'",
|
"--button-no-terminal 'Reload sway' 'swaymsg reload'";
|
||||||
.pid = -1,
|
config->swaynag_config_errors.detailed = true;
|
||||||
.detailed = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!(config->symbols = create_list())) goto cleanup;
|
if (!(config->symbols = create_list())) goto cleanup;
|
||||||
if (!(config->modes = create_list())) goto cleanup;
|
if (!(config->modes = create_list())) goto cleanup;
|
||||||
|
@ -411,10 +409,9 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
|
||||||
config->reloading = true;
|
config->reloading = true;
|
||||||
config->active = true;
|
config->active = true;
|
||||||
|
|
||||||
swaynag_kill(&old_config->swaynag_config_errors);
|
if (old_config->swaynag_config_errors.client != NULL) {
|
||||||
memcpy(&config->swaynag_config_errors,
|
wl_client_destroy(old_config->swaynag_config_errors.client);
|
||||||
&old_config->swaynag_config_errors,
|
}
|
||||||
sizeof(struct swaynag_instance));
|
|
||||||
|
|
||||||
input_manager_reset_all_inputs();
|
input_manager_reset_all_inputs();
|
||||||
}
|
}
|
||||||
|
@ -486,7 +483,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
|
||||||
spawn_swaybg();
|
spawn_swaybg();
|
||||||
|
|
||||||
config->reloading = false;
|
config->reloading = false;
|
||||||
if (config->swaynag_config_errors.pid > 0) {
|
if (config->swaynag_config_errors.client != NULL) {
|
||||||
swaynag_show(&config->swaynag_config_errors);
|
swaynag_show(&config->swaynag_config_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
@ -488,24 +487,6 @@ static void handle_swaybg_client_destroy(struct wl_listener *listener,
|
||||||
config->swaybg_client = NULL;
|
config->swaybg_client = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool set_cloexec(int fd, bool cloexec) {
|
|
||||||
int flags = fcntl(fd, F_GETFD);
|
|
||||||
if (flags == -1) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "fcntl failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (cloexec) {
|
|
||||||
flags = flags | FD_CLOEXEC;
|
|
||||||
} else {
|
|
||||||
flags = flags & ~FD_CLOEXEC;
|
|
||||||
}
|
|
||||||
if (fcntl(fd, F_SETFD, flags) == -1) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "fcntl failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool _spawn_swaybg(char **command) {
|
static bool _spawn_swaybg(char **command) {
|
||||||
if (config->swaybg_client != NULL) {
|
if (config->swaybg_client != NULL) {
|
||||||
wl_client_destroy(config->swaybg_client);
|
wl_client_destroy(config->swaybg_client);
|
||||||
|
|
|
@ -391,7 +391,7 @@ int main(int argc, char **argv) {
|
||||||
load_swaybars();
|
load_swaybars();
|
||||||
run_deferred_commands();
|
run_deferred_commands();
|
||||||
|
|
||||||
if (config->swaynag_config_errors.pid > 0) {
|
if (config->swaynag_config_errors.client != NULL) {
|
||||||
swaynag_show(&config->swaynag_config_errors);
|
swaynag_show(&config->swaynag_config_errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
124
sway/swaynag.c
124
sway/swaynag.c
|
@ -1,16 +1,32 @@
|
||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <fcntl.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "sway/server.h"
|
||||||
#include "sway/swaynag.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,
|
bool swaynag_spawn(const char *swaynag_command,
|
||||||
struct swaynag_instance *swaynag) {
|
struct swaynag_instance *swaynag) {
|
||||||
|
if (swaynag->client != NULL) {
|
||||||
|
wl_client_destroy(swaynag->client);
|
||||||
|
}
|
||||||
|
|
||||||
if (!swaynag_command) {
|
if (!swaynag_command) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -20,44 +36,94 @@ bool swaynag_spawn(const char *swaynag_command,
|
||||||
sway_log(SWAY_ERROR, "Failed to create pipe for swaynag");
|
sway_log(SWAY_ERROR, "Failed to create pipe for swaynag");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC);
|
if (!set_cloexec(swaynag->fd[1], true)) {
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pid_t pid;
|
int sockets[2];
|
||||||
if ((pid = fork()) == 0) {
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
|
||||||
if (swaynag->detailed) {
|
sway_log_errno(SWAY_ERROR, "socketpair failed");
|
||||||
close(swaynag->fd[1]);
|
goto failed;
|
||||||
dup2(swaynag->fd[0], STDIN_FILENO);
|
}
|
||||||
close(swaynag->fd[0]);
|
if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) {
|
||||||
}
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
|
swaynag->client = wl_client_create(server.wl_display, sockets[0]);
|
||||||
char *cmd = malloc(length);
|
if (swaynag->client == NULL) {
|
||||||
snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
|
sway_log_errno(SWAY_ERROR, "wl_client_create failed");
|
||||||
execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
|
goto failed;
|
||||||
_exit(0);
|
}
|
||||||
} else if (pid < 0) {
|
|
||||||
|
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");
|
sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
|
||||||
if (swaynag->detailed) {
|
goto failed;
|
||||||
close(swaynag->fd[0]);
|
} else if (pid == 0) {
|
||||||
close(swaynag->fd[1]);
|
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) {
|
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;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
|
failed:
|
||||||
void swaynag_kill(struct swaynag_instance *swaynag) {
|
if (swaynag->detailed) {
|
||||||
if (swaynag->pid > 0) {
|
if (close(swaynag->fd[0]) != 0) {
|
||||||
kill(swaynag->pid, SIGTERM);
|
sway_log_errno(SWAY_ERROR, "close failed");
|
||||||
swaynag->pid = -1;
|
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,
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) {
|
if (swaynag->client == NULL && !swaynag_spawn(swaynag_command, swaynag)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +162,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
|
||||||
}
|
}
|
||||||
|
|
||||||
void swaynag_show(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]);
|
close(swaynag->fd[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,17 +45,24 @@ static void swaynag_button_execute(struct swaynag *swaynag,
|
||||||
swaynag->details.visible = !swaynag->details.visible;
|
swaynag->details.visible = !swaynag->details.visible;
|
||||||
render_frame(swaynag);
|
render_frame(swaynag);
|
||||||
} else {
|
} else {
|
||||||
if (fork() == 0) {
|
pid_t pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
sway_log_errno(SWAY_DEBUG, "Failed to fork");
|
||||||
|
return;
|
||||||
|
} else if (pid == 0) {
|
||||||
// Child process. Will be used to prevent zombie processes
|
// Child process. Will be used to prevent zombie processes
|
||||||
setsid();
|
pid = fork();
|
||||||
if (fork() == 0) {
|
if (pid < 0) {
|
||||||
|
sway_log_errno(SWAY_DEBUG, "Failed to fork");
|
||||||
|
return;
|
||||||
|
} else if (pid == 0) {
|
||||||
// Child of the child. Will be reparented to the init process
|
// Child of the child. Will be reparented to the init process
|
||||||
char *terminal = getenv("TERMINAL");
|
char *terminal = getenv("TERMINAL");
|
||||||
if (button->terminal && terminal && strlen(terminal)) {
|
if (button->terminal && terminal && strlen(terminal)) {
|
||||||
sway_log(SWAY_DEBUG, "Found $TERMINAL: %s", terminal);
|
sway_log(SWAY_DEBUG, "Found $TERMINAL: %s", terminal);
|
||||||
if (!terminal_execute(terminal, button->action)) {
|
if (!terminal_execute(terminal, button->action)) {
|
||||||
swaynag_destroy(swaynag);
|
swaynag_destroy(swaynag);
|
||||||
exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (button->terminal) {
|
if (button->terminal) {
|
||||||
|
@ -63,12 +70,16 @@ static void swaynag_button_execute(struct swaynag *swaynag,
|
||||||
"$TERMINAL not found. Running directly");
|
"$TERMINAL not found. Running directly");
|
||||||
}
|
}
|
||||||
execl("/bin/sh", "/bin/sh", "-c", button->action, NULL);
|
execl("/bin/sh", "/bin/sh", "-c", button->action, NULL);
|
||||||
|
sway_log_errno(SWAY_DEBUG, "execl failed");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exit(EXIT_SUCCESS);
|
_exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
if (waitpid(pid, NULL, 0) < 0) {
|
||||||
|
sway_log_errno(SWAY_DEBUG, "waitpid failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wait(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void layer_surface_configure(void *data,
|
static void layer_surface_configure(void *data,
|
||||||
|
|
Loading…
Reference in a new issue