aboutsummaryrefslogtreecommitdiffstats
path: root/sway/commands
diff options
context:
space:
mode:
authorLibravatar Tony Crisci <tony@dubstepdish.com>2017-12-16 07:33:23 -0500
committerLibravatar Tony Crisci <tony@dubstepdish.com>2017-12-16 07:33:23 -0500
commit9fa70ce426a78921fa61f25f8b30a73a2a7d9ad7 (patch)
tree823cce0da3f7e0dc21c26bef7e639e8370e29b3d /sway/commands
parentkeyboard cleanup (diff)
parentMerge pull request #1503 from emersion/output-config (diff)
downloadsway-9fa70ce426a78921fa61f25f8b30a73a2a7d9ad7.tar.gz
sway-9fa70ce426a78921fa61f25f8b30a73a2a7d9ad7.tar.zst
sway-9fa70ce426a78921fa61f25f8b30a73a2a7d9ad7.zip
Merge branch 'wlroots' into feature/input
Diffstat (limited to 'sway/commands')
-rw-r--r--sway/commands/output.c311
1 files changed, 311 insertions, 0 deletions
diff --git a/sway/commands/output.c b/sway/commands/output.c
new file mode 100644
index 00000000..d71e4d8d
--- /dev/null
+++ b/sway/commands/output.c
@@ -0,0 +1,311 @@
1#define _XOPEN_SOURCE 500
2#include <ctype.h>
3#include <libgen.h>
4#include <stdlib.h>
5#include <string.h>
6#include <strings.h>
7#include <unistd.h>
8#include <wordexp.h>
9#include "sway/commands.h"
10#include "sway/config.h"
11#include "list.h"
12#include "log.h"
13#include "stringop.h"
14
15static char *bg_options[] = {
16 "stretch",
17 "center",
18 "fill",
19 "fit",
20 "tile",
21};
22
23struct cmd_results *cmd_output(int argc, char **argv) {
24 struct cmd_results *error = NULL;
25 if ((error = checkarg(argc, "output", EXPECTED_AT_LEAST, 1))) {
26 return error;
27 }
28 const char *name = argv[0];
29
30 struct output_config *output = new_output_config();
31 if (!output) {
32 sway_log(L_ERROR, "Failed to allocate output config");
33 return NULL;
34 }
35 output->name = strdup(name);
36
37 int i;
38 for (i = 1; i < argc; ++i) {
39 const char *command = argv[i];
40
41 if (strcasecmp(command, "disable") == 0) {
42 output->enabled = 0;
43 } else if (strcasecmp(command, "mode") == 0 ||
44 strcasecmp(command, "resolution") == 0 ||
45 strcasecmp(command, "res") == 0) {
46 if (++i >= argc) {
47 error = cmd_results_new(CMD_INVALID, "output",
48 "Missing mode argument.");
49 goto fail;
50 }
51
52 int width = -1, height = -1;
53 float refresh_rate = -1;
54
55 char *end;
56 width = strtol(argv[i], &end, 10);
57 if (*end) {
58 // Format is 1234x4321
59 if (*end != 'x') {
60 error = cmd_results_new(CMD_INVALID, "output",
61 "Invalid mode width.");
62 goto fail;
63 }
64 ++end;
65 height = strtol(end, &end, 10);
66 if (*end) {
67 if (*end != '@') {
68 error = cmd_results_new(CMD_INVALID, "output",
69 "Invalid mode height.");
70 goto fail;
71 }
72 ++end;
73 refresh_rate = strtof(end, &end);
74 if (strcasecmp("Hz", end) != 0) {
75 error = cmd_results_new(CMD_INVALID, "output",
76 "Invalid mode refresh rate.");
77 goto fail;
78 }
79 }
80 } else {
81 // Format is 1234 4321
82 if (++i >= argc) {
83 error = cmd_results_new(CMD_INVALID, "output",
84 "Missing mode argument (height).");
85 goto fail;
86 }
87 height = strtol(argv[i], &end, 10);
88 if (*end) {
89 error = cmd_results_new(CMD_INVALID, "output",
90 "Invalid mode height.");
91 goto fail;
92 }
93 }
94 output->width = width;
95 output->height = height;
96 output->refresh_rate = refresh_rate;
97 } else if (strcasecmp(command, "position") == 0 ||
98 strcasecmp(command, "pos") == 0) {
99 if (++i >= argc) {
100 error = cmd_results_new(CMD_INVALID, "output",
101 "Missing position argument.");
102 goto fail;
103 }
104
105 int x = -1, y = -1;
106
107 char *end;
108 x = strtol(argv[i], &end, 10);
109 if (*end) {
110 // Format is 1234,4321
111 if (*end != ',') {
112 error = cmd_results_new(CMD_INVALID, "output",
113 "Invalid position x.");
114 goto fail;
115 }
116 ++end;
117 y = strtol(end, &end, 10);
118 if (*end) {
119 error = cmd_results_new(CMD_INVALID, "output",
120 "Invalid position y.");
121 goto fail;
122 }
123 } else {
124 // Format is 1234 4321 (legacy)
125 if (++i >= argc) {
126 error = cmd_results_new(CMD_INVALID, "output",
127 "Missing position argument (y).");
128 goto fail;
129 }
130 y = strtol(argv[i], &end, 10);
131 if (*end) {
132 error = cmd_results_new(CMD_INVALID, "output",
133 "Invalid position y.");
134 goto fail;
135 }
136 }
137
138 output->x = x;
139 output->y = y;
140 } else if (strcasecmp(command, "scale") == 0) {
141 if (++i >= argc) {
142 error = cmd_results_new(CMD_INVALID, "output",
143 "Missing scale parameter.");
144 goto fail;
145 }
146 char *end;
147 output->scale = strtol(argv[i], &end, 10);
148 if (*end) {
149 error = cmd_results_new(CMD_INVALID, "output",
150 "Invalid scale.");
151 goto fail;
152 }
153 } else if (strcasecmp(command, "transform") == 0) {
154 if (++i >= argc) {
155 error = cmd_results_new(CMD_INVALID, "output",
156 "Missing transform parameter.");
157 goto fail;
158 }
159 char *value = argv[i];
160 if (strcmp(value, "normal") == 0) {
161 output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
162 } else if (strcmp(value, "90") == 0) {
163 output->transform = WL_OUTPUT_TRANSFORM_90;
164 } else if (strcmp(value, "180") == 0) {
165 output->transform = WL_OUTPUT_TRANSFORM_180;
166 } else if (strcmp(value, "270") == 0) {
167 output->transform = WL_OUTPUT_TRANSFORM_270;
168 } else if (strcmp(value, "flipped") == 0) {
169 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED;
170 } else if (strcmp(value, "flipped-90") == 0) {
171 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_90;
172 } else if (strcmp(value, "flipped-180") == 0) {
173 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
174 } else if (strcmp(value, "flipped-270") == 0) {
175 output->transform = WL_OUTPUT_TRANSFORM_FLIPPED_270;
176 } else {
177 error = cmd_results_new(CMD_INVALID, "output",
178 "Invalid output transform.");
179 goto fail;
180 }
181 } else if (strcasecmp(command, "background") == 0 ||
182 strcasecmp(command, "bg") == 0) {
183 wordexp_t p;
184 if (++i >= argc) {
185 error = cmd_results_new(CMD_INVALID, "output",
186 "Missing background file or color specification.");
187 goto fail;
188 }
189 if (i + 1 >= argc) {
190 error = cmd_results_new(CMD_INVALID, "output",
191 "Missing background scaling mode or `solid_color`.");
192 goto fail;
193 }
194 if (strcasecmp(argv[i + 1], "solid_color") == 0) {
195 output->background = strdup(argv[argc - 2]);
196 output->background_option = strdup("solid_color");
197 } else {
198 // argv[i+j]=bg_option
199 bool valid = false;
200 char *mode;
201 size_t j;
202 for (j = 0; j < (size_t) (argc - i); ++j) {
203 mode = argv[i + j];
204 size_t n = sizeof(bg_options) / sizeof(char *);
205 for (size_t k = 0; k < n; ++k) {
206 if (strcasecmp(mode, bg_options[k]) == 0) {
207 valid = true;
208 break;
209 }
210 }
211 if (valid) {
212 break;
213 }
214 }
215 if (!valid) {
216 error = cmd_results_new(CMD_INVALID, "output",
217 "Missing background scaling mode.");
218 goto fail;
219 }
220
221 char *src = join_args(argv + i, j);
222 if (wordexp(src, &p, 0) != 0 || p.we_wordv[0] == NULL) {
223 error = cmd_results_new(CMD_INVALID, "output",
224 "Invalid syntax (%s).", src);
225 goto fail;
226 }
227 free(src);
228 src = p.we_wordv[0];
229 if (config->reading && *src != '/') {
230 char *conf = strdup(config->current_config);
231 if (conf) {
232 char *conf_path = dirname(conf);
233 src = malloc(strlen(conf_path) + strlen(src) + 2);
234 if (src) {
235 sprintf(src, "%s/%s", conf_path, p.we_wordv[0]);
236 } else {
237 sway_log(L_ERROR,
238 "Unable to allocate background source");
239 }
240 free(conf);
241 } else {
242 sway_log(L_ERROR,
243 "Unable to allocate background source");
244 }
245 }
246 if (!src || access(src, F_OK) == -1) {
247 error = cmd_results_new(CMD_INVALID, "output",
248 "Background file unreadable (%s).", src);
249 wordfree(&p);
250 goto fail;
251 }
252
253 output->background = strdup(src);
254 output->background_option = strdup(mode);
255 if (src != p.we_wordv[0]) {
256 free(src);
257 }
258 wordfree(&p);
259
260 i += j;
261 }
262 } else {
263 error = cmd_results_new(CMD_INVALID, "output",
264 "Invalid output subcommand: %s.", command);
265 goto fail;
266 }
267 }
268
269 i = list_seq_find(config->output_configs, output_name_cmp, name);
270 if (i >= 0) {
271 // merge existing config
272 struct output_config *oc = config->output_configs->items[i];
273 merge_output_config(oc, output);
274 free_output_config(output);
275 output = oc;
276 } else {
277 list_add(config->output_configs, output);
278 }
279
280 sway_log(L_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
281 "position %d,%d scale %d transform %d) (bg %s %s)",
282 output->name, output->enabled, output->width, output->height,
283 output->refresh_rate, output->x, output->y, output->scale,
284 output->transform, output->background, output->background_option);
285
286 if (output->name) {
287 // Try to find the output container and apply configuration now. If
288 // this is during startup then there will be no container and config
289 // will be applied during normal "new output" event from wlroots.
290 swayc_t *cont = NULL;
291 for (int i = 0; i < root_container.children->length; ++i) {
292 cont = root_container.children->items[i];
293 if (cont->name && ((strcmp(cont->name, output->name) == 0) ||
294 (strcmp(output->name, "*") == 0))) {
295 apply_output_config(output, cont);
296
297 if (strcmp(output->name, "*") != 0) {
298 // Stop looking if the output config isn't applicable to all
299 // outputs
300 break;
301 }
302 }
303 }
304 }
305
306 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
307
308fail:
309 free_output_config(output);
310 return error;
311}