From 1d97202ec2b9ca3c4b77e0cc5ab2a574c3938447 Mon Sep 17 00:00:00 2001 From: emersion Date: Mon, 23 Jul 2018 22:48:00 +0100 Subject: [PATCH] examples: add gamma-control --- examples/gamma-control.c | 190 +++++++++++++++++++++++++++++++++++++++ examples/meson.build | 6 ++ protocol/meson.build | 1 + 3 files changed, 197 insertions(+) create mode 100644 examples/gamma-control.c diff --git a/examples/gamma-control.c b/examples/gamma-control.c new file mode 100644 index 000000000..161c6fd0e --- /dev/null +++ b/examples/gamma-control.c @@ -0,0 +1,190 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "wlr-gamma-control-unstable-v1-client-protocol.h" + +struct output { + struct wl_output *wl_output; + struct zwlr_gamma_control_v1 *gamma_control; + uint32_t ramp_size; + int table_fd; + uint16_t *table; + struct wl_list link; +}; + +static struct wl_list outputs; +static struct zwlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + +static int create_anonymous_file(off_t size) { + char template[] = "/tmp/wlroots-shared-XXXXXX"; + int fd = mkstemp(template); + if (fd < 0) { + return -1; + } + + int ret; + do { + errno = 0; + ret = ftruncate(fd, size); + } while (errno == EINTR); + if (ret < 0) { + close(fd); + return -1; + } + + unlink(template); + return fd; +} + +static int create_gamma_table(uint32_t ramp_size, uint16_t **table) { + size_t table_size = ramp_size * 3 * sizeof(uint16_t); + int fd = create_anonymous_file(table_size); + if (fd < 0) { + fprintf(stderr, "failed to create anonymous file\n"); + return -1; + } + + void *data = + mmap(NULL, table_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + fprintf(stderr, "failed to mmap()\n"); + close(fd); + return -1; + } + + *table = data; + return fd; +} + +static void gamma_control_handle_gamma_size(void *data, + struct zwlr_gamma_control_v1 *gamma_control, uint32_t ramp_size) { + struct output *output = data; + output->ramp_size = ramp_size; + output->table_fd = create_gamma_table(ramp_size, &output->table); + if (output->table_fd < 0) { + exit(EXIT_FAILURE); + } +} + +static void gamma_control_handle_failed(void *data, + struct zwlr_gamma_control_v1 *gamma_control) { + fprintf(stderr, "failed to set gamma table\n"); + exit(EXIT_FAILURE); +} + +static const struct zwlr_gamma_control_v1_listener gamma_control_listener = { + .gamma_size = gamma_control_handle_gamma_size, + .failed = gamma_control_handle_failed, +}; + +static void registry_handle_global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) { + if (strcmp(interface, wl_output_interface.name) == 0) { + struct output *output = calloc(1, sizeof(struct output)); + output->wl_output = wl_registry_bind(registry, name, + &wl_output_interface, 1); + wl_list_insert(&outputs, &output->link); + } else if (strcmp(interface, + zwlr_gamma_control_manager_v1_interface.name) == 0) { + gamma_control_manager = wl_registry_bind(registry, name, + &zwlr_gamma_control_manager_v1_interface, 1); + } +} + +static void registry_handle_global_remove(void *data, + struct wl_registry *registry, uint32_t name) { + // Who cares? +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; + +static void fill_gamma_table(uint16_t *table, uint32_t ramp_size, + double contrast, double brightness, double gamma) { + uint16_t *r = table; + uint16_t *g = table + ramp_size; + uint16_t *b = table + 2 * ramp_size; + for (uint32_t i = 0; i < ramp_size; ++i) { + double val = (double)i / (ramp_size - 1); + val = contrast * pow(val, 1.0 / gamma) + brightness; + r[i] = g[i] = b[i] = (uint16_t)(UINT16_MAX * val); + } +} + +static const char usage[] = "usage: gamma-control [options]\n" + " -h show this help message\n" + " -c set contrast (default: 1)\n" + " -b set brightness (default: 0)\n" + " -g set gamma (default: 1)\n"; + +int main(int argc, char *argv[]) { + wl_list_init(&outputs); + + double contrast = 1, brightness = 0, gamma = 1; + int opt; + while ((opt = getopt(argc, argv, "hc:b:g:")) != -1) { + switch (opt) { + case 'c': + contrast = strtod(optarg, NULL); + break; + case 'b': + brightness = strtod(optarg, NULL); + break; + case 'g': + gamma = strtod(optarg, NULL); + break; + case 'h': + default: + fprintf(stderr, usage); + return opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; + } + } + + struct wl_display *display = wl_display_connect(NULL); + if (display == NULL) { + fprintf(stderr, "failed to create display\n"); + return -1; + } + + struct wl_registry *registry = wl_display_get_registry(display); + wl_registry_add_listener(registry, ®istry_listener, NULL); + wl_display_dispatch(display); + wl_display_roundtrip(display); + + if (gamma_control_manager == NULL) { + fprintf(stderr, + "compositor doesn't support wlr-gamma-control-unstable-v1\n"); + return EXIT_FAILURE; + } + + struct output *output; + wl_list_for_each(output, &outputs, link) { + output->gamma_control = zwlr_gamma_control_manager_v1_get_gamma_control( + gamma_control_manager, output->wl_output); + zwlr_gamma_control_v1_add_listener(output->gamma_control, + &gamma_control_listener, output); + } + wl_display_roundtrip(display); + + wl_list_for_each(output, &outputs, link) { + fill_gamma_table(output->table, output->ramp_size, + contrast, brightness, gamma); + zwlr_gamma_control_v1_set_gamma(output->gamma_control, + output->table_fd); + } + + while (wl_display_dispatch(display) != -1) { + // This space is intentionnally left blank + } + + return EXIT_SUCCESS; +} diff --git a/examples/meson.build b/examples/meson.build index 26d208509..25ad7566e 100644 --- a/examples/meson.build +++ b/examples/meson.build @@ -50,6 +50,12 @@ executable( dependencies: [wayland_cursor, wayland_client, wlr_protos, wlroots] ) +executable( + 'gamma-control', + 'gamma-control.c', + dependencies: [wayland_cursor, wayland_client, wlr_protos, wlroots] +) + if libavutil.found() and libavcodec.found() and libavformat.found() executable( 'dmabuf-capture', diff --git a/protocol/meson.build b/protocol/meson.build index 23da1afc0..73a3156a7 100644 --- a/protocol/meson.build +++ b/protocol/meson.build @@ -56,6 +56,7 @@ client_protocols = [ 'idle.xml', 'screenshooter.xml', 'wlr-export-dmabuf-unstable-v1.xml', + 'wlr-gamma-control-unstable-v1.xml', 'wlr-input-inhibitor-unstable-v1.xml', 'wlr-layer-shell-unstable-v1.xml', 'wlr-screencopy-unstable-v1.xml',