output: introduce wlr_output_schedule_done

This commit introduces wlr_output_schedule_done and refactors the mechanism
used to send wl_output events to clients.

wlr_output_schedule_done schedules a wl_output.done event. This allows clients
to see wlr_output property changes as atomic.

This function is also useful for add-on interfaces like xdg_output which need
to trigger a wl_output.done event to apply their new state.
This commit is contained in:
Simon Ser 2019-04-27 12:25:40 +03:00 committed by Drew DeVault
parent 8b1220f5a3
commit bde5a1f4ea
2 changed files with 80 additions and 41 deletions

View File

@ -125,6 +125,7 @@ struct wlr_output {
} events; } events;
struct wl_event_source *idle_frame; struct wl_event_source *idle_frame;
struct wl_event_source *idle_done;
struct wl_list cursors; // wlr_output_cursor::link struct wl_list cursors; // wlr_output_cursor::link
struct wlr_output_cursor *hardware_cursor; struct wlr_output_cursor *hardware_cursor;
@ -194,7 +195,14 @@ bool wlr_output_set_custom_mode(struct wlr_output *output, int32_t width,
void wlr_output_set_transform(struct wlr_output *output, void wlr_output_set_transform(struct wlr_output *output,
enum wl_output_transform transform); enum wl_output_transform transform);
void wlr_output_set_scale(struct wlr_output *output, float scale); void wlr_output_set_scale(struct wlr_output *output, float scale);
void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel subpixel); void wlr_output_set_subpixel(struct wlr_output *output,
enum wl_output_subpixel subpixel);
/**
* Schedule a done event.
*
* This is intended to be used by wl_output add-on interfaces.
*/
void wlr_output_schedule_done(struct wlr_output *output);
void wlr_output_destroy(struct wlr_output *output); void wlr_output_destroy(struct wlr_output *output);
/** /**
* Computes the transformed output resolution. * Computes the transformed output resolution.

View File

@ -19,15 +19,16 @@
#define OUTPUT_VERSION 3 #define OUTPUT_VERSION 3
static void output_send_to_resource(struct wl_resource *resource) { static void send_geometry(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource); struct wlr_output *output = wlr_output_from_resource(resource);
const uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_GEOMETRY_SINCE_VERSION) {
wl_output_send_geometry(resource, 0, 0, wl_output_send_geometry(resource, 0, 0,
output->phys_width, output->phys_height, output->subpixel, output->phys_width, output->phys_height, output->subpixel,
output->make, output->model, output->transform); output->make, output->model, output->transform);
} }
if (version >= WL_OUTPUT_MODE_SINCE_VERSION) {
static void send_all_modes(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
struct wlr_output_mode *mode; struct wlr_output_mode *mode;
wl_list_for_each(mode, &output->modes, link) { wl_list_for_each(mode, &output->modes, link) {
uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED;
@ -38,27 +39,15 @@ static void output_send_to_resource(struct wl_resource *resource) {
mode->refresh); mode->refresh);
} }
if (wl_list_length(&output->modes) == 0) { if (wl_list_empty(&output->modes)) {
// Output has no mode, send the current width/height // Output has no mode, send the current width/height
wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT,
output->width, output->height, output->refresh); output->width, output->height, output->refresh);
} }
}
if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) {
wl_output_send_scale(resource, (uint32_t)ceil(output->scale));
}
if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
wl_output_send_done(resource);
}
} }
static void output_send_current_mode_to_resource( static void send_current_mode(struct wl_resource *resource) {
struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource); struct wlr_output *output = wlr_output_from_resource(resource);
const uint32_t version = wl_resource_get_version(resource);
if (version < WL_OUTPUT_MODE_SINCE_VERSION) {
return;
}
if (output->current_mode != NULL) { if (output->current_mode != NULL) {
struct wlr_output_mode *mode = output->current_mode; struct wlr_output_mode *mode = output->current_mode;
uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED; uint32_t flags = mode->flags & WL_OUTPUT_MODE_PREFERRED;
@ -69,6 +58,18 @@ static void output_send_current_mode_to_resource(
wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, output->width, wl_output_send_mode(resource, WL_OUTPUT_MODE_CURRENT, output->width,
output->height, output->refresh); output->height, output->refresh);
} }
}
static void send_scale(struct wl_resource *resource) {
struct wlr_output *output = wlr_output_from_resource(resource);
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_SCALE_SINCE_VERSION) {
wl_output_send_scale(resource, (uint32_t)ceil(output->scale));
}
}
static void send_done(struct wl_resource *resource) {
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_DONE_SINCE_VERSION) { if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
wl_output_send_done(resource); wl_output_send_done(resource);
} }
@ -100,7 +101,11 @@ static void output_bind(struct wl_client *wl_client, void *data,
wl_resource_set_implementation(resource, &output_impl, output, wl_resource_set_implementation(resource, &output_impl, output,
output_handle_resource_destroy); output_handle_resource_destroy);
wl_list_insert(&output->resources, wl_resource_get_link(resource)); wl_list_insert(&output->resources, wl_resource_get_link(resource));
output_send_to_resource(resource);
send_geometry(resource);
send_all_modes(resource);
send_scale(resource);
send_done(resource);
} }
void wlr_output_create_global(struct wlr_output *output) { void wlr_output_create_global(struct wlr_output *output) {
@ -203,8 +208,9 @@ void wlr_output_update_custom_mode(struct wlr_output *output, int32_t width,
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) { wl_resource_for_each(resource, &output->resources) {
output_send_current_mode_to_resource(resource); send_current_mode(resource);
} }
wlr_output_schedule_done(output);
wlr_signal_emit_safe(&output->events.mode, output); wlr_signal_emit_safe(&output->events.mode, output);
} }
@ -214,11 +220,11 @@ void wlr_output_set_transform(struct wlr_output *output,
output->impl->transform(output, transform); output->impl->transform(output, transform);
output_update_matrix(output); output_update_matrix(output);
// TODO: only send geometry and done
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) { wl_resource_for_each(resource, &output->resources) {
output_send_to_resource(resource); send_geometry(resource);
} }
wlr_output_schedule_done(output);
wlr_signal_emit_safe(&output->events.transform, output); wlr_signal_emit_safe(&output->events.transform, output);
} }
@ -230,16 +236,17 @@ void wlr_output_set_scale(struct wlr_output *output, float scale) {
output->scale = scale; output->scale = scale;
// TODO: only send mode and done
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) { wl_resource_for_each(resource, &output->resources) {
output_send_to_resource(resource); send_scale(resource);
} }
wlr_output_schedule_done(output);
wlr_signal_emit_safe(&output->events.scale, output); wlr_signal_emit_safe(&output->events.scale, output);
} }
void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel subpixel) { void wlr_output_set_subpixel(struct wlr_output *output,
enum wl_output_subpixel subpixel) {
if (output->subpixel == subpixel) { if (output->subpixel == subpixel) {
return; return;
} }
@ -248,8 +255,32 @@ void wlr_output_set_subpixel(struct wlr_output *output, enum wl_output_subpixel
struct wl_resource *resource; struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) { wl_resource_for_each(resource, &output->resources) {
output_send_to_resource(resource); send_geometry(resource);
} }
wlr_output_schedule_done(output);
}
static void schedule_done_handle_idle_timer(void *data) {
struct wlr_output *output = data;
output->idle_done = NULL;
struct wl_resource *resource;
wl_resource_for_each(resource, &output->resources) {
uint32_t version = wl_resource_get_version(resource);
if (version >= WL_OUTPUT_DONE_SINCE_VERSION) {
wl_output_send_done(resource);
}
}
}
void wlr_output_schedule_done(struct wlr_output *output) {
if (output->idle_done != NULL) {
return; // Already scheduled
}
struct wl_event_loop *ev = wl_display_get_event_loop(output->display);
output->idle_done =
wl_event_loop_add_idle(ev, schedule_done_handle_idle_timer, output);
} }
static void handle_display_destroy(struct wl_listener *listener, void *data) { static void handle_display_destroy(struct wl_listener *listener, void *data) {