summaryrefslogtreecommitdiffstats
path: root/sway/ipc-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r--sway/ipc-server.c983
1 files changed, 227 insertions, 756 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index b560b930..045802e1 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -1,51 +1,41 @@
1// See https://i3wm.org/docs/ipc.html for protocol information 1// See https://i3wm.org/docs/ipc.html for protocol information
2
3#ifndef __FreeBSD__ 2#ifndef __FreeBSD__
4// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) 3// Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0)
5#define _XOPEN_SOURCE 700 4#define _XOPEN_SOURCE 700
6#endif 5#endif
7 6#include <assert.h>
8#include <errno.h> 7#include <errno.h>
8#include <fcntl.h>
9#include <json-c/json.h>
10#include <stdbool.h>
11#include <stdint.h>
12#include <stdlib.h>
9#include <string.h> 13#include <string.h>
10#include <sys/socket.h> 14#include <sys/socket.h>
15#include <sys/ioctl.h>
11#include <sys/un.h> 16#include <sys/un.h>
12#include <stdbool.h>
13#include <wlc/wlc-render.h>
14#include <unistd.h> 17#include <unistd.h>
15#include <stdlib.h> 18#include <wayland-server.h>
16#include <sys/ioctl.h> 19#include "sway/commands.h"
17#include <fcntl.h>
18#include <json-c/json.h>
19#include <list.h>
20#include <libinput.h>
21#ifdef __linux__
22struct ucred {
23 pid_t pid;
24 uid_t uid;
25 gid_t gid;
26};
27#endif
28#include "sway/ipc-json.h" 20#include "sway/ipc-json.h"
29#include "sway/ipc-server.h" 21#include "sway/ipc-server.h"
30#include "sway/security.h" 22#include "sway/server.h"
31#include "sway/config.h" 23#include "sway/input/input-manager.h"
32#include "sway/commands.h" 24#include "sway/input/seat.h"
33#include "sway/input.h"
34#include "stringop.h"
35#include "log.h"
36#include "list.h" 25#include "list.h"
37#include "util.h" 26#include "log.h"
38 27
39static int ipc_socket = -1; 28static int ipc_socket = -1;
40static struct wlc_event_source *ipc_event_source = NULL; 29static struct wl_event_source *ipc_event_source = NULL;
41static struct sockaddr_un *ipc_sockaddr = NULL; 30static struct sockaddr_un *ipc_sockaddr = NULL;
42static list_t *ipc_client_list = NULL; 31static list_t *ipc_client_list = NULL;
43 32
44static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; 33static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
45 34
46struct ipc_client { 35struct ipc_client {
47 struct wlc_event_source *event_source; 36 struct wl_event_source *event_source;
48 struct wlc_event_source *writable_event_source; 37 struct wl_event_source *writable_event_source;
38 struct sway_server *server;
49 int fd; 39 int fd;
50 uint32_t payload_length; 40 uint32_t payload_length;
51 uint32_t security_policy; 41 uint32_t security_policy;
@@ -56,27 +46,6 @@ struct ipc_client {
56 char *write_buffer; 46 char *write_buffer;
57}; 47};
58 48
59static list_t *ipc_get_pixel_requests = NULL;
60
61struct get_pixels_request {
62 struct ipc_client *client;
63 wlc_handle output;
64 struct wlc_geometry geo;
65};
66
67struct get_clipboard_request {
68 struct ipc_client *client;
69 json_object *json;
70 int fd;
71 struct wlc_event_source *fd_event_source;
72 struct wlc_event_source *timer_event_source;
73 char *type;
74 unsigned int *pending;
75 char *buf;
76 size_t buf_size;
77 size_t buf_position;
78};
79
80struct sockaddr_un *ipc_user_sockaddr(void); 49struct sockaddr_un *ipc_user_sockaddr(void);
81int ipc_handle_connection(int fd, uint32_t mask, void *data); 50int ipc_handle_connection(int fd, uint32_t mask, void *data);
82int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); 51int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data);
@@ -84,11 +53,8 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data);
84void ipc_client_disconnect(struct ipc_client *client); 53void ipc_client_disconnect(struct ipc_client *client);
85void ipc_client_handle_command(struct ipc_client *client); 54void ipc_client_handle_command(struct ipc_client *client);
86bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length); 55bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t payload_length);
87void ipc_get_workspaces_callback(swayc_t *workspace, void *data);
88void ipc_get_outputs_callback(swayc_t *container, void *data);
89static void ipc_get_marks_callback(swayc_t *container, void *data);
90 56
91void ipc_init(void) { 57void ipc_init(struct sway_server *server) {
92 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); 58 ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
93 if (ipc_socket == -1) { 59 if (ipc_socket == -1) {
94 sway_abort("Unable to create IPC socket"); 60 sway_abort("Unable to create IPC socket");
@@ -116,14 +82,14 @@ void ipc_init(void) {
116 setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1); 82 setenv("SWAYSOCK", ipc_sockaddr->sun_path, 1);
117 83
118 ipc_client_list = create_list(); 84 ipc_client_list = create_list();
119 ipc_get_pixel_requests = create_list();
120 85
121 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); 86 ipc_event_source = wl_event_loop_add_fd(server->wl_event_loop, ipc_socket,
87 WL_EVENT_READABLE, ipc_handle_connection, server);
122} 88}
123 89
124void ipc_terminate(void) { 90void ipc_terminate(void) {
125 if (ipc_event_source) { 91 if (ipc_event_source) {
126 wlc_event_source_remove(ipc_event_source); 92 wl_event_source_remove(ipc_event_source);
127 } 93 }
128 close(ipc_socket); 94 close(ipc_socket);
129 unlink(ipc_sockaddr->sun_path); 95 unlink(ipc_sockaddr->sun_path);
@@ -157,100 +123,82 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
157 return ipc_sockaddr; 123 return ipc_sockaddr;
158} 124}
159 125
160static pid_t get_client_pid(int client_fd) {
161// FreeBSD supports getting uid/gid, but not pid
162#ifdef __linux__
163 struct ucred ucred;
164 socklen_t len = sizeof(struct ucred);
165
166 if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) {
167 return -1;
168 }
169
170 return ucred.pid;
171#else
172 return -1;
173#endif
174}
175
176int ipc_handle_connection(int fd, uint32_t mask, void *data) { 126int ipc_handle_connection(int fd, uint32_t mask, void *data) {
177 (void) fd; (void) data; 127 (void) fd;
178 sway_log(L_DEBUG, "Event on IPC listening socket"); 128 struct sway_server *server = data;
179 assert(mask == WLC_EVENT_READABLE); 129 wlr_log(L_DEBUG, "Event on IPC listening socket");
130 assert(mask == WL_EVENT_READABLE);
180 131
181 int client_fd = accept(ipc_socket, NULL, NULL); 132 int client_fd = accept(ipc_socket, NULL, NULL);
182 if (client_fd == -1) { 133 if (client_fd == -1) {
183 sway_log_errno(L_ERROR, "Unable to accept IPC client connection"); 134 wlr_log_errno(L_ERROR, "Unable to accept IPC client connection");
184 return 0; 135 return 0;
185 } 136 }
186 137
187 int flags; 138 int flags;
188 if ((flags = fcntl(client_fd, F_GETFD)) == -1 139 if ((flags = fcntl(client_fd, F_GETFD)) == -1
189 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) { 140 || fcntl(client_fd, F_SETFD, flags|FD_CLOEXEC) == -1) {
190 sway_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket"); 141 wlr_log_errno(L_ERROR, "Unable to set CLOEXEC on IPC client socket");
191 close(client_fd); 142 close(client_fd);
192 return 0; 143 return 0;
193 } 144 }
194 if ((flags = fcntl(client_fd, F_GETFL)) == -1 145 if ((flags = fcntl(client_fd, F_GETFL)) == -1
195 || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) { 146 || fcntl(client_fd, F_SETFL, flags|O_NONBLOCK) == -1) {
196 sway_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket"); 147 wlr_log_errno(L_ERROR, "Unable to set NONBLOCK on IPC client socket");
197 close(client_fd); 148 close(client_fd);
198 return 0; 149 return 0;
199 } 150 }
200 151
201 struct ipc_client* client = malloc(sizeof(struct ipc_client)); 152 struct ipc_client *client = malloc(sizeof(struct ipc_client));
202 if (!client) { 153 if (!client) {
203 sway_log(L_ERROR, "Unable to allocate ipc client"); 154 wlr_log(L_ERROR, "Unable to allocate ipc client");
204 close(client_fd); 155 close(client_fd);
205 return 0; 156 return 0;
206 } 157 }
158 client->server = server;
207 client->payload_length = 0; 159 client->payload_length = 0;
208 client->fd = client_fd; 160 client->fd = client_fd;
209 client->subscribed_events = 0; 161 client->subscribed_events = 0;
210 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); 162 client->event_source = wl_event_loop_add_fd(server->wl_event_loop,
163 client_fd, WL_EVENT_READABLE, ipc_client_handle_readable, client);
211 client->writable_event_source = NULL; 164 client->writable_event_source = NULL;
212 165
213 client->write_buffer_size = 128; 166 client->write_buffer_size = 128;
214 client->write_buffer_len = 0; 167 client->write_buffer_len = 0;
215 client->write_buffer = malloc(client->write_buffer_size); 168 client->write_buffer = malloc(client->write_buffer_size);
216 if (!client->write_buffer) { 169 if (!client->write_buffer) {
217 sway_log(L_ERROR, "Unable to allocate ipc client write buffer"); 170 wlr_log(L_ERROR, "Unable to allocate ipc client write buffer");
218 close(client_fd); 171 close(client_fd);
219 return 0; 172 return 0;
220 } 173 }
221 174
222 pid_t pid = get_client_pid(client->fd); 175 wlr_log(L_DEBUG, "New client: fd %d", client_fd);
223 client->security_policy = get_ipc_policy_mask(pid);
224
225 sway_log(L_DEBUG, "New client: fd %d, pid %d", client_fd, pid);
226
227 list_add(ipc_client_list, client); 176 list_add(ipc_client_list, client);
228
229 return 0; 177 return 0;
230} 178}
231 179
232static const int ipc_header_size = sizeof(ipc_magic)+8; 180static const int ipc_header_size = sizeof(ipc_magic) + 8;
233 181
234int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { 182int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
235 struct ipc_client *client = data; 183 struct ipc_client *client = data;
236 184
237 if (mask & WLC_EVENT_ERROR) { 185 if (mask & WL_EVENT_ERROR) {
238 sway_log(L_ERROR, "IPC Client socket error, removing client"); 186 wlr_log(L_ERROR, "IPC Client socket error, removing client");
239 ipc_client_disconnect(client); 187 ipc_client_disconnect(client);
240 return 0; 188 return 0;
241 } 189 }
242 190
243 if (mask & WLC_EVENT_HANGUP) { 191 if (mask & WL_EVENT_HANGUP) {
244 sway_log(L_DEBUG, "Client %d hung up", client->fd); 192 wlr_log(L_DEBUG, "Client %d hung up", client->fd);
245 ipc_client_disconnect(client); 193 ipc_client_disconnect(client);
246 return 0; 194 return 0;
247 } 195 }
248 196
249 sway_log(L_DEBUG, "Client %d readable", client->fd); 197 wlr_log(L_DEBUG, "Client %d readable", client->fd);
250 198
251 int read_available; 199 int read_available;
252 if (ioctl(client_fd, FIONREAD, &read_available) == -1) { 200 if (ioctl(client_fd, FIONREAD, &read_available) == -1) {
253 sway_log_errno(L_INFO, "Unable to read IPC socket buffer size"); 201 wlr_log_errno(L_INFO, "Unable to read IPC socket buffer size");
254 ipc_client_disconnect(client); 202 ipc_client_disconnect(client);
255 return 0; 203 return 0;
256 } 204 }
@@ -272,13 +220,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
272 // Should be fully available, because read_available >= ipc_header_size 220 // Should be fully available, because read_available >= ipc_header_size
273 ssize_t received = recv(client_fd, buf, ipc_header_size, 0); 221 ssize_t received = recv(client_fd, buf, ipc_header_size, 0);
274 if (received == -1) { 222 if (received == -1) {
275 sway_log_errno(L_INFO, "Unable to receive header from IPC client"); 223 wlr_log_errno(L_INFO, "Unable to receive header from IPC client");
276 ipc_client_disconnect(client); 224 ipc_client_disconnect(client);
277 return 0; 225 return 0;
278 } 226 }
279 227
280 if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) { 228 if (memcmp(buf, ipc_magic, sizeof(ipc_magic)) != 0) {
281 sway_log(L_DEBUG, "IPC header check failed"); 229 wlr_log(L_DEBUG, "IPC header check failed");
282 ipc_client_disconnect(client); 230 ipc_client_disconnect(client);
283 return 0; 231 return 0;
284 } 232 }
@@ -293,17 +241,110 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
293 return 0; 241 return 0;
294} 242}
295 243
244static bool ipc_has_event_listeners(enum ipc_command_type event) {
245 for (int i = 0; i < ipc_client_list->length; i++) {
246 struct ipc_client *client = ipc_client_list->items[i];
247 if ((client->subscribed_events & event_mask(event)) == 0) {
248 return true;
249 }
250 }
251 return false;
252}
253
254static void ipc_send_event(const char *json_string, enum ipc_command_type event) {
255 struct ipc_client *client;
256 for (int i = 0; i < ipc_client_list->length; i++) {
257 client = ipc_client_list->items[i];
258 if ((client->subscribed_events & event_mask(event)) == 0) {
259 continue;
260 }
261 client->current_command = event;
262 if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) {
263 wlr_log_errno(L_INFO, "Unable to send reply to IPC client");
264 ipc_client_disconnect(client);
265 }
266 }
267}
268
269void ipc_event_workspace(struct sway_container *old,
270 struct sway_container *new, const char *change) {
271 if (!ipc_has_event_listeners(IPC_EVENT_WORKSPACE)) {
272 return;
273 }
274 wlr_log(L_DEBUG, "Sending workspace::%s event", change);
275 json_object *obj = json_object_new_object();
276 json_object_object_add(obj, "change", json_object_new_string(change));
277 if (strcmp("focus", change) == 0) {
278 if (old) {
279 json_object_object_add(obj, "old",
280 ipc_json_describe_container_recursive(old));
281 } else {
282 json_object_object_add(obj, "old", NULL);
283 }
284 }
285
286 if (new) {
287 json_object_object_add(obj, "current",
288 ipc_json_describe_container_recursive(new));
289 } else {
290 json_object_object_add(obj, "current", NULL);
291 }
292
293 const char *json_string = json_object_to_json_string(obj);
294 ipc_send_event(json_string, IPC_EVENT_WORKSPACE);
295 json_object_put(obj);
296}
297
298void ipc_event_window(struct sway_container *window, const char *change) {
299 if (!ipc_has_event_listeners(IPC_EVENT_WINDOW)) {
300 return;
301 }
302 wlr_log(L_DEBUG, "Sending window::%s event", change);
303 json_object *obj = json_object_new_object();
304 json_object_object_add(obj, "change", json_object_new_string(change));
305 json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
306
307 const char *json_string = json_object_to_json_string(obj);
308 ipc_send_event(json_string, IPC_EVENT_WINDOW);
309 json_object_put(obj);
310}
311
312void ipc_event_barconfig_update(struct bar_config *bar) {
313 if (!ipc_has_event_listeners(IPC_EVENT_BARCONFIG_UPDATE)) {
314 return;
315 }
316 wlr_log(L_DEBUG, "Sending barconfig_update event");
317 json_object *json = ipc_json_describe_bar_config(bar);
318
319 const char *json_string = json_object_to_json_string(json);
320 ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE);
321 json_object_put(json);
322}
323
324void ipc_event_mode(const char *mode) {
325 if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
326 return;
327 }
328 wlr_log(L_DEBUG, "Sending mode::%s event", mode);
329 json_object *obj = json_object_new_object();
330 json_object_object_add(obj, "change", json_object_new_string(mode));
331
332 const char *json_string = json_object_to_json_string(obj);
333 ipc_send_event(json_string, IPC_EVENT_MODE);
334 json_object_put(obj);
335}
336
296int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { 337int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
297 struct ipc_client *client = data; 338 struct ipc_client *client = data;
298 339
299 if (mask & WLC_EVENT_ERROR) { 340 if (mask & WL_EVENT_ERROR) {
300 sway_log(L_ERROR, "IPC Client socket error, removing client"); 341 wlr_log(L_ERROR, "IPC Client socket error, removing client");
301 ipc_client_disconnect(client); 342 ipc_client_disconnect(client);
302 return 0; 343 return 0;
303 } 344 }
304 345
305 if (mask & WLC_EVENT_HANGUP) { 346 if (mask & WL_EVENT_HANGUP) {
306 sway_log(L_DEBUG, "Client %d hung up", client->fd); 347 wlr_log(L_DEBUG, "Client %d hung up", client->fd);
307 ipc_client_disconnect(client); 348 ipc_client_disconnect(client);
308 return 0; 349 return 0;
309 } 350 }
@@ -312,14 +353,14 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
312 return 0; 353 return 0;
313 } 354 }
314 355
315 sway_log(L_DEBUG, "Client %d writable", client->fd); 356 wlr_log(L_DEBUG, "Client %d writable", client->fd);
316 357
317 ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len); 358 ssize_t written = write(client->fd, client->write_buffer, client->write_buffer_len);
318 359
319 if (written == -1 && errno == EAGAIN) { 360 if (written == -1 && errno == EAGAIN) {
320 return 0; 361 return 0;
321 } else if (written == -1) { 362 } else if (written == -1) {
322 sway_log_errno(L_INFO, "Unable to send data from queue to IPC client"); 363 wlr_log_errno(L_INFO, "Unable to send data from queue to IPC client");
323 ipc_client_disconnect(client); 364 ipc_client_disconnect(client);
324 return 0; 365 return 0;
325 } 366 }
@@ -328,7 +369,7 @@ int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) {
328 client->write_buffer_len -= written; 369 client->write_buffer_len -= written;
329 370
330 if (client->write_buffer_len == 0 && client->writable_event_source) { 371 if (client->write_buffer_len == 0 && client->writable_event_source) {
331 wlc_event_source_remove(client->writable_event_source); 372 wl_event_source_remove(client->writable_event_source);
332 client->writable_event_source = NULL; 373 client->writable_event_source = NULL;
333 } 374 }
334 375
@@ -344,332 +385,48 @@ void ipc_client_disconnect(struct ipc_client *client) {
344 shutdown(client->fd, SHUT_RDWR); 385 shutdown(client->fd, SHUT_RDWR);
345 } 386 }
346 387
347 sway_log(L_INFO, "IPC Client %d disconnected", client->fd); 388 wlr_log(L_INFO, "IPC Client %d disconnected", client->fd);
348 wlc_event_source_remove(client->event_source); 389 wl_event_source_remove(client->event_source);
349 if (client->writable_event_source) { 390 if (client->writable_event_source) {
350 wlc_event_source_remove(client->writable_event_source); 391 wl_event_source_remove(client->writable_event_source);
351 } 392 }
352 int i = 0; 393 int i = 0;
353 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++; 394 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) {
395 i++;
396 }
354 list_del(ipc_client_list, i); 397 list_del(ipc_client_list, i);
355 free(client->write_buffer); 398 free(client->write_buffer);
356 close(client->fd); 399 close(client->fd);
357 free(client); 400 free(client);
358} 401}
359 402
360bool output_by_name_test(swayc_t *view, void *data) { 403static void ipc_get_workspaces_callback(struct sway_container *workspace,
361 char *name = (char *)data; 404 void *data) {
362 if (view->type != C_OUTPUT) { 405 if (workspace->type != C_WORKSPACE) {
363 return false;
364 }
365 return !strcmp(name, view->name);
366}
367
368void ipc_get_pixels(wlc_handle output) {
369 if (ipc_get_pixel_requests->length == 0) {
370 return; 406 return;
371 } 407 }
372 408 json_object *workspace_json = ipc_json_describe_container(workspace);
373 list_t *unhandled = create_list(); 409 // override the default focused indicator because
374 410 // it's set differently for the get_workspaces reply
375 struct get_pixels_request *req; 411 struct sway_seat *seat =
376 int i; 412 input_manager_get_default_seat(input_manager);
377 for (i = 0; i < ipc_get_pixel_requests->length; ++i) { 413 struct sway_container *focused_ws = seat_get_focus(seat);
378 req = ipc_get_pixel_requests->items[i]; 414 if (focused_ws != NULL && focused_ws->type != C_WORKSPACE) {
379 if (req->output != output) { 415 focused_ws = container_parent(focused_ws, C_WORKSPACE);
380 list_add(unhandled, req); 416 }
381 continue; 417 bool focused = workspace == focused_ws;
382 } 418 json_object_object_del(workspace_json, "focused");
383 419 json_object_object_add(workspace_json, "focused",
384 const struct wlc_size *size = &req->geo.size; 420 json_object_new_boolean(focused));
385 struct wlc_geometry g_out; 421 json_object_array_add((json_object *)data, workspace_json);
386 char response_header[9]; 422
387 memset(response_header, 0, sizeof(response_header)); 423 focused_ws = seat_get_focus_inactive(seat, workspace->parent);
388 char *data = malloc(sizeof(response_header) + size->w * size->h * 4); 424 if (focused_ws->type != C_WORKSPACE) {
389 if (!data) { 425 focused_ws = container_parent(focused_ws, C_WORKSPACE);
390 sway_log(L_ERROR, "Unable to allocate pixels for get_pixels"); 426 }
391 ipc_client_disconnect(req->client); 427 bool visible = workspace == focused_ws;
392 free(req); 428 json_object_object_add(workspace_json, "visible",
393 continue; 429 json_object_new_boolean(visible));
394 }
395 wlc_pixels_read(WLC_RGBA8888, &req->geo, &g_out, data + sizeof(response_header));
396
397 response_header[0] = 1;
398 uint32_t *_size = (uint32_t *)(response_header + 1);
399 _size[0] = g_out.size.w;
400 _size[1] = g_out.size.h;
401 size_t len = sizeof(response_header) + (g_out.size.w * g_out.size.h * 4);
402 memcpy(data, response_header, sizeof(response_header));
403 ipc_send_reply(req->client, data, len);
404 free(data);
405 // free the request since it has been handled
406 free(req);
407 }
408
409 // free old list of pixel requests and set new list to all unhandled
410 // requests (request for another output).
411 list_free(ipc_get_pixel_requests);
412 ipc_get_pixel_requests = unhandled;
413}
414
415static bool is_text_target(const char *target) {
416 return (strncmp(target, "text/", 5) == 0
417 || strcmp(target, "UTF8_STRING") == 0
418 || strcmp(target, "STRING") == 0
419 || strcmp(target, "TEXT") == 0
420 || strcmp(target, "COMPOUND_TEXT") == 0);
421}
422
423static void release_clipboard_request(struct get_clipboard_request *req) {
424 if (--(*req->pending) == 0) {
425 const char *str = json_object_to_json_string(req->json);
426 ipc_send_reply(req->client, str, (uint32_t)strlen(str));
427 json_object_put(req->json);
428 }
429
430 free(req->type);
431 free(req->buf);
432 wlc_event_source_remove(req->fd_event_source);
433 wlc_event_source_remove(req->timer_event_source);
434 close(req->fd);
435 free(req);
436}
437
438static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
439 assert(data);
440 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
441
442 if (mask & WLC_EVENT_ERROR) {
443 sway_log(L_ERROR, "Selection data fd error");
444 goto error;
445 }
446
447 if (mask & WLC_EVENT_READABLE) {
448 static const unsigned int max_size = 8192 * 1024;
449 int amt = 0;
450
451 do {
452 int size = req->buf_size - req->buf_position;
453 int amt = read(fd, req->buf + req->buf_position, size - 1);
454 if (amt < 0) {
455 if (errno == EAGAIN) {
456 return 0;
457 }
458
459 sway_log_errno(L_INFO, "Failed to read from clipboard data fd");
460 goto release;
461 }
462
463 req->buf_position += amt;
464 if (req->buf_position >= req->buf_size - 1) {
465 if (req->buf_size >= max_size) {
466 sway_log(L_ERROR, "get_clipbard: selection data too large");
467 goto error;
468 }
469 char *next = realloc(req->buf, req->buf_size *= 2);
470 if (!next) {
471 sway_log_errno(L_ERROR, "get_clipboard: realloc data buffer failed");
472 goto error;
473 }
474
475 req->buf = next;
476 }
477 } while(amt != 0);
478
479 req->buf[req->buf_position] = '\0';
480
481 json_object *obj = json_object_new_object();
482 json_object_object_add(obj, "success", json_object_new_boolean(true));
483 if (is_text_target(req->type)) {
484 json_object_object_add(obj, "content", json_object_new_string(req->buf));
485 json_object_object_add(req->json, req->type, obj);
486 } else {
487 size_t outlen;
488 char *b64 = b64_encode(req->buf, req->buf_position, &outlen);
489 json_object_object_add(obj, "content", json_object_new_string(b64));
490 free(b64);
491
492 char *type = malloc(strlen(req->type) + 8);
493 strcat(type, ";base64");
494 json_object_object_add(req->json, type, obj);
495 free(type);
496 }
497 }
498
499 goto release;
500
501error:;
502 json_object *obj = json_object_new_object();
503 json_object_object_add(obj, "success", json_object_new_boolean(false));
504 json_object_object_add(obj, "error",
505 json_object_new_string("Failed to retrieve data"));
506 json_object_object_add(req->json, req->type, obj);
507
508release:
509 release_clipboard_request(req);
510 return 0;
511}
512
513static int ipc_selection_timer_cb(void *data) {
514 assert(data);
515 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
516
517 sway_log(L_INFO, "get_clipbard: timeout for type %s", req->type);
518 json_object *obj = json_object_new_object();
519 json_object_object_add(obj, "success", json_object_new_boolean(false));
520 json_object_object_add(obj, "error", json_object_new_string("Timeout"));
521 json_object_object_add(req->json, req->type, obj);
522
523 release_clipboard_request(req);
524 return 0;
525}
526
527// greedy wildcard (only "*") matching
528bool mime_type_matches(const char *mime_type, const char *pattern) {
529 const char *wildcard = NULL;
530 while (*mime_type && *pattern) {
531 if (*pattern == '*' && !wildcard) {
532 wildcard = pattern;
533 ++pattern;
534 }
535
536 if (*mime_type != *pattern) {
537 if (!wildcard)
538 return false;
539
540 pattern = wildcard;
541 ++mime_type;
542 continue;
543 }
544
545 ++mime_type;
546 ++pattern;
547 }
548
549 while (*pattern == '*') {
550 ++pattern;
551 }
552
553 return (*mime_type == *pattern);
554}
555
556void ipc_get_clipboard(struct ipc_client *client, char *buf) {
557 size_t size;
558 const char **types = wlc_get_selection_types(&size);
559 if (client->payload_length == 0) {
560 json_object *obj = json_object_new_array();
561 for (size_t i = 0; i < size; ++i) {
562 json_object_array_add(obj, json_object_new_string(types[i]));
563 }
564
565 const char *str = json_object_to_json_string(obj);
566 ipc_send_reply(client, str, strlen(str));
567 json_object_put(obj);
568 return;
569 }
570
571 unescape_string(buf);
572 strip_quotes(buf);
573 list_t *requested = split_string(buf, " ");
574 json_object *json = json_object_new_object();
575 unsigned int *pending = malloc(sizeof(unsigned int));
576 *pending = 0;
577
578 for (size_t l = 0; l < (size_t) requested->length; ++l) {
579 const char *pattern = requested->items[l];
580 bool found = false;
581 for (size_t i = 0; i < size; ++i) {
582 if (!mime_type_matches(types[i], pattern)) {
583 continue;
584 }
585
586 found = true;
587
588 struct get_clipboard_request *req = malloc(sizeof(*req));
589 if (!req) {
590 sway_log(L_ERROR, "get_clipboard: request malloc failed");
591 goto data_error;
592 }
593
594 int pipes[2];
595 if (pipe(pipes) == -1) {
596 sway_log_errno(L_ERROR, "get_clipboard: pipe call failed");
597 free(req);
598 goto data_error;
599 }
600
601 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
602 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
603
604 if (!wlc_get_selection_data(types[i], pipes[1])) {
605 close(pipes[0]);
606 close(pipes[1]);
607 free(req);
608 sway_log(L_ERROR, "get_clipboard: failed to retrieve "
609 "selection data");
610 goto data_error;
611 }
612
613 if (!(req->buf = malloc(512))) {
614 close(pipes[0]);
615 close(pipes[1]);
616 free(req);
617 sway_log_errno(L_ERROR, "get_clipboard: buf malloc failed");
618 goto data_error;
619 }
620
621 (*pending)++;
622
623 req->client = client;
624 req->type = strdup(types[i]);
625 req->json = json;
626 req->pending = pending;
627 req->buf_position = 0;
628 req->buf_size = 512;
629 req->fd = pipes[0];
630 req->timer_event_source = wlc_event_loop_add_timer(ipc_selection_timer_cb, req);
631 req->fd_event_source = wlc_event_loop_add_fd(pipes[0],
632 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
633 &ipc_selection_data_cb, req);
634
635 wlc_event_source_timer_update(req->timer_event_source, 30000);
636
637 // NOTE: remove this goto to enable retrieving multiple
638 // targets at once. The whole implementation is already
639 // made for it. The only reason it was disabled
640 // at the time of writing is that neither wlc's xselection
641 // implementation nor (apparently) gtk on wayland supports
642 // multiple send requests at the same time which makes
643 // every request except the last one fail (and therefore
644 // return empty data)
645 goto cleanup;
646 }
647
648 if (!found) {
649 sway_log(L_INFO, "Invalid clipboard type %s requested", pattern);
650 }
651 }
652
653 if (*pending == 0) {
654 static const char *error_empty = "{ \"success\": false, \"error\": "
655 "\"No matching types found\" }";
656 ipc_send_reply(client, error_empty, (uint32_t)strlen(error_empty));
657 free(json);
658 free(pending);
659 }
660
661 goto cleanup;
662
663data_error:;
664 static const char *error_json = "{ \"success\": false, \"error\": "
665 "\"Failed to create clipboard data request\" }";
666 ipc_send_reply(client, error_json, (uint32_t)strlen(error_json));
667 free(json);
668 free(pending);
669
670cleanup:
671 list_free(requested);
672 free(types);
673} 430}
674 431
675void ipc_client_handle_command(struct ipc_client *client) { 432void ipc_client_handle_command(struct ipc_client *client) {
@@ -679,7 +436,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
679 436
680 char *buf = malloc(client->payload_length + 1); 437 char *buf = malloc(client->payload_length + 1);
681 if (!buf) { 438 if (!buf) {
682 sway_log_errno(L_INFO, "Unable to allocate IPC payload"); 439 wlr_log_errno(L_INFO, "Unable to allocate IPC payload");
683 ipc_client_disconnect(client); 440 ipc_client_disconnect(client);
684 return; 441 return;
685 } 442 }
@@ -688,7 +445,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
688 ssize_t received = recv(client->fd, buf, client->payload_length, 0); 445 ssize_t received = recv(client->fd, buf, client->payload_length, 0);
689 if (received == -1) 446 if (received == -1)
690 { 447 {
691 sway_log_errno(L_INFO, "Unable to receive payload from IPC client"); 448 wlr_log_errno(L_INFO, "Unable to receive payload from IPC client");
692 ipc_client_disconnect(client); 449 ipc_client_disconnect(client);
693 free(buf); 450 free(buf);
694 return; 451 return;
@@ -701,10 +458,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
701 switch (client->current_command) { 458 switch (client->current_command) {
702 case IPC_COMMAND: 459 case IPC_COMMAND:
703 { 460 {
704 if (!(client->security_policy & IPC_FEATURE_COMMAND)) { 461 config_clear_handler_context(config);
705 goto exit_denied; 462 struct cmd_results *results = execute_command(buf, NULL);
706 }
707 struct cmd_results *results = handle_command(buf, CONTEXT_IPC);
708 const char *json = cmd_results_to_json(results); 463 const char *json = cmd_results_to_json(results);
709 char reply[256]; 464 char reply[256];
710 int length = snprintf(reply, sizeof(reply), "%s", json); 465 int length = snprintf(reply, sizeof(reply), "%s", json);
@@ -713,18 +468,45 @@ void ipc_client_handle_command(struct ipc_client *client) {
713 goto exit_cleanup; 468 goto exit_cleanup;
714 } 469 }
715 470
471 case IPC_GET_OUTPUTS:
472 {
473 json_object *outputs = json_object_new_array();
474 for (int i = 0; i < root_container.children->length; ++i) {
475 struct sway_container *container = root_container.children->items[i];
476 if (container->type == C_OUTPUT) {
477 json_object_array_add(outputs,
478 ipc_json_describe_container(container));
479 }
480 }
481 const char *json_string = json_object_to_json_string(outputs);
482 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
483 json_object_put(outputs); // free
484 goto exit_cleanup;
485 }
486
487 case IPC_GET_WORKSPACES:
488 {
489 json_object *workspaces = json_object_new_array();
490 container_for_each_descendant_dfs(&root_container,
491 ipc_get_workspaces_callback, workspaces);
492 const char *json_string = json_object_to_json_string(workspaces);
493 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
494 json_object_put(workspaces); // free
495 goto exit_cleanup;
496 }
497
716 case IPC_SUBSCRIBE: 498 case IPC_SUBSCRIBE:
717 { 499 {
718 // TODO: Check if they're permitted to use these events 500 // TODO: Check if they're permitted to use these events
719 struct json_object *request = json_tokener_parse(buf); 501 struct json_object *request = json_tokener_parse(buf);
720 if (request == NULL) { 502 if (request == NULL) {
721 ipc_send_reply(client, "{\"success\": false}", 18); 503 ipc_send_reply(client, "{\"success\": false}", 18);
722 sway_log_errno(L_INFO, "Failed to read request"); 504 wlr_log_errno(L_INFO, "Failed to read request");
723 goto exit_cleanup; 505 goto exit_cleanup;
724 } 506 }
725 507
726 // parse requested event types 508 // parse requested event types
727 for (int i = 0; i < json_object_array_length(request); i++) { 509 for (size_t i = 0; i < json_object_array_length(request); i++) {
728 const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); 510 const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
729 if (strcmp(event_type, "workspace") == 0) { 511 if (strcmp(event_type, "workspace") == 0) {
730 client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); 512 client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE);
@@ -741,86 +523,39 @@ void ipc_client_handle_command(struct ipc_client *client) {
741 } else { 523 } else {
742 ipc_send_reply(client, "{\"success\": false}", 18); 524 ipc_send_reply(client, "{\"success\": false}", 18);
743 json_object_put(request); 525 json_object_put(request);
744 sway_log_errno(L_INFO, "Failed to parse request"); 526 wlr_log_errno(L_INFO, "Failed to parse request");
745 goto exit_cleanup; 527 goto exit_cleanup;
746 } 528 }
747 } 529 }
748 530
749 json_object_put(request); 531 json_object_put(request);
750
751 ipc_send_reply(client, "{\"success\": true}", 17); 532 ipc_send_reply(client, "{\"success\": true}", 17);
752 goto exit_cleanup; 533 goto exit_cleanup;
753 } 534 }
754 535
755 case IPC_GET_WORKSPACES:
756 {
757 if (!(client->security_policy & IPC_FEATURE_GET_WORKSPACES)) {
758 goto exit_denied;
759 }
760 json_object *workspaces = json_object_new_array();
761 container_map(&root_container, ipc_get_workspaces_callback, workspaces);
762 const char *json_string = json_object_to_json_string(workspaces);
763 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
764 json_object_put(workspaces); // free
765 goto exit_cleanup;
766 }
767
768 case IPC_GET_INPUTS: 536 case IPC_GET_INPUTS:
769 { 537 {
770 if (!(client->security_policy & IPC_FEATURE_GET_INPUTS)) {
771 goto exit_denied;
772 }
773 json_object *inputs = json_object_new_array(); 538 json_object *inputs = json_object_new_array();
774 if (input_devices) { 539 struct sway_input_device *device = NULL;
775 for(int i = 0; i<input_devices->length; i++) { 540 wl_list_for_each(device, &input_manager->devices, link) {
776 struct libinput_device *device = input_devices->items[i]; 541 json_object_array_add(inputs, ipc_json_describe_input(device));
777 json_object_array_add(inputs, ipc_json_describe_input(device));
778 }
779 } 542 }
780 const char *json_string = json_object_to_json_string(inputs); 543 const char *json_string = json_object_to_json_string(inputs);
781 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 544 ipc_send_reply(client, json_string, (uint32_t)strlen(json_string));
782 json_object_put(inputs); 545 json_object_put(inputs); // free
783 goto exit_cleanup;
784 }
785
786 case IPC_GET_OUTPUTS:
787 {
788 if (!(client->security_policy & IPC_FEATURE_GET_OUTPUTS)) {
789 goto exit_denied;
790 }
791 json_object *outputs = json_object_new_array();
792 container_map(&root_container, ipc_get_outputs_callback, outputs);
793 const char *json_string = json_object_to_json_string(outputs);
794 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
795 json_object_put(outputs); // free
796 goto exit_cleanup; 546 goto exit_cleanup;
797 } 547 }
798 548
799 case IPC_GET_TREE: 549 case IPC_GET_TREE:
800 { 550 {
801 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { 551 json_object *tree =
802 goto exit_denied; 552 ipc_json_describe_container_recursive(&root_container);
803 }
804 json_object *tree = ipc_json_describe_container_recursive(&root_container);
805 const char *json_string = json_object_to_json_string(tree); 553 const char *json_string = json_object_to_json_string(tree);
806 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 554 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
807 json_object_put(tree); 555 json_object_put(tree);
808 goto exit_cleanup; 556 goto exit_cleanup;
809 } 557 }
810 558
811 case IPC_GET_MARKS:
812 {
813 if (!(client->security_policy & IPC_FEATURE_GET_MARKS)) {
814 goto exit_denied;
815 }
816 json_object *marks = json_object_new_array();
817 container_map(&root_container, ipc_get_marks_callback, marks);
818 const char *json_string = json_object_to_json_string(marks);
819 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
820 json_object_put(marks);
821 goto exit_cleanup;
822 }
823
824 case IPC_GET_VERSION: 559 case IPC_GET_VERSION:
825 { 560 {
826 json_object *version = ipc_json_get_version(); 561 json_object *version = ipc_json_get_version();
@@ -830,62 +565,12 @@ void ipc_client_handle_command(struct ipc_client *client) {
830 goto exit_cleanup; 565 goto exit_cleanup;
831 } 566 }
832 567
833 case IPC_SWAY_GET_PIXELS:
834 {
835 char response_header[9];
836 memset(response_header, 0, sizeof(response_header));
837
838 json_object *obj = json_tokener_parse(buf);
839 json_object *o, *x, *y, *w, *h;
840
841 json_object_object_get_ex(obj, "output", &o);
842 json_object_object_get_ex(obj, "x", &x);
843 json_object_object_get_ex(obj, "y", &y);
844 json_object_object_get_ex(obj, "w", &w);
845 json_object_object_get_ex(obj, "h", &h);
846
847 struct wlc_geometry g = {
848 .origin = {
849 .x = json_object_get_int(x),
850 .y = json_object_get_int(y)
851 },
852 .size = {
853 .w = json_object_get_int(w),
854 .h = json_object_get_int(h)
855 }
856 };
857
858 swayc_t *output = swayc_by_test(&root_container, output_by_name_test, (void *)json_object_get_string(o));
859 json_object_put(obj);
860
861 if (!output) {
862 sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name");
863 ipc_send_reply(client, response_header, sizeof(response_header));
864 goto exit_cleanup;
865 }
866 struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request));
867 if (!req) {
868 sway_log(L_ERROR, "Unable to allocate get_pixels request");
869 goto exit_cleanup;
870 }
871 req->client = client;
872 req->output = output->handle;
873 req->geo = g;
874 list_add(ipc_get_pixel_requests, req);
875 wlc_output_schedule_render(output->handle);
876 goto exit_cleanup;
877 }
878
879 case IPC_GET_BAR_CONFIG: 568 case IPC_GET_BAR_CONFIG:
880 { 569 {
881 if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
882 goto exit_denied;
883 }
884 if (!buf[0]) { 570 if (!buf[0]) {
885 // Send list of configured bar IDs 571 // Send list of configured bar IDs
886 json_object *bars = json_object_new_array(); 572 json_object *bars = json_object_new_array();
887 int i; 573 for (int i = 0; i < config->bars->length; ++i) {
888 for (i = 0; i < config->bars->length; ++i) {
889 struct bar_config *bar = config->bars->items[i]; 574 struct bar_config *bar = config->bars->items[i];
890 json_object_array_add(bars, json_object_new_string(bar->id)); 575 json_object_array_add(bars, json_object_new_string(bar->id));
891 } 576 }
@@ -895,8 +580,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
895 } else { 580 } else {
896 // Send particular bar's details 581 // Send particular bar's details
897 struct bar_config *bar = NULL; 582 struct bar_config *bar = NULL;
898 int i; 583 for (int i = 0; i < config->bars->length; ++i) {
899 for (i = 0; i < config->bars->length; ++i) {
900 bar = config->bars->items[i]; 584 bar = config->bars->items[i];
901 if (strcmp(buf, bar->id) == 0) { 585 if (strcmp(buf, bar->id) == 0) {
902 break; 586 break;
@@ -916,24 +600,13 @@ void ipc_client_handle_command(struct ipc_client *client) {
916 goto exit_cleanup; 600 goto exit_cleanup;
917 } 601 }
918 602
919 case IPC_GET_CLIPBOARD:
920 {
921 if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) {
922 goto exit_denied;
923 }
924
925 ipc_get_clipboard(client, buf);
926 goto exit_cleanup;
927 }
928
929 default: 603 default:
930 sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); 604 wlr_log(L_INFO, "Unknown IPC command type %i", client->current_command);
931 goto exit_cleanup; 605 goto exit_cleanup;
932 } 606 }
933 607
934exit_denied:
935 ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); 608 ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied));
936 sway_log(L_DEBUG, "Denied IPC client access to %i", client->current_command); 609 wlr_log(L_DEBUG, "Denied IPC client access to %i", client->current_command);
937 610
938exit_cleanup: 611exit_cleanup:
939 client->payload_length = 0; 612 client->payload_length = 0;
@@ -956,16 +629,15 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
956 client->write_buffer_size *= 2; 629 client->write_buffer_size *= 2;
957 } 630 }
958 631
959 // TODO: reduce the limit back to 4 MB when screenshooter is implemented 632 if (client->write_buffer_size > 4e6) { // 4 MB
960 if (client->write_buffer_size > (1 << 28)) { // 256 MB 633 wlr_log(L_ERROR, "Client write buffer too big, disconnecting client");
961 sway_log(L_ERROR, "Client write buffer too big, disconnecting client");
962 ipc_client_disconnect(client); 634 ipc_client_disconnect(client);
963 return false; 635 return false;
964 } 636 }
965 637
966 char *new_buffer = realloc(client->write_buffer, client->write_buffer_size); 638 char *new_buffer = realloc(client->write_buffer, client->write_buffer_size);
967 if (!new_buffer) { 639 if (!new_buffer) {
968 sway_log(L_ERROR, "Unable to reallocate ipc client write buffer"); 640 wlr_log(L_ERROR, "Unable to reallocate ipc client write buffer");
969 ipc_client_disconnect(client); 641 ipc_client_disconnect(client);
970 return false; 642 return false;
971 } 643 }
@@ -977,212 +649,11 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
977 client->write_buffer_len += payload_length; 649 client->write_buffer_len += payload_length;
978 650
979 if (!client->writable_event_source) { 651 if (!client->writable_event_source) {
980 client->writable_event_source = wlc_event_loop_add_fd(client->fd, WLC_EVENT_WRITABLE, ipc_client_handle_writable, client); 652 client->writable_event_source = wl_event_loop_add_fd(
653 server.wl_event_loop, client->fd, WL_EVENT_WRITABLE,
654 ipc_client_handle_writable, client);
981 } 655 }
982 656
983 sway_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload); 657 wlr_log(L_DEBUG, "Added IPC reply to client %d queue: %s", client->fd, payload);
984
985 return true; 658 return true;
986} 659}
987
988void ipc_get_workspaces_callback(swayc_t *workspace, void *data) {
989 if (workspace->type == C_WORKSPACE) {
990 json_object *workspace_json = ipc_json_describe_container(workspace);
991 // override the default focused indicator because
992 // it's set differently for the get_workspaces reply
993 bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace;
994 json_object_object_del(workspace_json, "focused");
995 json_object_object_add(workspace_json, "focused", json_object_new_boolean(focused));
996 json_object_array_add((json_object *)data, workspace_json);
997 }
998}
999
1000void ipc_get_outputs_callback(swayc_t *container, void *data) {
1001 if (container->type == C_OUTPUT) {
1002 json_object_array_add((json_object *)data, ipc_json_describe_container(container));
1003 }
1004}
1005
1006static void ipc_get_marks_callback(swayc_t *container, void *data) {
1007 json_object *object = (json_object *)data;
1008 if (container->marks) {
1009 for (int i = 0; i < container->marks->length; ++i) {
1010 char *mark = (char *)container->marks->items[i];
1011 json_object_array_add(object, json_object_new_string(mark));
1012 }
1013 }
1014}
1015
1016void ipc_send_event(const char *json_string, enum ipc_command_type event) {
1017 static struct {
1018 enum ipc_command_type event;
1019 enum ipc_feature feature;
1020 } security_mappings[] = {
1021 { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE },
1022 { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT },
1023 { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE },
1024 { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW },
1025 { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING },
1026 { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT }
1027 };
1028
1029 uint32_t security_mask = 0;
1030 for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) {
1031 if (security_mappings[i].event == event) {
1032 security_mask = security_mappings[i].feature;
1033 break;
1034 }
1035 }
1036
1037 int i;
1038 struct ipc_client *client;
1039 for (i = 0; i < ipc_client_list->length; i++) {
1040 client = ipc_client_list->items[i];
1041 if (!(client->security_policy & security_mask)) {
1042 continue;
1043 }
1044 if ((client->subscribed_events & event_mask(event)) == 0) {
1045 continue;
1046 }
1047 client->current_command = event;
1048 if (!ipc_send_reply(client, json_string, (uint32_t) strlen(json_string))) {
1049 sway_log_errno(L_INFO, "Unable to send reply to IPC client");
1050 ipc_client_disconnect(client);
1051 }
1052 }
1053}
1054
1055void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) {
1056 sway_log(L_DEBUG, "Sending workspace::%s event", change);
1057 json_object *obj = json_object_new_object();
1058 json_object_object_add(obj, "change", json_object_new_string(change));
1059 if (strcmp("focus", change) == 0) {
1060 if (old) {
1061 json_object_object_add(obj, "old", ipc_json_describe_container_recursive(old));
1062 } else {
1063 json_object_object_add(obj, "old", NULL);
1064 }
1065 }
1066
1067 if (new) {
1068 json_object_object_add(obj, "current", ipc_json_describe_container_recursive(new));
1069 } else {
1070 json_object_object_add(obj, "current", NULL);
1071 }
1072
1073 const char *json_string = json_object_to_json_string(obj);
1074 ipc_send_event(json_string, IPC_EVENT_WORKSPACE);
1075
1076 json_object_put(obj); // free
1077}
1078
1079void ipc_event_window(swayc_t *window, const char *change) {
1080 sway_log(L_DEBUG, "Sending window::%s event", change);
1081 json_object *obj = json_object_new_object();
1082 json_object_object_add(obj, "change", json_object_new_string(change));
1083 json_object_object_add(obj, "container", ipc_json_describe_container_recursive(window));
1084
1085 const char *json_string = json_object_to_json_string(obj);
1086 ipc_send_event(json_string, IPC_EVENT_WINDOW);
1087
1088 json_object_put(obj); // free
1089}
1090
1091void ipc_event_barconfig_update(struct bar_config *bar) {
1092 sway_log(L_DEBUG, "Sending barconfig_update event");
1093 json_object *json = ipc_json_describe_bar_config(bar);
1094 const char *json_string = json_object_to_json_string(json);
1095 ipc_send_event(json_string, IPC_EVENT_BARCONFIG_UPDATE);
1096
1097 json_object_put(json); // free
1098}
1099
1100void ipc_event_mode(const char *mode) {
1101 sway_log(L_DEBUG, "Sending mode::%s event", mode);
1102 json_object *obj = json_object_new_object();
1103 json_object_object_add(obj, "change", json_object_new_string(mode));
1104
1105 const char *json_string = json_object_to_json_string(obj);
1106 ipc_send_event(json_string, IPC_EVENT_MODE);
1107
1108 json_object_put(obj); // free
1109}
1110
1111void ipc_event_modifier(uint32_t modifier, const char *state) {
1112 sway_log(L_DEBUG, "Sending modifier::%s event", state);
1113 json_object *obj = json_object_new_object();
1114 json_object_object_add(obj, "change", json_object_new_string(state));
1115
1116 const char *modifier_name = get_modifier_name_by_mask(modifier);
1117 json_object_object_add(obj, "modifier", json_object_new_string(modifier_name));
1118
1119 const char *json_string = json_object_to_json_string(obj);
1120 ipc_send_event(json_string, IPC_EVENT_MODIFIER);
1121
1122 json_object_put(obj); // free
1123}
1124
1125static void ipc_event_binding(json_object *sb_obj) {
1126 sway_log(L_DEBUG, "Sending binding::run event");
1127 json_object *obj = json_object_new_object();
1128 json_object_object_add(obj, "change", json_object_new_string("run"));
1129 json_object_object_add(obj, "binding", sb_obj);
1130
1131 const char *json_string = json_object_to_json_string(obj);
1132 ipc_send_event(json_string, IPC_EVENT_BINDING);
1133
1134 json_object_put(obj); // free
1135}
1136
1137void ipc_event_binding_keyboard(struct sway_binding *sb) {
1138 json_object *sb_obj = json_object_new_object();
1139 json_object_object_add(sb_obj, "command", json_object_new_string(sb->command));
1140
1141 const char *names[10];
1142
1143 int len = get_modifier_names(names, sb->modifiers);
1144 int i;
1145 json_object *modifiers = json_object_new_array();
1146 for (i = 0; i < len; ++i) {
1147 json_object_array_add(modifiers, json_object_new_string(names[i]));
1148 }
1149
1150 json_object_object_add(sb_obj, "event_state_mask", modifiers);
1151
1152 json_object *input_codes = json_object_new_array();
1153 int input_code = 0;
1154 json_object *symbols = json_object_new_array();
1155 json_object *symbol = NULL;
1156
1157 if (sb->bindcode) { // bindcode: populate input_codes
1158 uint32_t keycode;
1159 for (i = 0; i < sb->keys->length; ++i) {
1160 keycode = *(uint32_t *)sb->keys->items[i];
1161 json_object_array_add(input_codes, json_object_new_int(keycode));
1162 if (i == 0) {
1163 input_code = keycode;
1164 }
1165 }
1166 } else { // bindsym: populate symbols
1167 uint32_t keysym;
1168 char buffer[64];
1169 for (i = 0; i < sb->keys->length; ++i) {
1170 keysym = *(uint32_t *)sb->keys->items[i];
1171 if (xkb_keysym_get_name(keysym, buffer, 64) > 0) {
1172 json_object *str = json_object_new_string(buffer);
1173 json_object_array_add(symbols, str);
1174 if (i == 0) {
1175 symbol = str;
1176 }
1177 }
1178 }
1179 }
1180
1181 json_object_object_add(sb_obj, "input_codes", input_codes);
1182 json_object_object_add(sb_obj, "input_code", json_object_new_int(input_code));
1183 json_object_object_add(sb_obj, "symbols", symbols);
1184 json_object_object_add(sb_obj, "symbol", symbol);
1185 json_object_object_add(sb_obj, "input_type", json_object_new_string("keyboard"));
1186
1187 ipc_event_binding(sb_obj);
1188}