mirror of
https://github.com/swaywm/sway.git
synced 2026-04-27 06:46:25 -04:00
ipc: added backward-compatible I3SOCK ipc
Signed-off-by: Franklin "Snaipe" Mathieu <me@snai.pe>
This commit is contained in:
parent
822b5897ad
commit
3a890efe18
4 changed files with 145 additions and 34 deletions
|
|
@ -10,7 +10,7 @@ struct sway_server;
|
|||
|
||||
void ipc_init(struct sway_server *server);
|
||||
|
||||
struct sockaddr_un *ipc_user_sockaddr(void);
|
||||
struct sockaddr_un *ipc_user_sockaddr(const char *suffix);
|
||||
|
||||
void ipc_event_workspace(struct sway_workspace *old,
|
||||
struct sway_workspace *new, const char *change);
|
||||
|
|
@ -50,5 +50,6 @@ struct ipc_client_impl {
|
|||
};
|
||||
|
||||
extern const struct ipc_client_impl ipc_client_sway;
|
||||
extern const struct ipc_client_impl ipc_client_i3;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
85
sway/ipc-i3.c
Normal file
85
sway/ipc-i3.c
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
#include <json-c/json.h>
|
||||
#include "sway/config.h"
|
||||
#include "sway/ipc-json.h"
|
||||
#include "sway/ipc-sway.h"
|
||||
#include "sway/tree/view.h"
|
||||
|
||||
static void ipc_i3_json_describe_view(struct sway_container *c, json_object *object) {
|
||||
const char *app_id = view_get_app_id(c->view);
|
||||
const char *class = app_id;
|
||||
const char *instance = app_id;
|
||||
const char *role = NULL;
|
||||
uint32_t parent_id = 0;
|
||||
uint32_t window_id = 0;
|
||||
|
||||
#if HAVE_XWAYLAND
|
||||
if (c->view->type == SWAY_VIEW_XWAYLAND) {
|
||||
class = view_get_class(c->view);
|
||||
instance = view_get_instance(c->view);
|
||||
role = view_get_window_role(c->view);
|
||||
parent_id = view_get_x11_parent_id(c->view);
|
||||
window_id = view_get_x11_window_id(c->view);
|
||||
}
|
||||
#endif
|
||||
|
||||
json_object_object_add(object, "window", json_object_new_int(window_id));
|
||||
|
||||
json_object *window_props = json_object_new_object();
|
||||
|
||||
if (class) {
|
||||
json_object_object_add(window_props, "class", json_object_new_string(class));
|
||||
}
|
||||
if (instance) {
|
||||
json_object_object_add(window_props, "instance", json_object_new_string(instance));
|
||||
}
|
||||
if (c->title) {
|
||||
json_object_object_add(window_props, "title", json_object_new_string(c->title));
|
||||
}
|
||||
if (role) {
|
||||
json_object_object_add(window_props, "window_role", json_object_new_string(role));
|
||||
}
|
||||
json_object_object_add(window_props, "transient_for",
|
||||
parent_id ? json_object_new_int(parent_id) : NULL);
|
||||
|
||||
json_object_object_add(object, "window_properties", window_props);
|
||||
}
|
||||
|
||||
static void ipc_i3_json_describe_container(struct sway_node *node, json_object *object) {
|
||||
struct sway_container *c = node->sway_container;
|
||||
ipc_json_describe_container(node->sway_container, object);
|
||||
if (c->view) {
|
||||
ipc_json_describe_view_common(node->sway_container, object);
|
||||
ipc_i3_json_describe_view(node->sway_container, object);
|
||||
}
|
||||
}
|
||||
|
||||
const ipc_json_descriptor_map ipc_json_i3_descriptors = {
|
||||
[N_ROOT] = ipc_json_describe_root,
|
||||
[N_WORKSPACE] = ipc_json_describe_workspace,
|
||||
[N_OUTPUT] = ipc_json_describe_output,
|
||||
[N_CONTAINER] = ipc_i3_json_describe_container,
|
||||
};
|
||||
|
||||
static json_object *ipc_i3_get_tree(struct ipc_client *client,
|
||||
enum ipc_command_type *type, char *buf) {
|
||||
return ipc_json_describe_node_recursive(&root->node, &ipc_json_i3_descriptors);
|
||||
}
|
||||
|
||||
static const ipc_handler i3_commands[] = {
|
||||
[IPC_COMMAND] = ipc_sway_command,
|
||||
[IPC_GET_BAR_CONFIG] = ipc_sway_get_bar_config,
|
||||
[IPC_GET_BINDING_MODES] = ipc_sway_get_binding_modes,
|
||||
[IPC_GET_CONFIG] = ipc_sway_get_config,
|
||||
[IPC_GET_MARKS] = ipc_sway_get_marks,
|
||||
[IPC_GET_OUTPUTS] = ipc_sway_get_outputs,
|
||||
[IPC_GET_TREE] = ipc_i3_get_tree,
|
||||
[IPC_GET_VERSION] = ipc_sway_get_version,
|
||||
[IPC_GET_WORKSPACES] = ipc_sway_get_workspaces,
|
||||
[IPC_SEND_TICK] = ipc_sway_send_tick,
|
||||
[IPC_SUBSCRIBE] = ipc_sway_subscribe,
|
||||
};
|
||||
|
||||
const struct ipc_client_impl ipc_client_i3 = {
|
||||
.num_commands = sizeof (i3_commands) / sizeof (*i3_commands),
|
||||
.commands = i3_commands,
|
||||
};
|
||||
|
|
@ -30,9 +30,15 @@
|
|||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
static int ipc_socket = -1;
|
||||
static struct wl_event_source *ipc_event_source = NULL;
|
||||
static struct sockaddr_un *ipc_sockaddr = NULL;
|
||||
struct ipc {
|
||||
int socket;
|
||||
struct wl_event_source *event_source;
|
||||
struct sockaddr_un *sockaddr;
|
||||
};
|
||||
|
||||
static struct ipc sway_ipc = { .socket = -1 };
|
||||
static struct ipc i3_ipc = { .socket = -1 };
|
||||
|
||||
static list_t *ipc_client_list = NULL;
|
||||
static struct wl_listener ipc_display_destroy;
|
||||
|
||||
|
|
@ -40,7 +46,6 @@ static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
|
|||
|
||||
#define IPC_HEADER_SIZE (sizeof(ipc_magic) + 8)
|
||||
|
||||
struct sockaddr_un *ipc_user_sockaddr(void);
|
||||
int ipc_handle_connection(int fd, uint32_t mask, void *data);
|
||||
int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
|
||||
int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
|
||||
|
|
@ -48,66 +53,77 @@ void ipc_client_disconnect(struct ipc_client *client);
|
|||
void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_length,
|
||||
enum ipc_command_type payload_type);
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
if (ipc_event_source) {
|
||||
wl_event_source_remove(ipc_event_source);
|
||||
static void ipc_destroy(struct ipc *ipc) {
|
||||
if (ipc->event_source) {
|
||||
wl_event_source_remove(ipc->event_source);
|
||||
}
|
||||
close(ipc_socket);
|
||||
unlink(ipc_sockaddr->sun_path);
|
||||
close(ipc->socket);
|
||||
unlink(ipc->sockaddr->sun_path);
|
||||
}
|
||||
|
||||
static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||
ipc_destroy(&sway_ipc);
|
||||
ipc_destroy(&i3_ipc);
|
||||
|
||||
while (ipc_client_list->length) {
|
||||
ipc_client_disconnect(ipc_client_list->items[ipc_client_list->length-1]);
|
||||
}
|
||||
list_free(ipc_client_list);
|
||||
|
||||
free(ipc_sockaddr);
|
||||
free(sway_ipc.sockaddr);
|
||||
free(i3_ipc.sockaddr);
|
||||
|
||||
wl_list_remove(&ipc_display_destroy.link);
|
||||
}
|
||||
|
||||
void ipc_init(struct sway_server *server) {
|
||||
ipc_socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (ipc_socket == -1) {
|
||||
static void ipc_init_socket(struct sway_server *server, struct ipc *ipc,
|
||||
const char *envvar, const char *sockpath_suffix) {
|
||||
|
||||
ipc->sockaddr = ipc_user_sockaddr(sockpath_suffix);
|
||||
ipc->socket = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (ipc->socket == -1) {
|
||||
sway_abort("Unable to create IPC socket");
|
||||
}
|
||||
if (fcntl(ipc_socket, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
if (fcntl(ipc->socket, F_SETFD, FD_CLOEXEC) == -1) {
|
||||
sway_abort("Unable to set CLOEXEC on IPC socket");
|
||||
}
|
||||
if (fcntl(ipc_socket, F_SETFL, O_NONBLOCK) == -1) {
|
||||
if (fcntl(ipc->socket, F_SETFL, O_NONBLOCK) == -1) {
|
||||
sway_abort("Unable to set NONBLOCK on IPC socket");
|
||||
}
|
||||
|
||||
ipc_sockaddr = ipc_user_sockaddr();
|
||||
|
||||
// We want to use socket name set by user, not existing socket from another sway instance.
|
||||
if (getenv("SWAYSOCK") != NULL && access(getenv("SWAYSOCK"), F_OK) == -1) {
|
||||
strncpy(ipc_sockaddr->sun_path, getenv("SWAYSOCK"), sizeof(ipc_sockaddr->sun_path) - 1);
|
||||
ipc_sockaddr->sun_path[sizeof(ipc_sockaddr->sun_path) - 1] = 0;
|
||||
if (getenv(envvar) != NULL && access(getenv(envvar), F_OK) == -1) {
|
||||
strncpy(ipc->sockaddr->sun_path, getenv(envvar), sizeof(ipc->sockaddr->sun_path) - 1);
|
||||
ipc->sockaddr->sun_path[sizeof(ipc->sockaddr->sun_path) - 1] = 0;
|
||||
}
|
||||
|
||||
unlink(ipc_sockaddr->sun_path);
|
||||
if (bind(ipc_socket, (struct sockaddr *)ipc_sockaddr, sizeof(*ipc_sockaddr)) == -1) {
|
||||
unlink(ipc->sockaddr->sun_path);
|
||||
if (bind(ipc->socket, (struct sockaddr *)ipc->sockaddr, sizeof(*ipc->sockaddr)) == -1) {
|
||||
sway_abort("Unable to bind IPC socket");
|
||||
}
|
||||
|
||||
if (listen(ipc_socket, 3) == -1) {
|
||||
if (listen(ipc->socket, 3) == -1) {
|
||||
sway_abort("Unable to listen on IPC socket");
|
||||
}
|
||||
|
||||
// Set i3 IPC socket path so that i3-msg works out of the box
|
||||
setenv("I3SOCK", ipc_sockaddr->sun_path, 1);
|
||||
setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1);
|
||||
setenv(envvar, ipc->sockaddr->sun_path, 1);
|
||||
|
||||
ipc->event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc->socket,
|
||||
WL_EVENT_READABLE, ipc_handle_connection, server);
|
||||
}
|
||||
|
||||
void ipc_init(struct sway_server *server) {
|
||||
ipc_client_list = create_list();
|
||||
|
||||
ipc_display_destroy.notify = handle_display_destroy;
|
||||
wl_display_add_destroy_listener(server->wl_display, &ipc_display_destroy);
|
||||
|
||||
ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket,
|
||||
WL_EVENT_READABLE, ipc_handle_connection, server);
|
||||
ipc_init_socket(server, &sway_ipc, "SWAYSOCK", "");
|
||||
// Set i3 IPC socket path so that i3-msg works out of the box
|
||||
ipc_init_socket(server, &i3_ipc, "I3SOCK", ".i3");
|
||||
}
|
||||
|
||||
struct sockaddr_un *ipc_user_sockaddr(void) {
|
||||
struct sockaddr_un *ipc_user_sockaddr(const char *suffix) {
|
||||
struct sockaddr_un *ipc_sockaddr = malloc(sizeof(struct sockaddr_un));
|
||||
if (ipc_sockaddr == NULL) {
|
||||
sway_abort("Can't allocate ipc_sockaddr");
|
||||
|
|
@ -122,7 +138,7 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
|
|||
dir = "/tmp";
|
||||
}
|
||||
if (path_size <= snprintf(ipc_sockaddr->sun_path, path_size,
|
||||
"%s/sway-ipc.%i.%i.sock", dir, getuid(), getpid())) {
|
||||
"%s/sway-ipc%s.%i.%i.sock", dir, suffix, getuid(), getpid())) {
|
||||
sway_abort("Socket path won't fit into ipc_sockaddr->sun_path");
|
||||
}
|
||||
|
||||
|
|
@ -130,12 +146,11 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
|
|||
}
|
||||
|
||||
int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
||||
(void) fd;
|
||||
struct sway_server *server = data;
|
||||
sway_log(SWAY_DEBUG, "Event on IPC listening socket");
|
||||
assert(mask == WL_EVENT_READABLE);
|
||||
|
||||
int client_fd = accept(ipc_socket, NULL, NULL);
|
||||
int client_fd = accept(fd, NULL, NULL);
|
||||
if (client_fd == -1) {
|
||||
sway_log_errno(SWAY_ERROR, "Unable to accept IPC client connection");
|
||||
return 0;
|
||||
|
|
@ -177,7 +192,16 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
|||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
client->impl = &ipc_client_sway;
|
||||
|
||||
if (fd == sway_ipc.socket) {
|
||||
client->impl = &ipc_client_sway;
|
||||
} else if (fd == i3_ipc.socket) {
|
||||
client->impl = &ipc_client_i3;
|
||||
} else {
|
||||
sway_log(SWAY_ERROR, "Got connection event from unknown source");
|
||||
close(client_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sway_log(SWAY_DEBUG, "New client: fd %d", client_fd);
|
||||
list_add(ipc_client_list, client);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ sway_sources = files(
|
|||
'config.c',
|
||||
'criteria.c',
|
||||
'decoration.c',
|
||||
'ipc-i3.c',
|
||||
'ipc-json.c',
|
||||
'ipc-server.c',
|
||||
'ipc-sway.c',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue