From 8136605cfb72f2addc16c126519dd3a63e803ec2 Mon Sep 17 00:00:00 2001 From: emersion Date: Sat, 9 Mar 2019 23:12:27 +0100 Subject: [PATCH] output-management-v1: support applying configuration --- include/rootston/output.h | 2 + include/wlr/types/wlr_output_management_v1.h | 6 +- rootston/desktop.c | 20 ---- rootston/output.c | 46 +++++++- types/wlr_output_management_v1.c | 108 ++++++++++++++++++- 5 files changed, 152 insertions(+), 30 deletions(-) diff --git a/include/rootston/output.h b/include/rootston/output.h index 74b7e6eb..6b02d69f 100644 --- a/include/rootston/output.h +++ b/include/rootston/output.h @@ -61,6 +61,8 @@ void output_for_each_surface(struct roots_output *output, roots_surface_iterator_func_t iterator, void *user_data); void handle_new_output(struct wl_listener *listener, void *data); +void handle_output_manager_apply(struct wl_listener *listener, void *data); +void handle_output_manager_test(struct wl_listener *listener, void *data); struct roots_view; struct roots_drag_icon; diff --git a/include/wlr/types/wlr_output_management_v1.h b/include/wlr/types/wlr_output_management_v1.h index 4622e6da..c6429e04 100644 --- a/include/wlr/types/wlr_output_management_v1.h +++ b/include/wlr/types/wlr_output_management_v1.h @@ -56,11 +56,12 @@ struct wlr_output_head_v1 { struct wlr_output_configuration_v1 { struct wl_list heads; // wlr_output_configuration_head_v1::link + // client state struct wlr_output_manager_v1 *manager; uint32_t serial; bool finalized; // client has requested to apply the config bool finished; // feedback has been sent by the compositor - struct wl_resource *resource; // can be NULL + struct wl_resource *resource; // can be NULL if destroyed early }; struct wlr_output_configuration_head_v1 { @@ -68,7 +69,8 @@ struct wlr_output_configuration_head_v1 { struct wlr_output_configuration_v1 *config; struct wl_list link; // wlr_output_configuration_v1::heads - struct wl_resource *resource; // can be NULL + // client state + struct wl_resource *resource; // can be NULL if finalized or disabled struct wl_listener output_destroy; }; diff --git a/rootston/desktop.c b/rootston/desktop.c index 35962cbb..880849be 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -294,26 +294,6 @@ static void handle_pointer_constraint(struct wl_listener *listener, } } -static void handle_output_manager_apply(struct wl_listener *listener, - void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, output_manager_apply); - struct wlr_output_configuration_v1 *config = data; - (void)config; - wlr_log(WLR_DEBUG, "APPLY"); // TODO -} - -static void handle_output_manager_test(struct wl_listener *listener, - void *data) { - struct roots_desktop *desktop = - wl_container_of(listener, desktop, output_manager_test); - 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); -} - struct roots_desktop *desktop_create(struct roots_server *server, struct roots_config *config) { wlr_log(WLR_DEBUG, "Initializing roots desktop"); diff --git a/rootston/output.c b/rootston/output.c index 8ecac8ca..4afbfa7b 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -430,14 +430,54 @@ static void update_output_manager_config(struct roots_desktop *desktop) { struct roots_output *output; wl_list_for_each(output, &desktop->outputs, link) { - struct wlr_output_configuration_head_v1 *head = - wlr_output_configuration_head_v1_create(config, output->wlr_output); - (void)head; + wlr_output_configuration_head_v1_create(config, output->wlr_output); } wlr_output_manager_v1_set_configuration(desktop->output_manager_v1, config); } +void handle_output_manager_apply(struct wl_listener *listener, void *data) { + struct roots_desktop *desktop = + wl_container_of(listener, desktop, output_manager_apply); + struct wlr_output_configuration_v1 *config = data; + + bool ok = true; + struct wlr_output_configuration_head_v1 *config_head; + wl_list_for_each(config_head, &config->heads, link) { + struct wlr_output *wlr_output = config_head->state.output; + ok &= wlr_output_enable(wlr_output, config_head->state.enabled); + if (!config_head->state.enabled) { + continue; + } + if (config_head->state.mode != NULL) { + ok &= wlr_output_set_mode(wlr_output, config_head->state.mode); + } + wlr_output_layout_add(desktop->layout, wlr_output, + config_head->state.x, config_head->state.y); + wlr_output_set_transform(wlr_output, config_head->state.transform); + wlr_output_set_scale(wlr_output, config_head->state.scale); + } + + 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(desktop); +} + +void handle_output_manager_test(struct wl_listener *listener, void *data) { + struct roots_desktop *desktop = + wl_container_of(listener, desktop, output_manager_test); + 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); +} + static void output_destroy(struct roots_output *output) { // TODO: cursor //example_config_configure_cursor(sample->config, sample->cursor, diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c index d0865f5e..0f68f240 100644 --- a/types/wlr_output_management_v1.c +++ b/types/wlr_output_management_v1.c @@ -132,12 +132,94 @@ static const struct zwlr_output_configuration_head_v1_interface config_head_impl static struct wlr_output_configuration_head_v1 *config_head_from_resource( struct wl_resource *resource) { assert(wl_resource_instance_of(resource, - &zwlr_output_head_v1_interface, &config_head_impl)); + &zwlr_output_configuration_head_v1_interface, &config_head_impl)); return wl_resource_get_user_data(resource); } +static void config_head_handle_set_mode(struct wl_client *client, + struct wl_resource *config_head_resource, + struct wl_resource *mode_resource) { + struct wlr_output_configuration_head_v1 *config_head = + config_head_from_resource(config_head_resource); + if (config_head == NULL) { + return; + } + + struct wlr_output_mode *mode = mode_from_resource(mode_resource); + + bool found = false; + struct wlr_output_mode *m; + wl_list_for_each(m, &config_head->state.output->modes, link) { + if (mode == m) { + found = true; + break; + } + } + + if (!found) { + wl_resource_post_error(config_head_resource, + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_MODE, + "mode doesn't belong to head"); + return; + } + + config_head->state.mode = mode; +} + +static void config_head_handle_set_position(struct wl_client *client, + struct wl_resource *config_head_resource, int32_t x, int32_t y) { + struct wlr_output_configuration_head_v1 *config_head = + config_head_from_resource(config_head_resource); + if (config_head == NULL) { + return; + } + + config_head->state.x = x; + config_head->state.y = y; +} + +static void config_head_handle_set_transform(struct wl_client *client, + struct wl_resource *config_head_resource, int32_t transform) { + struct wlr_output_configuration_head_v1 *config_head = + config_head_from_resource(config_head_resource); + if (config_head == NULL) { + return; + } + + if (transform < WL_OUTPUT_TRANSFORM_NORMAL || + transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) { + wl_resource_post_error(config_head_resource, + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_TRANSFORM, + "invalid transform"); + return; + } + + config_head->state.transform = transform; +} + +static void config_head_handle_set_scale(struct wl_client *client, + struct wl_resource *config_head_resource, int32_t scale) { + struct wlr_output_configuration_head_v1 *config_head = + config_head_from_resource(config_head_resource); + if (config_head == NULL) { + return; + } + + if (scale <= 0) { + wl_resource_post_error(config_head_resource, + ZWLR_OUTPUT_CONFIGURATION_HEAD_V1_ERROR_INVALID_SCALE, + "invalid scale"); + return; + } + + config_head->state.scale = scale; +} + static const struct zwlr_output_configuration_head_v1_interface config_head_impl = { - 0 // TODO + .set_mode = config_head_handle_set_mode, + .set_position = config_head_handle_set_position, + .set_transform = config_head_handle_set_transform, + .set_scale = config_head_handle_set_scale, }; static void config_head_handle_resource_destroy(struct wl_resource *resource) { @@ -252,9 +334,12 @@ static void config_finalize(struct wlr_output_configuration_v1 *config) { // this point anyway struct wlr_output_configuration_head_v1 *config_head, *tmp; wl_list_for_each_safe(config_head, tmp, &config->heads, link) { - wl_resource_set_user_data(config_head->resource, NULL); - wl_resource_destroy(config_head->resource); - config_head->resource = NULL; + // Resource is NULL if head has been disabled + if (config_head->resource != NULL) { + wl_resource_set_user_data(config_head->resource, NULL); + wl_resource_destroy(config_head->resource); + config_head->resource = NULL; + } } config->finalized = true; @@ -385,13 +470,26 @@ void wlr_output_configuration_v1_send_failed( } +static const struct zwlr_output_manager_v1_interface manager_impl; + +static struct wlr_output_manager_v1 *manager_from_resource( + struct wl_resource *resource) { + assert(wl_resource_instance_of(resource, + &zwlr_output_manager_v1_interface, &manager_impl)); + return wl_resource_get_user_data(resource); +} + static void manager_handle_create_configuration(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, uint32_t serial) { + struct wlr_output_manager_v1 *manager = + manager_from_resource(manager_resource); + struct wlr_output_configuration_v1 *config = config_create(false); if (config == NULL) { wl_resource_post_no_memory(manager_resource); return; } + config->manager = manager; config->serial = serial; uint32_t version = wl_resource_get_version(manager_resource);