diff options
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r-- | sway/ipc-server.c | 136 |
1 files changed, 127 insertions, 9 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index be703915..7d2d8969 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -3,12 +3,18 @@ | |||
3 | // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) | 3 | // Any value will hide SOCK_CLOEXEC on FreeBSD (__BSD_VISIBLE=0) |
4 | #define _XOPEN_SOURCE 700 | 4 | #define _XOPEN_SOURCE 700 |
5 | #endif | 5 | #endif |
6 | #ifdef __linux__ | ||
7 | #include <linux/input-event-codes.h> | ||
8 | #elif __FreeBSD__ | ||
9 | #include <dev/evdev/input-event-codes.h> | ||
10 | #endif | ||
6 | #include <assert.h> | 11 | #include <assert.h> |
7 | #include <errno.h> | 12 | #include <errno.h> |
8 | #include <fcntl.h> | 13 | #include <fcntl.h> |
9 | #include <json-c/json.h> | 14 | #include <json-c/json.h> |
10 | #include <stdbool.h> | 15 | #include <stdbool.h> |
11 | #include <stdint.h> | 16 | #include <stdint.h> |
17 | #include <stdio.h> | ||
12 | #include <stdlib.h> | 18 | #include <stdlib.h> |
13 | #include <string.h> | 19 | #include <string.h> |
14 | #include <sys/socket.h> | 20 | #include <sys/socket.h> |
@@ -28,6 +34,7 @@ | |||
28 | #include "sway/tree/view.h" | 34 | #include "sway/tree/view.h" |
29 | #include "list.h" | 35 | #include "list.h" |
30 | #include "log.h" | 36 | #include "log.h" |
37 | #include "util.h" | ||
31 | 38 | ||
32 | static int ipc_socket = -1; | 39 | static int ipc_socket = -1; |
33 | static struct wl_event_source *ipc_event_source = NULL; | 40 | static struct wl_event_source *ipc_event_source = NULL; |
@@ -291,13 +298,11 @@ void ipc_event_workspace(struct sway_container *old, | |||
291 | wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); | 298 | wlr_log(WLR_DEBUG, "Sending workspace::%s event", change); |
292 | json_object *obj = json_object_new_object(); | 299 | json_object *obj = json_object_new_object(); |
293 | json_object_object_add(obj, "change", json_object_new_string(change)); | 300 | json_object_object_add(obj, "change", json_object_new_string(change)); |
294 | if (strcmp("focus", change) == 0) { | 301 | if (old) { |
295 | if (old) { | 302 | json_object_object_add(obj, "old", |
296 | json_object_object_add(obj, "old", | 303 | ipc_json_describe_container_recursive(old)); |
297 | ipc_json_describe_container_recursive(old)); | 304 | } else { |
298 | } else { | 305 | json_object_object_add(obj, "old", NULL); |
299 | json_object_object_add(obj, "old", NULL); | ||
300 | } | ||
301 | } | 306 | } |
302 | 307 | ||
303 | if (new) { | 308 | if (new) { |
@@ -353,6 +358,104 @@ void ipc_event_mode(const char *mode, bool pango) { | |||
353 | json_object_put(obj); | 358 | json_object_put(obj); |
354 | } | 359 | } |
355 | 360 | ||
361 | void ipc_event_shutdown(const char *reason) { | ||
362 | if (!ipc_has_event_listeners(IPC_EVENT_SHUTDOWN)) { | ||
363 | return; | ||
364 | } | ||
365 | wlr_log(WLR_DEBUG, "Sending shutdown::%s event", reason); | ||
366 | |||
367 | json_object *json = json_object_new_object(); | ||
368 | json_object_object_add(json, "change", json_object_new_string(reason)); | ||
369 | |||
370 | const char *json_string = json_object_to_json_string(json); | ||
371 | ipc_send_event(json_string, IPC_EVENT_SHUTDOWN); | ||
372 | json_object_put(json); | ||
373 | } | ||
374 | |||
375 | void ipc_event_binding(struct sway_binding *binding) { | ||
376 | if (!ipc_has_event_listeners(IPC_EVENT_BINDING)) { | ||
377 | return; | ||
378 | } | ||
379 | wlr_log(WLR_DEBUG, "Sending binding event"); | ||
380 | |||
381 | json_object *json_binding = json_object_new_object(); | ||
382 | json_object_object_add(json_binding, "command", json_object_new_string(binding->command)); | ||
383 | |||
384 | const char *names[10]; | ||
385 | int len = get_modifier_names(names, binding->modifiers); | ||
386 | json_object *modifiers = json_object_new_array(); | ||
387 | for (int i = 0; i < len; ++i) { | ||
388 | json_object_array_add(modifiers, json_object_new_string(names[i])); | ||
389 | } | ||
390 | json_object_object_add(json_binding, "event_state_mask", modifiers); | ||
391 | |||
392 | json_object *input_codes = json_object_new_array(); | ||
393 | int input_code = 0; | ||
394 | json_object *symbols = json_object_new_array(); | ||
395 | json_object *symbol = NULL; | ||
396 | |||
397 | if (binding->type == BINDING_KEYCODE) { // bindcode: populate input_codes | ||
398 | uint32_t keycode; | ||
399 | for (int i = 0; i < binding->keys->length; ++i) { | ||
400 | keycode = *(uint32_t *)binding->keys->items[i]; | ||
401 | json_object_array_add(input_codes, json_object_new_int(keycode)); | ||
402 | if (i == 0) { | ||
403 | input_code = keycode; | ||
404 | } | ||
405 | } | ||
406 | } else { // bindsym/mouse: populate symbols | ||
407 | uint32_t keysym; | ||
408 | char buffer[64]; | ||
409 | for (int i = 0; i < binding->keys->length; ++i) { | ||
410 | keysym = *(uint32_t *)binding->keys->items[i]; | ||
411 | if (keysym >= BTN_LEFT && keysym <= BTN_LEFT + 8) { | ||
412 | snprintf(buffer, 64, "button%u", keysym - BTN_LEFT + 1); | ||
413 | } else if (xkb_keysym_get_name(keysym, buffer, 64) < 0) { | ||
414 | continue; | ||
415 | } | ||
416 | |||
417 | json_object *str = json_object_new_string(buffer); | ||
418 | if (i == 0) { | ||
419 | // str is owned by both symbol and symbols. Make sure | ||
420 | // to bump the ref count. | ||
421 | json_object_array_add(symbols, json_object_get(str)); | ||
422 | symbol = str; | ||
423 | } else { | ||
424 | json_object_array_add(symbols, str); | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | json_object_object_add(json_binding, "input_codes", input_codes); | ||
430 | json_object_object_add(json_binding, "input_code", json_object_new_int(input_code)); | ||
431 | json_object_object_add(json_binding, "symbols", symbols); | ||
432 | json_object_object_add(json_binding, "symbol", symbol); | ||
433 | json_object_object_add(json_binding, "input_type", binding->type == BINDING_MOUSE ? | ||
434 | json_object_new_string("mouse") : json_object_new_string("keyboard")); | ||
435 | |||
436 | json_object *json = json_object_new_object(); | ||
437 | json_object_object_add(json, "change", json_object_new_string("run")); | ||
438 | json_object_object_add(json, "binding", json_binding); | ||
439 | const char *json_string = json_object_to_json_string(json); | ||
440 | ipc_send_event(json_string, IPC_EVENT_BINDING); | ||
441 | json_object_put(json); | ||
442 | } | ||
443 | |||
444 | static void ipc_event_tick(const char *payload) { | ||
445 | if (!ipc_has_event_listeners(IPC_EVENT_TICK)) { | ||
446 | return; | ||
447 | } | ||
448 | wlr_log(WLR_DEBUG, "Sending tick event"); | ||
449 | |||
450 | json_object *json = json_object_new_object(); | ||
451 | json_object_object_add(json, "first", json_object_new_boolean(false)); | ||
452 | json_object_object_add(json, "payload", json_object_new_string(payload)); | ||
453 | |||
454 | const char *json_string = json_object_to_json_string(json); | ||
455 | ipc_send_event(json_string, IPC_EVENT_TICK); | ||
456 | json_object_put(json); | ||
457 | } | ||
458 | |||
356 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { | 459 | int ipc_client_handle_writable(int client_fd, uint32_t mask, void *data) { |
357 | struct ipc_client *client = data; | 460 | struct ipc_client *client = data; |
358 | 461 | ||
@@ -494,6 +597,13 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
494 | goto exit_cleanup; | 597 | goto exit_cleanup; |
495 | } | 598 | } |
496 | 599 | ||
600 | case IPC_SEND_TICK: | ||
601 | { | ||
602 | ipc_event_tick(buf); | ||
603 | ipc_send_reply(client, "{\"success\": true}", 17); | ||
604 | goto exit_cleanup; | ||
605 | } | ||
606 | |||
497 | case IPC_GET_OUTPUTS: | 607 | case IPC_GET_OUTPUTS: |
498 | { | 608 | { |
499 | json_object *outputs = json_object_new_array(); | 609 | json_object *outputs = json_object_new_array(); |
@@ -540,6 +650,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
540 | goto exit_cleanup; | 650 | goto exit_cleanup; |
541 | } | 651 | } |
542 | 652 | ||
653 | bool is_tick = false; | ||
543 | // parse requested event types | 654 | // parse requested event types |
544 | for (size_t i = 0; i < json_object_array_length(request); i++) { | 655 | for (size_t i = 0; i < json_object_array_length(request); i++) { |
545 | const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); | 656 | const char *event_type = json_object_get_string(json_object_array_get_idx(request, i)); |
@@ -549,12 +660,15 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
549 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); | 660 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); |
550 | } else if (strcmp(event_type, "mode") == 0) { | 661 | } else if (strcmp(event_type, "mode") == 0) { |
551 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); | 662 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); |
663 | } else if (strcmp(event_type, "shutdown") == 0) { | ||
664 | client->subscribed_events |= event_mask(IPC_EVENT_SHUTDOWN); | ||
552 | } else if (strcmp(event_type, "window") == 0) { | 665 | } else if (strcmp(event_type, "window") == 0) { |
553 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); | 666 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); |
554 | } else if (strcmp(event_type, "modifier") == 0) { | ||
555 | client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); | ||
556 | } else if (strcmp(event_type, "binding") == 0) { | 667 | } else if (strcmp(event_type, "binding") == 0) { |
557 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); | 668 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); |
669 | } else if (strcmp(event_type, "tick") == 0) { | ||
670 | client->subscribed_events |= event_mask(IPC_EVENT_TICK); | ||
671 | is_tick = true; | ||
558 | } else { | 672 | } else { |
559 | client_valid = | 673 | client_valid = |
560 | ipc_send_reply(client, "{\"success\": false}", 18); | 674 | ipc_send_reply(client, "{\"success\": false}", 18); |
@@ -566,6 +680,10 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
566 | 680 | ||
567 | json_object_put(request); | 681 | json_object_put(request); |
568 | client_valid = ipc_send_reply(client, "{\"success\": true}", 17); | 682 | client_valid = ipc_send_reply(client, "{\"success\": true}", 17); |
683 | if (is_tick) { | ||
684 | client->current_command = IPC_EVENT_TICK; | ||
685 | ipc_send_reply(client, "{\"first\": true, \"payload\": \"\"}", 30); | ||
686 | } | ||
569 | goto exit_cleanup; | 687 | goto exit_cleanup; |
570 | } | 688 | } |
571 | 689 | ||