diff options
-rw-r--r-- | include/sway/config.h | 5 | ||||
-rw-r--r-- | sway/commands/workspace.c | 4 | ||||
-rw-r--r-- | sway/config/output.c | 328 | ||||
-rw-r--r-- | sway/desktop/layer_shell.c | 7 | ||||
-rw-r--r-- | sway/desktop/output.c | 3 | ||||
-rw-r--r-- | sway/sway_text_node.c | 8 | ||||
-rw-r--r-- | sway/tree/container.c | 4 |
7 files changed, 302 insertions, 57 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 0be1cd22..5ccc3e77 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -689,10 +689,13 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt | |||
689 | struct output_config *new_output_config(const char *name); | 689 | struct output_config *new_output_config(const char *name); |
690 | 690 | ||
691 | bool apply_output_configs(struct matched_output_config *configs, | 691 | bool apply_output_configs(struct matched_output_config *configs, |
692 | size_t configs_len, bool test_only); | 692 | size_t configs_len, bool test_only, bool degrade_to_off); |
693 | 693 | ||
694 | void apply_all_output_configs(void); | 694 | void apply_all_output_configs(void); |
695 | 695 | ||
696 | void sort_output_configs_by_priority(struct matched_output_config *configs, | ||
697 | size_t configs_len); | ||
698 | |||
696 | /** | 699 | /** |
697 | * store_output_config stores a new output config. An output may be matched by | 700 | * store_output_config stores a new output config. An output may be matched by |
698 | * three different config types, in order of precedence: Identifier, name and | 701 | * three different config types, in order of precedence: Identifier, name and |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index a14ebb20..37a201b4 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -157,6 +157,10 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
157 | return cmd_results_new(CMD_FAILURE, | 157 | return cmd_results_new(CMD_FAILURE, |
158 | "Unable to allocate workspace output"); | 158 | "Unable to allocate workspace output"); |
159 | } | 159 | } |
160 | if (output_location + 1 < argc) { | ||
161 | list_free_items_and_destroy(wsc->outputs); | ||
162 | wsc->outputs = create_list(); | ||
163 | } | ||
160 | for (int i = output_location + 1; i < argc; ++i) { | 164 | for (int i = output_location + 1; i < argc; ++i) { |
161 | list_add(wsc->outputs, strdup(argv[i])); | 165 | list_add(wsc->outputs, strdup(argv[i])); |
162 | } | 166 | } |
diff --git a/sway/config/output.c b/sway/config/output.c index 54af5d8e..fb1956df 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -210,7 +210,7 @@ static void merge_output_config(struct output_config *dst, struct output_config | |||
210 | void store_output_config(struct output_config *oc) { | 210 | void store_output_config(struct output_config *oc) { |
211 | bool merged = false; | 211 | bool merged = false; |
212 | bool wildcard = strcmp(oc->name, "*") == 0; | 212 | bool wildcard = strcmp(oc->name, "*") == 0; |
213 | struct sway_output *output = wildcard ? NULL : output_by_name_or_id(oc->name); | 213 | struct sway_output *output = wildcard ? NULL : all_output_by_name_or_id(oc->name); |
214 | 214 | ||
215 | char id[128]; | 215 | char id[128]; |
216 | if (output) { | 216 | if (output) { |
@@ -386,22 +386,18 @@ static int compute_default_scale(struct wlr_output *output, | |||
386 | return 2; | 386 | return 2; |
387 | } | 387 | } |
388 | 388 | ||
389 | /* Lists of formats to try, in order, when a specific render bit depth has | 389 | static bool render_format_is_10bit(uint32_t render_format) { |
390 | * been asked for. The second to last format in each list should always | 390 | return render_format == DRM_FORMAT_XRGB2101010 || |
391 | * be XRGB8888, as a reliable backup in case the others are not available; | 391 | render_format == DRM_FORMAT_XBGR2101010; |
392 | * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */ | 392 | } |
393 | static const uint32_t *bit_depth_preferences[] = { | 393 | |
394 | [RENDER_BIT_DEPTH_8] = (const uint32_t []){ | 394 | static bool render_format_is_bgr(uint32_t fmt) { |
395 | DRM_FORMAT_XRGB8888, | 395 | return fmt == DRM_FORMAT_XBGR2101010 || fmt == DRM_FORMAT_XBGR8888; |
396 | DRM_FORMAT_INVALID, | 396 | } |
397 | }, | 397 | |
398 | [RENDER_BIT_DEPTH_10] = (const uint32_t []){ | 398 | static bool output_config_is_disabling(struct output_config *oc) { |
399 | DRM_FORMAT_XRGB2101010, | 399 | return oc && (!oc->enabled || oc->power == 0); |
400 | DRM_FORMAT_XBGR2101010, | 400 | } |
401 | DRM_FORMAT_XRGB8888, | ||
402 | DRM_FORMAT_INVALID, | ||
403 | }, | ||
404 | }; | ||
405 | 401 | ||
406 | static void queue_output_config(struct output_config *oc, | 402 | static void queue_output_config(struct output_config *oc, |
407 | struct sway_output *output, struct wlr_output_state *pending) { | 403 | struct sway_output *output, struct wlr_output_state *pending) { |
@@ -411,7 +407,7 @@ static void queue_output_config(struct output_config *oc, | |||
411 | 407 | ||
412 | struct wlr_output *wlr_output = output->wlr_output; | 408 | struct wlr_output *wlr_output = output->wlr_output; |
413 | 409 | ||
414 | if (oc && (!oc->enabled || oc->power == 0)) { | 410 | if (output_config_is_disabling(oc)) { |
415 | sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); | 411 | sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name); |
416 | wlr_output_state_set_enabled(pending, false); | 412 | wlr_output_state_set_enabled(pending, false); |
417 | return; | 413 | return; |
@@ -434,22 +430,6 @@ static void queue_output_config(struct output_config *oc, | |||
434 | struct wlr_output_mode *preferred_mode = | 430 | struct wlr_output_mode *preferred_mode = |
435 | wlr_output_preferred_mode(wlr_output); | 431 | wlr_output_preferred_mode(wlr_output); |
436 | wlr_output_state_set_mode(pending, preferred_mode); | 432 | wlr_output_state_set_mode(pending, preferred_mode); |
437 | |||
438 | if (!wlr_output_test_state(wlr_output, pending)) { | ||
439 | sway_log(SWAY_DEBUG, "Preferred mode rejected, " | ||
440 | "falling back to another mode"); | ||
441 | struct wlr_output_mode *mode; | ||
442 | wl_list_for_each(mode, &wlr_output->modes, link) { | ||
443 | if (mode == preferred_mode) { | ||
444 | continue; | ||
445 | } | ||
446 | |||
447 | wlr_output_state_set_mode(pending, mode); | ||
448 | if (wlr_output_test_state(wlr_output, pending)) { | ||
449 | break; | ||
450 | } | ||
451 | } | ||
452 | } | ||
453 | } | 433 | } |
454 | 434 | ||
455 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { | 435 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { |
@@ -500,25 +480,17 @@ static void queue_output_config(struct output_config *oc, | |||
500 | sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, | 480 | sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name, |
501 | oc->adaptive_sync); | 481 | oc->adaptive_sync); |
502 | wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); | 482 | wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1); |
503 | if (oc->adaptive_sync == 1 && !wlr_output_test_state(wlr_output, pending)) { | ||
504 | sway_log(SWAY_DEBUG, "Adaptive sync failed, ignoring"); | ||
505 | wlr_output_state_set_adaptive_sync_enabled(pending, false); | ||
506 | } | ||
507 | } | 483 | } |
508 | 484 | ||
509 | if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { | 485 | if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) { |
510 | const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth]; | 486 | if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 && |
511 | assert(fmts); | 487 | render_format_is_10bit(output->wlr_output->render_format)) { |
512 | 488 | // 10-bit was set successfully before, try to save some tests by reusing the format | |
513 | for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) { | 489 | wlr_output_state_set_render_format(pending, output->wlr_output->render_format); |
514 | wlr_output_state_set_render_format(pending, fmts[i]); | 490 | } else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) { |
515 | if (wlr_output_test_state(wlr_output, pending)) { | 491 | wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010); |
516 | break; | 492 | } else { |
517 | } | 493 | wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888); |
518 | |||
519 | sway_log(SWAY_DEBUG, "Preferred output format 0x%08x " | ||
520 | "failed to work, falling back to next in " | ||
521 | "list, 0x%08x", fmts[i], fmts[i + 1]); | ||
522 | } | 494 | } |
523 | } | 495 | } |
524 | } | 496 | } |
@@ -649,8 +621,245 @@ struct output_config *find_output_config(struct sway_output *sway_output) { | |||
649 | return result; | 621 | return result; |
650 | } | 622 | } |
651 | 623 | ||
624 | static bool config_has_auto_mode(struct output_config *oc) { | ||
625 | if (!oc) { | ||
626 | return true; | ||
627 | } | ||
628 | if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) { | ||
629 | return true; | ||
630 | } else if (oc->width > 0 && oc->height > 0) { | ||
631 | return true; | ||
632 | } | ||
633 | return false; | ||
634 | } | ||
635 | |||
636 | struct search_context { | ||
637 | struct wlr_output_swapchain_manager *swapchain_mgr; | ||
638 | struct wlr_backend_output_state *states; | ||
639 | struct matched_output_config *configs; | ||
640 | size_t configs_len; | ||
641 | bool degrade_to_off; | ||
642 | }; | ||
643 | |||
644 | static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_state *state) { | ||
645 | sway_log(SWAY_DEBUG, "Output state for %s", wlr_output->name); | ||
646 | if (state->committed & WLR_OUTPUT_STATE_ENABLED) { | ||
647 | sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no"); | ||
648 | } | ||
649 | if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) { | ||
650 | sway_log(SWAY_DEBUG, " render_format: %d", state->render_format); | ||
651 | } | ||
652 | if (state->committed & WLR_OUTPUT_STATE_MODE) { | ||
653 | if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) { | ||
654 | sway_log(SWAY_DEBUG, " custom mode: %dx%d@%dmHz", | ||
655 | state->custom_mode.width, state->custom_mode.height, state->custom_mode.refresh); | ||
656 | } else { | ||
657 | sway_log(SWAY_DEBUG, " mode: %dx%d@%dmHz%s", | ||
658 | state->mode->width, state->mode->height, state->mode->refresh, | ||
659 | state->mode->preferred ? " (preferred)" : ""); | ||
660 | } | ||
661 | } | ||
662 | if (state->committed & WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED) { | ||
663 | sway_log(SWAY_DEBUG, " adaptive_sync: %s", | ||
664 | state->adaptive_sync_enabled ? "enabled": "disabled"); | ||
665 | } | ||
666 | } | ||
667 | |||
668 | static bool search_valid_config(struct search_context *ctx, size_t output_idx); | ||
669 | |||
670 | static void reset_output_state(struct wlr_output_state *state) { | ||
671 | wlr_output_state_finish(state); | ||
672 | wlr_output_state_init(state); | ||
673 | state->committed = 0; | ||
674 | } | ||
675 | |||
676 | static void clear_later_output_states(struct wlr_backend_output_state *states, | ||
677 | size_t configs_len, size_t output_idx) { | ||
678 | |||
679 | // Clear and disable all output states after this one to avoid conflict | ||
680 | // with previous tests. | ||
681 | for (size_t idx = output_idx+1; idx < configs_len; idx++) { | ||
682 | struct wlr_backend_output_state *backend_state = &states[idx]; | ||
683 | struct wlr_output_state *state = &backend_state->base; | ||
684 | |||
685 | reset_output_state(state); | ||
686 | wlr_output_state_set_enabled(state, false); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | static bool search_finish(struct search_context *ctx, size_t output_idx) { | ||
691 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
692 | struct wlr_output_state *state = &backend_state->base; | ||
693 | struct wlr_output *wlr_output = backend_state->output; | ||
694 | |||
695 | clear_later_output_states(ctx->states, ctx->configs_len, output_idx); | ||
696 | dump_output_state(wlr_output, state); | ||
697 | return wlr_output_swapchain_manager_prepare(ctx->swapchain_mgr, ctx->states, ctx->configs_len) && | ||
698 | search_valid_config(ctx, output_idx+1); | ||
699 | } | ||
700 | |||
701 | static bool search_adaptive_sync(struct search_context *ctx, size_t output_idx) { | ||
702 | struct matched_output_config *cfg = &ctx->configs[output_idx]; | ||
703 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
704 | struct wlr_output_state *state = &backend_state->base; | ||
705 | |||
706 | if (cfg->config && cfg->config->adaptive_sync == 1) { | ||
707 | wlr_output_state_set_adaptive_sync_enabled(state, true); | ||
708 | if (search_finish(ctx, output_idx)) { | ||
709 | return true; | ||
710 | } | ||
711 | } | ||
712 | if (!cfg->config || cfg->config->adaptive_sync != -1) { | ||
713 | wlr_output_state_set_adaptive_sync_enabled(state, false); | ||
714 | if (search_finish(ctx, output_idx)) { | ||
715 | return true; | ||
716 | } | ||
717 | } | ||
718 | // If adaptive sync has not been set, or fallback in case we are on a | ||
719 | // backend that cannot disable adaptive sync such as the wayland backend. | ||
720 | state->committed &= ~WLR_OUTPUT_STATE_ADAPTIVE_SYNC_ENABLED; | ||
721 | return search_finish(ctx, output_idx); | ||
722 | } | ||
723 | |||
724 | static bool search_mode(struct search_context *ctx, size_t output_idx) { | ||
725 | struct matched_output_config *cfg = &ctx->configs[output_idx]; | ||
726 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
727 | struct wlr_output_state *state = &backend_state->base; | ||
728 | struct wlr_output *wlr_output = backend_state->output; | ||
729 | |||
730 | if (!config_has_auto_mode(cfg->config)) { | ||
731 | return search_adaptive_sync(ctx, output_idx); | ||
732 | } | ||
733 | |||
734 | struct wlr_output_mode *preferred_mode = wlr_output_preferred_mode(wlr_output); | ||
735 | if (preferred_mode) { | ||
736 | wlr_output_state_set_mode(state, preferred_mode); | ||
737 | if (search_adaptive_sync(ctx, output_idx)) { | ||
738 | return true; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | if (wl_list_empty(&wlr_output->modes)) { | ||
743 | state->committed &= ~WLR_OUTPUT_STATE_MODE; | ||
744 | return search_adaptive_sync(ctx, output_idx); | ||
745 | } | ||
746 | |||
747 | struct wlr_output_mode *mode; | ||
748 | wl_list_for_each(mode, &backend_state->output->modes, link) { | ||
749 | if (mode == preferred_mode) { | ||
750 | continue; | ||
751 | } | ||
752 | wlr_output_state_set_mode(state, mode); | ||
753 | if (search_adaptive_sync(ctx, output_idx)) { | ||
754 | return true; | ||
755 | } | ||
756 | } | ||
757 | |||
758 | return false; | ||
759 | } | ||
760 | |||
761 | static bool search_render_format(struct search_context *ctx, size_t output_idx) { | ||
762 | struct matched_output_config *cfg = &ctx->configs[output_idx]; | ||
763 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
764 | struct wlr_output_state *state = &backend_state->base; | ||
765 | struct wlr_output *wlr_output = backend_state->output; | ||
766 | |||
767 | uint32_t fmts[] = { | ||
768 | DRM_FORMAT_XRGB2101010, | ||
769 | DRM_FORMAT_XBGR2101010, | ||
770 | DRM_FORMAT_XRGB8888, | ||
771 | DRM_FORMAT_INVALID, | ||
772 | }; | ||
773 | if (render_format_is_bgr(wlr_output->render_format)) { | ||
774 | // Start with BGR in the unlikely event that we previously required it. | ||
775 | fmts[0] = DRM_FORMAT_XBGR2101010; | ||
776 | fmts[1] = DRM_FORMAT_XRGB2101010; | ||
777 | } | ||
778 | |||
779 | const struct wlr_drm_format_set *primary_formats = | ||
780 | wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF); | ||
781 | bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10; | ||
782 | for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) { | ||
783 | if (!need_10bit && render_format_is_10bit(fmts[idx])) { | ||
784 | continue; | ||
785 | } | ||
786 | if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) { | ||
787 | // This is not a supported format for this output | ||
788 | continue; | ||
789 | } | ||
790 | wlr_output_state_set_render_format(state, fmts[idx]); | ||
791 | if (search_mode(ctx, output_idx)) { | ||
792 | return true; | ||
793 | } | ||
794 | } | ||
795 | return false; | ||
796 | } | ||
797 | |||
798 | static bool search_valid_config(struct search_context *ctx, size_t output_idx) { | ||
799 | if (output_idx >= ctx->configs_len) { | ||
800 | // We reached the end of the search, all good! | ||
801 | return true; | ||
802 | } | ||
803 | |||
804 | struct matched_output_config *cfg = &ctx->configs[output_idx]; | ||
805 | struct wlr_backend_output_state *backend_state = &ctx->states[output_idx]; | ||
806 | struct wlr_output_state *state = &backend_state->base; | ||
807 | struct wlr_output *wlr_output = backend_state->output; | ||
808 | |||
809 | if (!output_config_is_disabling(cfg->config)) { | ||
810 | // Search through our possible configurations, doing a depth-first | ||
811 | // through render_format, modes, adaptive_sync and the next output's | ||
812 | // config. | ||
813 | queue_output_config(cfg->config, cfg->output, &backend_state->base); | ||
814 | if (search_render_format(ctx, output_idx)) { | ||
815 | return true; | ||
816 | } else if (!ctx->degrade_to_off) { | ||
817 | return false; | ||
818 | } | ||
819 | // We could not get anything to work, try to disable this output to see | ||
820 | // if we can at least make the outputs before us work. | ||
821 | sway_log(SWAY_DEBUG, "Unable to find valid config with output %s, disabling", | ||
822 | wlr_output->name); | ||
823 | reset_output_state(state); | ||
824 | } | ||
825 | |||
826 | wlr_output_state_set_enabled(state, false); | ||
827 | return search_finish(ctx, output_idx); | ||
828 | } | ||
829 | |||
830 | static int compare_matched_output_config_priority(const void *a, const void *b) { | ||
831 | |||
832 | const struct matched_output_config *amc = a; | ||
833 | const struct matched_output_config *bmc = b; | ||
834 | bool a_disabling = output_config_is_disabling(amc->config); | ||
835 | bool b_disabling = output_config_is_disabling(bmc->config); | ||
836 | bool a_enabled = amc->output->enabled; | ||
837 | bool b_enabled = bmc->output->enabled; | ||
838 | |||
839 | // We want to give priority to existing enabled outputs. To do so, we want | ||
840 | // the configuration order to be: | ||
841 | // 1. Existing, enabled outputs | ||
842 | // 2. Outputs that need to be enabled | ||
843 | // 3. Disabled or disabling outputs | ||
844 | if (a_enabled && !a_disabling) { | ||
845 | return -1; | ||
846 | } else if (b_enabled && !b_disabling) { | ||
847 | return 1; | ||
848 | } else if (b_disabling && !a_disabling) { | ||
849 | return -1; | ||
850 | } else if (a_disabling && !b_disabling) { | ||
851 | return 1; | ||
852 | } | ||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | void sort_output_configs_by_priority(struct matched_output_config *configs, | ||
857 | size_t configs_len) { | ||
858 | qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority); | ||
859 | } | ||
860 | |||
652 | bool apply_output_configs(struct matched_output_config *configs, | 861 | bool apply_output_configs(struct matched_output_config *configs, |
653 | size_t configs_len, bool test_only) { | 862 | size_t configs_len, bool test_only, bool degrade_to_off) { |
654 | struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); | 863 | struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states)); |
655 | if (!states) { | 864 | if (!states) { |
656 | return false; | 865 | return false; |
@@ -674,8 +883,18 @@ bool apply_output_configs(struct matched_output_config *configs, | |||
674 | 883 | ||
675 | bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len); | 884 | bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len); |
676 | if (!ok) { | 885 | if (!ok) { |
677 | sway_log(SWAY_ERROR, "Swapchain prepare failed"); | 886 | sway_log(SWAY_ERROR, "Requested backend configuration failed, searching for valid fallbacks"); |
678 | goto out; | 887 | struct search_context ctx = { |
888 | .swapchain_mgr = &swapchain_mgr, | ||
889 | .states = states, | ||
890 | .configs = configs, | ||
891 | .configs_len = configs_len, | ||
892 | .degrade_to_off = degrade_to_off, | ||
893 | }; | ||
894 | if (!search_valid_config(&ctx, 0)) { | ||
895 | sway_log(SWAY_ERROR, "Search for valid config failed"); | ||
896 | goto out; | ||
897 | } | ||
679 | } | 898 | } |
680 | 899 | ||
681 | if (test_only) { | 900 | if (test_only) { |
@@ -761,7 +980,8 @@ void apply_all_output_configs(void) { | |||
761 | config->config = find_output_config(sway_output); | 980 | config->config = find_output_config(sway_output); |
762 | } | 981 | } |
763 | 982 | ||
764 | apply_output_configs(configs, configs_len, false); | 983 | sort_output_configs_by_priority(configs, configs_len); |
984 | apply_output_configs(configs, configs_len, false, true); | ||
765 | for (size_t idx = 0; idx < configs_len; idx++) { | 985 | for (size_t idx = 0; idx < configs_len; idx++) { |
766 | struct matched_output_config *cfg = &configs[idx]; | 986 | struct matched_output_config *cfg = &configs[idx]; |
767 | free_output_config(cfg->config); | 987 | free_output_config(cfg->config); |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index 4b2584b6..6221b7b9 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <wayland-server-core.h> | 4 | #include <wayland-server-core.h> |
5 | #include <wlr/types/wlr_fractional_scale_v1.h> | ||
5 | #include <wlr/types/wlr_layer_shell_v1.h> | 6 | #include <wlr/types/wlr_layer_shell_v1.h> |
6 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
7 | #include <wlr/types/wlr_scene.h> | 8 | #include <wlr/types/wlr_scene.h> |
@@ -432,6 +433,12 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
432 | 433 | ||
433 | surface->output = output; | 434 | surface->output = output; |
434 | 435 | ||
436 | // now that the surface's output is known, we can advertise its scale | ||
437 | wlr_fractional_scale_v1_notify_scale(surface->layer_surface->surface, | ||
438 | layer_surface->output->scale); | ||
439 | wlr_surface_set_preferred_buffer_scale(surface->layer_surface->surface, | ||
440 | ceil(layer_surface->output->scale)); | ||
441 | |||
435 | surface->surface_commit.notify = handle_surface_commit; | 442 | surface->surface_commit.notify = handle_surface_commit; |
436 | wl_signal_add(&layer_surface->surface->events.commit, | 443 | wl_signal_add(&layer_surface->surface->events.commit, |
437 | &surface->surface_commit); | 444 | &surface->surface_commit); |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 70987feb..2722e556 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -609,7 +609,8 @@ static void output_manager_apply(struct sway_server *server, | |||
609 | } | 609 | } |
610 | } | 610 | } |
611 | 611 | ||
612 | bool ok = apply_output_configs(configs, configs_len, test_only); | 612 | sort_output_configs_by_priority(configs, configs_len); |
613 | bool ok = apply_output_configs(configs, configs_len, test_only, false); | ||
613 | for (size_t idx = 0; idx < configs_len; idx++) { | 614 | for (size_t idx = 0; idx < configs_len; idx++) { |
614 | struct matched_output_config *cfg = &configs[idx]; | 615 | struct matched_output_config *cfg = &configs[idx]; |
615 | 616 | ||
diff --git a/sway/sway_text_node.c b/sway/sway_text_node.c index 5eba53ba..4b7ee999 100644 --- a/sway/sway_text_node.c +++ b/sway/sway_text_node.c | |||
@@ -58,7 +58,7 @@ struct text_buffer { | |||
58 | 58 | ||
59 | static int get_text_width(struct sway_text_node *props) { | 59 | static int get_text_width(struct sway_text_node *props) { |
60 | int width = props->width; | 60 | int width = props->width; |
61 | if (props->max_width) { | 61 | if (props->max_width >= 0) { |
62 | width = MIN(width, props->max_width); | 62 | width = MIN(width, props->max_width); |
63 | } | 63 | } |
64 | return MAX(width, 0); | 64 | return MAX(width, 0); |
@@ -81,6 +81,11 @@ static void render_backing_buffer(struct text_buffer *buffer) { | |||
81 | return; | 81 | return; |
82 | } | 82 | } |
83 | 83 | ||
84 | if (buffer->props.max_width == 0) { | ||
85 | wlr_scene_buffer_set_buffer(buffer->buffer_node, NULL); | ||
86 | return; | ||
87 | } | ||
88 | |||
84 | float scale = buffer->scale; | 89 | float scale = buffer->scale; |
85 | int width = ceil(buffer->props.width * scale); | 90 | int width = ceil(buffer->props.width * scale); |
86 | int height = ceil(buffer->props.height * scale); | 91 | int height = ceil(buffer->props.height * scale); |
@@ -236,6 +241,7 @@ struct sway_text_node *sway_text_node_create(struct wlr_scene_tree *parent, | |||
236 | 241 | ||
237 | buffer->buffer_node = node; | 242 | buffer->buffer_node = node; |
238 | buffer->props.node = &node->node; | 243 | buffer->props.node = &node->node; |
244 | buffer->props.max_width = -1; | ||
239 | buffer->text = strdup(text); | 245 | buffer->text = strdup(text); |
240 | if (!buffer->text) { | 246 | if (!buffer->text) { |
241 | free(buffer); | 247 | free(buffer); |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 9224b4fb..80ef34fe 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -352,6 +352,8 @@ void container_arrange_title_bar(struct sway_container *con) { | |||
352 | 352 | ||
353 | int alloc_width = MIN((int)node->width, | 353 | int alloc_width = MIN((int)node->width, |
354 | width - h_padding - config->titlebar_h_padding); | 354 | width - h_padding - config->titlebar_h_padding); |
355 | alloc_width = MAX(alloc_width, 0); | ||
356 | |||
355 | sway_text_node_set_max_width(node, alloc_width); | 357 | sway_text_node_set_max_width(node, alloc_width); |
356 | wlr_scene_node_set_position(node->node, | 358 | wlr_scene_node_set_position(node->node, |
357 | h_padding, (height - node->height) >> 1); | 359 | h_padding, (height - node->height) >> 1); |
@@ -376,6 +378,8 @@ void container_arrange_title_bar(struct sway_container *con) { | |||
376 | 378 | ||
377 | int alloc_width = MIN((int) node->width, | 379 | int alloc_width = MIN((int) node->width, |
378 | width - h_padding - config->titlebar_h_padding); | 380 | width - h_padding - config->titlebar_h_padding); |
381 | alloc_width = MAX(alloc_width, 0); | ||
382 | |||
379 | sway_text_node_set_max_width(node, alloc_width); | 383 | sway_text_node_set_max_width(node, alloc_width); |
380 | wlr_scene_node_set_position(node->node, | 384 | wlr_scene_node_set_position(node->node, |
381 | h_padding, (height - node->height) >> 1); | 385 | h_padding, (height - node->height) >> 1); |