diff --git a/include/sway/output.h b/include/sway/output.h index d4438c0e..3d430ea2 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -154,4 +154,8 @@ void scale_box(struct wlr_box *box, float scale); enum wlr_direction opposite_direction(enum wlr_direction d); +void handle_output_manager_apply(struct wl_listener *listener, void *data); + +void handle_output_manager_test(struct wl_listener *listener, void *data); + #endif diff --git a/include/sway/server.h b/include/sway/server.h index 39cf4f18..fd613bb6 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,10 @@ struct sway_server { struct wlr_pointer_constraints_v1 *pointer_constraints; struct wl_listener pointer_constraint; + struct wlr_output_manager_v1 *output_manager_v1; + struct wl_listener output_manager_apply; + struct wl_listener output_manager_test; + size_t txn_timeout_ms; list_t *transactions; list_t *dirty_nodes; diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 1636a58b..dccb2432 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c @@ -578,6 +578,30 @@ static void update_textures(struct sway_container *con, void *data) { container_update_marks_textures(con); } +static void update_output_manager_config(struct sway_server *server) { + struct wlr_output_configuration_v1 *config = + wlr_output_configuration_v1_create(); + + struct sway_output *output; + wl_list_for_each(output, &root->all_outputs, link) { + if (output == root->noop_output) { + continue; + } + struct wlr_output_configuration_head_v1 *config_head = + wlr_output_configuration_head_v1_create(config, output->wlr_output); + struct wlr_box *output_box = wlr_output_layout_get_box( + root->output_layout, output->wlr_output); + // We mark the output enabled even if it is switched off by DPMS + config_head->state.enabled = output->enabled; + if (output_box) { + config_head->state.x = output_box->x; + config_head->state.y = output_box->y; + } + } + + wlr_output_manager_v1_set_configuration(server->output_manager_v1, config); +} + static void handle_scale(struct wl_listener *listener, void *data) { struct sway_output *output = wl_container_of(listener, output, scale); if (!output->enabled || !output->configured) { @@ -651,4 +675,73 @@ void handle_new_output(struct wl_listener *listener, void *data) { } transaction_commit_dirty(); + + update_output_manager_config(server); +} + +void handle_output_manager_apply(struct wl_listener *listener, void *data) { + struct sway_server *server = + wl_container_of(listener, server, output_manager_apply); + struct wlr_output_configuration_v1 *config = data; + + struct wlr_output_configuration_head_v1 *config_head; + // First disable outputs we need to disable + bool ok = true; + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + struct sway_output *output = wlr_output->data; + if (!output->enabled || config_head->state.enabled) { + continue; + } + struct output_config *oc = new_output_config(output->wlr_output->name); + oc->enabled = false; + + oc = store_output_config(oc); + ok &= apply_output_config(oc, output); + } + + // Then enable outputs that need to + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + struct sway_output *output = wlr_output->data; + if (!config_head->state.enabled) { + continue; + } + struct output_config *oc = new_output_config(output->wlr_output->name); + oc->enabled = true; + if (config_head->state.mode != NULL) { + struct wlr_output_mode *mode = config_head->state.mode; + oc->width = mode->width; + oc->height = mode->height; + oc->refresh_rate = mode->refresh; + } else { + oc->width = config_head->state.custom_mode.width; + oc->height = config_head->state.custom_mode.height; + oc->refresh_rate = config_head->state.custom_mode.refresh; + } + oc->x = config_head->state.x; + oc->y = config_head->state.y; + oc->transform = config_head->state.transform; + oc->scale = config_head->state.scale; + + oc = store_output_config(oc); + ok &= apply_output_config(oc, output); + } + + if (ok) { + wlr_output_configuration_v1_send_succeeded(config); + } else { + wlr_output_configuration_v1_send_failed(config); + } + wlr_output_configuration_v1_destroy(config); + + update_output_manager_config(server); +} + +void handle_output_manager_test(struct wl_listener *listener, void *data) { + struct wlr_output_configuration_v1 *config = data; + + // TODO: implement test-only mode + wlr_output_configuration_v1_send_succeeded(config); + wlr_output_configuration_v1_destroy(config); } diff --git a/sway/server.c b/sway/server.c index b24cc1dc..e5200d59 100644 --- a/sway/server.c +++ b/sway/server.c @@ -120,6 +120,15 @@ bool server_init(struct sway_server *server) { server->presentation = wlr_presentation_create(server->wl_display, server->backend); + server->output_manager_v1 = + wlr_output_manager_v1_create(server->wl_display); + server->output_manager_apply.notify = handle_output_manager_apply; + wl_signal_add(&server->output_manager_v1->events.apply, + &server->output_manager_apply); + server->output_manager_test.notify = handle_output_manager_test; + wl_signal_add(&server->output_manager_v1->events.test, + &server->output_manager_test); + wlr_export_dmabuf_manager_v1_create(server->wl_display); wlr_screencopy_manager_v1_create(server->wl_display); wlr_data_control_manager_v1_create(server->wl_display);