commit 3e03eb3a017d144137dbe6591891f3a51a61dea0
parent e2f3ebad8c1943800dd5f017d547d9d98bfb8bb1
Author: Kenny Levinsen <kl@kl.wtf>
Date: Sat, 16 Mar 2024 00:48:56 +0100
config/output: Introduce apply_output_configs
Introduce apply_output_configs, which applies the specified matched
output configs as a single backend commit.
Reimplement apply_output_config_to_outputs using apply_output_configs.
Diffstat:
2 files changed, 135 insertions(+), 24 deletions(-)
diff --git a/include/sway/config.h b/include/sway/config.h
@@ -292,6 +292,14 @@ struct output_config {
};
/**
+ * An output config pre-matched to an output
+ */
+struct matched_output_config {
+ struct sway_output *output;
+ struct output_config *config;
+};
+
+/**
* Stores size of gaps for each side
*/
struct side_gaps {
@@ -684,6 +692,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src);
bool apply_output_config(struct output_config *oc, struct sway_output *output);
+bool apply_output_configs(struct matched_output_config *configs,
+ size_t configs_len, bool test_only);
+
bool test_output_config(struct output_config *oc, struct sway_output *output);
struct output_config *store_output_config(struct output_config *oc);
diff --git a/sway/config/output.c b/sway/config/output.c
@@ -9,6 +9,7 @@
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_output_layout.h>
#include <wlr/types/wlr_output.h>
+#include <wlr/types/wlr_output_swapchain_manager.h>
#include "sway/config.h"
#include "sway/input/cursor.h"
#include "sway/output.h"
@@ -716,39 +717,138 @@ struct output_config *find_output_config(struct sway_output *output) {
return get_output_config(id, output);
}
-void apply_output_config_to_outputs(struct output_config *oc) {
- // Try to find the output container and apply configuration now. If
- // this is during startup then there will be no container and config
- // will be applied during normal "new output" event from wlroots.
- bool wildcard = strcmp(oc->name, "*") == 0;
- struct sway_output *sway_output, *tmp;
- wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
- if (output_match_name_or_id(sway_output, oc->name)) {
- char id[128];
- output_get_identifier(id, sizeof(id), sway_output);
- struct output_config *current = get_output_config(id, sway_output);
- if (!current) {
- // No stored output config matched, apply oc directly
- sway_log(SWAY_DEBUG, "Applying oc directly");
- current = new_output_config(oc->name);
- merge_output_config(current, oc);
- }
- apply_output_config(current, sway_output);
- free_output_config(current);
+bool apply_output_configs(struct matched_output_config *configs,
+ size_t configs_len, bool test_only) {
+ struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
+ if (!states) {
+ return false;
+ }
- if (!wildcard) {
- // Stop looking if the output config isn't applicable to all
- // outputs
- break;
- }
+ sway_log(SWAY_DEBUG, "Committing %zd outputs", configs_len);
+ for (size_t idx = 0; idx < configs_len; idx++) {
+ struct matched_output_config *cfg = &configs[idx];
+ struct wlr_backend_output_state *backend_state = &states[idx];
+
+ backend_state->output = cfg->output->wlr_output;
+ wlr_output_state_init(&backend_state->base);
+
+ sway_log(SWAY_DEBUG, "Preparing config for %s",
+ cfg->output->wlr_output->name);
+ queue_output_config(cfg->config, cfg->output, &backend_state->base);
+ }
+
+ struct wlr_output_swapchain_manager swapchain_mgr;
+ wlr_output_swapchain_manager_init(&swapchain_mgr, server.backend);
+
+ bool ok = wlr_output_swapchain_manager_prepare(&swapchain_mgr, states, configs_len);
+ if (!ok) {
+ sway_log(SWAY_ERROR, "Swapchain prepare failed");
+ goto out;
+ }
+
+ if (test_only) {
+ // The swapchain manager already did a test for us
+ goto out;
+ }
+
+ for (size_t idx = 0; idx < configs_len; idx++) {
+ struct matched_output_config *cfg = &configs[idx];
+ struct wlr_backend_output_state *backend_state = &states[idx];
+
+ struct wlr_scene_output_state_options opts = {
+ .swapchain = wlr_output_swapchain_manager_get_swapchain(
+ &swapchain_mgr, backend_state->output),
+ };
+ struct wlr_scene_output *scene_output = cfg->output->scene_output;
+ struct wlr_output_state *state = &backend_state->base;
+ if (!wlr_scene_output_build_state(scene_output, state, &opts)) {
+ sway_log(SWAY_ERROR, "Building output state for '%s' failed",
+ backend_state->output->name);
+ goto out;
}
}
+ ok = wlr_backend_commit(server.backend, states, configs_len);
+ if (!ok) {
+ sway_log(SWAY_ERROR, "Backend commit failed");
+ goto out;
+ }
+
+ sway_log(SWAY_DEBUG, "Commit of %zd outputs succeeded", configs_len);
+
+ wlr_output_swapchain_manager_apply(&swapchain_mgr);
+
+ for (size_t idx = 0; idx < configs_len; idx++) {
+ struct matched_output_config *cfg = &configs[idx];
+ sway_log(SWAY_DEBUG, "Finalizing config for %s",
+ cfg->output->wlr_output->name);
+ finalize_output_config(cfg->config, cfg->output);
+ }
+
+out:
+ wlr_output_swapchain_manager_finish(&swapchain_mgr);
+ for (size_t idx = 0; idx < configs_len; idx++) {
+ struct wlr_backend_output_state *backend_state = &states[idx];
+ wlr_output_state_finish(&backend_state->base);
+ }
+ free(states);
+
+ // Reconfigure all devices, since input config may have been applied before
+ // this output came online, and some config items (like map_to_output) are
+ // dependent on an output being present.
+ input_manager_configure_all_input_mappings();
+ // Reconfigure the cursor images, since the scale may have changed.
+ input_manager_configure_xcursor();
+
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
cursor_rebase(seat->cursor);
}
+
+ return ok;
+}
+
+void apply_output_config_to_outputs(struct output_config *oc) {
+ size_t configs_len = wl_list_length(&root->all_outputs);
+ struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
+ if (!configs) {
+ return;
+ }
+
+ // Try to find the output container and apply configuration now. If
+ // this is during startup then there will be no container and config
+ // will be applied during normal "new output" event from wlroots.
+ int config_idx = 0;
+ struct sway_output *sway_output;
+ wl_list_for_each(sway_output, &root->all_outputs, link) {
+ if (sway_output == root->fallback_output) {
+ configs_len--;
+ continue;
+ }
+
+ struct matched_output_config *config = &configs[config_idx++];
+ config->output = sway_output;
+ config->config = find_output_config(sway_output);
+
+ if (!output_match_name_or_id(sway_output, oc->name)) {
+ continue;
+ }
+
+ if (!config->config && oc) {
+ // No stored output config matched, apply oc directly
+ sway_log(SWAY_DEBUG, "Applying oc directly");
+ config->config = new_output_config(oc->name);
+ merge_output_config(config->config, oc);
+ }
+ }
+
+ apply_output_configs(configs, configs_len, false);
+ for (size_t idx = 0; idx < configs_len; idx++) {
+ struct matched_output_config *cfg = &configs[idx];
+ free_output_config(cfg->config);
+ }
+ free(configs);
}
void reset_outputs(void) {