Add apply and test events to manager

This commit is contained in:
emersion 2019-03-08 14:28:24 +01:00 committed by Drew DeVault
parent 0b64ecc162
commit d695003498
2 changed files with 138 additions and 17 deletions

View file

@ -9,6 +9,7 @@
#ifndef WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H #ifndef WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
#define WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H #define WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
#include <stdbool.h>
#include <wayland-server.h> #include <wayland-server.h>
#include <wlr/types/wlr_output.h> #include <wlr/types/wlr_output.h>
@ -21,6 +22,8 @@ struct wlr_output_manager_v1 {
uint32_t serial; uint32_t serial;
struct { struct {
struct wl_signal apply; // wlr_output_configuration_v1
struct wl_signal test; // wlr_output_configuration_v1
struct wl_signal destroy; struct wl_signal destroy;
} events; } events;
@ -47,7 +50,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
struct wlr_output_manager_v1 *manager;
uint32_t serial; 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 wlr_output_configuration_head_v1 { struct wlr_output_configuration_head_v1 {
@ -69,6 +77,10 @@ void wlr_output_manager_v1_set_configuration(
struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void); struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void);
void wlr_output_configuration_v1_destroy( void wlr_output_configuration_v1_destroy(
struct wlr_output_configuration_v1 *config); struct wlr_output_configuration_v1 *config);
void wlr_output_configuration_v1_send_succeeded(
struct wlr_output_configuration_v1 *config);
void wlr_output_configuration_v1_send_failed(
struct wlr_output_configuration_v1 *config);
struct wlr_output_configuration_head_v1 * struct wlr_output_configuration_head_v1 *
wlr_output_configuration_head_v1_create( wlr_output_configuration_head_v1_create(

View file

@ -122,6 +122,7 @@ static void config_head_handle_resource_destroy(struct wl_resource *resource) {
static const struct zwlr_output_configuration_v1_interface config_impl; static const struct zwlr_output_configuration_v1_interface config_impl;
// Can return NULL if the config has been used
static struct wlr_output_configuration_v1 *config_from_resource( static struct wlr_output_configuration_v1 *config_from_resource(
struct wl_resource *resource) { struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, assert(wl_resource_instance_of(resource,
@ -145,7 +146,12 @@ static void config_handle_enable_head(struct wl_client *client,
struct wl_resource *head_resource) { struct wl_resource *head_resource) {
struct wlr_output_configuration_v1 *config = struct wlr_output_configuration_v1 *config =
config_from_resource(config_resource); config_from_resource(config_resource);
// Can be NULL if the head no longer exists if (config == NULL || config->finalized) {
wl_resource_post_error(config_resource,
ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED,
"configuration object has already been used");
return;
}
struct wlr_output_head_v1 *head = head_from_resource(head_resource); struct wlr_output_head_v1 *head = head_from_resource(head_resource);
// Create an inert resource if the head no longer exists // Create an inert resource if the head no longer exists
@ -179,6 +185,12 @@ static void config_handle_disable_head(struct wl_client *client,
struct wl_resource *head_resource) { struct wl_resource *head_resource) {
struct wlr_output_configuration_v1 *config = struct wlr_output_configuration_v1 *config =
config_from_resource(config_resource); config_from_resource(config_resource);
if (config == NULL || config->finalized) {
wl_resource_post_error(config_resource,
ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED,
"configuration object has already been used");
return;
}
struct wlr_output_head_v1 *head = head_from_resource(head_resource); struct wlr_output_head_v1 *head = head_from_resource(head_resource);
if (head == NULL) { if (head == NULL) {
return; return;
@ -194,70 +206,165 @@ static void config_handle_disable_head(struct wl_client *client,
config_head->state.enabled = false; config_head->state.enabled = false;
} }
static void config_finalize(struct wlr_output_configuration_v1 *config) {
if (config->finalized) {
return;
}
// Destroy config head resources now, the client is forbidden to use them at
// 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;
}
config->finalized = true;
}
// Destroys the config if serial is invalid
static bool config_validate_serial(struct wlr_output_configuration_v1 *config) {
if (config->serial != config->manager->serial) {
wlr_log(WLR_DEBUG, "Ignored configuration request: invalid serial");
zwlr_output_configuration_v1_send_cancelled(config->resource);
wlr_output_configuration_v1_destroy(config);
return false;
}
return true;
}
static void config_handle_apply(struct wl_client *client, static void config_handle_apply(struct wl_client *client,
struct wl_resource *config_resource) { struct wl_resource *config_resource) {
//struct wlr_output_configuration_v1 *config = struct wlr_output_configuration_v1 *config =
// config_from_resource(config_resource); config_from_resource(config_resource);
// TODO: post already_used if needed if (config == NULL || config->finalized) {
wl_resource_post_error(config_resource,
ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED,
"configuration object has already been used");
return;
}
// TODO config_finalize(config);
if (!config_validate_serial(config)) {
return;
}
wlr_signal_emit_safe(&config->manager->events.apply, config);
}
static void config_handle_test(struct wl_client *client,
struct wl_resource *config_resource) {
struct wlr_output_configuration_v1 *config =
config_from_resource(config_resource);
if (config == NULL || config->finalized) {
wl_resource_post_error(config_resource,
ZWLR_OUTPUT_CONFIGURATION_V1_ERROR_ALREADY_USED,
"configuration object has already been used");
return;
}
config_finalize(config);
if (!config_validate_serial(config)) {
return;
}
wlr_signal_emit_safe(&config->manager->events.test, config);
} }
static void config_handle_destroy(struct wl_client *client, static void config_handle_destroy(struct wl_client *client,
struct wl_resource *config_resource) { struct wl_resource *config_resource) {
wl_resource_destroy(config_resource); wl_resource_destroy(config_resource);
// TODO: destroy head configurations
} }
static const struct zwlr_output_configuration_v1_interface config_impl = { static const struct zwlr_output_configuration_v1_interface config_impl = {
.enable_head = config_handle_enable_head, .enable_head = config_handle_enable_head,
.disable_head = config_handle_disable_head, .disable_head = config_handle_disable_head,
.apply = config_handle_apply, .apply = config_handle_apply,
// TODO: test .test = config_handle_test,
.destroy = config_handle_destroy, .destroy = config_handle_destroy,
}; };
struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void) { static struct wlr_output_configuration_v1 *config_create(bool finalized) {
struct wlr_output_configuration_v1 *config = calloc(1, sizeof(*config)); struct wlr_output_configuration_v1 *config = calloc(1, sizeof(*config));
if (config == NULL) { if (config == NULL) {
return NULL; return NULL;
} }
wl_list_init(&config->heads); wl_list_init(&config->heads);
config->finalized = finalized;
return config; return config;
} }
struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void) {
return config_create(true);
}
void wlr_output_configuration_v1_destroy( void wlr_output_configuration_v1_destroy(
struct wlr_output_configuration_v1 *config) { struct wlr_output_configuration_v1 *config) {
if (config == NULL) { if (config == NULL) {
return; return;
} }
struct wlr_output_configuration_head_v1 *head, *tmp; config_finalize(config);
wl_list_for_each_safe(head, tmp, &config->heads, link) { if (config->resource != NULL) {
config_head_destroy(head); wl_resource_set_user_data(config->resource, NULL); // make inert
}
struct wlr_output_configuration_head_v1 *config_head, *tmp;
wl_list_for_each_safe(config_head, tmp, &config->heads, link) {
config_head_destroy(config_head);
} }
free(config); free(config);
} }
static void config_handle_resource_destroy(struct wl_resource *resource) { static void config_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_output_configuration_v1 *config = config_from_resource(resource); struct wlr_output_configuration_v1 *config = config_from_resource(resource);
wlr_output_configuration_v1_destroy(config); if (config == NULL) {
return;
}
if (config->finalized) {
config->resource = NULL; // we no longer own the config
} else {
wlr_output_configuration_v1_destroy(config);
}
}
void wlr_output_configuration_v1_send_succeeded(
struct wlr_output_configuration_v1 *config) {
assert(!config->finished);
if (config->resource == NULL) {
return; // client destroyed the resource early
}
zwlr_output_configuration_v1_send_succeeded(config->resource);
config->finished = true;
}
void wlr_output_configuration_v1_send_failed(
struct wlr_output_configuration_v1 *config) {
assert(!config->finished);
if (config->resource == NULL) {
return; // client destroyed the resource early
}
zwlr_output_configuration_v1_send_failed(config->resource);
config->finished = true;
} }
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_configuration_v1 *config = struct wlr_output_configuration_v1 *config = config_create(false);
wlr_output_configuration_v1_create(); if (config == NULL) {
wl_resource_post_no_memory(manager_resource);
return;
}
config->serial = serial; config->serial = serial;
uint32_t version = wl_resource_get_version(manager_resource); uint32_t version = wl_resource_get_version(manager_resource);
struct wl_resource *resource = wl_resource_create(client, config->resource = wl_resource_create(client,
&zwlr_output_configuration_v1_interface, version, id); &zwlr_output_configuration_v1_interface, version, id);
if (resource == NULL) { if (config->resource == NULL) {
wl_client_post_no_memory(client); wl_client_post_no_memory(client);
return; return;
} }
wl_resource_set_implementation(resource, &config_impl, wl_resource_set_implementation(config->resource, &config_impl,
config, config_handle_resource_destroy); config, config_handle_resource_destroy);
} }
@ -315,6 +422,8 @@ struct wlr_output_manager_v1 *wlr_output_manager_v1_create(
manager->display = display; manager->display = display;
wl_signal_init(&manager->events.destroy); wl_signal_init(&manager->events.destroy);
wl_signal_init(&manager->events.apply);
wl_signal_init(&manager->events.test);
manager->global = wl_global_create(display, manager->global = wl_global_create(display,
&zwlr_output_manager_v1_interface, OUTPUT_MANAGER_VERSION, &zwlr_output_manager_v1_interface, OUTPUT_MANAGER_VERSION,