aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar nyorain <nyorain@gmail.com>2017-07-07 21:51:34 +0200
committerLibravatar nyorain <nyorain@gmail.com>2017-07-07 21:51:34 +0200
commitc0f2acce4e08eecdcf29058335aece113467daee (patch)
tree7f871abe8b5d1cdf4a74512810d68e9e66f0d57f
parentFix/Simplify get_clipboard ipc-server impl (diff)
downloadsway-c0f2acce4e08eecdcf29058335aece113467daee.tar.gz
sway-c0f2acce4e08eecdcf29058335aece113467daee.tar.zst
sway-c0f2acce4e08eecdcf29058335aece113467daee.zip
Rework get_clipboard implementation
-rw-r--r--completions/zsh/_swaymsg1
-rw-r--r--include/sway/config.h2
-rw-r--r--include/util.h5
-rw-r--r--sway/CMakeLists.txt3
-rw-r--r--sway/base64.c221
-rw-r--r--sway/ipc-server.c275
-rw-r--r--swaymsg/main.c41
-rw-r--r--swaymsg/swaymsg.1.txt6
8 files changed, 453 insertions, 101 deletions
diff --git a/completions/zsh/_swaymsg b/completions/zsh/_swaymsg
index 4207ce3b..1c3ccd65 100644
--- a/completions/zsh/_swaymsg
+++ b/completions/zsh/_swaymsg
@@ -21,6 +21,7 @@ types=(
21'get_marks' 21'get_marks'
22'get_bar_config' 22'get_bar_config'
23'get_version' 23'get_version'
24'get_clipboard'
24) 25)
25 26
26_arguments -s \ 27_arguments -s \
diff --git a/include/sway/config.h b/include/sway/config.h
index b0cd86eb..a05d5ede 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -235,7 +235,7 @@ 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 IPC_FEATURE_GET_CLIPBOARD = 16384,
239 239
240 IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384, 240 IPC_FEATURE_ALL_COMMANDS = 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 16384,
241 IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192, 241 IPC_FEATURE_ALL_EVENTS = 256 | 512 | 1024 | 2048 | 4096 | 8192,
diff --git a/include/util.h b/include/util.h
index e5365458..f68deae8 100644
--- a/include/util.h
+++ b/include/util.h
@@ -3,6 +3,7 @@
3 3
4#include <stdint.h> 4#include <stdint.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <sys/types.h>
6#include <xkbcommon/xkbcommon.h> 7#include <xkbcommon/xkbcommon.h>
7 8
8/** 9/**
@@ -57,4 +58,8 @@ uint32_t parse_color(const char *color);
57 * to a dangling symlink, NULL is returned. 58 * to a dangling symlink, NULL is returned.
58 */ 59 */
59char* resolve_path(const char* path); 60char* resolve_path(const char* path);
61
62char *b64_encode(const char* binaryData, size_t len, size_t *flen);
63unsigned char *b64_decode(const char *ascii, size_t len, size_t *flen);
64
60#endif 65#endif
diff --git a/sway/CMakeLists.txt b/sway/CMakeLists.txt
index bf0b2e7f..11bec4df 100644
--- a/sway/CMakeLists.txt
+++ b/sway/CMakeLists.txt
@@ -19,6 +19,7 @@ file(GLOB cmds
19add_executable(sway 19add_executable(sway
20 commands.c 20 commands.c
21 ${cmds} 21 ${cmds}
22 base64.c
22 config.c 23 config.c
23 container.c 24 container.c
24 criteria.c 25 criteria.c
@@ -35,7 +36,7 @@ add_executable(sway
35 output.c 36 output.c
36 workspace.c 37 workspace.c
37 border.c 38 border.c
38 security.c 39 security.c
39) 40)
40 41
41add_definitions( 42add_definitions(
diff --git a/sway/base64.c b/sway/base64.c
new file mode 100644
index 00000000..0d51b5c7
--- /dev/null
+++ b/sway/base64.c
@@ -0,0 +1,221 @@
1/*
2 * Adapted from https://github.com/littlstar/b64.c
3 * License under the MIT License:
4 * Copyright (c) 2014 Little Star Media, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#include <ctype.h>
26#include <stdlib.h>
27#include "util.h"
28
29static const char b64_table[] = {
30 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
31 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
32 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
33 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
34 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
35 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
36 'w', 'x', 'y', 'z', '0', '1', '2', '3',
37 '4', '5', '6', '7', '8', '9', '+', '/'
38};
39
40char *b64_encode(const char *src, size_t len, size_t *flen) {
41 int i = 0;
42 int j = 0;
43 char *enc = NULL;
44 size_t size = len * 4 / 3;
45 size_t idx = 0;
46 unsigned char buf[4];
47 char tmp[3];
48
49 // alloc
50 enc = (char *) malloc(size + 1);
51 if (NULL == enc) { return NULL; }
52
53 // parse until end of source
54 while (len--) {
55 // read up to 3 bytes at a time into `tmp'
56 tmp[i++] = *(src++);
57
58 // if 3 bytes read then encode into `buf'
59 if (3 == i) {
60 buf[0] = (tmp[0] & 0xfc) >> 2;
61 buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
62 buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
63 buf[3] = tmp[2] & 0x3f;
64
65 // shouldn't really happen
66 if (idx + 4 > size) {
67 size += 16;
68 enc = (char *) realloc(enc, size + 1);
69 }
70 for (i = 0; i < 4; ++i) {
71 enc[idx++] = b64_table[buf[i]];
72 }
73
74 // reset index
75 i = 0;
76 }
77 }
78
79 // remainder
80 if (i > 0) {
81 // fill `tmp' with `\0' at most 3 times
82 for (j = i; j < 3; ++j) {
83 tmp[j] = '\0';
84 }
85
86 // perform same codec as above
87 buf[0] = (tmp[0] & 0xfc) >> 2;
88 buf[1] = ((tmp[0] & 0x03) << 4) + ((tmp[1] & 0xf0) >> 4);
89 buf[2] = ((tmp[1] & 0x0f) << 2) + ((tmp[2] & 0xc0) >> 6);
90 buf[3] = tmp[2] & 0x3f;
91
92 // perform same write to `enc` with new allocation
93 size_t delta = (i > 3 ? 0 : 3 - i) + (j > i + 1 ? 0 : i + 1 - j);
94 if (idx + delta > size) {
95 size += delta;
96 enc = (char *) realloc(enc, size + 1);
97 }
98 for (j = 0; (j < i + 1); ++j) {
99 enc[idx++] = b64_table[buf[j]];
100 }
101
102 // while there is still a remainder
103 // append `=' to `enc'
104 while ((i++ < 3)) {
105 enc[idx++] = '=';
106 }
107 }
108
109 enc[idx] = '\0';
110
111 if (flen)
112 *flen = size;
113 return enc;
114}
115
116unsigned char *b64_decode(const char *src, size_t len, size_t *decsize) {
117 int i = 0;
118 int j = 0;
119 int l = 0;
120 // max size estimate
121 size_t size = len * 3 / 4;
122 size_t idx = 0;
123 unsigned char *dec = NULL;
124 unsigned char buf[3];
125 unsigned char tmp[4];
126
127 // alloc
128 dec = (unsigned char *) malloc(size + 1);
129 if (NULL == dec) { return NULL; }
130
131 // parse until end of source
132 while (len--) {
133 if (isspace(src[j])) { j++; continue; }
134 // break if char is `=' or not base64 char
135 if ('=' == src[j]) { break; }
136 if (!(isalnum(src[j]) || '+' == src[j] || '/' == src[j])) { break; }
137
138 // read up to 4 bytes at a time into `tmp'
139 tmp[i++] = src[j++];
140
141 // if 4 bytes read then decode into `buf'
142 if (4 == i) {
143 // translate values in `tmp' from table
144 for (i = 0; i < 4; ++i) {
145 // find translation char in `b64_table'
146 for (l = 0; l < 64; ++l) {
147 if (tmp[i] == b64_table[l]) {
148 tmp[i] = l;
149 break;
150 }
151 }
152 }
153
154 // decode
155 buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
156 buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
157 buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
158
159 // unlikely
160 if (idx + 3 > size) {
161 size += 16;
162 dec = (unsigned char *) realloc(dec, size + 1);
163 }
164 if (dec != NULL){
165 for (i = 0; i < 3; ++i) {
166 dec[idx++] = buf[i];
167 }
168 } else {
169 return NULL;
170 }
171
172 // reset
173 i = 0;
174 }
175 }
176
177 // remainder
178 if (i > 0) {
179 // fill `tmp' with `\0' at most 4 times
180 for (j = i; j < 4; ++j) {
181 tmp[j] = '\0';
182 }
183
184 // translate remainder
185 for (j = 0; j < 4; ++j) {
186 // find translation char in `b64_table'
187 for (l = 0; l < 64; ++l) {
188 if (tmp[j] == b64_table[l]) {
189 tmp[j] = l;
190 break;
191 }
192 }
193 }
194
195 // decode remainder
196 buf[0] = (tmp[0] << 2) + ((tmp[1] & 0x30) >> 4);
197 buf[1] = ((tmp[1] & 0xf) << 4) + ((tmp[2] & 0x3c) >> 2);
198 buf[2] = ((tmp[2] & 0x3) << 6) + tmp[3];
199
200 // write remainer decoded buffer to `dec'
201 if (idx + (i - 1) > size) {
202 size += 16;
203 dec = (unsigned char *) realloc(dec, size + 1);
204 }
205 if (dec != NULL){
206 for (j = 0; (j < i - 1); ++j) {
207 dec[idx++] = buf[j];
208 }
209 } else {
210 return NULL;
211 }
212 }
213
214 dec[idx] = '\0';
215 // Return back the size of decoded string if demanded.
216 if (decsize != NULL) {
217 *decsize = size;
218 }
219
220 return dec;
221}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index b6268404..70692f64 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -1,5 +1,6 @@
1// See https://i3wm.org/docs/ipc.html for protocol information 1// See https://i3wm.org/docs/ipc.html for protocol information
2 2
3#define _XOPEN_SOURCE 700
3#include <errno.h> 4#include <errno.h>
4#include <string.h> 5#include <string.h>
5#include <sys/socket.h> 6#include <sys/socket.h>
@@ -56,8 +57,11 @@ struct get_pixels_request {
56}; 57};
57 58
58struct get_clipboard_request { 59struct get_clipboard_request {
59 struct ipc_client *client; 60 struct ipc_client *client;
60 struct wlc_event_source *event_source; 61 json_object *json;
62 struct wlc_event_source *event_source;
63 char *type;
64 unsigned int *pending;
61}; 65};
62 66
63struct sockaddr_un *ipc_user_sockaddr(void); 67struct sockaddr_un *ipc_user_sockaddr(void);
@@ -327,44 +331,201 @@ void ipc_get_pixels(wlc_handle output) {
327 ipc_get_pixel_requests = unhandled; 331 ipc_get_pixel_requests = unhandled;
328} 332}
329 333
330static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) 334static int ipc_selection_data_cb(int fd, uint32_t mask, void *data) {
331{
332 assert(data); 335 assert(data);
333 struct get_clipboard_request *req = (struct get_clipboard_request*) data; 336 struct get_clipboard_request *req = (struct get_clipboard_request *)data;
334 337
335 if (mask & WLC_EVENT_ERROR) { 338 if (mask & WLC_EVENT_ERROR) {
336 sway_log(L_ERROR, "Selection data fd error"); 339 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; 340 goto cleanup;
341 } 341 }
342 342
343 if (mask & WLC_EVENT_READABLE) { 343 if (mask & WLC_EVENT_READABLE || true) {
344 char buf[512]; 344 static const int step_size = 512;
345 int ret = read(fd, buf, 511); 345 char *data = NULL;
346 if (ret < 0) { 346 int ret = 0;
347 sway_log_errno(L_ERROR, "Reading from selection data fd failed"); 347 int current = 0;
348 const char *error = "{ \"success\": false, \"error\": " 348
349 "\"Could not receive text data from clipboard\" }"; 349 // read data as long as there is data avilable
350 ipc_send_reply(req->client, error, (uint32_t)strlen(error)); 350 // grow the buffer step_size in every iteration
351 goto cleanup; 351 do {
352 if (data == NULL) {
353 data = malloc(step_size);
354 } else {
355 data = realloc(data, current + step_size);
356 }
357
358 ret = read(fd, data + current, step_size - 1);
359 if (ret < 0) {
360 sway_log_errno(L_ERROR, "Reading from selection data fd failed");
361 goto cleanup;
362 }
363
364 current += ret;
365 } while (ret == step_size - 1);
366
367 data[current] = '\0';
368
369 if (strncmp(req->type, "text/", 5) == 0) {
370 json_object_object_add(req->json, req->type,
371 json_object_new_string(data));
372 } else {
373 size_t outlen;
374 char *b64 = b64_encode(data, current, &outlen);
375 json_object_object_add(req->json, req->type,
376 json_object_new_string(b64));
377 free(b64);
352 } 378 }
353 379
354 buf[ret] = '\0'; 380 free(data);
355 json_object *obj = json_object_new_object(); 381 } else {
356 json_object_object_add(obj, "success", json_object_new_boolean(true)); 382 return 0; // TODO
357 json_object_object_add(obj, "content", json_object_new_string(buf)); 383 }
358 const char *str = json_object_to_json_string(obj); 384
385cleanup:
386 close(fd);
387
388 if (--(*req->pending) == 0) {
389 const char *str = json_object_to_json_string(req->json);
359 ipc_send_reply(req->client, str, (uint32_t)strlen(str)); 390 ipc_send_reply(req->client, str, (uint32_t)strlen(str));
391 json_object_put(req->json);
392 }
393
394 free(req->type);
395 wlc_event_source_remove(req->event_source);
396 free(req);
397 return 0;
398}
399
400// greedy wildcard (only "*") matching
401bool mime_type_matches(const char *mime_type, const char *pattern) {
402 const char* wildcard = NULL;
403 while (*mime_type && *pattern) {
404 if (*pattern == '*' && !wildcard) {
405 wildcard = pattern;
406 ++pattern;
407 }
408
409 if (*mime_type != *pattern) {
410 if (!wildcard)
411 return false;
412
413 pattern = wildcard;
414 ++mime_type;
415 continue;
416 }
417
418 ++mime_type;
419 ++pattern;
420 }
421
422 while (*pattern == '*') {
423 ++pattern;
424 }
425
426 return (*mime_type == *pattern);
427}
428
429void ipc_get_clipboard(struct ipc_client *client, char *buf) {
430 static const char *error_json = "{ \"success\": false, \"error\": "
431 "\"Failed to retrieve clipboard data\" }";
432
433 size_t size;
434 const char **types = wlc_get_selection_types(&size);
435 if (client->payload_length == 0) {
436 json_object *obj = json_object_new_array();
437 for (size_t i = 0; i < size; ++i) {
438 json_object_array_add(obj, json_object_new_string(types[i]));
439 }
440
441 const char *str = json_object_to_json_string(obj);
442 ipc_send_reply(client, str, strlen(str));
360 json_object_put(obj); 443 json_object_put(obj);
444 return;
445 }
446
447 unescape_string(buf);
448 strip_quotes(buf);
449 list_t *requested = split_string(buf, " ");
450 json_object *json = json_object_new_object();
451 unsigned int *pending = malloc(sizeof(unsigned int));
452 *pending = 0;
453
454 for (size_t l = 0; l < (size_t) requested->length; ++l) {
455 const char *pattern = requested->items[l];
456 bool found = false;
457 for (size_t i = 0; i < size; ++i) {
458 if (mime_type_matches(types[i], pattern)) {
459 found = true;
460
461 struct get_clipboard_request *req = malloc(sizeof(*req));
462 if (!req) {
463 sway_log(L_ERROR, "Cannot allocate get_clipboard_request");
464 goto data_error;
465 }
466
467 int pipes[2];
468 if (pipe(pipes) == -1) {
469 sway_log_errno(L_ERROR, "pipe call failed");
470 free(req);
471 goto data_error;
472 }
473
474 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
475 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
476
477 if (!wlc_get_selection_data(types[i], pipes[1])) {
478 close(pipes[0]);
479 close(pipes[1]);
480 free(req);
481 sway_log(L_ERROR, "wlc_get_selection_data failed");
482 goto data_error;
483 }
484
485 (*pending)++;
486
487 req->client = client;
488 req->type = strdup(types[i]);
489 req->json = json;
490 req->pending = pending;
491 req->event_source = wlc_event_loop_add_fd(pipes[0],
492 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
493 &ipc_selection_data_cb, req);
494
495 // NOTE: remove this goto to enable retrieving multiple
496 // targets at once. The whole implementation is already
497 // made for it. The only reason it was disabled
498 // at the time of writing is that neither wlc's xselection
499 // implementation nor (apparently) gtk on wayland supports
500 // multiple send requests at the same time which makes
501 // every request except the last one fail (and therefore
502 // return empty data)
503 goto cleanup;
504 }
505 }
506
507 if (!found) {
508 sway_log(L_INFO, "Invalid clipboard type %s requested", pattern);
509 }
361 } 510 }
362 511
512 if (*pending == 0) {
513 static const char *empty = "[]";
514 ipc_send_reply(client, empty, (uint32_t)strlen(empty));
515 free(json);
516 free(pending);
517 }
518
519 goto cleanup;
520
521data_error:
522 ipc_send_reply(client, error_json, (uint32_t)strlen(error_json));
523 free(json);
524 free(pending);
525
363cleanup: 526cleanup:
364 wlc_event_source_remove(req->event_source); 527 list_free(requested);
365 close(fd); 528 free(types);
366 free(req);
367 return 0;
368} 529}
369 530
370void ipc_client_handle_command(struct ipc_client *client) { 531void ipc_client_handle_command(struct ipc_client *client) {
@@ -610,69 +771,13 @@ void ipc_client_handle_command(struct ipc_client *client) {
610 goto exit_cleanup; 771 goto exit_cleanup;
611 } 772 }
612 773
613 case IPC_GET_CLIPBOARD: 774 case IPC_GET_CLIPBOARD:
614 { 775 {
615 if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) { 776 if (!(client->security_policy & IPC_FEATURE_GET_CLIPBOARD)) {
616 goto exit_denied; 777 goto exit_denied;
617 } 778 }
618 779
619 size_t size; 780 ipc_get_clipboard(client, buf);
620 const char **types = wlc_get_selection_types(&size);
621 const char *type = NULL;
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 type = types[i];
633 break;
634 }
635 }
636
637 if (type) {
638 struct get_clipboard_request *req = malloc(sizeof(*req));
639 if (!req) {
640 sway_log(L_ERROR, "Unable to allocate get_clipboard_request");
641 goto clipboard_error;
642 }
643
644 int pipes[2];
645 if (pipe(pipes) == -1) {
646 sway_log_errno(L_ERROR, "pipe call failed");
647 free(req);
648 goto clipboard_error;
649 }
650
651 fcntl(pipes[0], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
652 fcntl(pipes[1], F_SETFD, FD_CLOEXEC | O_NONBLOCK);
653 if (!wlc_get_selection_data(type, pipes[1])) {
654 close(pipes[0]);
655 close(pipes[1]);
656 free(req);
657 sway_log(L_ERROR, "wlc_get_selection_data failed");
658 goto clipboard_error;
659 }
660
661 req->client = client;
662 req->event_source = wlc_event_loop_add_fd(pipes[0],
663 WLC_EVENT_READABLE | WLC_EVENT_ERROR | WLC_EVENT_HANGUP,
664 &ipc_selection_data_cb, req);
665 free(types);
666 goto exit_cleanup;
667 }
668
669clipboard_error:
670 sway_log(L_INFO, "Clipboard has to text data");
671 const char *error = "{ \"success\": false, \"error\": "
672 "\"Could not receive text data from clipboard\" }";
673 ipc_send_reply(client, error, (uint32_t)strlen(error));
674
675 free(types);
676 goto exit_cleanup; 781 goto exit_cleanup;
677 } 782 }
678 783
diff --git a/swaymsg/main.c b/swaymsg/main.c
index fa28553b..450df673 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -19,15 +19,17 @@ void sway_terminate(int exit_code) {
19 exit(exit_code); 19 exit(exit_code);
20} 20}
21 21
22static void pretty_print_cmd(json_object *r) { 22static bool success(json_object *r, bool fallback) {
23 bool _success;
24 json_object *success; 23 json_object *success;
25 if (!json_object_object_get_ex(r, "success", &success)) { 24 if (!json_object_object_get_ex(r, "success", &success)) {
26 _success = true; 25 return fallback;
27 } else { 26 } else {
28 _success = json_object_get_boolean(success); 27 return json_object_get_boolean(success);
29 } 28 }
30 if (!_success) { 29}
30
31static void pretty_print_cmd(json_object *r) {
32 if (!success(r, true)) {
31 json_object *error; 33 json_object *error;
32 if (!json_object_object_get_ex(r, "error", &error)) { 34 if (!json_object_object_get_ex(r, "error", &error)) {
33 printf("An unknkown error occured"); 35 printf("An unknkown error occured");
@@ -145,15 +147,23 @@ static void pretty_print_version(json_object *v) {
145} 147}
146 148
147static void pretty_print_clipboard(json_object *v) { 149static void pretty_print_clipboard(json_object *v) {
148 bool _success; 150 if (success(v, true)) {
149 json_object *success; 151 if (json_object_is_type(v, json_type_array)) {
150 json_object_object_get_ex(v, "success", &success); 152 for (int i = 0; i < json_object_array_length(v); ++i) {
151 _success = json_object_get_boolean(success); 153 json_object *o = json_object_array_get_idx(v, i);
152 154 printf("%s\n", json_object_get_string(o));
153 if (_success) { 155 }
154 json_object *ver; 156 } else {
155 json_object_object_get_ex(v, "content", &ver); 157 // NOTE: could be extended to print all received types
156 printf("%s\n", json_object_get_string(ver)); 158 // instead just the first one when sways ipc server
159 // supports it
160 struct json_object_iterator iter = json_object_iter_begin(v);
161 struct json_object_iterator end = json_object_iter_end(v);
162 if (!json_object_iter_equal(&iter, &end)) {
163 printf("%s\n", json_object_get_string(
164 json_object_iter_peek_value(&iter)));
165 }
166 }
157 } 167 }
158} 168}
159 169
@@ -310,6 +320,9 @@ int main(int argc, char **argv) {
310 printf("%s\n", resp); 320 printf("%s\n", resp);
311 ret = 1; 321 ret = 1;
312 } else { 322 } else {
323 if (!success(obj, true)) {
324 ret = 1;
325 }
313 if (raw) { 326 if (raw) {
314 printf("%s\n", json_object_to_json_string_ext(obj, 327 printf("%s\n", json_object_to_json_string_ext(obj,
315 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED)); 328 JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_SPACED));
diff --git a/swaymsg/swaymsg.1.txt b/swaymsg/swaymsg.1.txt
index 1f03bee3..6fd08e81 100644
--- a/swaymsg/swaymsg.1.txt
+++ b/swaymsg/swaymsg.1.txt
@@ -65,6 +65,12 @@ IPC Message Types
65*get_version*:: 65*get_version*::
66 Get JSON-encoded version information for the running instance of sway. 66 Get JSON-encoded version information for the running instance of sway.
67 67
68*get_clipboard*::
69 Get JSON-encoded information about the clipboard.
70 Returns the current clipboard mime-types if called without
71 arguments, otherwise returns the clipboard data in the requested
72 formats. Encodes the data using base64 for non-text mime types.
73
68Authors 74Authors
69------- 75-------
70 76