From b3fbc67c9e19672c58e95d7f3387b3d1cdc9aab9 Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Fri, 1 May 2015 23:56:03 +0300 Subject: [PATCH 01/17] 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 02/17] 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 03/17] 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 04/17] 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. + + + + + From ffb813815d1bb9e84134d742b43d93c865a26d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 22 Dec 2017 21:09:27 +0100 Subject: [PATCH 05/17] make wayland actually work --- src/gamma-wl.c | 40 +++++++++++++++++++++++++++++++++++----- src/gamma-wl.h | 23 +---------------------- src/redshift.c | 7 +++++++ 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 16ac6dce..1846783c 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -40,6 +40,17 @@ #include "gamma-control-client-protocol.h" #include "orbital-authorizer-client-protocol.h" +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; + struct output *outputs; + int authorized; +} wayland_state_t; + struct output { uint32_t global_id; struct wl_output *output; @@ -48,10 +59,13 @@ struct output { }; int -wayland_init(wayland_state_t *state) +wayland_init(wayland_state_t **state) { /* Initialize state. */ - memset(state, 0, sizeof *state); + *state = malloc(sizeof(**state)); + if (*state == NULL) return -1; + + memset(*state, 0, sizeof **state); return 0; } @@ -193,6 +207,11 @@ wayland_restore(wayland_state_t *state) void wayland_free(wayland_state_t *state) { + + if (state->callback) { + wl_callback_destroy(state->callback); + } + for (int i = 0; i < state->num_outputs; ++i) { struct output *output = &state->outputs[i]; gamma_control_destroy(output->gamma_control); @@ -202,9 +221,8 @@ 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); - } + + free(state); } void @@ -317,3 +335,15 @@ wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) return 0; } + +const gamma_method_t wl_gamma_method = { + "wayland", + 1, + (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, +}; diff --git a/src/gamma-wl.h b/src/gamma-wl.h index 0d5c79c2..333e99b2 100644 --- a/src/gamma-wl.h +++ b/src/gamma-wl.h @@ -26,28 +26,7 @@ #include "redshift.h" -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; - struct output *outputs; - int authorized; -} 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); +extern const gamma_method_t wl_gamma_method; #endif /* ! REDSHIFT_GAMMA_DRM_H */ diff --git a/src/redshift.c b/src/redshift.c index e0221d5e..856547f7 100644 --- a/src/redshift.c +++ b/src/redshift.c @@ -94,6 +94,10 @@ int poll(struct pollfd *fds, int nfds, int timeout) { abort(); return -1; } # include "gamma-w32gdi.h" #endif +#ifdef ENABLE_WAYLAND +# include "gamma-wl.h" +#endif + #include "location-manual.h" @@ -916,6 +920,9 @@ main(int argc, char *argv[]) #endif #ifdef ENABLE_WINGDI w32gdi_gamma_method, +#endif +#ifdef ENABLE_WAYLAND + wl_gamma_method, #endif dummy_gamma_method, { NULL } From f393516f4ea3f7996a3dc290eabedb7d683d866a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Fri, 22 Dec 2017 21:26:48 +0100 Subject: [PATCH 06/17] properly handle generated files --- .gitignore | 4 ++++ src/Makefile.am | 3 +++ 2 files changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 077bca29..c3a2db18 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,10 @@ src/redshift-gtk/redshift-gtk contrib/redshift.spec src/redshift src/redshift-gtk/__pycache__/ +src/gamma-control-client-protocol.h +src/gamma-control-protocol.c +src/orbital-authorizer-client-protocol.h +src/orbital-authorizer-protocol.c /data/systemd/redshift.service /data/systemd/redshift-gtk.service /data/appdata/redshift-gtk.appdata.xml diff --git a/src/Makefile.am b/src/Makefile.am index f3e1080e..f313d3eb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -125,6 +125,9 @@ endif .rc.o: $(AM_V_GEN)$(WINDRES) -I$(top_builddir) -i $< -o $@ + +CLEANFILES = *-protocol.c *-client-protocol.h + %-protocol.c : $(srcdir)/%.xml $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ From b0d420c829a341a0c31ccd681776ef9c7da9edee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 24 Dec 2017 15:44:38 +0100 Subject: [PATCH 07/17] unify logic --- src/gamma-wl.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 1846783c..7175b84b 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -97,12 +97,8 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id, const cha 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) { + state->num_outputs++; + if (!(state->outputs = realloc(state->outputs, state->num_outputs * sizeof(struct output)))) { fprintf(stderr, _("Failed to allcate memory\n")); return; } From 3995e3b4bf6a9f0987fb2e8fbe8d0ac92782f46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Sun, 24 Dec 2017 16:07:47 +0100 Subject: [PATCH 08/17] disable wayland on appveyor --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 0ac39835..b750c4dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,7 @@ build_script: $env:MSYSTEM = "MINGW32" } - $env:CONFIGURE_FLAGS = "--disable-drm --disable-randr --disable-vidmode --enable-wingdi --disable-quartz --disable-geoclue2 --disable-corelocation --disable-gui --disable-ubuntu --disable-nls --host=$env:arch-w64-mingw32" + $env:CONFIGURE_FLAGS = "--disable-drm --disable-wayland --disable-randr --disable-vidmode --enable-wingdi --disable-quartz --disable-geoclue2 --disable-corelocation --disable-gui --disable-ubuntu --disable-nls --host=$env:arch-w64-mingw32" - ps: md (Join-Path $env:APPVEYOR_BUILD_FOLDER root) - C:\msys64\usr\bin\bash -lc "cd $APPVEYOR_BUILD_FOLDER && ./bootstrap" From f9469812b27f0c4921e550fcca39832fdce08045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 28 Dec 2017 18:06:17 +0100 Subject: [PATCH 09/17] [wayland] fix presence detection --- configure.ac | 6 +----- src/Makefile.am | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/configure.ac b/configure.ac index f3e21851..533b802b 100644 --- a/configure.ac +++ b/configure.ac @@ -68,11 +68,7 @@ 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_VAR(WAYLAND_SCANNER, wayland-scanner, wayland_scanner) PKG_CHECK_MODULES([GLIB], [glib-2.0 gobject-2.0], [have_glib=yes], [have_glib=no]) PKG_CHECK_MODULES([GEOCLUE2], [glib-2.0 gio-2.0 >= 2.26], [have_geoclue2=yes], [have_geoclue2=no]) diff --git a/src/Makefile.am b/src/Makefile.am index f313d3eb..38569d46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,8 +24,6 @@ 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 \ orbital-authorizer-protocol.c \ orbital-authorizer-client-protocol.h \ gamma-randr.c gamma-randr.h \ @@ -37,12 +35,6 @@ EXTRA_redshift_SOURCES = \ windows/appicon.rc \ windows/versioninfo.rc -BUILT_SOURCES = \ - gamma-control-protocol.c \ - gamma-control-client-protocol.h \ - orbital-authorizer-protocol.c \ - orbital-authorizer-client-protocol.h - AM_CFLAGS = redshift_LDADD = @LIBINTL@ EXTRA_DIST = windows/redshift.ico @@ -60,9 +52,17 @@ redshift_SOURCES += gamma-wl.c gamma-wl.h \ gamma-control-protocol.c \ orbital-authorizer-protocol.c \ orbital-authorizer-client-protocol.h + AM_CFLAGS += $(WAYLAND_CFLAGS) + redshift_LDADD += \ $(WAYLAND_LIBS) $(WAYLAND_CFLAGS) + +BUILT_SOURCES = \ + gamma-control-protocol.c \ + gamma-control-client-protocol.h \ + orbital-authorizer-protocol.c \ + orbital-authorizer-client-protocol.h endif if ENABLE_RANDR @@ -129,7 +129,7 @@ endif CLEANFILES = *-protocol.c *-client-protocol.h %-protocol.c : $(srcdir)/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(WAYLAND_SCANNER) code < $< > $@ %-client-protocol.h : $(srcdir)/%.xml - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@ + $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(WAYLAND_SCANNER) client-header < $< > $@ From 369e98a97bfc442e7880297818c326bb5e0da8ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Thu, 28 Dec 2017 18:11:18 +0100 Subject: [PATCH 10/17] [wayland] build on travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4f4ab0e3..ec24290e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,8 @@ addons: # VidMode - libx11-dev - libxxf86vm-dev + # Wayland + - libwayland-dev # GeoClue2 - libglib2.0-dev # GUI From 2abb158e247d517a18ea1d91ada76adae983817a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 10 Jan 2018 08:04:21 +0100 Subject: [PATCH 11/17] backport pkg.m4 --- m4/pkg.m4 | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 m4/pkg.m4 diff --git a/m4/pkg.m4 b/m4/pkg.m4 new file mode 100644 index 00000000..13a88901 --- /dev/null +++ b/m4/pkg.m4 @@ -0,0 +1,275 @@ +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.2]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $2]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR From 44b512a66799fcfdda2511899bbfba9a3f2f98c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 10 Jan 2018 08:36:08 +0100 Subject: [PATCH 12/17] [wayland] don't distribute generated wayland sources --- src/Makefile.am | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 38569d46..53f5b6fe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,8 +24,6 @@ redshift_SOURCES = \ EXTRA_redshift_SOURCES = \ gamma-drm.c gamma-drm.h \ gamma-wl.c gamma-wl.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 \ @@ -47,17 +45,19 @@ redshift_LDADD += \ endif if ENABLE_WAYLAND -redshift_SOURCES += gamma-wl.c gamma-wl.h \ - gamma-control-client-protocol.h \ - gamma-control-protocol.c \ - orbital-authorizer-protocol.c \ - orbital-authorizer-client-protocol.h +redshift_SOURCES += gamma-wl.c gamma-wl.h AM_CFLAGS += $(WAYLAND_CFLAGS) redshift_LDADD += \ $(WAYLAND_LIBS) $(WAYLAND_CFLAGS) +nodist_redshift_SOURCES = \ + gamma-control-client-protocol.h \ + gamma-control-protocol.c \ + orbital-authorizer-protocol.c \ + orbital-authorizer-client-protocol.h + BUILT_SOURCES = \ gamma-control-protocol.c \ gamma-control-client-protocol.h \ From 4149ba30d889f7a67d1e5ebd73b9d8ee7e5e6a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 10 Jan 2018 10:19:55 +0100 Subject: [PATCH 13/17] [wayland] add error handling --- src/gamma-wl.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 7175b84b..581d57b5 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -175,6 +175,10 @@ int wayland_start(wayland_state_t *state) { state->display = wl_display_connect(NULL); + if (!state->display) { + fputs(_("Could not connect to wayland display, exiting.\n"), stderr); + return -1; + } state->registry = wl_display_get_registry(state->display); wl_registry_add_listener(state->registry, ®istry_listener, state); @@ -214,9 +218,15 @@ wayland_free(wayland_state_t *state) wl_output_destroy(output->output); } - gamma_control_manager_destroy(state->gamma_control_manager); - wl_registry_destroy(state->registry); - wl_display_disconnect(state->display); + if (state->gamma_control_manager) { + gamma_control_manager_destroy(state->gamma_control_manager); + } + if (state->registry) { + wl_registry_destroy(state->registry); + } + if (state->display) { + wl_display_disconnect(state->display); + } free(state); } From b5b5f5ad2df082eaf8ff5b51ca917ccd6bca2d9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= Date: Wed, 10 Jan 2018 10:38:03 +0100 Subject: [PATCH 14/17] [wayland] don't export any functions --- src/gamma-wl.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 581d57b5..10e4e67a 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -58,7 +58,7 @@ struct output { uint32_t gamma_size; }; -int +static int wayland_init(wayland_state_t **state) { /* Initialize state. */ @@ -171,7 +171,7 @@ static const struct gamma_control_listener gamma_control_listener = { gamma_control_gamma_size }; -int +static int wayland_start(wayland_state_t *state) { state->display = wl_display_connect(NULL); @@ -194,7 +194,7 @@ wayland_start(wayland_state_t *state) return 0; } -void +static void wayland_restore(wayland_state_t *state) { for (int i = 0; i < state->num_outputs; ++i) { @@ -204,7 +204,7 @@ wayland_restore(wayland_state_t *state) wl_display_flush(state->display); } -void +static void wayland_free(wayland_state_t *state) { @@ -231,14 +231,14 @@ wayland_free(wayland_state_t *state) free(state); } -void +static void wayland_print_help(FILE *f) { fputs(_("Adjust gamma ramps with a Wayland compositor.\n"), f); fputs("\n", f); } -int +static int wayland_set_option(wayland_state_t *state, const char *key, const char *value) { return 0; @@ -256,7 +256,7 @@ static const struct wl_callback_listener callback_listener = { callback_done }; -int +static int wayland_set_temperature(wayland_state_t *state, const color_setting_t *setting) { int ret = 0, roundtrip = 0; From be97d9393adfe6b38fc14b12b309ae64825583b3 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 10 Jan 2018 10:50:26 +0100 Subject: [PATCH 15/17] add doc about m4/pkg.m4 this file could be removed once pkg-config is used in a recent version --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ad02f8b..59eb404b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -59,6 +59,13 @@ Dependencies Ubuntu users will find all these dependencies in the packages listed in ``.travis.yml``. +Notes: + +An external file `m4/pkg.m4` has been added because older versions of pkg-config do not support the +`PKG_CHECK_VAR` [macro](https://github.com/jonls/redshift/pull/568#discussion_r160624641). +This file can be removed once users (Travis CI, Ubuntu 14.04) have enough recent version. + + Coding style ------------ From 211404663b8f3e4b6a5426035c38bdaa9d3ab9a5 Mon Sep 17 00:00:00 2001 From: Marek Otahal Date: Wed, 10 Jan 2018 17:38:34 +0100 Subject: [PATCH 16/17] fix: guard gamma_controll_destroy from NULL param --- src/gamma-wl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index 10e4e67a..b0617d68 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -214,7 +214,9 @@ 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); + if (output!=NULL && output->gamma_control!=NULL) { + gamma_control_destroy(output->gamma_control); + } wl_output_destroy(output->output); } From ed4f8ef11b6b6327210bdb94a9dda82eba67c1fa Mon Sep 17 00:00:00 2001 From: Dominique Martinet Date: Mon, 12 Feb 2018 17:20:46 +0100 Subject: [PATCH 17/17] gamma-wl: wait for sync callback on destroy This prevents destroying gamma control before gamma_control_set_gamma() has been effectively handled by the wayland server, otherwise we risk not setting gamma at all in one-shot mode (or miss the last set temperature call) --- src/gamma-wl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gamma-wl.c b/src/gamma-wl.c index b0617d68..684d173b 100644 --- a/src/gamma-wl.c +++ b/src/gamma-wl.c @@ -207,8 +207,14 @@ wayland_restore(wayland_state_t *state) static void wayland_free(wayland_state_t *state) { - + int ret = 0; + /* Wait for the sync callback to destroy everything, otherwise + * we could destroy the gamma control before gamma has been set */ + while (state->callback && ret >= 0) { + ret = wl_display_dispatch(state->display); + } if (state->callback) { + fprintf(stderr, _("Ignoring error on wayland connection while waiting to disconnect: %d\n"), ret); wl_callback_destroy(state->callback); }