aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_output_management_v1.h12
-rw-r--r--types/wlr_output_management_v1.c143
2 files changed, 138 insertions, 17 deletions
diff --git a/include/wlr/types/wlr_output_management_v1.h b/include/wlr/types/wlr_output_management_v1.h
index 55d15528..b7272cfe 100644
--- a/include/wlr/types/wlr_output_management_v1.h
+++ b/include/wlr/types/wlr_output_management_v1.h
@@ -9,6 +9,7 @@
#ifndef WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
#define WLR_TYPES_WLR_OUTPUT_MANAGEMENT_V1_H
+#include <stdbool.h>
#include <wayland-server.h>
#include <wlr/types/wlr_output.h>
@@ -21,6 +22,8 @@ struct wlr_output_manager_v1 {
uint32_t serial;
struct {
+ struct wl_signal apply; // wlr_output_configuration_v1
+ struct wl_signal test; // wlr_output_configuration_v1
struct wl_signal destroy;
} events;
@@ -47,7 +50,12 @@ struct wlr_output_head_v1 {
struct wlr_output_configuration_v1 {
struct wl_list heads; // wlr_output_configuration_head_v1::link
+
+ 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 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);
void wlr_output_configuration_v1_destroy(
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 *
wlr_output_configuration_head_v1_create(
diff --git a/types/wlr_output_management_v1.c b/types/wlr_output_management_v1.c
index 66d3c454..4d9a5672 100644
--- a/types/wlr_output_management_v1.c
+++ b/types/wlr_output_management_v1.c
@@ -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;
+// Can return NULL if the config has been used
static struct wlr_output_configuration_v1 *config_from_resource(
struct wl_resource *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 wlr_output_configuration_v1 *config =
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);
// 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 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;
+ }
struct wlr_output_head_v1 *head = head_from_resource(head_resource);
if (head == NULL) {
return;
@@ -194,70 +206,165 @@ static void config_handle_disable_head(struct wl_client *client,
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,
struct wl_resource *config_resource) {
- //struct wlr_output_configuration_v1 *config =
- // config_from_resource(config_resource);
- // TODO: post already_used if needed
+ 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;
+ }
- // 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,
struct wl_resource *config_resource) {
wl_resource_destroy(config_resource);
- // TODO: destroy head configurations
}
static const struct zwlr_output_configuration_v1_interface config_impl = {
.enable_head = config_handle_enable_head,
.disable_head = config_handle_disable_head,
.apply = config_handle_apply,
- // TODO: test
+ .test = config_handle_test,
.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));
if (config == NULL) {
return NULL;
}
wl_list_init(&config->heads);
+ config->finalized = finalized;
return config;
}
+struct wlr_output_configuration_v1 *wlr_output_configuration_v1_create(void) {
+ return config_create(true);
+}
+
void wlr_output_configuration_v1_destroy(
struct wlr_output_configuration_v1 *config) {
if (config == NULL) {
return;
}
- struct wlr_output_configuration_head_v1 *head, *tmp;
- wl_list_for_each_safe(head, tmp, &config->heads, link) {
- config_head_destroy(head);
+ config_finalize(config);
+ if (config->resource != NULL) {
+ 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);
}
static void config_handle_resource_destroy(struct wl_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,
struct wl_resource *manager_resource, uint32_t id, uint32_t serial) {
- struct wlr_output_configuration_v1 *config =
- wlr_output_configuration_v1_create();
+ struct wlr_output_configuration_v1 *config = config_create(false);
+ if (config == NULL) {
+ wl_resource_post_no_memory(manager_resource);
+ return;
+ }
config->serial = serial;
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);
- if (resource == NULL) {
+ if (config->resource == NULL) {
wl_client_post_no_memory(client);
return;
}
- wl_resource_set_implementation(resource, &config_impl,
+ wl_resource_set_implementation(config->resource, &config_impl,
config, config_handle_resource_destroy);
}
@@ -315,6 +422,8 @@ struct wlr_output_manager_v1 *wlr_output_manager_v1_create(
manager->display = display;
wl_signal_init(&manager->events.destroy);
+ wl_signal_init(&manager->events.apply);
+ wl_signal_init(&manager->events.test);
manager->global = wl_global_create(display,
&zwlr_output_manager_v1_interface, OUTPUT_MANAGER_VERSION,