aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rootston/output.h2
-rw-r--r--include/wlr/types/wlr_output_management_v1.h6
-rw-r--r--rootston/desktop.c20
-rw-r--r--rootston/output.c46
-rw-r--r--types/wlr_output_management_v1.c108
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);