aboutsummaryrefslogtreecommitdiffstats
path: root/sway/config/output.c
diff options
context:
space:
mode:
Diffstat (limited to 'sway/config/output.c')
-rw-r--r--sway/config/output.c299
1 files changed, 202 insertions, 97 deletions
diff --git a/sway/config/output.c b/sway/config/output.c
index c9ec6745..1a5215fe 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,10 +1,12 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <drm_fourcc.h>
3#include <stdbool.h> 4#include <stdbool.h>
4#include <string.h> 5#include <string.h>
5#include <sys/socket.h> 6#include <sys/socket.h>
6#include <sys/wait.h> 7#include <sys/wait.h>
7#include <unistd.h> 8#include <unistd.h>
9#include <wlr/config.h>
8#include <wlr/types/wlr_cursor.h> 10#include <wlr/types/wlr_cursor.h>
9#include <wlr/types/wlr_output_layout.h> 11#include <wlr/types/wlr_output_layout.h>
10#include <wlr/types/wlr_output.h> 12#include <wlr/types/wlr_output.h>
@@ -15,6 +17,10 @@
15#include "log.h" 17#include "log.h"
16#include "util.h" 18#include "util.h"
17 19
20#if WLR_HAS_DRM_BACKEND
21#include <wlr/backend/drm.h>
22#endif
23
18int output_name_cmp(const void *item, const void *data) { 24int output_name_cmp(const void *item, const void *data) {
19 const struct output_config *output = item; 25 const struct output_config *output = item;
20 const char *name = data; 26 const char *name = data;
@@ -25,8 +31,10 @@ int output_name_cmp(const void *item, const void *data) {
25void output_get_identifier(char *identifier, size_t len, 31void output_get_identifier(char *identifier, size_t len,
26 struct sway_output *output) { 32 struct sway_output *output) {
27 struct wlr_output *wlr_output = output->wlr_output; 33 struct wlr_output *wlr_output = output->wlr_output;
28 snprintf(identifier, len, "%s %s %s", wlr_output->make, wlr_output->model, 34 snprintf(identifier, len, "%s %s %s",
29 wlr_output->serial); 35 wlr_output->make ? wlr_output->make : "Unknown",
36 wlr_output->model ? wlr_output->model : "Unknown",
37 wlr_output->serial ? wlr_output->serial : "Unknown");
30} 38}
31 39
32const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) { 40const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filter) {
@@ -58,6 +66,7 @@ struct output_config *new_output_config(const char *name) {
58 oc->width = oc->height = -1; 66 oc->width = oc->height = -1;
59 oc->refresh_rate = -1; 67 oc->refresh_rate = -1;
60 oc->custom_mode = -1; 68 oc->custom_mode = -1;
69 oc->drm_mode.type = -1;
61 oc->x = oc->y = -1; 70 oc->x = oc->y = -1;
62 oc->scale = -1; 71 oc->scale = -1;
63 oc->scale_filter = SCALE_FILTER_DEFAULT; 72 oc->scale_filter = SCALE_FILTER_DEFAULT;
@@ -65,6 +74,8 @@ struct output_config *new_output_config(const char *name) {
65 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; 74 oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
66 oc->max_render_time = -1; 75 oc->max_render_time = -1;
67 oc->adaptive_sync = -1; 76 oc->adaptive_sync = -1;
77 oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
78 oc->power = -1;
68 return oc; 79 return oc;
69} 80}
70 81
@@ -99,6 +110,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
99 if (src->custom_mode != -1) { 110 if (src->custom_mode != -1) {
100 dst->custom_mode = src->custom_mode; 111 dst->custom_mode = src->custom_mode;
101 } 112 }
113 if (src->drm_mode.type != (uint32_t) -1) {
114 memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode));
115 }
102 if (src->transform != -1) { 116 if (src->transform != -1) {
103 dst->transform = src->transform; 117 dst->transform = src->transform;
104 } 118 }
@@ -108,6 +122,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
108 if (src->adaptive_sync != -1) { 122 if (src->adaptive_sync != -1) {
109 dst->adaptive_sync = src->adaptive_sync; 123 dst->adaptive_sync = src->adaptive_sync;
110 } 124 }
125 if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
126 dst->render_bit_depth = src->render_bit_depth;
127 }
111 if (src->background) { 128 if (src->background) {
112 free(dst->background); 129 free(dst->background);
113 dst->background = strdup(src->background); 130 dst->background = strdup(src->background);
@@ -120,8 +137,8 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
120 free(dst->background_fallback); 137 free(dst->background_fallback);
121 dst->background_fallback = strdup(src->background_fallback); 138 dst->background_fallback = strdup(src->background_fallback);
122 } 139 }
123 if (src->dpms_state != 0) { 140 if (src->power != -1) {
124 dst->dpms_state = src->dpms_state; 141 dst->power = src->power;
125 } 142 }
126} 143}
127 144
@@ -136,25 +153,16 @@ static void merge_wildcard_on_all(struct output_config *wildcard) {
136} 153}
137 154
138static void merge_id_on_name(struct output_config *oc) { 155static void merge_id_on_name(struct output_config *oc) {
139 char *id_on_name = NULL; 156 struct sway_output *output = all_output_by_name_or_id(oc->name);
140 char id[128]; 157 if (output == NULL) {
141 char *name = NULL; 158 return;
142 struct sway_output *output;
143 wl_list_for_each(output, &root->all_outputs, link) {
144 name = output->wlr_output->name;
145 output_get_identifier(id, sizeof(id), output);
146 if (strcmp(name, oc->name) == 0 || strcmp(id, oc->name) == 0) {
147 size_t length = snprintf(NULL, 0, "%s on %s", id, name) + 1;
148 id_on_name = malloc(length);
149 if (!id_on_name) {
150 sway_log(SWAY_ERROR, "Failed to allocate id on name string");
151 return;
152 }
153 snprintf(id_on_name, length, "%s on %s", id, name);
154 break;
155 }
156 } 159 }
157 160
161 const char *name = output->wlr_output->name;
162 char id[128];
163 output_get_identifier(id, sizeof(id), output);
164
165 char *id_on_name = format_str("%s on %s", id, name);
158 if (!id_on_name) { 166 if (!id_on_name) {
159 return; 167 return;
160 } 168 }
@@ -180,11 +188,11 @@ static void merge_id_on_name(struct output_config *oc) {
180 list_add(config->output_configs, ion_oc); 188 list_add(config->output_configs, ion_oc);
181 sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\"" 189 sway_log(SWAY_DEBUG, "Generated id on name output config \"%s\""
182 " (enabled: %d) (%dx%d@%fHz position %d,%d scale %f " 190 " (enabled: %d) (%dx%d@%fHz position %d,%d scale %f "
183 "transform %d) (bg %s %s) (dpms %d) (max render time: %d)", 191 "transform %d) (bg %s %s) (power %d) (max render time: %d)",
184 ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height, 192 ion_oc->name, ion_oc->enabled, ion_oc->width, ion_oc->height,
185 ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale, 193 ion_oc->refresh_rate, ion_oc->x, ion_oc->y, ion_oc->scale,
186 ion_oc->transform, ion_oc->background, 194 ion_oc->transform, ion_oc->background,
187 ion_oc->background_option, ion_oc->dpms_state, 195 ion_oc->background_option, ion_oc->power,
188 ion_oc->max_render_time); 196 ion_oc->max_render_time);
189 } 197 }
190 } 198 }
@@ -225,50 +233,74 @@ struct output_config *store_output_config(struct output_config *oc) {
225 } 233 }
226 234
227 sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz " 235 sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
228 "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (dpms %d) " 236 "position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
229 "(max render time: %d)", 237 "(max render time: %d)",
230 oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate, 238 oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
231 oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel), 239 oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
232 oc->transform, oc->background, oc->background_option, oc->dpms_state, 240 oc->transform, oc->background, oc->background_option, oc->power,
233 oc->max_render_time); 241 oc->max_render_time);
234 242
235 return oc; 243 return oc;
236} 244}
237 245
238static void set_mode(struct wlr_output *output, int width, int height, 246static void set_mode(struct wlr_output *output, struct wlr_output_state *pending,
239 float refresh_rate, bool custom) { 247 int width, int height, float refresh_rate, bool custom) {
240 // Not all floating point integers can be represented exactly 248 // Not all floating point integers can be represented exactly
241 // as (int)(1000 * mHz / 1000.f) 249 // as (int)(1000 * mHz / 1000.f)
242 // round() the result to avoid any error 250 // round() the result to avoid any error
243 int mhz = (int)round(refresh_rate * 1000); 251 int mhz = (int)roundf(refresh_rate * 1000);
252 // If no target refresh rate is given, match highest available
253 mhz = mhz <= 0 ? INT_MAX : mhz;
244 254
245 if (wl_list_empty(&output->modes) || custom) { 255 if (wl_list_empty(&output->modes) || custom) {
246 sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name); 256 sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
247 wlr_output_set_custom_mode(output, width, height, 257 wlr_output_state_set_custom_mode(pending, width, height,
248 refresh_rate > 0 ? mhz : 0); 258 refresh_rate > 0 ? mhz : 0);
249 return; 259 return;
250 } 260 }
251 261
252 struct wlr_output_mode *mode, *best = NULL; 262 struct wlr_output_mode *mode, *best = NULL;
263 int best_diff_mhz = INT_MAX;
253 wl_list_for_each(mode, &output->modes, link) { 264 wl_list_for_each(mode, &output->modes, link) {
254 if (mode->width == width && mode->height == height) { 265 if (mode->width == width && mode->height == height) {
255 if (mode->refresh == mhz) { 266 int diff_mhz = abs(mode->refresh - mhz);
256 best = mode; 267 if (diff_mhz < best_diff_mhz) {
257 break; 268 best_diff_mhz = diff_mhz;
258 }
259 if (best == NULL || mode->refresh > best->refresh) {
260 best = mode; 269 best = mode;
270 if (best_diff_mhz == 0) {
271 break;
272 }
261 } 273 }
262 } 274 }
263 } 275 }
264 if (!best) { 276 if (best) {
265 sway_log(SWAY_ERROR, "Configured mode for %s not available", output->name); 277 sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s",
266 sway_log(SWAY_INFO, "Picking preferred mode instead"); 278 best->width, best->height, best->refresh / 1000.f, output->name);
267 best = wlr_output_preferred_mode(output);
268 } else { 279 } else {
269 sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name); 280 best = wlr_output_preferred_mode(output);
281 sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
282 "applying preferred mode (%dx%d@%.3fHz)",
283 width, height, refresh_rate,
284 best->width, best->height, best->refresh / 1000.f);
270 } 285 }
271 wlr_output_set_mode(output, best); 286 wlr_output_state_set_mode(pending, best);
287}
288
289static void set_modeline(struct wlr_output *output,
290 struct wlr_output_state *pending, drmModeModeInfo *drm_mode) {
291#if WLR_HAS_DRM_BACKEND
292 if (!wlr_output_is_drm(output)) {
293 sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
294 return;
295 }
296 sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
297 struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
298 if (mode) {
299 wlr_output_state_set_mode(pending, mode);
300 }
301#else
302 sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
303#endif
272} 304}
273 305
274/* Some manufacturers hardcode the aspect-ratio of the output in the physical 306/* Some manufacturers hardcode the aspect-ratio of the output in the physical
@@ -289,23 +321,24 @@ static bool phys_size_is_aspect_ratio(struct wlr_output *output) {
289// 1 inch = 25.4 mm 321// 1 inch = 25.4 mm
290#define MM_PER_INCH 25.4 322#define MM_PER_INCH 25.4
291 323
292static int compute_default_scale(struct wlr_output *output) { 324static int compute_default_scale(struct wlr_output *output,
325 struct wlr_output_state *pending) {
293 struct wlr_box box = { .width = output->width, .height = output->height }; 326 struct wlr_box box = { .width = output->width, .height = output->height };
294 if (output->pending.committed & WLR_OUTPUT_STATE_MODE) { 327 if (pending->committed & WLR_OUTPUT_STATE_MODE) {
295 switch (output->pending.mode_type) { 328 switch (pending->mode_type) {
296 case WLR_OUTPUT_STATE_MODE_FIXED: 329 case WLR_OUTPUT_STATE_MODE_FIXED:
297 box.width = output->pending.mode->width; 330 box.width = pending->mode->width;
298 box.height = output->pending.mode->height; 331 box.height = pending->mode->height;
299 break; 332 break;
300 case WLR_OUTPUT_STATE_MODE_CUSTOM: 333 case WLR_OUTPUT_STATE_MODE_CUSTOM:
301 box.width = output->pending.custom_mode.width; 334 box.width = pending->custom_mode.width;
302 box.height = output->pending.custom_mode.height; 335 box.height = pending->custom_mode.height;
303 break; 336 break;
304 } 337 }
305 } 338 }
306 enum wl_output_transform transform = output->transform; 339 enum wl_output_transform transform = output->transform;
307 if (output->pending.committed & WLR_OUTPUT_STATE_TRANSFORM) { 340 if (pending->committed & WLR_OUTPUT_STATE_TRANSFORM) {
308 transform = output->pending.transform; 341 transform = pending->transform;
309 } 342 }
310 wlr_box_transform(&box, &box, transform, box.width, box.height); 343 wlr_box_transform(&box, &box, transform, box.width, box.height);
311 344
@@ -334,42 +367,90 @@ static int compute_default_scale(struct wlr_output *output) {
334 return 2; 367 return 2;
335} 368}
336 369
370/* Lists of formats to try, in order, when a specific render bit depth has
371 * been asked for. The second to last format in each list should always
372 * be XRGB8888, as a reliable backup in case the others are not available;
373 * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */
374static const uint32_t *bit_depth_preferences[] = {
375 [RENDER_BIT_DEPTH_8] = (const uint32_t []){
376 DRM_FORMAT_XRGB8888,
377 DRM_FORMAT_INVALID,
378 },
379 [RENDER_BIT_DEPTH_10] = (const uint32_t []){
380 DRM_FORMAT_XRGB2101010,
381 DRM_FORMAT_XBGR2101010,
382 DRM_FORMAT_XRGB8888,
383 DRM_FORMAT_INVALID,
384 },
385};
386
337static void queue_output_config(struct output_config *oc, 387static void queue_output_config(struct output_config *oc,
338 struct sway_output *output) { 388 struct sway_output *output, struct wlr_output_state *pending) {
339 if (output == root->noop_output) { 389 if (output == root->fallback_output) {
340 return; 390 return;
341 } 391 }
342 392
343 struct wlr_output *wlr_output = output->wlr_output; 393 struct wlr_output *wlr_output = output->wlr_output;
344 394
345 if (oc && (!oc->enabled || oc->dpms_state == DPMS_OFF)) { 395 if (oc && (!oc->enabled || oc->power == 0)) {
346 sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); 396 sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
347 wlr_output_enable(wlr_output, false); 397 wlr_output_state_set_enabled(pending, false);
348 return; 398 return;
349 } 399 }
350 400
351 sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); 401 sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
352 wlr_output_enable(wlr_output, true); 402 wlr_output_state_set_enabled(pending, true);
353 403
354 if (oc && oc->width > 0 && oc->height > 0) { 404 if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
405 sway_log(SWAY_DEBUG, "Set %s modeline",
406 wlr_output->name);
407 set_modeline(wlr_output, pending, &oc->drm_mode);
408 } else if (oc && oc->width > 0 && oc->height > 0) {
355 sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", 409 sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
356 wlr_output->name, oc->width, oc->height, oc->refresh_rate); 410 wlr_output->name, oc->width, oc->height, oc->refresh_rate);
357 set_mode(wlr_output, oc->width, oc->height, 411 set_mode(wlr_output, pending, oc->width, oc->height,
358 oc->refresh_rate, oc->custom_mode == 1); 412 oc->refresh_rate, oc->custom_mode == 1);
359 } else if (!wl_list_empty(&wlr_output->modes)) { 413 } else if (!wl_list_empty(&wlr_output->modes)) {
360 struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); 414 sway_log(SWAY_DEBUG, "Set preferred mode");
361 wlr_output_set_mode(wlr_output, mode); 415 struct wlr_output_mode *preferred_mode =
416 wlr_output_preferred_mode(wlr_output);
417 wlr_output_state_set_mode(pending, preferred_mode);
418
419 if (!wlr_output_test_state(wlr_output, pending)) {
420 sway_log(SWAY_DEBUG, "Preferred mode rejected, "
421 "falling back to another mode");
422 struct wlr_output_mode *mode;
423 wl_list_for_each(mode, &wlr_output->modes, link) {
424 if (mode == preferred_mode) {
425 continue;
426 }
427
428 wlr_output_state_set_mode(pending, mode);
429 if (wlr_output_test_state(wlr_output, pending)) {
430 break;
431 }
432 }
433 }
362 } 434 }
363 435
364 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { 436 if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
365 sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name, 437 sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
366 sway_wl_output_subpixel_to_string(oc->subpixel)); 438 sway_wl_output_subpixel_to_string(oc->subpixel));
367 wlr_output_set_subpixel(wlr_output, oc->subpixel); 439 wlr_output_state_set_subpixel(pending, oc->subpixel);
368 } 440 }
369 441
442 enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
370 if (oc && oc->transform >= 0) { 443 if (oc && oc->transform >= 0) {
371 sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform); 444 tr = oc->transform;
372 wlr_output_set_transform(wlr_output, oc->transform); 445#if WLR_HAS_DRM_BACKEND
446 } else if (wlr_output_is_drm(wlr_output)) {
447 tr = wlr_drm_connector_get_panel_orientation(wlr_output);
448 sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
449#endif
450 }
451 if (wlr_output->transform != tr) {
452 sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr);
453 wlr_output_state_set_transform(pending, tr);
373 } 454 }
374 455
375 // Apply the scale last before the commit, because the scale auto-detection 456 // Apply the scale last before the commit, because the scale auto-detection
@@ -377,24 +458,54 @@ static void queue_output_config(struct output_config *oc,
377 float scale; 458 float scale;
378 if (oc && oc->scale > 0) { 459 if (oc && oc->scale > 0) {
379 scale = oc->scale; 460 scale = oc->scale;
461
462 // The factional-scale-v1 protocol uses increments of 120ths to send
463 // the scale factor to the client. Adjust the scale so that we use the
464 // same value as the clients'.
465 float adjusted_scale = round(scale * 120) / 120;
466 if (scale != adjusted_scale) {
467 sway_log(SWAY_INFO, "Adjusting output scale from %f to %f",
468 scale, adjusted_scale);
469 scale = adjusted_scale;
470 }
380 } else { 471 } else {
381 scale = compute_default_scale(wlr_output); 472 scale = compute_default_scale(wlr_output, pending);
382 sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale); 473 sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
383 } 474 }
384 if (scale != wlr_output->scale) { 475 if (scale != wlr_output->scale) {
385 sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale); 476 sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
386 wlr_output_set_scale(wlr_output, scale); 477 wlr_output_state_set_scale(pending, scale);
387 } 478 }
388 479
389 if (oc && oc->adaptive_sync != -1) { 480 if (oc && oc->adaptive_sync != -1) {
390 sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, 481 sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
391 oc->adaptive_sync); 482 oc->adaptive_sync);
392 wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1); 483 wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
484 if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) {
485 sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring");
486 wlr_output_state_set_adaptive_sync_enabled(pending, false);
487 }
488 }
489
490 if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
491 const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth];
492 assert(fmts);
493
494 for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
495 wlr_output_state_set_render_format(pending, fmts[i]);
496 if (wlr_output_test_state(wlr_output, pending)) {
497 break;
498 }
499
500 sway_log(SWAY_DEBUG, "Preferred output format 0x%08x "
501 "failed to work, falling back to next in "
502 "list, 0x%08x", fmts[i], fmts[i + 1]);
503 }
393 } 504 }
394} 505}
395 506
396bool apply_output_config(struct output_config *oc, struct sway_output *output) { 507bool apply_output_config(struct output_config *oc, struct sway_output *output) {
397 if (output == root->noop_output) { 508 if (output == root->fallback_output) {
398 return false; 509 return false;
399 } 510 }
400 511
@@ -403,14 +514,11 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
403 // Flag to prevent the output mode event handler from calling us 514 // Flag to prevent the output mode event handler from calling us
404 output->enabling = (!oc || oc->enabled); 515 output->enabling = (!oc || oc->enabled);
405 516
406 queue_output_config(oc, output); 517 struct wlr_output_state pending = {0};
407 518 queue_output_config(oc, output, &pending);
408 if (!oc || oc->dpms_state != DPMS_OFF) {
409 output->current_mode = wlr_output->pending.mode;
410 }
411 519
412 sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name); 520 sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
413 if (!wlr_output_commit(wlr_output)) { 521 if (!wlr_output_commit_state(wlr_output, &pending)) {
414 // Failed to commit output changes, maybe the output is missing a CRTC. 522 // Failed to commit output changes, maybe the output is missing a CRTC.
415 // Leave the output disabled for now and try again when the output gets 523 // Leave the output disabled for now and try again when the output gets
416 // the mode we asked for. 524 // the mode we asked for.
@@ -430,10 +538,6 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
430 return true; 538 return true;
431 } 539 }
432 540
433 if (config->reloading) {
434 output_damage_whole(output);
435 }
436
437 if (oc) { 541 if (oc) {
438 enum scale_filter_mode scale_filter_old = output->scale_filter; 542 enum scale_filter_mode scale_filter_old = output->scale_filter;
439 switch (oc->scale_filter) { 543 switch (oc->scale_filter) {
@@ -450,6 +554,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
450 if (scale_filter_old != output->scale_filter) { 554 if (scale_filter_old != output->scale_filter) {
451 sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name, 555 sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
452 sway_output_scale_filter_to_string(output->scale_filter)); 556 sway_output_scale_filter_to_string(output->scale_filter));
557 wlr_damage_ring_add_whole(&output->scene_output->damage_ring);
453 } 558 }
454 } 559 }
455 560
@@ -462,12 +567,12 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
462 } 567 }
463 568
464 // Update output->{lx, ly, width, height} 569 // Update output->{lx, ly, width, height}
465 struct wlr_box *output_box = 570 struct wlr_box output_box;
466 wlr_output_layout_get_box(root->output_layout, wlr_output); 571 wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
467 output->lx = output_box->x; 572 output->lx = output_box.x;
468 output->ly = output_box->y; 573 output->ly = output_box.y;
469 output->width = output_box->width; 574 output->width = output_box.width;
470 output->height = output_box->height; 575 output->height = output_box.height;
471 576
472 if (!output->enabled) { 577 if (!output->enabled) {
473 output_enable(output); 578 output_enable(output);
@@ -482,24 +587,26 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
482 // Reconfigure all devices, since input config may have been applied before 587 // Reconfigure all devices, since input config may have been applied before
483 // this output came online, and some config items (like map_to_output) are 588 // this output came online, and some config items (like map_to_output) are
484 // dependent on an output being present. 589 // dependent on an output being present.
485 input_manager_configure_all_inputs(); 590 input_manager_configure_all_input_mappings();
591 // Reconfigure the cursor images, since the scale may have changed.
592 input_manager_configure_xcursor();
486 return true; 593 return true;
487} 594}
488 595
489bool test_output_config(struct output_config *oc, struct sway_output *output) { 596bool test_output_config(struct output_config *oc, struct sway_output *output) {
490 if (output == root->noop_output) { 597 if (output == root->fallback_output) {
491 return false; 598 return false;
492 } 599 }
493 600
494 queue_output_config(oc, output); 601 struct wlr_output_state pending = {0};
495 bool ok = wlr_output_test(output->wlr_output); 602 queue_output_config(oc, output, &pending);
496 wlr_output_rollback(output->wlr_output); 603 return wlr_output_test_state(output->wlr_output, &pending);
497 return ok;
498} 604}
499 605
500static void default_output_config(struct output_config *oc, 606static void default_output_config(struct output_config *oc,
501 struct wlr_output *wlr_output) { 607 struct wlr_output *wlr_output) {
502 oc->enabled = 1; 608 oc->enabled = 1;
609 oc->power = 1;
503 struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); 610 struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
504 if (mode != NULL) { 611 if (mode != NULL) {
505 oc->width = mode->width; 612 oc->width = mode->width;
@@ -512,7 +619,6 @@ static void default_output_config(struct output_config *oc,
512 struct sway_output *output = wlr_output->data; 619 struct sway_output *output = wlr_output->data;
513 oc->subpixel = output->detected_subpixel; 620 oc->subpixel = output->detected_subpixel;
514 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL; 621 oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
515 oc->dpms_state = DPMS_ON;
516 oc->max_render_time = 0; 622 oc->max_render_time = 0;
517} 623}
518 624
@@ -524,9 +630,7 @@ static struct output_config *get_output_config(char *identifier,
524 struct output_config *oc_name = NULL; 630 struct output_config *oc_name = NULL;
525 struct output_config *oc_id = NULL; 631 struct output_config *oc_id = NULL;
526 632
527 size_t length = snprintf(NULL, 0, "%s on %s", identifier, name) + 1; 633 char *id_on_name = format_str("%s on %s", identifier, name);
528 char *id_on_name = malloc(length);
529 snprintf(id_on_name, length, "%s on %s", identifier, name);
530 int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name); 634 int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
531 if (i >= 0) { 635 if (i >= 0) {
532 oc_id_on_name = config->output_configs->items[i]; 636 oc_id_on_name = config->output_configs->items[i];
@@ -567,10 +671,10 @@ static struct output_config *get_output_config(char *identifier,
567 671
568 sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)" 672 sway_log(SWAY_DEBUG, "Generated output config \"%s\" (enabled: %d)"
569 " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)" 673 " (%dx%d@%fHz position %d,%d scale %f transform %d) (bg %s %s)"
570 " (dpms %d) (max render time: %d)", result->name, result->enabled, 674 " (power %d) (max render time: %d)", result->name, result->enabled,
571 result->width, result->height, result->refresh_rate, 675 result->width, result->height, result->refresh_rate,
572 result->x, result->y, result->scale, result->transform, 676 result->x, result->y, result->scale, result->transform,
573 result->background, result->background_option, result->dpms_state, 677 result->background, result->background_option, result->power,
574 result->max_render_time); 678 result->max_render_time);
575 } else if (oc_name) { 679 } else if (oc_name) {
576 // No identifier config, just return a copy of the name config 680 // No identifier config, just return a copy of the name config
@@ -613,12 +717,11 @@ void apply_output_config_to_outputs(struct output_config *oc) {
613 // this is during startup then there will be no container and config 717 // this is during startup then there will be no container and config
614 // will be applied during normal "new output" event from wlroots. 718 // will be applied during normal "new output" event from wlroots.
615 bool wildcard = strcmp(oc->name, "*") == 0; 719 bool wildcard = strcmp(oc->name, "*") == 0;
616 char id[128];
617 struct sway_output *sway_output, *tmp; 720 struct sway_output *sway_output, *tmp;
618 wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) { 721 wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
619 char *name = sway_output->wlr_output->name; 722 if (output_match_name_or_id(sway_output, oc->name)) {
620 output_get_identifier(id, sizeof(id), sway_output); 723 char id[128];
621 if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) { 724 output_get_identifier(id, sizeof(id), sway_output);
622 struct output_config *current = get_output_config(id, sway_output); 725 struct output_config *current = get_output_config(id, sway_output);
623 if (!current) { 726 if (!current) {
624 // No stored output config matched, apply oc directly 727 // No stored output config matched, apply oc directly
@@ -702,6 +805,8 @@ static bool _spawn_swaybg(char **command) {
702 sway_log_errno(SWAY_ERROR, "fork failed"); 805 sway_log_errno(SWAY_ERROR, "fork failed");
703 return false; 806 return false;
704 } else if (pid == 0) { 807 } else if (pid == 0) {
808 restore_nofile_limit();
809
705 pid = fork(); 810 pid = fork();
706 if (pid < 0) { 811 if (pid < 0) {
707 sway_log_errno(SWAY_ERROR, "fork failed"); 812 sway_log_errno(SWAY_ERROR, "fork failed");