diff options
-rw-r--r-- | include/ipc.h | 1 | ||||
-rw-r--r-- | include/sway/config.h | 3 | ||||
-rw-r--r-- | sway/commands/ipc.c | 1 | ||||
-rw-r--r-- | sway/ipc-server.c | 109 | ||||
-rw-r--r-- | swaymsg/main.c | 22 |
5 files changed, 134 insertions, 2 deletions
diff --git a/include/ipc.h b/include/ipc.h index 98390335..2b16dc50 100644 --- a/include/ipc.h +++ b/include/ipc.h | |||
@@ -13,6 +13,7 @@ enum ipc_command_type { | |||
13 | IPC_GET_BAR_CONFIG = 6, | 13 | IPC_GET_BAR_CONFIG = 6, |
14 | IPC_GET_VERSION = 7, | 14 | IPC_GET_VERSION = 7, |
15 | IPC_GET_INPUTS = 8, | 15 | IPC_GET_INPUTS = 8, |
16 | IPC_GET_CLIPBOARD = 9, | ||
16 | // Events send from sway to clients. Events have the highest bits set. | 17 | // Events send from sway to clients. Events have the highest bits set. |
17 | IPC_EVENT_WORKSPACE = ((1<<31) | 0), | 18 | IPC_EVENT_WORKSPACE = ((1<<31) | 0), |
18 | IPC_EVENT_OUTPUT = ((1<<31) | 1), | 19 | IPC_EVENT_OUTPUT = ((1<<31) | 1), |
diff --git a/include/sway/config.h b/include/sway/config.h index 999a471a..b0cd86eb 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -235,8 +235,9 @@ enum ipc_feature { | |||
235 | IPC_FEATURE_EVENT_WINDOW = 2048, | 235 | IPC_FEATURE_EVENT_WINDOW = 2048, |
236 | IPC_FEATURE_EVENT_BINDING = 4096, | 236 | IPC_FEATURE_EVENT_BINDING = 4096, |
237 | IPC_FEATURE_EVENT_INPUT = 8192, | 237 | IPC_FEATURE_EVENT_INPUT = 8192, |
238 | IPC_FEATURE_GET_CLIPBOARD = 16384, | ||
238 | 239 | ||
239 | IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128, | 240 | IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, |
240 | IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, | 241 | IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, |
241 | 242 | ||
242 | IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, | 243 | IPC_FEATURE_ALL = IPC_FEATURE_ALL_COMMANDS | IPC_FEATURE_ALL_EVENTS, |
diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c index f0b3035a..0c678961 100644 --- a/sway/commands/ipc.c +++ b/sway/commands/ipc.c | |||
@@ -89,6 +89,7 @@ struct cmd_results *cmd_ipc_cmd(int argc, char **argv) { | |||
89 | { "marks", IPC_FEATURE_GET_MARKS }, | 89 | { "marks", IPC_FEATURE_GET_MARKS }, |
90 | { "bar-config", IPC_FEATURE_GET_BAR_CONFIG }, | 90 | { "bar-config", IPC_FEATURE_GET_BAR_CONFIG }, |
91 | { "inputs", IPC_FEATURE_GET_INPUTS }, | 91 | { "inputs", IPC_FEATURE_GET_INPUTS }, |
92 | { "clipboard", IPC_FEATURE_GET_CLIPBOARD }, | ||
92 | }; | 93 | }; |
93 | 94 | ||
94 | uint32_t type = 0; | 95 | uint32_t type = 0; |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index dca881fa..5bc64b1f 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -55,6 +55,11 @@ struct get_pixels_request { | |||
55 | struct wlc_geometry geo; | 55 | struct wlc_geometry geo; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct get_clipboard_request { | ||
59 | struct ipc_client *client; | ||
60 | struct wlc_event_source *event_source; | ||
61 | }; | ||
62 | |||
58 | struct sockaddr_un *ipc_user_sockaddr(void); | 63 | struct sockaddr_un *ipc_user_sockaddr(void); |
59 | int ipc_handle_connection(int fd, uint32_t mask, void *data); | 64 | int ipc_handle_connection(int fd, uint32_t mask, void *data); |
60 | int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); | 65 | int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data); |
@@ -322,6 +327,46 @@ void ipc_get_pixels(wlc_handle output) { | |||
322 | ipc_get_pixel_requests = unhandled; | 327 | ipc_get_pixel_requests = unhandled; |
323 | } | 328 | } |
324 | 329 | ||
330 | static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) | ||
331 | { | ||
332 | assert(data); | ||
333 | struct get_clipboard_request *req = (struct get_clipboard_request*) data; | ||
334 | |||
335 | if (mask & WLC_EVENT_ERROR) { | ||
336 | sway_log(L_ERROR, "Selection data fd error"); | ||
337 | const char *error = "{ \"success\": false, \"error\": " | ||
338 | "\"Could not receive text data from clipboard\" }"; | ||
339 | ipc_send_reply(req->client, error, (uint32_t)strlen(error)); | ||
340 | goto cleanup; | ||
341 | } | ||
342 | |||
343 | if (mask & WLC_EVENT_READABLE) { | ||
344 | char buf[512]; | ||
345 | int ret = read(fd, buf, 511); | ||
346 | if (ret < 0) { | ||
347 | sway_log_errno(L_ERROR, "Reading from selection data fd failed"); | ||
348 | const char *error = "{ \"success\": false, \"error\": " | ||
349 | "\"Could not receive text data from clipboard\" }"; | ||
350 | ipc_send_reply(req->client, error, (uint32_t)strlen(error)); | ||
351 | goto cleanup; | ||
352 | } | ||
353 | |||
354 | buf[ret] = '\0'; | ||
355 | json_object *obj = json_object_new_object(); | ||
356 | json_object_object_add(obj, "success", json_object_new_boolean(true)); | ||
357 | json_object_object_add(obj, "content", json_object_new_string(buf)); | ||
358 | const char *str = json_object_to_json_string(obj); | ||
359 | ipc_send_reply(req->client, str, (uint32_t)strlen(str)); | ||
360 | json_object_put(obj); | ||
361 | } | ||
362 | |||
363 | cleanup: | ||
364 | wlc_event_source_remove(req->event_source); | ||
365 | close(fd); | ||
366 | free(req); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
325 | void ipc_client_handle_command(struct ipc_client *client) { | 370 | void ipc_client_handle_command(struct ipc_client *client) { |
326 | if (!sway_assert(client != NULL, "client != NULL")) { | 371 | if (!sway_assert(client != NULL, "client != NULL")) { |
327 | return; | 372 | return; |
@@ -565,6 +610,70 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
565 | goto exit_cleanup; | 610 | goto exit_cleanup; |
566 | } | 611 | } |
567 | 612 | ||
613 | case IPC_GET_CLIPBOARD: | ||
614 | { | ||
615 | if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) { | ||
616 | goto exit_denied; | ||
617 | } | ||
618 | |||
619 | size_t size; | ||
620 | bool found = false; | ||
621 | const char **types = wlc_get_selection_types(&size); | ||
622 | if (types == NULL || size == 0) { | ||
623 | const char *error = "{ \"success\": false, \"error\": " | ||
624 | "\"Empty clipboard\" }"; | ||
625 | ipc_send_reply(client, error, (uint32_t)strlen(error)); | ||
626 | goto exit_cleanup; | ||
627 | } | ||
628 | |||
629 | for (size_t i = 0; i < size; ++i) { | ||
630 | if (strcmp(types[i], "text/plain;charset=utf-8") != 0 | ||
631 | && strcmp(types[i], "text/plain") != 0) { | ||
632 | continue; | ||
633 | } | ||
634 | |||
635 | struct get_clipboard_request *req = malloc(sizeof(*req)); | ||
636 | if (!req) { | ||
637 | sway_log(L_ERROR, "Unable to allocate get_clipboard_request"); | ||
638 | goto exit_cleanup; | ||
639 | } | ||
640 | |||
641 | int pipes[2]; | ||
642 | if (pipe(pipes) == -1) { | ||
643 | sway_log_errno(L_ERROR, "pipe call failed"); | ||
644 | free(req); | ||
645 | break; | ||
646 | } | ||
647 | |||
648 | fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK); | ||
649 | fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK); | ||
650 | if (!wlc_get_selection_data(types[i], pipes[1])) { | ||
651 | close(pipes[0]); | ||
652 | close(pipes[1]); | ||
653 | free(req); | ||
654 | sway_log(L_ERROR, "wlc_get_selection_data failed"); | ||
655 | break; | ||
656 | } | ||
657 | |||
658 | req->client = client; | ||
659 | req->event_source = wlc_event_loop_add_fd(pipes[0], | ||
660 | WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP, | ||
661 | &ipc_selection_data_cb, req); | ||
662 | found = true; | ||
663 | break; | ||
664 | } | ||
665 | |||
666 | if (!found) { | ||
667 | sway_log(L_INFO, "Clipboard has to text data"); | ||
668 | const char *error = "{ \"success\": false, \"error\": " | ||
669 | "\"Could not receive text data from clipboard\" }"; | ||
670 | ipc_send_reply(client, error, (uint32_t)strlen(error)); | ||
671 | } | ||
672 | |||
673 | free(types); | ||
674 | goto exit_cleanup; | ||
675 | } | ||
676 | |||
568 | default: | 677 | default: |
569 | sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); | 678 | sway_log(L_INFO, "Unknown IPC command type %i", client->current_command); |
570 | goto exit_cleanup; | 679 | goto exit_cleanup; |
diff --git a/swaymsg/main.c b/swaymsg/main.c index efd0ec25..fa28553b 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c | |||
@@ -144,10 +144,23 @@ static void pretty_print_version(json_object *v) { | |||
144 | printf("sway version %s\n", json_object_get_string(ver)); | 144 | printf("sway version %s\n", json_object_get_string(ver)); |
145 | } | 145 | } |
146 | 146 | ||
147 | static void pretty_print_clipboard(json_object *v) { | ||
148 | bool _success; | ||
149 | json_object *success; | ||
150 | json_object_object_get_ex(v, "success", &success); | ||
151 | _success = json_object_get_boolean(success); | ||
152 | |||
153 | if (_success) { | ||
154 | json_object *ver; | ||
155 | json_object_object_get_ex(v, "content", &ver); | ||
156 | printf("%s\n", json_object_get_string(ver)); | ||
157 | } | ||
158 | } | ||
159 | |||
147 | static void pretty_print(int type, json_object *resp) { | 160 | static void pretty_print(int type, json_object *resp) { |
148 | if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES && | 161 | if (type != IPC_COMMAND && type != IPC_GET_WORKSPACES && |
149 | type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS && | 162 | type != IPC_GET_INPUTS && type != IPC_GET_OUTPUTS && |
150 | type != IPC_GET_VERSION) { | 163 | type != IPC_GET_VERSION && type != IPC_GET_CLIPBOARD) { |
151 | printf("%s\n", json_object_to_json_string_ext(resp, | 164 | printf("%s\n", json_object_to_json_string_ext(resp, |
152 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); | 165 | JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); |
153 | return; | 166 | return; |
@@ -158,6 +171,11 @@ static void pretty_print(int type, json_object *resp) { | |||
158 | return; | 171 | return; |
159 | } | 172 | } |
160 | 173 | ||
174 | if (type == IPC_GET_CLIPBOARD) { | ||
175 | pretty_print_clipboard(resp); | ||
176 | return; | ||
177 | } | ||
178 | |||
161 | json_object *obj; | 179 | json_object *obj; |
162 | size_t len = json_object_array_length(resp); | 180 | size_t len = json_object_array_length(resp); |
163 | for (size_t i = 0; i < len; ++i) { | 181 | for (size_t i = 0; i < len; ++i) { |
@@ -267,6 +285,8 @@ int main(int argc, char **argv) { | |||
267 | type = IPC_GET_BAR_CONFIG; | 285 | type = IPC_GET_BAR_CONFIG; |
268 | } else if (strcasecmp(cmdtype, "get_version") == 0) { | 286 | } else if (strcasecmp(cmdtype, "get_version") == 0) { |
269 | type = IPC_GET_VERSION; | 287 | type = IPC_GET_VERSION; |
288 | } else if (strcasecmp(cmdtype, "get_clipboard") == 0) { | ||
289 | type = IPC_GET_CLIPBOARD; | ||
270 | } else { | 290 | } else { |
271 | sway_abort("Unknown message type %s", cmdtype); | 291 | sway_abort("Unknown message type %s", cmdtype); |
272 | } | 292 | } |