From b3fbc67c9e19672c58e95d7f3387b3d1cdc9aab9 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Fri, 1 May 2015 23:56:03 +0300 Subject: [PATCH 1/4] Add support for some wayland compositors This uses a protocol extension, not in core Wayland. --- configure.ac | 31 ++++++ po/POTFILES.in | 1 + src/Makefile.am | 22 ++++ src/gamma-control.xml | 57 ++++++++++ src/gamma-wl.c | 246 ++++++++++++++++++++++++++++++++++++++++++ src/gamma-wl.h | 51 +++++++++ src/redshift.c | 19 ++++ 7 files changed, 427 insertions(+) create mode 100644 src/gamma-control.xml create mode 100644 src/gamma-wl.c create mode 100644 src/gamma-wl.h diff --git a/configure.ac b/configure.ac index 5659776d..1eb018f4 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,12 @@ PKG_CHECK_MODULES([XF86VM], [xxf86vm], [have_xf86vm=yes], [have_xf86vm=no]) PKG_CHECK_MODULES([XCB], [xcb], [have_xcb=yes], [have_xcb=no]) PKG_CHECK_MODULES([XCB_RANDR], [xcb-randr], [have_xcb_randr=yes], [have_xcb_randr=no]) +PKG_CHECK_MODULES([WAYLAND], [wayland-client wayland-scanner], [have_wayland=yes], [have_wayland=no]) +AC_PATH_PROG([wayland_scanner], [wayland-scanner]) +if test x$wayland_scanner = x; then + PKG_CHECK_MODULES(WAYLAND_SCANNER, [wayland-scanner]) + wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner` +fi PKG_CHECK_MODULES([GLIB], [glib-2.0 gobject-2.0], [have_glib=yes], [have_glib=no]) PKG_CHECK_MODULES([GEOCLUE], [geoclue], [have_geoclue=yes], [have_geoclue=no]) @@ -104,6 +110,30 @@ AS_IF([test "x$enable_drm" != xno], [ ]) AM_CONDITIONAL([ENABLE_DRM], [test "x$enable_drm" = xyes]) +# Check Wayland method +AC_MSG_CHECKING([whether to enable Wayland method]) +AC_ARG_ENABLE([wayland], [AC_HELP_STRING([--enable-wayland], + [enable Wayland method])], + [enable_wayland=$enableval],[enable_wayland=maybe]) +AS_IF([test "x$enable_wayland" != xno], [ + AS_IF([test $have_wayland = yes], [ + AC_DEFINE([ENABLE_WAYLAND], 1, + [Define to 1 to enable Wayland method]) + AC_MSG_RESULT([yes]) + enable_wayland=yes + ], [ + AC_MSG_RESULT([missing dependencies]) + AS_IF([test "x$enable_wayland" = xyes], [ + AC_MSG_ERROR([missing dependencies for Wayland method]) + ]) + enable_wayland=no + ]) +], [ + AC_MSG_RESULT([no]) + enable_wayland=no +]) +AM_CONDITIONAL([ENABLE_WAYLAND], [test "x$enable_wayland" = xyes]) + # Check RANDR method AC_MSG_CHECKING([whether to enable RANDR method]) AC_ARG_ENABLE([randr], [AC_HELP_STRING([--enable-randr], @@ -365,6 +395,7 @@ echo " Adjustment methods: DRM: ${enable_drm} + Wayland: ${enable_wayland} RANDR: ${enable_randr} VidMode: ${enable_vidmode} Quartz (OSX): ${enable_quartz} diff --git a/po/POTFILES.in b/po/POTFILES.in index 4241670b..0ff9c392 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -9,6 +9,7 @@ src/redshift.c src/config-ini.c src/gamma-drm.c +src/gamma-wl.c src/gamma-randr.c src/gamma-vidmode.c src/gamma-quartz.c diff --git a/src/Makefile.am b/src/Makefile.am index c7a5444e..546eb6e7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -20,12 +20,19 @@ redshift_SOURCES = \ EXTRA_redshift_SOURCES = \ gamma-drm.c gamma-drm.h \ + gamma-wl.c gamma-wl.h \ + gamma-control-protocol.c \ + gamma-control-client-protocol.h \ gamma-randr.c gamma-randr.h \ gamma-vidmode.c gamma-vidmode.h \ gamma-quartz.c gamma-quartz.h \ gamma-w32gdi.c gamma-w32gdi.h \ location-geoclue.c location-geoclue.h +BUILT_SOURCES = \ + gamma-control-protocol.c \ + gamma-control-client-protocol.h + AM_CFLAGS = redshift_LDADD = @LIBINTL@ EXTRA_DIST = @@ -37,6 +44,15 @@ redshift_LDADD += \ $(DRM_LIBS) $(DRM_CFLAGS) endif +if ENABLE_WAYLAND +redshift_SOURCES += gamma-wl.c gamma-wl.h \ + gamma-control-client-protocol.h \ + gamma-control-protocol.c +AM_CFLAGS += $(WAYLAND_CFLAGS) +redshift_LDADD += \ + $(WAYLAND_LIBS) $(WAYLAND_CFLAGS) +endif + if ENABLE_RANDR redshift_SOURCES += gamma-randr.c gamma-randr.h AM_CFLAGS += $(XCB_CFLAGS) $(XCB_RANDR_CFLAGS) @@ -98,3 +114,9 @@ liblocation_corelocation_la_LIBADD = \ $(CORELOCATION_CFLAGS) $(CORELOCATION_LIBS) redshift_LDADD += liblocation-corelocation.la endif + +%-protocol.c : $(srcdir)/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ + +%-client-protocol.h : $(srcdir)/%.xml + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@ diff --git a/src/gamma-control.xml b/src/gamma-control.xml new file mode 100644 index 00000000..e6e33265 --- /dev/null +++ b/src/gamma-control.xml @@ -0,0 +1,57 @@ + + + + + Copyright © 2015 Giulio camuffo + + Permission to use, copy, modify, distribute, and sell this + software and its documentation for any purpose is hereby granted + without fee, provided that the above copyright notice appear in + all copies and that both that copyright notice and this permission + notice appear in supporting documentation, and that the name of + the copyright holders not be used in advertising or publicity + pertaining to distribution of the software without specific, + written prior permission. The copyright holders make no + representations about the suitability of this software for any + purpose. It is provided "as is" without express or implied + warranty. + + THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS + SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY + SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN + AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF + THIS SOFTWARE. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/gamma-wl.c b/src/gamma-wl.c new file mode 100644 index 00000000..7c46a469 --- /dev/null +++ b/src/gamma-wl.c @@ -0,0 +1,246 @@ +/* gamma-wl.c -- Wayland gamma adjustment header + This file is part of Redshift. + + Redshift is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Redshift is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Redshift. If not, see . + + Copyright (c) 2015 Giulio Camuffo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENABLE_NLS +# include +# define _(s) gettext(s) +#else +# define _(s) s +#endif + +#include "gamma-wl.h" +#include "colorramp.h" + +#include "gamma-control-client-protocol.h" + +struct output { + uint32_t global_id; + struct wl_output *output; + struct gamma_control *gamma_control; + uint32_t gamma_size; +}; + +int +wayland_init(wayland_state_t *state) +{ + /* Initialize state. */ + memset(state, 0, sizeof *state); + return 0; +} + +static void +registry_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) +{ + wayland_state_t *state = data; + + if (strcmp(interface, "gamma_control_manager") == 0) { + state->gamma_control_manager_id = id; + state->gamma_control_manager = wl_registry_bind(registry, id, &gamma_control_manager_interface, 1); + } else if (strcmp(interface, "wl_output") == 0) { + if (state->num_outputs++ == 0) { + state->outputs = malloc(sizeof(struct output)); + } else { + state->outputs = realloc(state->outputs, state->num_outputs * sizeof(struct output)); + } + if (!state->outputs) { + fprintf(stderr, _("Failed to allcate memory\n")); + return; + } + + struct output *output = &state->outputs[state->num_outputs - 1]; + output->global_id = id; + output->output = wl_registry_bind(registry, id, &wl_output_interface, 1); + } +} + +static void +registry_global_remove(void *data, struct wl_registry *registry, uint32_t id) +{ + wayland_state_t *state = data; + + if (state->gamma_control_manager_id == id) { + fprintf(stderr, _("The gamma_control_manager was removed\n")); + exit(EXIT_FAILURE); + } + + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + if (output->global_id == id) { + gamma_control_destroy(output->gamma_control); + wl_output_destroy(output->output); + + /* If the removed output is not the last one in the array move the last one + * in the now empty slot. Then shrink the array */ + if (i < --state->num_outputs) { + memcpy(output, &state->outputs[state->num_outputs], sizeof(struct output)); + } + state->outputs = realloc(state->outputs, state->num_outputs * sizeof(struct output)); + + return; + } + } +} + +static const struct wl_registry_listener registry_listener = { + registry_global, + registry_global_remove +}; + +static void +gamma_control_gamma_size(void *data, struct gamma_control *control, uint32_t size) +{ + struct output *output = data; + output->gamma_size = size; +} + +static const struct gamma_control_listener gamma_control_listener = { + gamma_control_gamma_size +}; + +int +wayland_start(wayland_state_t *state) +{ + state->display = wl_display_connect(NULL); + state->registry = wl_display_get_registry(state->display); + + wl_registry_add_listener(state->registry, ®istry_listener, state); + + wl_display_roundtrip(state->display); + if (!state->gamma_control_manager) { + return -1; + } + if (state->num_outputs > 0 && !state->outputs) { + return -1; + } + + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + output->gamma_control = gamma_control_manager_get_gamma_control(state->gamma_control_manager, output->output); + gamma_control_add_listener(output->gamma_control, &gamma_control_listener, output); + } + wl_display_roundtrip(state->display); + + return 0; +} + +void +wayland_restore(wayland_state_t *state) +{ + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + gamma_control_reset_gamma(output->gamma_control); + } + wl_display_flush(state->display); +} + +void +wayland_free(wayland_state_t *state) +{ + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + gamma_control_destroy(output->gamma_control); + wl_output_destroy(output->output); + } + + gamma_control_manager_destroy(state->gamma_control_manager); + wl_registry_destroy(state->registry); + wl_display_disconnect(state->display); +} + +void +wayland_print_help(FILE *f) +{ + fputs(_("Adjust gamma ramps with a Wayland compositor.\n"), f); + fputs("\n", f); +} + +int +wayland_set_option(wayland_state_t *state, const char *key, const char *value) +{ + return 0; +} + +int +wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) +{ + struct wl_array red; + struct wl_array green; + struct wl_array blue; + uint16_t *r_gamma = NULL; + uint16_t *g_gamma = NULL; + uint16_t *b_gamma = NULL; + + wl_array_init(&red); + wl_array_init(&green); + wl_array_init(&blue); + + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + int size = output->gamma_size; + size_t byteSize = size * sizeof(uint16_t); + + if (red.size < byteSize) { + wl_array_add(&red, byteSize - red.size); + } + if (green.size < byteSize) { + wl_array_add(&green, byteSize - green.size); + } + if (blue.size < byteSize) { + wl_array_add(&blue, byteSize - blue.size); + } + + r_gamma = red.data; + g_gamma = green.data; + b_gamma = blue.data; + + if (!r_gamma || !g_gamma || !b_gamma) { + return -1; + } + + /* Initialize gamma ramps to pure state */ + for (int i = 0; i < size; i++) { + uint16_t value = (double)i / size * (UINT16_MAX+1); + r_gamma[i] = value; + g_gamma[i] = value; + b_gamma[i] = value; + } + + colorramp_fill(r_gamma, g_gamma, b_gamma, size, setting); + + gamma_control_set_gamma(output->gamma_control, &red, &green, &blue); + } + + wl_display_flush(state->display); + + wl_array_release(&red); + wl_array_release(&green); + wl_array_release(&blue); + + return 0; +} diff --git a/src/gamma-wl.h b/src/gamma-wl.h new file mode 100644 index 00000000..dd7d99a6 --- /dev/null +++ b/src/gamma-wl.h @@ -0,0 +1,51 @@ +/* gamma-wl.h -- Wayland gamma adjustment header + This file is part of Redshift. + + Redshift is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Redshift is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Redshift. If not, see . + + Copyright (c) 2015 Giulio Camuffo +*/ + +#ifndef REDSHIFT_GAMMA_WAYLAND_H +#define REDSHIFT_GAMMA_WAYLAND_H + +#include + +#include + +#include "redshift.h" + +typedef struct { + struct wl_display *display; + struct wl_registry *registry; + uint32_t gamma_control_manager_id; + struct gamma_control_manager *gamma_control_manager; + int num_outputs; + struct output *outputs; +} wayland_state_t; + + +int wayland_init(wayland_state_t *state); +int wayland_start(wayland_state_t *state); +void wayland_free(wayland_state_t *state); + +void wayland_print_help(FILE *f); +int wayland_set_option(wayland_state_t *state, const char *key, const char *value); + +void wayland_restore(wayland_state_t *state); +int wayland_set_temperature(wayland_state_t *state, + const color_setting_t *setting); + + +#endif /* ! REDSHIFT_GAMMA_DRM_H */ diff --git a/src/redshift.c b/src/redshift.c index defd0a16..47fb5f04 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -61,6 +61,10 @@ # include "gamma-drm.h" #endif +#ifdef ENABLE_WAYLAND +# include "gamma-wl.h" +#endif + #ifdef ENABLE_RANDR # include "gamma-randr.h" #endif @@ -100,6 +104,9 @@ typedef union { #ifdef ENABLE_DRM drm_state_t drm; #endif +#ifdef ENABLE_WAYLAND + wayland_state_t wayland; +#endif #ifdef ENABLE_RANDR randr_state_t randr; #endif @@ -129,6 +136,18 @@ static const gamma_method_t gamma_methods[] = { (gamma_method_set_temperature_func *)drm_set_temperature }, #endif +#ifdef ENABLE_WAYLAND + { + "wayland", 0, + (gamma_method_init_func *)wayland_init, + (gamma_method_start_func *)wayland_start, + (gamma_method_free_func *)wayland_free, + (gamma_method_print_help_func *)wayland_print_help, + (gamma_method_set_option_func *)wayland_set_option, + (gamma_method_restore_func *)wayland_restore, + (gamma_method_set_temperature_func *)wayland_set_temperature + }, +#endif #ifdef ENABLE_RANDR { "randr", 1, From e28906208b4f461e4c3ff6b67768c773f397f52d Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Sun, 3 May 2015 12:23:42 +0300 Subject: [PATCH 2/4] Throttle the set_gamma requests --- src/gamma-wl.c | 30 ++++++++++++++++++++++++++++++ src/gamma-wl.h | 1 + 2 files changed, 31 insertions(+) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 7c46a469..ffba67d1 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -171,6 +171,9 @@ wayland_free(wayland_state_t *state) gamma_control_manager_destroy(state->gamma_control_manager); wl_registry_destroy(state->registry); wl_display_disconnect(state->display); + if (state->callback) { + wl_callback_destroy(state->callback); + } } void @@ -186,9 +189,22 @@ wayland_set_option(wayland_state_t *state, const char *key, const char *value) return 0; } +static void +callback_done(void *data, struct wl_callback *cb, uint32_t t) +{ + wayland_state_t *state = data; + state->callback = NULL; + wl_callback_destroy(cb); +} + +static const struct wl_callback_listener callback_listener = { + callback_done +}; + int wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) { + int ret = 0; struct wl_array red; struct wl_array green; struct wl_array blue; @@ -196,6 +212,18 @@ wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) uint16_t *g_gamma = NULL; uint16_t *b_gamma = NULL; + /* We wait for the sync callback to throttle a bit and not send more + * requests than the compositor can manage, otherwise we'd get disconnected. + * This also allows us to dispatch other incoming events such as + * wl_registry.global_remove. */ + while (state->callback && ret >= 0) { + ret = wl_display_dispatch(state->display); + } + if (ret < 0) { + fprintf(stderr, _("The Wayland connection experienced a fatal error: %d\n"), ret); + return ret; + } + wl_array_init(&red); wl_array_init(&green); wl_array_init(&blue); @@ -236,6 +264,8 @@ wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) gamma_control_set_gamma(output->gamma_control, &red, &green, &blue); } + state->callback = wl_display_sync(state->display); + wl_callback_add_listener(state->callback, &callback_listener, state); wl_display_flush(state->display); wl_array_release(&red); diff --git a/src/gamma-wl.h b/src/gamma-wl.h index dd7d99a6..bdda4903 100644 --- a/src/gamma-wl.h +++ b/src/gamma-wl.h @@ -29,6 +29,7 @@ typedef struct { struct wl_display *display; struct wl_registry *registry; + struct wl_callback *callback; uint32_t gamma_control_manager_id; struct gamma_control_manager *gamma_control_manager; int num_outputs; From d786f8bb549ad1bbf445d7fab32b5b011b34537e Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Sun, 3 May 2015 17:46:19 +0300 Subject: [PATCH 3/4] Fix crash when hotplugging a new output --- src/gamma-wl.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index ffba67d1..22a6130a 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -76,6 +76,7 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, const cha struct output *output = &state->outputs[state->num_outputs - 1]; output->global_id = id; output->output = wl_registry_bind(registry, id, &wl_output_interface, 1); + output->gamma_control = NULL; } } @@ -139,13 +140,6 @@ wayland_start(wayland_state_t *state) return -1; } - for (int i = 0; i < state->num_outputs; ++i) { - struct output *output = &state->outputs[i]; - output->gamma_control = gamma_control_manager_get_gamma_control(state->gamma_control_manager, output->output); - gamma_control_add_listener(output->gamma_control, &gamma_control_listener, output); - } - wl_display_roundtrip(state->display); - return 0; } @@ -204,7 +198,7 @@ static const struct wl_callback_listener callback_listener = { int wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) { - int ret = 0; + int ret = 0, roundtrip = 0; struct wl_array red; struct wl_array green; struct wl_array blue; @@ -224,6 +218,18 @@ wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) return ret; } + for (int i = 0; i < state->num_outputs; ++i) { + struct output *output = &state->outputs[i]; + if (!output->gamma_control) { + output->gamma_control = gamma_control_manager_get_gamma_control(state->gamma_control_manager, output->output); + gamma_control_add_listener(output->gamma_control, &gamma_control_listener, output); + roundtrip = 1; + } + } + if (roundtrip) { + wl_display_roundtrip(state->display); + } + wl_array_init(&red); wl_array_init(&green); wl_array_init(&blue); From 1b9c8ac11125e2df0b8f9779376dd35cd56d5951 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Tue, 24 Nov 2015 15:54:32 +0200 Subject: [PATCH 4/4] Use a new protocol to ask the compositor authorization to change the gamma A compositor may want to restrict the access to the gamma_control_manager interface, to avoid clients changing the gamma without the user knowing. With the new protocol extension redshift request permission to the compositor to bind the gamma control global, so that the compositor can grant/deny it, or ask the user for input. --- src/Makefile.am | 10 +++++-- src/gamma-wl.c | 37 +++++++++++++++++++++++ src/gamma-wl.h | 1 + src/orbital-authorizer.xml | 61 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 src/orbital-authorizer.xml diff --git a/src/Makefile.am b/src/Makefile.am index 546eb6e7..9f9afdc6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,6 +23,8 @@ EXTRA_redshift_SOURCES = \ gamma-wl.c gamma-wl.h \ gamma-control-protocol.c \ gamma-control-client-protocol.h \ + orbital-authorizer-protocol.c \ + orbital-authorizer-client-protocol.h \ gamma-randr.c gamma-randr.h \ gamma-vidmode.c gamma-vidmode.h \ gamma-quartz.c gamma-quartz.h \ @@ -31,7 +33,9 @@ EXTRA_redshift_SOURCES = \ BUILT_SOURCES = \ gamma-control-protocol.c \ - gamma-control-client-protocol.h + gamma-control-client-protocol.h \ + orbital-authorizer-protocol.c \ + orbital-authorizer-client-protocol.h AM_CFLAGS = redshift_LDADD = @LIBINTL@ @@ -47,7 +51,9 @@ endif if ENABLE_WAYLAND redshift_SOURCES += gamma-wl.c gamma-wl.h \ gamma-control-client-protocol.h \ - gamma-control-protocol.c + gamma-control-protocol.c \ + orbital-authorizer-protocol.c \ + orbital-authorizer-client-protocol.h AM_CFLAGS += $(WAYLAND_CFLAGS) redshift_LDADD += \ $(WAYLAND_LIBS) $(WAYLAND_CFLAGS) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 22a6130a..16ac6dce 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -38,6 +38,7 @@ #include "colorramp.h" #include "gamma-control-client-protocol.h" +#include "orbital-authorizer-client-protocol.h" struct output { uint32_t global_id; @@ -54,6 +55,25 @@ wayland_init(wayland_state_t *state) return 0; } +static void +authorizer_feedback_granted(void *data, struct orbital_authorizer_feedback *feedback) +{ + wayland_state_t *state = data; + state->authorized = 1; +} + +static void +authorizer_feedback_denied(void *data, struct orbital_authorizer_feedback *feedback) +{ + fprintf(stderr, _("Fatal: redshift was not authorized to bind the 'gamma_control_manager' interface.\n")); + exit(EXIT_FAILURE); +} + +static const struct orbital_authorizer_feedback_listener authorizer_feedback_listener = { + authorizer_feedback_granted, + authorizer_feedback_denied +}; + static void registry_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) { @@ -77,6 +97,23 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, const cha output->global_id = id; output->output = wl_registry_bind(registry, id, &wl_output_interface, 1); output->gamma_control = NULL; + } else if (strcmp(interface, "orbital_authorizer") == 0) { + struct wl_event_queue *queue = wl_display_create_queue(state->display); + + struct orbital_authorizer *auth = wl_registry_bind(registry, id, &orbital_authorizer_interface, 1u); + wl_proxy_set_queue((struct wl_proxy *)auth, queue); + + struct orbital_authorizer_feedback *feedback = orbital_authorizer_authorize(auth, "gamma_control_manager"); + orbital_authorizer_feedback_add_listener(feedback, &authorizer_feedback_listener, state); + + int ret = 0; + while (!state->authorized && ret >= 0) { + ret = wl_display_dispatch_queue(state->display, queue); + } + + orbital_authorizer_feedback_destroy(feedback); + orbital_authorizer_destroy(auth); + wl_event_queue_destroy(queue); } } diff --git a/src/gamma-wl.h b/src/gamma-wl.h index bdda4903..0d5c79c2 100644 --- a/src/gamma-wl.h +++ b/src/gamma-wl.h @@ -34,6 +34,7 @@ typedef struct { struct gamma_control_manager *gamma_control_manager; int num_outputs; struct output *outputs; + int authorized; } wayland_state_t; diff --git a/src/orbital-authorizer.xml b/src/orbital-authorizer.xml new file mode 100644 index 00000000..bccaa081 --- /dev/null +++ b/src/orbital-authorizer.xml @@ -0,0 +1,61 @@ + + + + + The orbital_authorizer global interface allows clients to + ask the compositor the authorization to bind certain restricted + global interfaces. + Any client that aims to bind restricted interfaces should first + request the authorization by using this interface. Failing to do + so will result in the compositor sending a protocol error to the + client when it binds the restricted interface. + + The list of restricted interfaces is compositor dependant, but must + not include the core interfaces defined in wayland.xml. + + + + + + + + + The authorize request allows the client to ask the compositor the + authorization to bind a restricted global interface. The newly + created orbital_authorizer_feedback will be invalid after the + compositor send either the granted or denied event so the client + must destroy it immediately after. + + + + + + + + + The orbital_authorizer_feedback interface is used by requesting + an authorization with the orbital_authorizer.authorize request. + The compositor will send either the granted or denied event based + on the system and user configuration. How the authorization process + works is compositor specific, but a compositor is allowed to ask + for user input, so the response for an authorization request may + come after some time. + + + + + The authorization was granted. The client can now bind the restricted + interface. + + + + + + The authorization was denied. The client is not allowed to bind the + restricted interface and trying to do so will trigger a protocol + error killing the client. + + + + +