summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/ipc.h4
-rw-r--r--sway/ipc.c132
-rw-r--r--sway/workspace.c4
3 files changed, 110 insertions, 30 deletions
diff --git a/include/ipc.h b/include/ipc.h
index 1932ad2d..36957ac1 100644
--- a/include/ipc.h
+++ b/include/ipc.h
@@ -1,6 +1,8 @@
1#ifndef _SWAY_IPC_H 1#ifndef _SWAY_IPC_H
2#define _SWAY_IPC_H 2#define _SWAY_IPC_H
3 3
4#include "container.h"
5
4enum ipc_command_type { 6enum ipc_command_type {
5 IPC_COMMAND = 0, 7 IPC_COMMAND = 0,
6 IPC_GET_WORKSPACES = 1, 8 IPC_GET_WORKSPACES = 1,
@@ -16,4 +18,6 @@ void ipc_init(void);
16void ipc_terminate(void); 18void ipc_terminate(void);
17struct sockaddr_un *ipc_user_sockaddr(void); 19struct sockaddr_un *ipc_user_sockaddr(void);
18 20
21void ipc_event_workspace(swayc_t *old, swayc_t *new);
22
19#endif 23#endif
diff --git a/sway/ipc.c b/sway/ipc.c
index 1134f1a2..4c87101c 100644
--- a/sway/ipc.c
+++ b/sway/ipc.c
@@ -12,6 +12,7 @@
12#include <fcntl.h> 12#include <fcntl.h>
13#include <ctype.h> 13#include <ctype.h>
14#include <json-c/json.h> 14#include <json-c/json.h>
15#include <list.h>
15#include "ipc.h" 16#include "ipc.h"
16#include "log.h" 17#include "log.h"
17#include "config.h" 18#include "config.h"
@@ -22,6 +23,7 @@
22static int ipc_socket = -1; 23static int ipc_socket = -1;
23static struct wlc_event_source *ipc_event_source = NULL; 24static struct wlc_event_source *ipc_event_source = NULL;
24static struct sockaddr_un *ipc_sockaddr = NULL; 25static struct sockaddr_un *ipc_sockaddr = NULL;
26static list_t *ipc_client_list = NULL;
25 27
26static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'}; 28static const char ipc_magic[] = {'i', '3', '-', 'i', 'p', 'c'};
27 29
@@ -30,6 +32,7 @@ struct ipc_client {
30 int fd; 32 int fd;
31 uint32_t payload_length; 33 uint32_t payload_length;
32 enum ipc_command_type current_command; 34 enum ipc_command_type current_command;
35 enum ipc_command_type subscribed_events;
33}; 36};
34 37
35struct sockaddr_un *ipc_user_sockaddr(void); 38struct sockaddr_un *ipc_user_sockaddr(void);
@@ -65,6 +68,8 @@ void ipc_init(void) {
65 // Set i3 IPC socket path so that i3-msg works out of the box 68 // Set i3 IPC socket path so that i3-msg works out of the box
66 setenv("I3SOCK", ipc_sockaddr->sun_path, 1); 69 setenv("I3SOCK", ipc_sockaddr->sun_path, 1);
67 70
71 ipc_client_list = create_list();
72
68 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL); 73 ipc_event_source = wlc_event_loop_add_fd(ipc_socket, WLC_EVENT_READABLE, ipc_handle_connection, NULL);
69} 74}
70 75
@@ -75,6 +80,8 @@ void ipc_terminate(void) {
75 close(ipc_socket); 80 close(ipc_socket);
76 unlink(ipc_sockaddr->sun_path); 81 unlink(ipc_sockaddr->sun_path);
77 82
83 list_free(ipc_client_list);
84
78 if (ipc_sockaddr) { 85 if (ipc_sockaddr) {
79 free(ipc_sockaddr); 86 free(ipc_sockaddr);
80 } 87 }
@@ -122,6 +129,8 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
122 client->fd = client_fd; 129 client->fd = client_fd;
123 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); 130 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
124 131
132 list_add(ipc_client_list, client);
133
125 return 0; 134 return 0;
126} 135}
127 136
@@ -133,11 +142,13 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
133 142
134 if (mask & WLC_EVENT_ERROR) { 143 if (mask & WLC_EVENT_ERROR) {
135 sway_log(L_INFO, "IPC Client socket error, removing client"); 144 sway_log(L_INFO, "IPC Client socket error, removing client");
145 client->fd = -1;
136 ipc_client_disconnect(client); 146 ipc_client_disconnect(client);
137 return 0; 147 return 0;
138 } 148 }
139 149
140 if (mask & WLC_EVENT_HANGUP) { 150 if (mask & WLC_EVENT_HANGUP) {
151 client->fd = -1;
141 ipc_client_disconnect(client); 152 ipc_client_disconnect(client);
142 return 0; 153 return 0;
143 } 154 }
@@ -195,8 +206,15 @@ void ipc_client_disconnect(struct ipc_client *client)
195 return; 206 return;
196 } 207 }
197 208
209 if (client->fd != -1) {
210 shutdown(client->fd, SHUT_RDWR);
211 }
212
198 sway_log(L_INFO, "IPC Client %d disconnected", client->fd); 213 sway_log(L_INFO, "IPC Client %d disconnected", client->fd);
199 wlc_event_source_remove(client->event_source); 214 wlc_event_source_remove(client->event_source);
215 int i = 0;
216 while (i < ipc_client_list->length && ipc_client_list->items[i] != client) i++;
217 list_del(ipc_client_list, i);
200 close(client->fd); 218 close(client->fd);
201 free(client); 219 free(client);
202} 220}
@@ -230,6 +248,35 @@ void ipc_client_handle_command(struct ipc_client *client) {
230 free_cmd_results(results); 248 free_cmd_results(results);
231 break; 249 break;
232 } 250 }
251 case IPC_SUBSCRIBE:
252 {
253 buf[client->payload_length] = '\0';
254 struct json_object *request = json_tokener_parse(buf);
255 if (request == NULL) {
256 ipc_send_reply(client, "{\"success\": false}", 18);
257 ipc_client_disconnect(client);
258 return;
259 }
260
261 // parse requested event types
262 for (int i = 0; i < json_object_array_length(request); i++) {
263 const char *event_type = json_object_get_string(json_object_array_get_idx(request, i));
264 if (strcmp(event_type, "workspace") == 0) {
265 client->subscribed_events |= IPC_GET_WORKSPACES;
266 }
267 else {
268 ipc_send_reply(client, "{\"success\": false}", 18);
269 ipc_client_disconnect(client);
270 json_object_put(request);
271 return;
272 }
273 }
274
275 json_object_put(request);
276
277 ipc_send_reply(client, "{\"success\": true}", 17);
278 break;
279 }
233 case IPC_GET_WORKSPACES: 280 case IPC_GET_WORKSPACES:
234 { 281 {
235 json_object *workspaces = json_object_new_array(); 282 json_object *workspaces = json_object_new_array();
@@ -309,44 +356,69 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
309 return true; 356 return true;
310} 357}
311 358
359json_object *ipc_json_describe_workspace(swayc_t *workspace) {
360 int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1;
361 json_object *object = json_object_new_object();
362 json_object *rect = json_object_new_object();
363 json_object_object_add(rect, "x", json_object_new_int((int32_t) workspace->x));
364 json_object_object_add(rect, "y", json_object_new_int((int32_t) workspace->y));
365 json_object_object_add(rect, "width", json_object_new_int((int32_t) workspace->width));
366 json_object_object_add(rect, "height", json_object_new_int((int32_t) workspace->height));
367
368 json_object_object_add(object, "num", json_object_new_int(num));
369 json_object_object_add(object, "name", json_object_new_string(workspace->name));
370 json_object_object_add(object, "visible", json_object_new_boolean(workspace->visible));
371 bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace;
372 json_object_object_add(object, "focused", json_object_new_boolean(focused));
373 json_object_object_add(object, "rect", rect);
374 json_object_object_add(object, "output", json_object_new_string(workspace->parent ? workspace->parent->name : "null"));
375 json_object_object_add(object, "urgent", json_object_new_boolean(false));
376
377 return object;
378}
379
312void ipc_get_workspaces_callback(swayc_t *workspace, void *data) { 380void ipc_get_workspaces_callback(swayc_t *workspace, void *data) {
313 if (workspace->type == C_WORKSPACE) { 381 if (workspace->type == C_WORKSPACE) {
314 int num = isdigit(workspace->name[0]) ? atoi(workspace->name) : -1; 382 json_object_array_add((json_object *)data, ipc_json_describe_workspace(workspace));
315 json_object *object = json_object_new_object();
316 json_object *rect = json_object_new_object();
317 json_object_object_add(rect, "x", json_object_new_int((int32_t) workspace->x));
318 json_object_object_add(rect, "y", json_object_new_int((int32_t) workspace->y));
319 json_object_object_add(rect, "width", json_object_new_int((int32_t) workspace->width));
320 json_object_object_add(rect, "height", json_object_new_int((int32_t) workspace->height));
321
322 json_object_object_add(object, "num", json_object_new_int(num));
323 json_object_object_add(object, "name", json_object_new_string(workspace->name));
324 json_object_object_add(object, "visible", json_object_new_boolean(workspace->visible));
325 bool focused = root_container.focused == workspace->parent && workspace->parent->focused == workspace;
326 json_object_object_add(object, "focused", json_object_new_boolean(focused));
327 json_object_object_add(object, "rect", rect);
328 json_object_object_add(object, "output", json_object_new_string(workspace->parent->name));
329 json_object_object_add(object, "urgent", json_object_new_boolean(false));
330
331 json_object_array_add((json_object *)data, object);
332 } 383 }
333} 384}
334 385
386json_object *ipc_json_describe_output(swayc_t *output) {
387 json_object *object = json_object_new_object();
388 json_object *rect = json_object_new_object();
389 json_object_object_add(rect, "x", json_object_new_int((int32_t) output->x));
390 json_object_object_add(rect, "y", json_object_new_int((int32_t) output->y));
391 json_object_object_add(rect, "width", json_object_new_int((int32_t) output->width));
392 json_object_object_add(rect, "height", json_object_new_int((int32_t) output->height));
393
394 json_object_object_add(object, "name", json_object_new_string(output->name));
395 json_object_object_add(object, "active", json_object_new_boolean(true));
396 json_object_object_add(object, "primary", json_object_new_boolean(false));
397 json_object_object_add(object, "rect", rect);
398 json_object_object_add(object, "current_workspace",
399 output->focused ? json_object_new_string(output->focused->name) : NULL);
400
401 return object;
402}
403
335void ipc_get_outputs_callback(swayc_t *container, void *data) { 404void ipc_get_outputs_callback(swayc_t *container, void *data) {
336 if (container->type == C_OUTPUT) { 405 if (container->type == C_OUTPUT) {
337 json_object *object = json_object_new_object(); 406 json_object_array_add((json_object *)data, ipc_json_describe_output(container));
338 json_object *rect = json_object_new_object(); 407 }
339 json_object_object_add(rect, "x", json_object_new_int((int32_t) container->x)); 408}
340 json_object_object_add(rect, "y", json_object_new_int((int32_t) container->y));
341 json_object_object_add(rect, "width", json_object_new_int((int32_t) container->width));
342 json_object_object_add(rect, "height", json_object_new_int((int32_t) container->height));
343 409
344 json_object_object_add(object, "name", json_object_new_string(container->name)); 410void ipc_event_workspace(swayc_t *old, swayc_t *new) {
345 json_object_object_add(object, "active", json_object_new_boolean(true)); 411 json_object *obj = json_object_new_object();
346 json_object_object_add(object, "primary", json_object_new_boolean(false)); 412 json_object_object_add(obj, "change", json_object_new_string("focus"));
347 json_object_object_add(object, "rect", rect); 413 json_object_object_add(obj, "old", ipc_json_describe_workspace(old));
348 json_object_object_add(object, "current_workspace", container->focused ? json_object_new_string(container->focused->name) : NULL); 414 json_object_object_add(obj, "current", ipc_json_describe_workspace(new));
415 const char *json_string = json_object_to_json_string(obj);
349 416
350 json_object_array_add((json_object *)data, object); 417 for (int i = 0; i < ipc_client_list->length; i++) {
418 struct ipc_client *client = ipc_client_list->items[i];
419 if ((client->subscribed_events & IPC_GET_WORKSPACES) == 0) break;
420 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
351 } 421 }
422
423 json_object_put(obj); // free
352} 424}
diff --git a/sway/workspace.c b/sway/workspace.c
index b7e9760b..604fc8e4 100644
--- a/sway/workspace.c
+++ b/sway/workspace.c
@@ -13,6 +13,7 @@
13#include "stringop.h" 13#include "stringop.h"
14#include "focus.h" 14#include "focus.h"
15#include "util.h" 15#include "util.h"
16#include "ipc.h"
16 17
17char *prev_workspace_name = NULL; 18char *prev_workspace_name = NULL;
18 19
@@ -221,5 +222,8 @@ bool workspace_switch(swayc_t *workspace) {
221 return false; 222 return false;
222 } 223 }
223 arrange_windows(workspace, -1, -1); 224 arrange_windows(workspace, -1, -1);
225
226 ipc_event_workspace(active_ws, workspace);
227
224 return true; 228 return true;
225} 229}