aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2016-09-19 06:53:29 +0900
committerLibravatar GitHub <noreply@github.com>2016-09-19 06:53:29 +0900
commitd98c26d0edbab66042ff3da0348d339fd857f99d (patch)
tree78146ff883ee17c5f56610cce67ae658a2d2412d
parentMerge pull request #907 from zandrmartin/fix-json-tree-focus-property (diff)
parentimplement "focused container" feature for swaygrab (diff)
downloadsway-d98c26d0edbab66042ff3da0348d339fd857f99d.tar.gz
sway-d98c26d0edbab66042ff3da0348d339fd857f99d.tar.zst
sway-d98c26d0edbab66042ff3da0348d339fd857f99d.zip
Merge pull request #909 from zandrmartin/grab-focused
implement "focused container" option for swaygrab
-rw-r--r--include/swaygrab/json.h10
-rw-r--r--sway/ipc-json.c1
-rw-r--r--sway/ipc-server.c35
-rw-r--r--swaygrab/CMakeLists.txt1
-rw-r--r--swaygrab/json.c123
-rw-r--r--swaygrab/main.c99
6 files changed, 221 insertions, 48 deletions
diff --git a/include/swaygrab/json.h b/include/swaygrab/json.h
new file mode 100644
index 00000000..c1093ef1
--- /dev/null
+++ b/include/swaygrab/json.h
@@ -0,0 +1,10 @@
1#include <json-c/json.h>
2#include "wlc/wlc.h"
3
4void init_json_tree(int socketfd);
5void free_json_tree();
6char *get_focused_output();
7char *create_payload(const char *output, struct wlc_geometry *g);
8struct wlc_geometry *get_container_geometry(json_object *container);
9json_object *get_focused_container();
10json_object *get_output_container(const char *output);
diff --git a/sway/ipc-json.c b/sway/ipc-json.c
index 5d10ff59..1ca7f9ce 100644
--- a/sway/ipc-json.c
+++ b/sway/ipc-json.c
@@ -169,7 +169,6 @@ static void ipc_json_describe_view(swayc_t *c, json_object *object) {
169 json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL); 169 json_object_object_add(object, "percent", (percent > 0) ? json_object_new_double(percent) : NULL);
170 // TODO: make urgency actually work once Sway supports it 170 // TODO: make urgency actually work once Sway supports it
171 json_object_object_add(object, "urgent", json_object_new_boolean(false)); 171 json_object_object_add(object, "urgent", json_object_new_boolean(false));
172
173 json_object_object_add(object, "layout", 172 json_object_object_add(object, "layout",
174 (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout)); 173 (strcmp(layout, "null") == 0) ? NULL : json_object_new_string(layout));
175 json_object_object_add(object, "last_split_layout", 174 json_object_object_add(object, "last_split_layout",
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 4c54e56a..ebb5ce58 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -43,6 +43,7 @@ static list_t *ipc_get_pixel_requests = NULL;
43struct get_pixels_request { 43struct get_pixels_request {
44 struct ipc_client *client; 44 struct ipc_client *client;
45 wlc_handle output; 45 wlc_handle output;
46 struct wlc_geometry geo;
46}; 47};
47 48
48struct sockaddr_un *ipc_user_sockaddr(void); 49struct sockaddr_un *ipc_user_sockaddr(void);
@@ -259,16 +260,12 @@ void ipc_get_pixels(wlc_handle output) {
259 continue; 260 continue;
260 } 261 }
261 262
262 const struct wlc_size *size = wlc_output_get_resolution(req->output); 263 const struct wlc_size *size = &req->geo.size;
263 struct wlc_geometry g = {
264 .size = *size,
265 .origin = { 0, 0 },
266 };
267 struct wlc_geometry g_out; 264 struct wlc_geometry g_out;
268 char response_header[9]; 265 char response_header[9];
269 memset(response_header, 0, sizeof(response_header)); 266 memset(response_header, 0, sizeof(response_header));
270 char *data = malloc(sizeof(response_header) + size->w * size->h * 4); 267 char *data = malloc(sizeof(response_header) + size->w * size->h * 4);
271 wlc_pixels_read(WLC_RGBA8888, &g, &g_out, data + sizeof(response_header)); 268 wlc_pixels_read(WLC_RGBA8888, &req->geo, &g_out, data + sizeof(response_header));
272 269
273 response_header[0] = 1; 270 response_header[0] = 1;
274 uint32_t *_size = (uint32_t *)(response_header + 1); 271 uint32_t *_size = (uint32_t *)(response_header + 1);
@@ -425,7 +422,30 @@ void ipc_client_handle_command(struct ipc_client *client) {
425 { 422 {
426 char response_header[9]; 423 char response_header[9];
427 memset(response_header, 0, sizeof(response_header)); 424 memset(response_header, 0, sizeof(response_header));
428 swayc_t *output = swayc_by_test(&root_container, output_by_name_test, buf); 425
426 json_object *obj = json_tokener_parse(buf);
427 json_object *o, *x, *y, *w, *h;
428
429 json_object_object_get_ex(obj, "output", &o);
430 json_object_object_get_ex(obj, "x", &x);
431 json_object_object_get_ex(obj, "y", &y);
432 json_object_object_get_ex(obj, "w", &w);
433 json_object_object_get_ex(obj, "h", &h);
434
435 struct wlc_geometry g = {
436 .origin = {
437 .x = json_object_get_int(x),
438 .y = json_object_get_int(y)
439 },
440 .size = {
441 .w = json_object_get_int(w),
442 .h = json_object_get_int(h)
443 }
444 };
445
446 swayc_t *output = swayc_by_test(&root_container, output_by_name_test, (void *)json_object_get_string(o));
447 json_object_put(obj);
448
429 if (!output) { 449 if (!output) {
430 sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name"); 450 sway_log(L_ERROR, "IPC GET_PIXELS request with unknown output name");
431 ipc_send_reply(client, response_header, sizeof(response_header)); 451 ipc_send_reply(client, response_header, sizeof(response_header));
@@ -434,6 +454,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
434 struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request)); 454 struct get_pixels_request *req = malloc(sizeof(struct get_pixels_request));
435 req->client = client; 455 req->client = client;
436 req->output = output->handle; 456 req->output = output->handle;
457 req->geo = g;
437 list_add(ipc_get_pixel_requests, req); 458 list_add(ipc_get_pixel_requests, req);
438 wlc_output_schedule_render(output->handle); 459 wlc_output_schedule_render(output->handle);
439 goto exit_cleanup; 460 goto exit_cleanup;
diff --git a/swaygrab/CMakeLists.txt b/swaygrab/CMakeLists.txt
index b4aee357..a5e91e9c 100644
--- a/swaygrab/CMakeLists.txt
+++ b/swaygrab/CMakeLists.txt
@@ -6,6 +6,7 @@ include_directories(
6 6
7add_executable(swaygrab 7add_executable(swaygrab
8 main.c 8 main.c
9 json.c
9) 10)
10 11
11target_link_libraries(swaygrab 12target_link_libraries(swaygrab
diff --git a/swaygrab/json.c b/swaygrab/json.c
new file mode 100644
index 00000000..7cd73cbe
--- /dev/null
+++ b/swaygrab/json.c
@@ -0,0 +1,123 @@
1#include <stdio.h>
2#include <stdbool.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include "ipc-client.h"
6#include "swaygrab/json.h"
7
8static json_object *tree;
9
10void init_json_tree(int socketfd) {
11 uint32_t len = 0;
12 char *res = ipc_single_command(socketfd, IPC_GET_TREE, NULL, &len);
13 tree = json_tokener_parse(res);
14}
15
16void free_json_tree() {
17 json_object_put(tree);
18}
19
20static bool is_focused(json_object *c) {
21 json_object *focused;
22 json_object_object_get_ex(c, "focused", &focused);
23 return json_object_get_boolean(focused);
24}
25
26static json_object *get_focused_container_r(json_object *c) {
27 json_object *name;
28 json_object_object_get_ex(c, "name", &name);
29 if (is_focused(c)) {
30 return c;
31 } else {
32 json_object *nodes, *node, *child;
33 json_object_object_get_ex(c, "nodes", &nodes);
34 int i;
35 for (i = 0; i < json_object_array_length(nodes); i++) {
36 node = json_object_array_get_idx(nodes, i);
37
38 if ((child = get_focused_container_r(node))) {
39 return child;
40 }
41 }
42
43 json_object_object_get_ex(c, "floating_nodes", &nodes);
44 for (i = 0; i < json_object_array_length(nodes); i++) {
45 node = json_object_array_get_idx(nodes, i);
46
47 if ((child = get_focused_container_r(node))) {
48 return child;
49 }
50 }
51
52 }
53
54 return NULL;
55}
56
57json_object *get_focused_container() {
58 return get_focused_container_r(tree);
59}
60
61char *get_focused_output() {
62 json_object *outputs, *output, *name;
63 json_object_object_get_ex(tree, "nodes", &outputs);
64
65 for (int i = 0; i < json_object_array_length(outputs); i++) {
66 output = json_object_array_get_idx(outputs, i);
67
68 if (get_focused_container_r(output)) {
69 json_object_object_get_ex(output, "name", &name);
70 return strdup(json_object_get_string(name));
71 }
72 }
73
74 return NULL;
75}
76
77char *create_payload(const char *output, struct wlc_geometry *g) {
78 char *payload_str = malloc(256);
79 json_object *payload = json_object_new_object();
80
81 json_object_object_add(payload, "output", json_object_new_string(output));
82 json_object_object_add(payload, "x", json_object_new_int(g->origin.x));
83 json_object_object_add(payload, "y", json_object_new_int(g->origin.y));
84 json_object_object_add(payload, "w", json_object_new_int(g->size.w));
85 json_object_object_add(payload, "h", json_object_new_int(g->size.h));
86
87 snprintf(payload_str, 256, "%s", json_object_to_json_string(payload));
88 return strdup(payload_str);
89}
90
91struct wlc_geometry *get_container_geometry(json_object *container) {
92 struct wlc_geometry *geo = malloc(sizeof(struct wlc_geometry));
93 json_object *rect, *x, *y, *w, *h;
94
95 json_object_object_get_ex(container, "rect", &rect);
96 json_object_object_get_ex(rect, "x", &x);
97 json_object_object_get_ex(rect, "y", &y);
98 json_object_object_get_ex(rect, "width", &w);
99 json_object_object_get_ex(rect, "height", &h);
100
101 geo->origin.x = json_object_get_int(x);
102 geo->origin.y = json_object_get_int(y);
103 geo->size.w = json_object_get_int(w);
104 geo->size.h = json_object_get_int(h);
105
106 return geo;
107}
108
109json_object *get_output_container(const char *output) {
110 json_object *outputs, *json_output, *name;
111 json_object_object_get_ex(tree, "nodes", &outputs);
112
113 for (int i = 0; i < json_object_array_length(outputs); i++) {
114 json_output = json_object_array_get_idx(outputs, i);
115 json_object_object_get_ex(json_output, "name", &name);
116
117 if (strcmp(json_object_get_string(name), output) == 0) {
118 return json_output;
119 }
120 }
121
122 return NULL;
123}
diff --git a/swaygrab/main.c b/swaygrab/main.c
index 96290957..a88a6bcc 100644
--- a/swaygrab/main.c
+++ b/swaygrab/main.c
@@ -1,4 +1,5 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <stdbool.h>
2#include <stdlib.h> 3#include <stdlib.h>
3#include <string.h> 4#include <string.h>
4#include <getopt.h> 5#include <getopt.h>
@@ -10,16 +11,17 @@
10#include "log.h" 11#include "log.h"
11#include "ipc-client.h" 12#include "ipc-client.h"
12#include "util.h" 13#include "util.h"
14#include "swaygrab/json.h"
13 15
14void sway_terminate(int exit_code) { 16void sway_terminate(int exit_code) {
15 exit(exit_code); 17 exit(exit_code);
16} 18}
17 19
18void grab_and_apply_magick(const char *file, const char *output, 20void grab_and_apply_magick(const char *file, const char *payload,
19 int socketfd, int raw) { 21 int socketfd, int raw) {
20 uint32_t len = strlen(output); 22 uint32_t len = strlen(payload);
21 char *pixels = ipc_single_command(socketfd, 23 char *pixels = ipc_single_command(socketfd,
22 IPC_SWAY_GET_PIXELS, output, &len); 24 IPC_SWAY_GET_PIXELS, payload, &len);
23 uint32_t *u32pixels = (uint32_t *)(pixels + 1); 25 uint32_t *u32pixels = (uint32_t *)(pixels + 1);
24 uint32_t width = u32pixels[0]; 26 uint32_t width = u32pixels[0];
25 uint32_t height = u32pixels[1]; 27 uint32_t height = u32pixels[1];
@@ -27,7 +29,13 @@ void grab_and_apply_magick(const char *file, const char *output,
27 pixels += 9; 29 pixels += 9;
28 30
29 if (width == 0 || height == 0) { 31 if (width == 0 || height == 0) {
30 sway_abort("Unknown output %s.", output); 32 // indicates geometry was clamped by WLC because it was outside of the output's area
33 json_object *obj = json_tokener_parse(payload);
34 json_object *output;
35 json_object_object_get_ex(obj, "output", &output);
36 const char *name = json_object_get_string(output);
37 json_object_put(obj);
38 sway_abort("Unknown output %s.", name);
31 } 39 }
32 40
33 if (raw) { 41 if (raw) {
@@ -50,22 +58,28 @@ void grab_and_apply_magick(const char *file, const char *output,
50 free(cmd); 58 free(cmd);
51} 59}
52 60
53void grab_and_apply_movie_magic(const char *file, const char *output, 61void grab_and_apply_movie_magic(const char *file, const char *payload,
54 int socketfd, int raw, int framerate) { 62 int socketfd, int raw, int framerate) {
55 if (raw) { 63 if (raw) {
56 sway_log(L_ERROR, "Raw capture data is not yet supported. Proceeding with ffmpeg normally."); 64 sway_log(L_ERROR, "Raw capture data is not yet supported. Proceeding with ffmpeg normally.");
57 } 65 }
58 66
59 uint32_t len = strlen(output); 67 uint32_t len = strlen(payload);
60 char *pixels = ipc_single_command(socketfd, 68 char *pixels = ipc_single_command(socketfd,
61 IPC_SWAY_GET_PIXELS, output, &len); 69 IPC_SWAY_GET_PIXELS, payload, &len);
62 uint32_t *u32pixels = (uint32_t *)(pixels + 1); 70 uint32_t *u32pixels = (uint32_t *)(pixels + 1);
63 uint32_t width = u32pixels[0]; 71 uint32_t width = u32pixels[0];
64 uint32_t height = u32pixels[1]; 72 uint32_t height = u32pixels[1];
65 pixels += 9; 73 pixels += 9;
66 74
67 if (width == 0 || height == 0) { 75 if (width == 0 || height == 0) {
68 sway_abort("Unknown output %s.", output); 76 // indicates geometry was clamped by WLC because it was outside of the output's area
77 json_object *obj = json_tokener_parse(payload);
78 json_object *output;
79 json_object_object_get_ex(obj, "output", &output);
80 const char *name = json_object_get_string(output);
81 json_object_put(obj);
82 sway_abort("Unknown output %s.", name);
69 } 83 }
70 84
71 const char *fmt = "ffmpeg -f rawvideo -framerate %d " 85 const char *fmt = "ffmpeg -f rawvideo -framerate %d "
@@ -86,9 +100,9 @@ void grab_and_apply_movie_magic(const char *file, const char *output,
86 int sleep = 0; 100 int sleep = 0;
87 while (sleep != -1) { 101 while (sleep != -1) {
88 clock_gettime(CLOCK_MONOTONIC, &start); 102 clock_gettime(CLOCK_MONOTONIC, &start);
89 len = strlen(output); 103 len = strlen(payload);
90 pixels = ipc_single_command(socketfd, 104 pixels = ipc_single_command(socketfd,
91 IPC_SWAY_GET_PIXELS, output, &len); 105 IPC_SWAY_GET_PIXELS, payload, &len);
92 pixels += 9; 106 pixels += 9;
93 len -= 9; 107 len -= 9;
94 108
@@ -112,30 +126,6 @@ void grab_and_apply_movie_magic(const char *file, const char *output,
112 free(cmd); 126 free(cmd);
113} 127}
114 128
115char *get_focused_output(int socketfd) {
116 uint32_t len = 0;
117 char *res = ipc_single_command(socketfd, IPC_GET_WORKSPACES, NULL, &len);
118 json_object *workspaces = json_tokener_parse(res);
119
120 int length = json_object_array_length(workspaces);
121 json_object *workspace, *focused, *json_output;
122 char *output = NULL;
123 int i;
124 for (i = 0; i < length; ++i) {
125 workspace = json_object_array_get_idx(workspaces, i);
126 json_object_object_get_ex(workspace, "focused", &focused);
127 if (json_object_get_boolean(focused) == TRUE) {
128 json_object_object_get_ex(workspace, "output", &json_output);
129 output = strdup(json_object_get_string(json_output));
130 break;
131 }
132 }
133
134 json_object_put(workspaces);
135 free(res);
136 return output;
137}
138
139char *default_filename(const char *extension) { 129char *default_filename(const char *extension) {
140 int ext_len = strlen(extension); 130 int ext_len = strlen(extension);
141 int len = 28 + ext_len; // format: "2015-12-17-180040_swaygrab.ext" 131 int len = 28 + ext_len; // format: "2015-12-17-180040_swaygrab.ext"
@@ -154,6 +144,7 @@ int main(int argc, char **argv) {
154 char *socket_path = NULL; 144 char *socket_path = NULL;
155 char *output = NULL; 145 char *output = NULL;
156 int framerate = 30; 146 int framerate = 30;
147 bool grab_focused = false;
157 148
158 init_log(L_INFO); 149 init_log(L_INFO);
159 150
@@ -165,6 +156,7 @@ int main(int argc, char **argv) {
165 {"socket", required_argument, NULL, 's'}, 156 {"socket", required_argument, NULL, 's'},
166 {"raw", no_argument, NULL, 'r'}, 157 {"raw", no_argument, NULL, 'r'},
167 {"rate", required_argument, NULL, 'R'}, 158 {"rate", required_argument, NULL, 'R'},
159 {"focused", no_argument, NULL, 'f'},
168 {0, 0, 0, 0} 160 {0, 0, 0, 0}
169 }; 161 };
170 162
@@ -177,16 +169,20 @@ int main(int argc, char **argv) {
177 " -v, --version Show the version number and quit.\n" 169 " -v, --version Show the version number and quit.\n"
178 " -s, --socket <socket> Use the specified socket.\n" 170 " -s, --socket <socket> Use the specified socket.\n"
179 " -R, --rate <rate> Specify framerate (default: 30)\n" 171 " -R, --rate <rate> Specify framerate (default: 30)\n"
180 " -r, --raw Write raw rgba data to stdout.\n"; 172 " -r, --raw Write raw rgba data to stdout.\n"
173 " -f, --focused Grab the focused container.\n";
181 174
182 int c; 175 int c;
183 while (1) { 176 while (1) {
184 int option_index = 0; 177 int option_index = 0;
185 c = getopt_long(argc, argv, "hco:vs:R:r", long_options, &option_index); 178 c = getopt_long(argc, argv, "hco:vs:R:rf", long_options, &option_index);
186 if (c == -1) { 179 if (c == -1) {
187 break; 180 break;
188 } 181 }
189 switch (c) { 182 switch (c) {
183 case 'f':
184 grab_focused = true;
185 break;
190 case 's': // Socket 186 case 's': // Socket
191 socket_path = strdup(optarg); 187 socket_path = strdup(optarg);
192 break; 188 break;
@@ -235,10 +231,32 @@ int main(int argc, char **argv) {
235 int socketfd = ipc_open_socket(socket_path); 231 int socketfd = ipc_open_socket(socket_path);
236 free(socket_path); 232 free(socket_path);
237 233
238 if (!output) { 234 init_json_tree(socketfd);
239 output = get_focused_output(socketfd); 235
236 struct wlc_geometry *geo;
237
238 if (grab_focused) {
239 output = get_focused_output();
240 json_object *con = get_focused_container();
241 json_object *name;
242 json_object_object_get_ex(con, "name", &name);
243 geo = get_container_geometry(con);
244 free(con);
245 } else {
246 if (!output) {
247 output = get_focused_output();
248 }
249 geo = get_container_geometry(get_output_container(output));
250 // the geometry of the output in the get_tree response is relative to a global (0, 0).
251 // we need it to be relative to itself, so set origin to (0, 0) always.
252 geo->origin.x = 0;
253 geo->origin.y = 0;
240 } 254 }
241 255
256 const char *payload = create_payload(output, geo);
257
258 free(geo);
259
242 if (!file) { 260 if (!file) {
243 if (!capture) { 261 if (!capture) {
244 file = default_filename("png"); 262 file = default_filename("png");
@@ -248,11 +266,12 @@ int main(int argc, char **argv) {
248 } 266 }
249 267
250 if (!capture) { 268 if (!capture) {
251 grab_and_apply_magick(file, output, socketfd, raw); 269 grab_and_apply_magick(file, payload, socketfd, raw);
252 } else { 270 } else {
253 grab_and_apply_movie_magic(file, output, socketfd, raw, framerate); 271 grab_and_apply_movie_magic(file, payload, socketfd, raw, framerate);
254 } 272 }
255 273
274 free_json_tree();
256 free(output); 275 free(output);
257 free(file); 276 free(file);
258 close(socketfd); 277 close(socketfd);