diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 8f80e65c..d0bdfcd5 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -211,13 +211,13 @@ static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { } static void wlr_drm_connector_set_gamma(struct wlr_output *output, - uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b) { + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; struct wlr_drm_backend *drm = (struct wlr_drm_backend *)output->backend; drmModeCrtcSetGamma(drm->fd, conn->crtc->id, size, r, g, b); } -static uint16_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { +static uint32_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; drmModeCrtc *crtc = conn->old_crtc; return crtc ? crtc->gamma_size : 0; diff --git a/include/wlr/interfaces/wlr_output.h b/include/wlr/interfaces/wlr_output.h index 338d3375..636cc06c 100644 --- a/include/wlr/interfaces/wlr_output.h +++ b/include/wlr/interfaces/wlr_output.h @@ -18,8 +18,8 @@ struct wlr_output_impl { void (*make_current)(struct wlr_output *output); void (*swap_buffers)(struct wlr_output *output); void (*set_gamma)(struct wlr_output *output, - uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b); - uint16_t (*get_gamma_size)(struct wlr_output *output); + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); + uint32_t (*get_gamma_size)(struct wlr_output *output); }; void wlr_output_init(struct wlr_output *output, struct wlr_backend *backend, diff --git a/include/wlr/types/wlr_gamma_control.h b/include/wlr/types/wlr_gamma_control.h index 96c9f545..59f18494 100644 --- a/include/wlr/types/wlr_gamma_control.h +++ b/include/wlr/types/wlr_gamma_control.h @@ -5,18 +5,28 @@ struct wlr_gamma_control_manager { struct wl_global *wl_global; + struct wl_list controls; // list of wlr_gamma_control void *data; }; struct wlr_gamma_control { struct wl_resource *resource; - struct wl_resource *output; + struct wlr_output *output; + struct wl_list link; + + struct wl_listener output_destroy_listener; + + struct { + struct wl_signal destroy; + } events; void* data; }; -struct wlr_gamma_control_manager *wlr_gamma_control_manager_create(struct wl_display *display); -void wlr_gamma_control_manager_destroy(struct wlr_gamma_control_manager *gamma_control_manager); +struct wlr_gamma_control_manager *wlr_gamma_control_manager_create( + struct wl_display *display); +void wlr_gamma_control_manager_destroy( + struct wlr_gamma_control_manager *gamma_control_manager); #endif diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index d8649bbb..74eb15ed 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -84,7 +84,7 @@ void wlr_output_effective_resolution(struct wlr_output *output, void wlr_output_make_current(struct wlr_output *output); void wlr_output_swap_buffers(struct wlr_output *output); void wlr_output_set_gamma(struct wlr_output *output, - uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b); -uint16_t wlr_output_get_gamma_size(struct wlr_output *output); + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b); +uint32_t wlr_output_get_gamma_size(struct wlr_output *output); #endif diff --git a/types/wlr_gamma_control.c b/types/wlr_gamma_control.c index 973fd613..9d74e749 100644 --- a/types/wlr_gamma_control.c +++ b/types/wlr_gamma_control.c @@ -6,96 +6,155 @@ #include #include "gamma-control-protocol.h" -static void resource_destroy(struct wl_client *client, struct wl_resource *resource) { +static void resource_destroy(struct wl_client *client, + struct wl_resource *resource) { wl_resource_destroy(resource); } -static void gamma_control_destroy(struct wl_resource *resource) { - struct wlr_gamma_control *gamma_control = wl_resource_get_user_data(resource); +static void gamma_control_destroy(struct wlr_gamma_control *gamma_control) { + wl_signal_emit(&gamma_control->events.destroy, gamma_control); + wl_list_remove(&gamma_control->output_destroy_listener.link); + wl_resource_set_user_data(gamma_control->resource, NULL); free(gamma_control); } +static void gamma_control_destroy_resource(struct wl_resource *resource) { + struct wlr_gamma_control *gamma_control = + wl_resource_get_user_data(resource); + gamma_control_destroy(gamma_control); +} + +static void gamma_control_handle_output_destroy(struct wl_listener *listener, + void *data) { + struct wlr_gamma_control *gamma_control = + wl_container_of(listener, gamma_control, output_destroy_listener); + gamma_control_destroy(gamma_control); +} + static void gamma_control_set_gamma(struct wl_client *client, - struct wl_resource *_gamma_control, struct wl_array *red, + struct wl_resource *gamma_control_resource, struct wl_array *red, struct wl_array *green, struct wl_array *blue) { + struct wlr_gamma_control *gamma_control = + wl_resource_get_user_data(gamma_control_resource); + if (red->size != green->size || red->size != blue->size) { - wl_resource_post_error(_gamma_control, GAMMA_CONTROL_ERROR_INVALID_GAMMA, + wl_resource_post_error(gamma_control_resource, + GAMMA_CONTROL_ERROR_INVALID_GAMMA, "The gamma ramps don't have the same size"); return; } + + uint32_t size = red->size / sizeof(uint16_t); uint16_t *r = (uint16_t *)red->data; uint16_t *g = (uint16_t *)green->data; uint16_t *b = (uint16_t *)blue->data; - struct wlr_gamma_control *gamma_control = wl_resource_get_user_data(_gamma_control); - struct wlr_output *output = wl_resource_get_user_data(gamma_control->output); - wlr_output_set_gamma(output, red->size / sizeof(uint16_t), r, g, b); + + wlr_output_set_gamma(gamma_control->output, size, r, g, b); } static void gamma_control_reset_gamma(struct wl_client *client, - struct wl_resource *_gamma_control) { + struct wl_resource *gamma_control_resource) { // TODO } -static const struct gamma_control_interface gamma_control_implementation = { +static const struct gamma_control_interface gamma_control_impl = { .destroy = resource_destroy, .set_gamma = gamma_control_set_gamma, .reset_gamma = gamma_control_reset_gamma, }; static void gamma_control_manager_get_gamma_control(struct wl_client *client, - struct wl_resource *_gamma_control_manager, uint32_t id, - struct wl_resource *_output) { - //struct wlr_gamma_control_manager *gamma_control_manager = - // wl_resource_get_user_data(_gamma_control_manager); - struct wlr_output *output = wl_resource_get_user_data(_output); - struct wlr_gamma_control *gamma_control; - if (!(gamma_control = calloc(1, sizeof(struct wlr_gamma_control)))) { + struct wl_resource *gamma_control_manager_resource, uint32_t id, + struct wl_resource *output_resource) { + struct wlr_gamma_control_manager *gamma_control_manager = + wl_resource_get_user_data(gamma_control_manager_resource); + struct wlr_output *output = wl_resource_get_user_data(output_resource); + + struct wlr_gamma_control *gamma_control = + calloc(1, sizeof(struct wlr_gamma_control)); + if (gamma_control == NULL) { + wl_client_post_no_memory(client); return; } - gamma_control->output = _output; + gamma_control->output = output; + + int version = wl_resource_get_version(gamma_control_manager_resource); gamma_control->resource = wl_resource_create(client, - &gamma_control_interface, wl_resource_get_version(_gamma_control_manager), id); - wlr_log(L_DEBUG, "new gamma_control %p (res %p)", gamma_control, gamma_control->resource); + &gamma_control_interface, version, id); + if (gamma_control->resource == NULL) { + wl_client_post_no_memory(client); + free(gamma_control); + return; + } + wlr_log(L_DEBUG, "new gamma_control %p (res %p)", gamma_control, + gamma_control->resource); wl_resource_set_implementation(gamma_control->resource, - &gamma_control_implementation, gamma_control, gamma_control_destroy); - gamma_control_send_gamma_size(gamma_control->resource, wlr_output_get_gamma_size(output)); + &gamma_control_impl, gamma_control, gamma_control_destroy_resource); + + wl_signal_init(&gamma_control->events.destroy); + + wl_signal_add(&output->events.destroy, + &gamma_control->output_destroy_listener); + gamma_control->output_destroy_listener.notify = + gamma_control_handle_output_destroy; + + wl_list_insert(&gamma_control_manager->controls, &gamma_control->link); + + gamma_control_send_gamma_size(gamma_control->resource, + wlr_output_get_gamma_size(output)); } static struct gamma_control_manager_interface gamma_control_manager_impl = { .get_gamma_control = gamma_control_manager_get_gamma_control, }; -static void gamma_control_manager_bind(struct wl_client *wl_client, +static void gamma_control_manager_bind(struct wl_client *client, void *_gamma_control_manager, uint32_t version, uint32_t id) { - struct wlr_gamma_control_manager *gamma_control_manager = _gamma_control_manager; - assert(wl_client && gamma_control_manager); + struct wlr_gamma_control_manager *gamma_control_manager = + _gamma_control_manager; + assert(client && gamma_control_manager); - struct wl_resource *wl_resource = wl_resource_create( - wl_client, &gamma_control_manager_interface, version, id); - wl_resource_set_implementation(wl_resource, &gamma_control_manager_impl, + struct wl_resource *resource = wl_resource_create(client, + &gamma_control_manager_interface, version, id); + if (resource == NULL) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &gamma_control_manager_impl, gamma_control_manager, NULL); } -struct wlr_gamma_control_manager *wlr_gamma_control_manager_create(struct wl_display *display) { +struct wlr_gamma_control_manager *wlr_gamma_control_manager_create( + struct wl_display *display) { struct wlr_gamma_control_manager *gamma_control_manager = calloc(1, sizeof(struct wlr_gamma_control_manager)); if (!gamma_control_manager) { return NULL; } struct wl_global *wl_global = wl_global_create(display, - &gamma_control_manager_interface, 1, gamma_control_manager, gamma_control_manager_bind); + &gamma_control_manager_interface, 1, gamma_control_manager, + gamma_control_manager_bind); if (!wl_global) { free(gamma_control_manager); return NULL; } gamma_control_manager->wl_global = wl_global; + + wl_list_init(&gamma_control_manager->controls); + return gamma_control_manager; } -void wlr_gamma_control_manager_destroy(struct wlr_gamma_control_manager *gamma_control_manager) { +void wlr_gamma_control_manager_destroy( + struct wlr_gamma_control_manager *gamma_control_manager) { if (!gamma_control_manager) { return; } + struct wlr_gamma_control *gamma_control, *tmp; + wl_list_for_each_safe(gamma_control, tmp, &gamma_control_manager->controls, + link) { + gamma_control_destroy(gamma_control); + } // TODO: this segfault (wl_display->registry_resource_list is not init) // wl_global_destroy(gamma_control_manager->wl_global); free(gamma_control_manager); diff --git a/types/wlr_output.c b/types/wlr_output.c index eb5bdd26..a02798b2 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -404,13 +404,13 @@ void wlr_output_swap_buffers(struct wlr_output *output) { } void wlr_output_set_gamma(struct wlr_output *output, - uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b) { + uint32_t size, uint16_t *r, uint16_t *g, uint16_t *b) { if (output->impl->set_gamma) { output->impl->set_gamma(output, size, r, g, b); } } -uint16_t wlr_output_get_gamma_size(struct wlr_output *output) { +uint32_t wlr_output_get_gamma_size(struct wlr_output *output) { if (!output->impl->get_gamma_size) { return 0; }