output-management-v1: support applying configuration

This commit is contained in:
emersion 2019-03-09 23:12:27 +01:00 committed by Drew DeVault
parent d71ebde545
commit 8136605cfb
5 changed files with 152 additions and 30 deletions

View file

@ -61,6 +61,8 @@ void output_for_each_surface(struct roots_output *output,
roots_surface_iterator_func_t iterator, void *user_data); roots_surface_iterator_func_t iterator, void *user_data);
void handle_new_output(struct wl_listener *listener, void *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_view;
struct roots_drag_icon; struct roots_drag_icon;

View file

@ -56,11 +56,12 @@ struct wlr_output_head_v1 {
struct wlr_output_configuration_v1 { struct wlr_output_configuration_v1 {
struct wl_list heads; // wlr_output_configuration_head_v1::link struct wl_list heads; // wlr_output_configuration_head_v1::link
// client state
struct wlr_output_manager_v1 *manager; struct wlr_output_manager_v1 *manager;
uint32_t serial; uint32_t serial;
bool finalized; // client has requested to apply the config bool finalized; // client has requested to apply the config
bool finished; // feedback has been sent by the compositor 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 { struct wlr_output_configuration_head_v1 {
@ -68,7 +69,8 @@ struct wlr_output_configuration_head_v1 {
struct wlr_output_configuration_v1 *config; struct wlr_output_configuration_v1 *config;
struct wl_list link; // wlr_output_configuration_v1::heads 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; struct wl_listener output_destroy;
}; };

View file

@ -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_desktop *desktop_create(struct roots_server *server,
struct roots_config *config) { struct roots_config *config) {
wlr_log(WLR_DEBUG, "Initializing roots desktop"); wlr_log(WLR_DEBUG, "Initializing roots desktop");

View file

@ -430,14 +430,54 @@ static void update_output_manager_config(struct roots_desktop *desktop) {
struct roots_output *output; struct roots_output *output;
wl_list_for_each(output, &desktop->outputs, link) { 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);
wlr_output_configuration_head_v1_create(config, output->wlr_output);
(void)head;
} }
wlr_output_manager_v1_set_configuration(desktop->output_manager_v1, config); 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) { static void output_destroy(struct roots_output *output) {
// TODO: cursor // TODO: cursor
//example_config_configure_cursor(sample->config, sample->cursor, //example_config_configure_cursor(sample->config, sample->cursor,

View file

@ -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( static struct wlr_output_configuration_head_v1 *config_head_from_resource(
struct wl_resource *resource) { struct wl_resource *resource) {
assert(wl_resource_instance_of(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); 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 = { 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) { 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 // this point anyway
struct wlr_output_configuration_head_v1 *config_head, *tmp; struct wlr_output_configuration_head_v1 *config_head, *tmp;
wl_list_for_each_safe(config_head, tmp, &config->heads, link) { wl_list_for_each_safe(config_head, tmp, &config->heads, link) {
wl_resource_set_user_data(config_head->resource, NULL); // Resource is NULL if head has been disabled
wl_resource_destroy(config_head->resource); if (config_head->resource != NULL) {
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; 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, static void manager_handle_create_configuration(struct wl_client *client,
struct wl_resource *manager_resource, uint32_t id, uint32_t serial) { 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); struct wlr_output_configuration_v1 *config = config_create(false);
if (config == NULL) { if (config == NULL) {
wl_resource_post_no_memory(manager_resource); wl_resource_post_no_memory(manager_resource);
return; return;
} }
config->manager = manager;
config->serial = serial; config->serial = serial;
uint32_t version = wl_resource_get_version(manager_resource); uint32_t version = wl_resource_get_version(manager_resource);