mirror of
https://github.com/swaywm/sway.git
synced 2026-04-22 06:46:27 -04:00
Add a connection label for wayland clients lauched by sway
This adds a few arguments to exec that cause sway to create a wayland socket file descriptor and point the WAYLAND_SOCKET environment variable at the socket. This in turn allows sway to track all windows created by this client (in a more robust manner than the existing pid-based tracking). Note that this only works if the exec ends up launching a single wayland client (a script that launches multiple commands will not work correctly; a process that uses libwayland-client itself and runs other processes is fine). "exec --use-wayland-socket command" only sets WAYLAND_SOCKET and does nothing else. "exec --label <label> <program>" will associate the specified label with the wl_client and all windows it creates.
This commit is contained in:
parent
f614f35e73
commit
05a418c9fe
5 changed files with 132 additions and 5 deletions
4
include/sway/client_label.h
Normal file
4
include/sway/client_label.h
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
|
||||||
|
char* wl_client_label_get(struct wl_client *client);
|
||||||
|
void wl_client_label_set(struct wl_client *client, char* label);
|
||||||
|
|
@ -231,6 +231,8 @@ const char *view_get_class(struct sway_view *view);
|
||||||
|
|
||||||
const char *view_get_instance(struct sway_view *view);
|
const char *view_get_instance(struct sway_view *view);
|
||||||
|
|
||||||
|
const char *view_get_conn_label(struct sway_view *view);
|
||||||
|
|
||||||
uint32_t view_get_x11_window_id(struct sway_view *view);
|
uint32_t view_get_x11_window_id(struct sway_view *view);
|
||||||
|
|
||||||
uint32_t view_get_x11_parent_id(struct sway_view *view);
|
uint32_t view_get_x11_parent_id(struct sway_view *view);
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include "sway/client_label.h"
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
|
@ -13,6 +15,7 @@
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
|
|
@ -27,14 +30,39 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
||||||
|
|
||||||
struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
|
bool use_wl_socket = false;
|
||||||
|
int skip_argc = 0;
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
if (strcmp(argv[0], "--no-startup-id") == 0) {
|
char *label = NULL;
|
||||||
|
|
||||||
|
while (skip_argc < argc && strncmp(argv[skip_argc], "--", 2) == 0) {
|
||||||
|
if (strcmp(argv[skip_argc], "--no-startup-id") == 0) {
|
||||||
sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored.");
|
sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored.");
|
||||||
--argc; ++argv;
|
skip_argc++;
|
||||||
if ((error = checkarg(argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
} else if (strcmp(argv[skip_argc], "--use-wayland-socket") == 0) {
|
||||||
|
use_wl_socket = true;
|
||||||
|
skip_argc++;
|
||||||
|
} else if (strcmp(argv[skip_argc], "--label") == 0) {
|
||||||
|
skip_argc++;
|
||||||
|
if (skip_argc >= argc)
|
||||||
|
return cmd_results_new(CMD_INVALID, "--label requires an argument");
|
||||||
|
label = argv[skip_argc];
|
||||||
|
skip_argc++;
|
||||||
|
} else if (strcmp(argv[skip_argc], "--") == 0) {
|
||||||
|
skip_argc++;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return cmd_results_new(CMD_INVALID, "Unknown switch %s", argv[skip_argc]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((error = checkarg(argc - skip_argc, argv[-1], EXPECTED_AT_LEAST, 1))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
argc -= skip_argc;
|
||||||
|
argv += skip_argc;
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
use_wl_socket = true;
|
||||||
|
|
||||||
if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) {
|
if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) {
|
||||||
cmd = strdup(argv[0]);
|
cmd = strdup(argv[0]);
|
||||||
|
|
@ -50,6 +78,17 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
sway_log(SWAY_ERROR, "Unable to create pipe for fork");
|
sway_log(SWAY_ERROR, "Unable to create pipe for fork");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int sockets[2];
|
||||||
|
struct wl_client* client = NULL;
|
||||||
|
if (use_wl_socket) {
|
||||||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
|
||||||
|
sway_log_errno(SWAY_ERROR, "socketpair failed in exec");
|
||||||
|
use_wl_socket = false;
|
||||||
|
} else {
|
||||||
|
sway_set_cloexec(sockets[0], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pid_t pid, child;
|
pid_t pid, child;
|
||||||
// Fork process
|
// Fork process
|
||||||
if ((pid = fork()) == 0) {
|
if ((pid = fork()) == 0) {
|
||||||
|
|
@ -61,6 +100,15 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||||
signal(SIGPIPE, SIG_DFL);
|
signal(SIGPIPE, SIG_DFL);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
|
if (use_wl_socket) {
|
||||||
|
close(sockets[0]);
|
||||||
|
sway_set_cloexec(sockets[1], false);
|
||||||
|
|
||||||
|
char wayland_socket_str[16];
|
||||||
|
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
||||||
|
"%d", sockets[1]);
|
||||||
|
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
||||||
|
}
|
||||||
if ((child = fork()) == 0) {
|
if ((child = fork()) == 0) {
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
execlp("sh", "sh", "-c", cmd, (void *)NULL);
|
execlp("sh", "sh", "-c", cmd, (void *)NULL);
|
||||||
|
|
@ -77,10 +125,18 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
free(cmd);
|
free(cmd);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
|
if (use_wl_socket) {
|
||||||
|
close(sockets[0]);
|
||||||
|
close(sockets[1]);
|
||||||
|
}
|
||||||
return cmd_results_new(CMD_FAILURE, "fork() failed");
|
return cmd_results_new(CMD_FAILURE, "fork() failed");
|
||||||
}
|
}
|
||||||
free(cmd);
|
free(cmd);
|
||||||
close(fd[1]); // close write
|
close(fd[1]); // close write
|
||||||
|
if (use_wl_socket) {
|
||||||
|
close(sockets[1]);
|
||||||
|
client = wl_client_create(server.wl_display, sockets[0]);
|
||||||
|
}
|
||||||
ssize_t s = 0;
|
ssize_t s = 0;
|
||||||
while ((size_t)s < sizeof(pid_t)) {
|
while ((size_t)s < sizeof(pid_t)) {
|
||||||
s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
||||||
|
|
@ -95,6 +151,10 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
|
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client && label) {
|
||||||
|
wl_client_label_set(client, strdup(label));
|
||||||
|
}
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
#include <wlr/util/edges.h>
|
#include <wlr/util/edges.h>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "sway/client_label.h"
|
||||||
#include "sway/decoration.h"
|
#include "sway/decoration.h"
|
||||||
#include "sway/desktop.h"
|
#include "sway/desktop.h"
|
||||||
#include "sway/desktop/transaction.h"
|
#include "sway/desktop/transaction.h"
|
||||||
|
|
@ -521,3 +522,47 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
xdg_surface->data = xdg_shell_view;
|
xdg_surface->data = xdg_shell_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wl_client_label {
|
||||||
|
struct wl_listener listener;
|
||||||
|
char* label;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void wl_client_label_notify_fn(struct wl_listener *listener, void *data) {
|
||||||
|
// struct wl_client *client = data;
|
||||||
|
struct wl_client_label *label = wl_container_of(listener, label, listener);
|
||||||
|
free(label->label);
|
||||||
|
free(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *wl_client_label_get(struct wl_client *client) {
|
||||||
|
struct wl_listener *label_l =
|
||||||
|
wl_client_get_destroy_listener(client, wl_client_label_notify_fn);
|
||||||
|
if (!label_l) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct wl_client_label *label_s = wl_container_of(label_l, label_s, listener);
|
||||||
|
return label_s->label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wl_client_label_set(struct wl_client *client, char* label) {
|
||||||
|
struct wl_listener *label_l =
|
||||||
|
wl_client_get_destroy_listener(client, wl_client_label_notify_fn);
|
||||||
|
struct wl_client_label *label_s;
|
||||||
|
if (label_l) {
|
||||||
|
label_s = wl_container_of(label_l, label_s, listener);
|
||||||
|
free(label_s->label);
|
||||||
|
} else if (label == NULL) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
label_s = calloc(1, sizeof(*label_s));
|
||||||
|
if (label_s == NULL) {
|
||||||
|
sway_log(SWAY_ERROR, "Allocation failed");
|
||||||
|
free(label);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
label_s->listener.notify = wl_client_label_notify_fn;
|
||||||
|
wl_client_add_destroy_listener(client, &label_s->listener);
|
||||||
|
}
|
||||||
|
label_s->label = label;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
#endif
|
#endif
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "sway/client_label.h"
|
||||||
#include "sway/criteria.h"
|
#include "sway/criteria.h"
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/desktop.h"
|
#include "sway/desktop.h"
|
||||||
|
|
@ -110,6 +111,21 @@ const char *view_get_instance(struct sway_view *view) {
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *view_get_conn_label(struct sway_view *view) {
|
||||||
|
switch (view->type) {
|
||||||
|
case SWAY_VIEW_XDG_SHELL:;
|
||||||
|
struct wl_client *client =
|
||||||
|
wl_resource_get_client(view->surface->resource);
|
||||||
|
return wl_client_label_get(client);
|
||||||
|
#if HAVE_XWAYLAND
|
||||||
|
case SWAY_VIEW_XWAYLAND:;
|
||||||
|
// Is this concept useful in xwayland?
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
uint32_t view_get_x11_window_id(struct sway_view *view) {
|
uint32_t view_get_x11_window_id(struct sway_view *view) {
|
||||||
if (view->impl->get_int_prop) {
|
if (view->impl->get_int_prop) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue