From a9b1ef6a0781b82da512d1272327e7f60c024fc1 Mon Sep 17 00:00:00 2001 From: Dima Krasner Date: Wed, 22 Dec 2021 08:29:17 +0200 Subject: [PATCH] Add basic wlr-output-management support Fixes #118 --- cage.c | 12 ++++++ output.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- output.h | 2 + server.h | 3 ++ 4 files changed, 142 insertions(+), 1 deletion(-) diff --git a/cage.c b/cage.c index 44f489c..6cdf809 100644 --- a/cage.c +++ b/cage.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -445,6 +446,17 @@ main(int argc, char *argv[]) goto end; } + server.output_manager_v1 = wlr_output_manager_v1_create(server.wl_display); + if (!server.output_manager_v1) { + wlr_log(WLR_ERROR, "Unable to create the output manager"); + ret = 1; + goto end; + } + 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); + gamma_control_manager = wlr_gamma_control_manager_v1_create(server.wl_display); if (!gamma_control_manager) { wlr_log(WLR_ERROR, "Unable to create the gamma control manager"); diff --git a/output.c b/output.c index e819d9b..db40a8c 100644 --- a/output.c +++ b/output.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,33 @@ #include "xwayland.h" #endif +static void +update_output_manager_config(struct cg_server *server) +{ + struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); + + struct cg_output *output; + wl_list_for_each (output, &server->outputs, link) { + struct wlr_output *wlr_output = output->wlr_output; + struct wlr_output_configuration_head_v1 *config_head = + wlr_output_configuration_head_v1_create(config, wlr_output); + + struct wlr_box *box = wlr_output_layout_get_box(server->output_layout, wlr_output); + if (box) { + config_head->state.x = box->x; + config_head->state.y = box->y; + } + + // We mark the output enabled even if it is switched off by DPMS + config_head->state.enabled = wlr_output->current_mode != NULL && wlr_output->enabled; + config_head->state.mode = wlr_output->current_mode; + config_head->state.scale = wlr_output->scale; + config_head->state.transform = wlr_output->transform; + } + + wlr_output_manager_v1_set_configuration(server->output_manager_v1, config); +} + static void output_enable(struct cg_output *output) { @@ -63,6 +91,8 @@ output_enable(struct cg_output *output) } } assert(output->scene_output != NULL); + + update_output_manager_config(output->server); } static void @@ -81,6 +111,37 @@ output_disable(struct cg_output *output) wlr_output_enable(wlr_output, false); wlr_output_layout_remove(output->server->output_layout, wlr_output); wlr_output_commit(wlr_output); + + update_output_manager_config(output->server); +} + +static void +output_apply_config(struct cg_output *output, struct wlr_output_configuration_head_v1 *head) +{ + struct wlr_output *wlr_output = output->wlr_output; + + wlr_log(WLR_DEBUG, "Applying configuration for output %s", wlr_output->name); + + if (!head->state.enabled) { + output_disable(output); + return; + } + + if (head->state.mode) { + wlr_output_set_mode(wlr_output, head->state.mode); + } else { + wlr_output_set_custom_mode(wlr_output, head->state.custom_mode.width, head->state.custom_mode.height, + head->state.custom_mode.refresh); + } + + wlr_output_layout_add(output->server->output_layout, head->state.output, head->state.x, head->state.y); + wlr_output_set_scale(wlr_output, head->state.scale); + wlr_output_set_transform(wlr_output, head->state.transform); + + wlr_output_enable(wlr_output, true); + wlr_output_commit(wlr_output); + + update_output_manager_config(output->server); } static void @@ -109,11 +170,13 @@ handle_output_commit(struct wl_listener *listener, void *data) return; } - if (event->committed & WLR_OUTPUT_STATE_TRANSFORM) { + if (event->committed & (WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) { struct cg_view *view; wl_list_for_each (view, &output->server->views, link) { view_position(view); } + + update_output_manager_config(output->server); } } @@ -130,6 +193,8 @@ handle_output_mode(struct wl_listener *listener, void *data) wl_list_for_each (view, &output->server->views, link) { view_position(view); } + + update_output_manager_config(output->server); } static void @@ -261,3 +326,62 @@ output_set_window_title(struct cg_output *output, const char *title) #endif } } + +static bool +output_config_test(struct cg_server *server, struct wlr_output_configuration_v1 *config) +{ + /* TODO */ + return true; +} + +static bool +output_config_apply(struct cg_server *server, struct wlr_output_configuration_v1 *config) +{ + if (!output_config_test(server, config)) { + return false; + } + + struct wlr_output_configuration_head_v1 *head; + wl_list_for_each (head, &config->heads, link) { + struct cg_output *output; + wl_list_for_each (output, &server->outputs, link) { + if (strcmp(head->state.output->name, output->wlr_output->name) == 0) { + wlr_log(WLR_INFO, "Applying configuration for output %s", output->wlr_output->name); + output_apply_config(output, head); + break; + } + } + } + + return true; +} + +void +handle_output_manager_apply(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, output_manager_apply); + struct wlr_output_configuration_v1 *config = data; + + if (output_config_apply(server, config)) { + wlr_output_configuration_v1_send_succeeded(config); + } else { + wlr_output_configuration_v1_send_failed(config); + } + + wlr_output_configuration_v1_destroy(config); +} + +void +handle_output_manager_test(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, output_manager_test); + struct wlr_output_configuration_v1 *config = data; + + if (output_config_test(server, config)) { + wlr_output_configuration_v1_send_succeeded(config); + } else { + wlr_output_configuration_v1_send_failed(config); + } + + wlr_output_configuration_v1_destroy(config); +} diff --git a/output.h b/output.h index ced06f6..a22f41a 100644 --- a/output.h +++ b/output.h @@ -21,6 +21,8 @@ struct cg_output { struct wl_list link; // cg_server::outputs }; +void handle_output_manager_apply(struct wl_listener *listener, void *data); +void handle_output_manager_test(struct wl_listener *listener, void *data); void handle_new_output(struct wl_listener *listener, void *data); void output_set_window_title(struct cg_output *output, const char *title); diff --git a/server.h b/server.h index 1b87f0d..3fa57c4 100644 --- a/server.h +++ b/server.h @@ -47,6 +47,9 @@ struct cg_server { #if CAGE_HAS_XWAYLAND struct wl_listener new_xwayland_surface; #endif + struct wlr_output_manager_v1 *output_manager_v1; + struct wl_listener output_manager_apply; + struct wl_listener output_manager_test; bool xdg_decoration; bool allow_vt_switch;