summaryrefslogtreecommitdiffstats
path: root/swaygrab/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'swaygrab/main.c')
-rw-r--r--swaygrab/main.c99
1 files changed, 59 insertions, 40 deletions
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);