diff options
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/edid.c | 79 | ||||
-rw-r--r-- | src/lib/edid.h | 39 | ||||
-rw-r--r-- | src/lib/fake-quartz-cg.c | 314 | ||||
-rw-r--r-- | src/lib/fake-quartz-cg.h | 72 | ||||
-rw-r--r-- | src/lib/fake-w32-gdi.c | 297 | ||||
-rw-r--r-- | src/lib/fake-w32-gdi.h | 82 | ||||
-rw-r--r-- | src/lib/gamma-dummy.c | 310 | ||||
-rw-r--r-- | src/lib/gamma-dummy.h | 253 | ||||
-rw-r--r-- | src/lib/gamma-helper.c | 258 | ||||
-rw-r--r-- | src/lib/gamma-helper.h | 165 | ||||
-rw-r--r-- | src/lib/gamma-linux-drm.c | 831 | ||||
-rw-r--r-- | src/lib/gamma-linux-drm.h | 162 | ||||
-rw-r--r-- | src/lib/gamma-quartz-cg.c | 353 | ||||
-rw-r--r-- | src/lib/gamma-quartz-cg.h | 162 | ||||
-rw-r--r-- | src/lib/gamma-w32-gdi.c | 333 | ||||
-rw-r--r-- | src/lib/gamma-w32-gdi.h | 162 | ||||
-rw-r--r-- | src/lib/gamma-x-randr.c | 916 | ||||
-rw-r--r-- | src/lib/gamma-x-randr.h | 162 | ||||
-rw-r--r-- | src/lib/gamma-x-vidmode.c | 292 | ||||
-rw-r--r-- | src/lib/gamma-x-vidmode.h | 162 | ||||
-rw-r--r-- | src/lib/libgamma-error.c.gpp | 133 | ||||
-rw-r--r-- | src/lib/libgamma-error.h | 332 | ||||
-rw-r--r-- | src/lib/libgamma-facade.c | 1644 | ||||
-rw-r--r-- | src/lib/libgamma-facade.h | 510 | ||||
-rw-r--r-- | src/lib/libgamma-method.c | 274 | ||||
-rw-r--r-- | src/lib/libgamma-method.h | 1154 | ||||
-rw-r--r-- | src/lib/libgamma.h | 30 |
27 files changed, 9481 insertions, 0 deletions
diff --git a/src/lib/edid.c b/src/lib/edid.c new file mode 100644 index 0000000..76867c7 --- /dev/null +++ b/src/lib/edid.c @@ -0,0 +1,79 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#include "edid.h" + +#include "libgamma-method.h" +#include "libgamma-error.h" + +#include <stdint.h> + + +/** + * Parse the EDID of a monitor. + * + * @param this Instance of a data structure to fill with the information about the EDID. + * It must contain the EDID and its length. + * @param feilds OR:ed identifiers for the information about the EDID that should be parsed. + * Fields that do not have to do with EDID are ignored. + * @return Non-zero on error. + */ +int libgamma_parse_edid(libgamma_crtc_information_t* restrict this, int32_t fields) +{ +#define __test_version(edid, major, minor) (((edid)[18] == major) && ((edid)[19] == minor)) + + int error = 0; + int checksum = 0; + size_t i; + + if (this->edid_length != 128) + error = LIBGAMMA_EDID_LENGTH_UNSUPPORTED; + else if ((this->edid[0] != 0x00) || (this->edid[1] != 0xFF) || (this->edid[2] != 0xFF) || (this->edid[3] != 0xFF) || + (this->edid[4] != 0xFF) || (this->edid[5] != 0xFF) || (this->edid[6] != 0xFF) || (this->edid[7] != 0x00)) + error = LIBGAMMA_EDID_WRONG_MAGIC_NUMBER; + else if (__test_version(this->edid, 1, 3) == 0) + error = LIBGAMMA_EDID_REVISION_UNSUPPORTED; + + this->width_mm_edid_error = this->height_mm_edid_error = this->gamma_error = error; + + this->width_mm_edid = (size_t)(this->edid[21]) * 10; + this->height_mm_edid = (size_t)(this->edid[22]) * 10; + + if ((fields & LIBGAMMA_CRTC_INFO_GAMMA) && (error == 0)) + { + if (this->edid[23] == 0xFF) + this->gamma_error = LIBGAMMA_GAMMA_NOT_SPECIFIED; + else + this->gamma_red = this->gamma_green = this->gamma_blue = (float)((int)(this->edid[23]) + 100) / 100.f; + } + + if (error == 0) + for (i = 0; i < this->edid_length; i++) + checksum += (int)(this->edid[i]); + if ((checksum & 255)) + { + error = LIBGAMMA_EDID_CHECKSUM_ERROR; + this->edid_error = this->width_mm_edid_error = this->height_mm_edid_error = error; + this->gamma_error = this->gamma_error == LIBGAMMA_GAMMA_NOT_SPECIFIED + ? LIBGAMMA_GAMMA_NOT_SPECIFIED_AND_EDID_CHECKSUM_ERROR : 0; + } + + return error | this->gamma_error; + +#undef __test_version +} + diff --git a/src/lib/edid.h b/src/lib/edid.h new file mode 100644 index 0000000..68df0e9 --- /dev/null +++ b/src/lib/edid.h @@ -0,0 +1,39 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_EDID_H +#define LIBGAMMA_EDID_H + +#include "libgamma-method.h" + +#include <stdint.h> + + +/** + * Parse the EDID of a monitor. + * + * @param this Instance of a data structure to fill with the information about the EDID. + * It must contain the EDID and its length. + * @param feilds OR:ed identifiers for the information about the EDID that should be parsed. + * Fields that do not have to do with EDID are ignored. + * @return Non-zero on error. + */ +int libgamma_parse_edid(libgamma_crtc_information_t* restrict out, int32_t fields); + + +#endif + diff --git a/src/lib/fake-quartz-cg.c b/src/lib/fake-quartz-cg.c new file mode 100644 index 0000000..f599dbb --- /dev/null +++ b/src/lib/fake-quartz-cg.c @@ -0,0 +1,314 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# error Compiling fake-quartz-cg.c without FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +#endif + +/* This file very sloppily translates Mac OS X Quartz calls to X RandR calls. + * It should by no means be used, without additional modification, as a + * part of a compatibility layer. The purpose of this file is only to make + * it possible to test for logical errors in Max OS X specific code on + * a GNU/Linux system under X. */ + + +#include "fake-quartz-cg.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#ifndef HAVE_LIBGAMMA_METHOD_X_RANDR + +CGError CGGetOnlineDisplayList(uint32_t max_size, + CGDirectDisplayID* restrict displays_out, uint32_t* restrict count_out) +{ + uint32_t i; + for (i = 0; (i < max_size) && (i < 2); i++) + displays_out[i] = (CGDirectDisplayID)i; + *count_out = i; + + return kCGErrorSuccess; +} + + +CGError CGSetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, const CGGammaValue* red, + const CGGammaValue* green, const CGGammaValue* blue) +{ + (void) display; + (void) red; + (void) green; + (void) blue; + + if (gamma_size != 256) + { + fprintf(stderr, "Gamma size should be 256.\n"); + abort(); + } + + return kCGErrorSuccess; +} + + +CGError CGGetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, + CGGammaValue* restrict red, CGGammaValue* restrict green, + CGGammaValue* restrict blue, uint32_t* restrict gamma_size_out) +{ + long i; + (void) display; + + if (gamma_size != 256) + { + fprintf(stderr, "Gamma size should be 256.\n"); + abort(); + } + + *gamma_size_out = 256; + + for (i = 0; i < 256; i++) + red[i] = green[i] = blue[i] = (CGGammaValue)i / 255; + + return kCGErrorSuccess; +} + +void CGDisplayRestoreColorSyncSettings(void) +{ + /* Do nothing. */ +} + +uint32_t CGDisplayGammaTableCapacity(CGDirectDisplayID display) +{ + (void) display; + return 256; +} + +void close_fake_quartz(void) +{ + /* Do nothing. */ +} + + +#else + +#include <xcb/xcb.h> +#include <xcb/randr.h> + + + +static xcb_connection_t* restrict connection = NULL; +static xcb_randr_get_screen_resources_current_reply_t* restrict res_reply = NULL; +static uint32_t crtc_count = 0; +static xcb_randr_crtc_t* restrict crtcs = NULL; +static uint16_t* restrict original_ramps = NULL; + + + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Waggregate-return" + +CGError CGGetOnlineDisplayList(uint32_t max_size, + CGDirectDisplayID* restrict displays_out, uint32_t* restrict count_out) +{ + uint32_t i; + + if (connection == NULL) + { + xcb_generic_error_t* error; + xcb_screen_iterator_t iter; + xcb_randr_get_screen_resources_current_cookie_t res_cookie; + xcb_randr_get_crtc_gamma_cookie_t gamma_cookie; + xcb_randr_get_crtc_gamma_reply_t* restrict gamma_reply; + + connection = xcb_connect(NULL, NULL); + + iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); + res_cookie = xcb_randr_get_screen_resources_current(connection, iter.data->root); + res_reply = xcb_randr_get_screen_resources_current_reply(connection, res_cookie, &error); + + if (error) + { + fprintf(stderr, "Failed to open X connection.\n"); + xcb_disconnect(connection); + crtc_count = 0; + return ~kCGErrorSuccess; + } + + crtc_count = (uint32_t)(res_reply->num_crtcs); + crtcs = xcb_randr_get_screen_resources_current_crtcs(res_reply); + + original_ramps = malloc(crtc_count * 3 * 256 * sizeof(uint16_t)); + if (original_ramps == NULL) + { + perror("malloc"); + xcb_disconnect(connection); + crtc_count = 0; + return ~kCGErrorSuccess; + } + + for (i = 0; i < crtc_count; i++) + { + gamma_cookie = xcb_randr_get_crtc_gamma(connection, crtcs[i]); + gamma_reply = xcb_randr_get_crtc_gamma_reply(connection, gamma_cookie, &error); + + if (error) + { + fprintf(stderr, "Failed to read gamma ramps.\n"); + xcb_disconnect(connection); + crtc_count = 0; + return ~kCGErrorSuccess; + } + +#define __DEST(C) original_ramps + (C + 3 * i) * 256 +#define __SRC(C) xcb_randr_get_crtc_gamma_##C(gamma_reply) + memcpy(__DEST(0), __SRC(red), 256 * sizeof(uint16_t)); + memcpy(__DEST(1), __SRC(green), 256 * sizeof(uint16_t)); + memcpy(__DEST(2), __SRC(blue), 256 * sizeof(uint16_t)); +#undef __SRC +#undef __DEST + + free(gamma_reply); + } + } + + for (i = 0; (i < max_size) && (i < crtc_count); i++) + *(displays_out + i) = (CGDirectDisplayID)i; + + *count_out = i; + return kCGErrorSuccess; +} + + +CGError CGSetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, const CGGammaValue* red, + const CGGammaValue* green, const CGGammaValue* blue) +{ + xcb_void_cookie_t gamma_cookie; + uint16_t r_int[256]; + uint16_t g_int[256]; + uint16_t b_int[256]; + long i; + int32_t v; + + if (gamma_size != 256) + { + fprintf(stderr, "Gamma size should be 256.\n"); + abort(); + } + + for (i = 0; i < 256; i++) + { + v = (int32_t)(red[i] * UINT16_MAX); + r_int[i] = (uint16_t)(v < 0 ? 0 : v > UINT16_MAX ? UINT16_MAX : v); + + v = (int32_t)(green[i] * UINT16_MAX); + g_int[i] = (uint16_t)(v < 0 ? 0 : v > UINT16_MAX ? UINT16_MAX : v); + + v = (int32_t)(blue[i] * UINT16_MAX); + b_int[i] = (uint16_t)(v < 0 ? 0 : v > UINT16_MAX ? UINT16_MAX : v); + } + + gamma_cookie = xcb_randr_set_crtc_gamma_checked(connection, crtcs[display], + (uint16_t)gamma_size, r_int, g_int, b_int); + return xcb_request_check(connection, gamma_cookie) == NULL ? kCGErrorSuccess : ~kCGErrorSuccess; +} + + +CGError CGGetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, + CGGammaValue* restrict red, CGGammaValue* restrict green, + CGGammaValue* restrict blue, uint32_t* restrict gamma_size_out) +{ + xcb_randr_get_crtc_gamma_cookie_t gamma_cookie; + xcb_randr_get_crtc_gamma_reply_t* restrict gamma_reply; + xcb_generic_error_t* error; + uint16_t* restrict r_int; + uint16_t* restrict g_int; + uint16_t* restrict b_int; + long i; + + if (gamma_size != 256) + { + fprintf(stderr, "Gamma size should be 256.\n"); + abort(); + } + + *gamma_size_out = 256; + + gamma_cookie = xcb_randr_get_crtc_gamma(connection, crtcs[display]); + gamma_reply = xcb_randr_get_crtc_gamma_reply(connection, gamma_cookie, &error); + + if (error) + { + fprintf(stderr, "Failed to write gamma ramps.\n"); + return ~kCGErrorSuccess; + } + + r_int = xcb_randr_get_crtc_gamma_red(gamma_reply); + g_int = xcb_randr_get_crtc_gamma_green(gamma_reply); + b_int = xcb_randr_get_crtc_gamma_blue(gamma_reply); + + for (i = 0; i < 256; i++) + { + red[i] = (CGGammaValue)(r_int[i]) / UINT16_MAX; + green[i] = (CGGammaValue)(g_int[i]) / UINT16_MAX; + blue[i] = (CGGammaValue)(b_int[i]) / UINT16_MAX; + } + + free(gamma_reply); + return kCGErrorSuccess; +} + + +void CGDisplayRestoreColorSyncSettings(void) +{ + xcb_generic_error_t* error; + xcb_void_cookie_t gamma_cookie; + uint32_t i; + + for (i = 0; i < crtc_count; i++) + { + gamma_cookie = xcb_randr_set_crtc_gamma_checked(connection, crtcs[i], 256, + original_ramps + (0 + 3 * i) * 256, + original_ramps + (1 + 3 * i) * 256, + original_ramps + (2 + 3 * i) * 256); + if ((error = xcb_request_check(connection, gamma_cookie))) + fprintf(stderr, "Quartz gamma reset emulation with RandR returned %i\n", error->error_code); + } +} + + +uint32_t CGDisplayGammaTableCapacity(CGDirectDisplayID display) +{ + (void) display; + return 256; +} + +# pragma GCC diagnostic pop + + +void close_fake_quartz_cg(void) +{ + free(res_reply); + res_reply = NULL; + if (connection != NULL) + xcb_disconnect(connection); + connection = NULL; + free(original_ramps); + original_ramps = NULL; +} + +#endif + diff --git a/src/lib/fake-quartz-cg.h b/src/lib/fake-quartz-cg.h new file mode 100644 index 0000000..8f995ea --- /dev/null +++ b/src/lib/fake-quartz-cg.h @@ -0,0 +1,72 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_FAKE_QUARTZ_CG_H +#define LIBGAMMA_FAKE_QUARTZ_CG_H + +#ifndef FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# error Including fake-quartz-cg.h without FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +#endif + + +/* This header file contains some capabilities of + * <CoreGraphics/CGDirectDisplay.h> and <CoreGraphics/CGError.h>, + * and can be used modify gamma ramps without Mac OS X and Quartz + * but with its API. + * + * The content of this file is based on the documentation found on: + * + * https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/Quartz_Services_Ref/Reference/reference.html + * + * https://developer.apple.com/library/mac/documentation/CoreGraphics/Reference/CoreGraphicsConstantsRef/Reference/reference.html#//apple_ref/c/tdef/CGError */ + + +#include <stdint.h> + + +typedef int32_t CGError; +#define kCGErrorSuccess 0 + +typedef float CGGammaValue; +typedef uint32_t CGDirectDisplayID; + + +CGError CGGetOnlineDisplayList(uint32_t max_size, + CGDirectDisplayID* restrict displays_out, uint32_t* restrict count_out); + +CGError CGSetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, const CGGammaValue* red, + const CGGammaValue* green, const CGGammaValue* blue); + +CGError CGGetDisplayTransferByTable(CGDirectDisplayID display, uint32_t gamma_size, + CGGammaValue* restrict red, CGGammaValue* restrict green, + CGGammaValue* restrict blue, uint32_t* restrict gamma_size_out); + +void CGDisplayRestoreColorSyncSettings(void); + +uint32_t CGDisplayGammaTableCapacity(CGDirectDisplayID display) __attribute__((const)); + + +/* The follow part most only be used when this module is used, + * it cannot be used when the real CoreGraphics is used. + * CoreGraphics does not have this function, it is added so + * that there is a way to cleanly close the X connection + * and free resources needed by this module. */ +void close_fake_quartz_cg(void); + + +#endif + diff --git a/src/lib/fake-w32-gdi.c b/src/lib/fake-w32-gdi.c new file mode 100644 index 0000000..541b3c8 --- /dev/null +++ b/src/lib/fake-w32-gdi.c @@ -0,0 +1,297 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_W32_GDI +# error Compiling fake-w32-gdi.c without FAKE_LIBGAMMA_METHOD_W32_GDI +#endif + +/* This file very sloppily translates Windows GDI calls to X RandR calls. + * It should by no means be used, without additional modification, as a + * part of a compatibility layer. The purpose of this file is only to make + * it possible to test for logical errors in Windows specific code on + * a GNU/Linux system under X. */ + + +#include "fake-w32-gdi.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#ifndef HAVE_LIBGAMMA_METHOD_X_RANDR + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx */ +HDC GetDC(HWND hWnd) +{ + (void) hWnd; + return (HDC*)16; +} + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162920(v=vs.85).aspx */ +int ReleaseDC(HWND hWnd, HDC hDC) +{ + (void) hWnd; + (void) hDC; + return 1; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877(v=vs.85).aspx */ +int GetDeviceCaps(HDC hDC, int nIndex) +{ + (void) hDC; + return CM_GAMMA_RAMP + nIndex - COLORMGMTCAPS; +} + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd372194(v=vs.85).aspx */ +BOOL SetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp) +{ + (void) hDC; + (void) lpRamp; + return TRUE; +} + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd316946(v=vs.85).aspx */ +BOOL GetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp) +{ + (void) hDC; + (void) lpRamp; + return TRUE; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd183490(v=vs.85).aspx */ +HDC CreateDC(LPCTSTR restrict lpszDriver, LPCTSTR restrict lpszDevice, + void* restrict lpszOutput, void* restrict lpInitData) +{ + (void) lpszOutput; + (void) lpInitData; + (void) lpszDevice; + if (strcmp(lpszDriver, "DISPLAY")) + return NULL; + return (HDC*)16; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx */ +BOOL EnumDisplayDevices(LPCTSTR lpDevice, restrict DWORD iDevNum, + PDISPLAY_DEVICE restrict lpDisplayDevice, DWORD dwFlags) +{ + (void) dwFlags; + if (lpDevice != NULL) + { + fprintf(stderr, "lpDevice (argument 1) for EnumDisplayDevices should be NULL\n"); + abort(); + return FALSE; + } + if (iDevNum >= 2) + return FALSE; + if (lpDisplayDevice->cb != sizeof(DISPLAY_DEVICE)) + { + fprintf(stderr, + "lpDisplayDevice->cb for EnumDisplayDevices is not sizeof(DISPLAY_DEVICE)\n"); + abort(); + return FALSE; + } + strcmp(lpDisplayDevice->DeviceName, "some monitor"); + lpDisplayDevice->StateFlags = DISPLAY_DEVICE_ACTIVE; + return TRUE; +} + +#else + + +#include <xcb/xcb.h> +#include <xcb/randr.h> + + +#define GAMMA_RAMP_SIZE 256 + + +static xcb_connection_t* restrict connection = NULL; +static size_t dc_count = 0; +static ssize_t crtc_count = -1; +static xcb_randr_crtc_t* restrict crtcs = NULL; +static xcb_randr_get_screen_resources_current_reply_t* restrict res_reply = NULL; + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx */ +HDC GetDC(HWND hWnd) +{ + (void) hWnd; + return CreateDC(TEXT("DISPLAY"), "0", NULL, NULL); +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162920(v=vs.85).aspx */ +int ReleaseDC(HWND hWnd, HDC hDC) +{ + (void) hWnd; + (void) hDC; + dc_count--; + if (dc_count == 0) + { + if (connection != NULL) + xcb_disconnect(connection); + connection = NULL; + free(res_reply); + res_reply = NULL; + } + return 1; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877(v=vs.85).aspx */ +int GetDeviceCaps(HDC hDC, int nIndex) +{ + (void) hDC; + return CM_GAMMA_RAMP + nIndex - COLORMGMTCAPS; +} + + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Waggregate-return" + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd372194(v=vs.85).aspx */ +BOOL SetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp) +{ + xcb_void_cookie_t gamma_cookie = + xcb_randr_set_crtc_gamma_checked(connection, *(xcb_randr_crtc_t*)hDC, GAMMA_RAMP_SIZE, + ((uint16_t*)lpRamp) + 0 * GAMMA_RAMP_SIZE, + ((uint16_t*)lpRamp) + 1 * GAMMA_RAMP_SIZE, + ((uint16_t*)lpRamp) + 2 * GAMMA_RAMP_SIZE); + xcb_generic_error_t* error = xcb_request_check(connection, gamma_cookie); + return error == NULL ? TRUE : FALSE; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd316946(v=vs.85).aspx */ +BOOL GetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp) +{ + xcb_randr_get_crtc_gamma_cookie_t gamma_cookie; + xcb_randr_get_crtc_gamma_reply_t* restrict gamma_reply; + xcb_generic_error_t* error; + + gamma_cookie = xcb_randr_get_crtc_gamma(connection, *(xcb_randr_crtc_t*)hDC); + gamma_reply = xcb_randr_get_crtc_gamma_reply(connection, gamma_cookie, &error); + + if (error) + return FALSE; + +#define DEST_RAMP(I) (((uint16_t*)lpRamp) + (I) * GAMMA_RAMP_SIZE) +#define SRC_RAMP(C) (xcb_randr_get_crtc_gamma_##C(gamma_reply)) + + memcpy(DEST_RAMP(0), SRC_RAMP(red), GAMMA_RAMP_SIZE * sizeof(uint16_t)); + memcpy(DEST_RAMP(1), SRC_RAMP(green), GAMMA_RAMP_SIZE * sizeof(uint16_t)); + memcpy(DEST_RAMP(2), SRC_RAMP(blue), GAMMA_RAMP_SIZE * sizeof(uint16_t)); + +#undef SRC_RAMP +#undef DEST_RAMP + + free(gamma_reply); + return TRUE; +} + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd183490(v=vs.85).aspx */ +HDC CreateDC(LPCTSTR restrict lpszDriver, LPCTSTR restrict lpszDevice, + void* restrict lpszOutput, void* restrict lpInitData) +{ + int crtc_index = atoi(lpszDevice); + + (void) lpszOutput; + (void) lpInitData; + + if (strcmp(lpszDriver, "DISPLAY")) + return NULL; + + if (dc_count == 0) { + xcb_generic_error_t* error; + xcb_screen_iterator_t iter; + xcb_randr_get_screen_resources_current_cookie_t res_cookie; + + connection = xcb_connect(NULL, NULL); + + iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); + res_cookie = xcb_randr_get_screen_resources_current(connection, iter.data->root); + res_reply = xcb_randr_get_screen_resources_current_reply(connection, res_cookie, &error); + + if (error) + { + xcb_disconnect(connection); + crtc_count = -1; + return NULL; + } + + crtc_count = res_reply->num_crtcs; + crtcs = xcb_randr_get_screen_resources_current_crtcs(res_reply); + } + + if (crtc_index >= crtc_count) + { + if (dc_count == 0) + { + xcb_disconnect(connection); + crtc_count = -1; + } + return NULL; + } + + dc_count++; + return crtcs + crtc_index; +} + +# pragma GCC diagnostic pop + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx */ +BOOL EnumDisplayDevices(LPCTSTR restrict lpDevice, DWORD iDevNum, + PDISPLAY_DEVICE restrict lpDisplayDevice, DWORD dwFlags) +{ + size_t count = (size_t)crtc_count; + (void) dwFlags; + if (lpDevice != NULL) + { + fprintf(stderr, "lpDevice (argument 1) for EnumDisplayDevices should be NULL\n"); + abort(); + return FALSE; + } + if (crtc_count < 0) + { + if (GetDC(NULL) == NULL) + return FALSE; + dc_count = 0; + count = (size_t)crtc_count; + ReleaseDC(NULL, NULL); + } + if (iDevNum >= count) + return FALSE; + if (lpDisplayDevice->cb != sizeof(DISPLAY_DEVICE)) + { + fprintf(stderr, "lpDisplayDevice->cb for EnumDisplayDevices is not sizeof(DISPLAY_DEVICE)\n"); + abort(); + return FALSE; + } + sprintf(lpDisplayDevice->DeviceName, "%i", iDevNum); + lpDisplayDevice->StateFlags = DISPLAY_DEVICE_ACTIVE; + return TRUE; +} + + +#endif + diff --git a/src/lib/fake-w32-gdi.h b/src/lib/fake-w32-gdi.h new file mode 100644 index 0000000..1995847 --- /dev/null +++ b/src/lib/fake-w32-gdi.h @@ -0,0 +1,82 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_FAKE_W32_GDI_H +#define LIBGAMMA_FAKE_W32_GDI_H + +#ifndef FAKE_LIBGAMMA_METHOD_W32_GDI +# error Including fake-w32-gdi.h without FAKE_LIBGAMMA_METHOD_W32_GDI +#endif + + +#include <stdint.h> + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx */ +typedef uint16_t WORD; +typedef uint32_t DWORD; +typedef int BOOL; +typedef void* HDC; +typedef void* HWND; +typedef void* LPVOID; +typedef const char* LPCTSTR; +typedef char TCHAR; +#define TRUE 1 +#define FALSE 0 + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144871(v=vs.85).aspx */ +HDC GetDC(HWND hWnd); + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162920(v=vs.85).aspx */ +int ReleaseDC(HWND hWnd, HDC hDC); + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877(v=vs.85).aspx */ +int GetDeviceCaps(HDC hDC, int nIndex) __attribute__((const)); +#define COLORMGMTCAPS 1 +#define CM_GAMMA_RAMP 1 + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd372194(v=vs.85).aspx */ +BOOL SetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp); + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd316946(v=vs.85).aspx */ +BOOL GetDeviceGammaRamp(HDC hDC, LPVOID restrict lpRamp); + + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd183490(v=vs.85).aspx */ +HDC CreateDC(LPCTSTR restrict lpszDriver, LPCTSTR restrict lpszDevice, + void* restrict lpszOutput, void* restrict lpInitData); +#define TEXT(X) ((LPCTSTR)(X)) + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd183569(v=vs.85).aspx */ +typedef struct +{ + DWORD cb; + TCHAR DeviceName[32]; + DWORD StateFlags; +} DISPLAY_DEVICE; +typedef DISPLAY_DEVICE* PDISPLAY_DEVICE; +#define DISPLAY_DEVICE_ACTIVE 1 + +/* http://msdn.microsoft.com/en-us/library/windows/desktop/dd162609(v=vs.85).aspx */ +BOOL EnumDisplayDevices(LPCTSTR restrict lpDevice, DWORD iDevNum, + PDISPLAY_DEVICE restrict lpDisplayDevice, DWORD dwFlags); + + +#endif + diff --git a/src/lib/gamma-dummy.c b/src/lib/gamma-dummy.c new file mode 100644 index 0000000..e508b4a --- /dev/null +++ b/src/lib/gamma-dummy.c @@ -0,0 +1,310 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_DUMMY +# error Compiling gamma-dummy.c without HAVE_LIBGAMMA_METHOD_DUMMY +#endif + +#include "gamma-dummy.h" + +#include "libgamma-error.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_dummy_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ +} + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_dummy_site_destroy(libgamma_site_state_t* restrict this) +{ +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_site_restore(libgamma_site_state_t* restrict this) +{ +} + + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_dummy_partition_destroy(libgamma_partition_state_t* restrict this) +{ +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_partition_restore(libgamma_partition_state_t* restrict this) +{ +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_dummy_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_restore(libgamma_crtc_state_t* restrict this) +{ +} + + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_dummy_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +} + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ +} + + + +/** + * Get current the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t* restrict ramps) +{ +} + + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t ramps) +{ +} + + + +/** + * Get current the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t* restrict ramps) +{ +} + + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t ramps) +{ +} + + + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps) +{ +} + + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps) +{ +} + + +/** + * Get current the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t* restrict ramps) +{ +} + + +/** + * Set the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t ramps) +{ +} + diff --git a/src/lib/gamma-dummy.h b/src/lib/gamma-dummy.h new file mode 100644 index 0000000..342d119 --- /dev/null +++ b/src/lib/gamma-dummy.h @@ -0,0 +1,253 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_DUMMY_H +#define LIBGAMMA_GAMMA_DUMMY_H + +#ifndef HAVE_LIBGAMMA_METHOD_DUMMY +# error Including gamma-dummy.h without HAVE_LIBGAMMA_METHOD_DUMMY +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_dummy_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_dummy_site_destroy(libgamma_site_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_dummy_partition_destroy(libgamma_partition_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_dummy_crtc_destroy(libgamma_crtc_state_t* restrict this); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_dummy_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps); + + +/** + * Get current the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t ramps); + + +/** + * Get current the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t ramps); + + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps); + +/** + * Get current the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_get_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_dummy_crtc_set_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t ramps); + + +#endif + diff --git a/src/lib/gamma-helper.c b/src/lib/gamma-helper.c new file mode 100644 index 0000000..dd4e027 --- /dev/null +++ b/src/lib/gamma-helper.c @@ -0,0 +1,258 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#include "gamma-helper.h" + +#include "libgamma-method.h" +#include "libgamma-error.h" + +#include <errno.h> +#include <stdlib.h> +#include <stdint.h> + + +#define ANY bits64 + + +/** + * Convert any set of gamma ramps into a 64-bit integer array with all channels. + * + * @param depth The depth of the gamma ramp, `-1` for `float`, `-2` for `double`. + * @param n The grand size of gamma ramps (sum of all channels' sizes.) + * @param out Output array. + * @param in Input gamma ramps. + */ +static void translate_to_64(signed depth, size_t n, uint64_t* restrict out, libgamma_gamma_ramps_any_t in) +{ + size_t i; + switch (depth) + { + case 16: + for (i = 0; i < n; i++) + out[i] = (uint64_t)(in.bits16.red[i]) * 0x0001000100010001ULL; + break; + + case 32: + for (i = 0; i < n; i++) + out[i] = (uint64_t)(in.bits32.red[i]) * 0x0000000100000001ULL; + break; + + case 64: + for (i = 0; i < n; i++) + out[i] = in.bits64.red[i]; + break; + + case -1: + for (i = 0; i < n; i++) + out[i] = (uint64_t)(in.float_single.red[i] * (float)UINT64_MAX); + break; + + case -2: + for (i = 0; i < n; i++) + out[i] = (uint64_t)(in.float_double.red[i] * (double)UINT64_MAX); + break; + + default: /* This is not possible. */ + abort(); + break; + } +} + + +/** + * Undo the actions of `translate_to_64`. + * + * @param depth The depth of the gamma ramp, `-1` for `float`, `-2` for `double`. + * @param n The grand size of gamma ramps (sum of all channels' sizes.) + * @param out Output gamma ramps. + * @param in Input array, may be modified. + */ +static void translate_from_64(signed depth, size_t n, libgamma_gamma_ramps_any_t out, uint64_t* restrict in) +{ + size_t i; + + switch (depth) + { + case 16: + for (i = 0; i < n; i++) + out.bits16.red[i] = (uint16_t)(in[i] / 0x0001000100010001ULL); + break; + + case 32: + for (i = 0; i < n; i++) + out.bits32.red[i] = (uint32_t)(in[i] / 0x0000000100000001ULL); + break; + + case 64: + for (i = 0; i < n; i++) + out.bits64.red[i] = in[i]; + break; + + case -1: + for (i = 0; i < n; i++) + out.float_single.red[i] = (float)(in[i]) / (float)UINT64_MAX; + break; + + case -2: + for (i = 0; i < n; i++) + out.float_double.red[i] = (double)(in[i]) / (double)UINT64_MAX; + break; + + default: /* This is not possible. */ + abort(); + break; + } +} + + +/** + * Allocate and initalise a gamma ramp with any depth. + * + * @param ramps_sys Output gamma ramps. + * @param ramps The gamma ramps whose sizes should be duplicated. + * @param depth The depth of the gamma ramps to allocate, + * `-1` for `float`, `-2` for `double`. + * @param elements Output reference for the grand size of the gamma ramps. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +static int allocated_any_ramp(libgamma_gamma_ramps_any_t* restrict ramps_sys, + libgamma_gamma_ramps_any_t ramps, signed depth, size_t* restrict elements) +{ + size_t n = 0; + size_t d; + + switch (depth) + { + case 16: d = sizeof(uint16_t); break; + case 32: d = sizeof(uint32_t); break; + case 64: d = sizeof(uint64_t); break; + case -1: d = sizeof(float); break; + case -2: d = sizeof(double); break; + default: + return errno = EINVAL, LIBGAMMA_ERRNO_SET; + } + + n += ramps_sys->ANY. red_size = ramps.ANY. red_size; + n += ramps_sys->ANY.green_size = ramps.ANY.green_size; + n += ramps_sys->ANY. blue_size = ramps.ANY. blue_size; + + ramps_sys->ANY.red = malloc(n * d); + ramps_sys->ANY.green = (void*)(((char*)(ramps_sys->ANY. red)) + ramps.ANY. red_size * d / sizeof(char)); + ramps_sys->ANY.blue = (void*)(((char*)(ramps_sys->ANY.green)) + ramps.ANY.green_size * d / sizeof(char)); + + *elements = n; + return ramps_sys->ANY.red ? 0 : LIBGAMMA_ERRNO_SET; +} + + +/** + * Get current the gamma ramps for a CRTC, re-encoding version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used read the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_translated_ramp_get_(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t* restrict ramps, + signed depth_user, signed depth_system, + libgamma_get_ramps_any_fun* fun) +{ + size_t n; + int r; + libgamma_gamma_ramps_any_t ramps_sys; + uint64_t* restrict ramps_full; + + if ((r = allocated_any_ramp(&ramps_sys, *ramps, depth_system, &n))) + return r; + + if ((r = fun(this, &ramps_sys))) + { + free(ramps_sys.ANY.red); + return r; + } + + if ((ramps_full = malloc(n * sizeof(uint64_t))) == NULL) + { + free(ramps_sys.ANY.red); + return LIBGAMMA_ERRNO_SET; + } + + translate_to_64(depth_system, n, ramps_full, ramps_sys); + free(ramps_sys.ANY.red); + + translate_from_64(depth_user, n, *ramps, ramps_full); + free(ramps_full); + return 0; +} + + +/** + * Set the gamma ramps for a CRTC, re-encoding version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used write the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_translated_ramp_set_(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t ramps, + signed depth_user, signed depth_system, + libgamma_set_ramps_any_fun* fun) +{ + size_t n; + int r; + libgamma_gamma_ramps_any_t ramps_sys; + uint64_t* restrict ramps_full; + + if ((r = allocated_any_ramp(&ramps_sys, ramps, depth_system, &n))) + return r; + + if ((ramps_full = malloc(n * sizeof(uint64_t))) == NULL) + { + free(ramps_sys.ANY.red); + return LIBGAMMA_ERRNO_SET; + } + + translate_to_64(depth_user, n, ramps_full, ramps); + translate_from_64(depth_system, n, ramps_sys, ramps_full); + free(ramps_full); + + r = fun(this, ramps_sys); + + free(ramps_sys.ANY.red); + return r; +} + + +#undef ANY + diff --git a/src/lib/gamma-helper.h b/src/lib/gamma-helper.h new file mode 100644 index 0000000..e0711ff --- /dev/null +++ b/src/lib/gamma-helper.h @@ -0,0 +1,165 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_HELPER_H +#define LIBGAMMA_GAMMA_HELPER_H + + +#include "libgamma-method.h" + + +/** + * Gamma ramp structure union for different depths. + */ +typedef union libgamma_gamma_ramps_any +{ + /** + * 16-bit gamma ramps. + */ + libgamma_gamma_ramps_t bits16; + + /** + * 32-bit gamma ramps. + */ + libgamma_gamma_ramps32_t bits32; + + /** + * 64-bit gamma ramps. + */ + libgamma_gamma_ramps64_t bits64; + + /** + * Single precision float gamma ramps. + */ + libgamma_gamma_rampsf_t float_single; + + /** + * Double precision float gamma ramps. + */ + libgamma_gamma_rampsd_t float_double; + +} libgamma_gamma_ramps_any_t; + + +/** + * A function for reading the gamma ramps from a CRTC. + * + * @param this The CRTC state. + * @param ramps The store for the gamma ramps. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +typedef int libgamma_get_ramps_any_fun(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t* restrict ramps); + +/** + * A function for writing the gamma ramps to a CRTC. + * + * @param this The CRTC state. + * @param ramps The gamma ramps. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +typedef int libgamma_set_ramps_any_fun(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t ramps); + + + +/** + * Get current the gamma ramps for a CRTC, re-encoding versio.n + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used read the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +#define libgamma_translated_ramp_get(this, ramps, depth_user, depth_system, fun) \ + libgamma_translated_ramp_get_(this, ramps, depth_user, depth_system, \ + (libgamma_get_ramps_any_fun*)(fun)) + + +/** + * Set the gamma ramps for a CRTC, re-encoding version + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used write the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +#define libgamma_translated_ramp_set(this, ramps, depth_user, depth_system, fun) \ + libgamma_translated_ramp_set_(this, ramps, depth_user, depth_system, \ + (libgamma_set_ramps_any_fun*)(fun)) + + +/** + * Get current the gamma ramps for a CRTC, re-encoding version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used read the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_translated_ramp_get_(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t* restrict ramps, + signed depth_user, signed depth_system, + libgamma_get_ramps_any_fun* fun); + + +/** + * Set the gamma ramps for a CRTC, re-encoding version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @param depth_user The depth of the gamma ramps that are provided by the user, + * `-1` for `float`, `-2` for `double`. + * @param depth_system The depth of the gamma ramps as required by the adjustment method, + * `-1` for `float`, `-2` for `double`. + * @param fun Function that is to be used write the ramps, its parameters have + * the same function as those of this function with the same names, + * and the return value too is identical. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_translated_ramp_set_(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_any_t ramps, + signed depth_user, signed depth_system, + libgamma_set_ramps_any_fun* fun); + + +#endif + diff --git a/src/lib/gamma-linux-drm.c b/src/lib/gamma-linux-drm.c new file mode 100644 index 0000000..36ba442 --- /dev/null +++ b/src/lib/gamma-linux-drm.c @@ -0,0 +1,831 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_LINUX_DRM +# error Compiling gamma-linux-drm.c without HAVE_LIBGAMMA_METHOD_LINUX_DRM +#endif + +#define _GNU_SOURCE + +#include "gamma-linux-drm.h" + +#include "libgamma-error.h" +#include "edid.h" + +#include <limits.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <grp.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> + +#include <xf86drm.h> +#include <xf86drmMode.h> + +#ifndef O_CLOEXEC +# define O_CLOEXEC 02000000 +#endif +#ifndef NGROUPS_MAX +# define NGROUPS_MAX 65536 +#endif +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + + + +/** + * Graphics card data for the Direct Rendering Manager adjustment method. + */ +typedef struct libgamma_drm_card_data +{ + /** + * File descriptor for the connection to the graphics card. + */ + int fd; + + /** + * The graphics card's mode resources. + */ + drmModeRes* res; + + /** + * Resources for open connectors. + */ + drmModeConnector** connectors; + + /** + * Resources for open encoders. + */ + drmModeEncoder** encoders; + +} libgamma_drm_card_data_t; + + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_linux_drm_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ + this->crtc_information = LIBGAMMA_CRTC_INFO_EDID + | LIBGAMMA_CRTC_INFO_WIDTH_MM + | LIBGAMMA_CRTC_INFO_HEIGHT_MM + | LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID + | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID + | LIBGAMMA_CRTC_INFO_GAMMA_SIZE + | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH + | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER + | LIBGAMMA_CRTC_INFO_ACTIVE + | LIBGAMMA_CRTC_INFO_CONNECTOR_NAME + | LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE + | LIBGAMMA_CRTC_INFO_GAMMA; + this->default_site_known = 1; + this->multiple_sites = 0; + this->multiple_partitions = 1; + this->multiple_crtcs = 1; + this->partitions_are_graphics_cards = 1; + this->site_restore = 0; + this->partition_restore = 0; + this->crtc_restore = 0; + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 0; + this->fixed_gamma_depth = 1; + this->real = 1; + this->fake = 0; +} + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ + char pathname[PATH_MAX]; + struct stat _attr; + + if (site != NULL) + return LIBGAMMA_NO_SUCH_SITE; + + /* Count the number of available graphics cards by + * stat:ing there existence in an API filesystem. */ + this->partitions_available = 0; + for (;;) + { + snprintf(pathname, sizeof(pathname) / sizeof(char), + DRM_DEV_NAME, DRM_DIR_NAME, (int)(this->partitions_available)); + if (stat(pathname, &_attr)) + break; + if (this->partitions_available++ > INT_MAX) + return LIBGAMMA_IMPOSSIBLE_AMOUNT; + } + return 0; +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_linux_drm_site_destroy(libgamma_site_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + +/** + * Figure out why `open` failed for a graphics card + * + * @param pathname The pathname of the error card + * @return The error code to report + */ +static int figure_out_card_open_error(const char* pathname) +{ + if ((errno == ENXIO) || (errno == ENODEV)) + return LIBGAMMA_NO_SUCH_PARTITION; + + if (errno == EACCES) + { + gid_t supplemental_groups[NGROUPS_MAX]; + struct group* group; + int i, n; + struct stat attr; + int r; + + + r = stat(pathname, &attr); + +#define __test(R, W) ((attr.st_mode & (R | W)) == (R | W)) + if (r) + return errno == EACCES ? LIBGAMMA_NO_SUCH_PARTITION : LIBGAMMA_ERRNO_SET; + + if ((attr.st_uid == geteuid() && __test(S_IRUSR, S_IWUSR)) || + (attr.st_gid == getegid() && __test(S_IRGRP, S_IWGRP)) || + __test(S_IROTH, S_IWOTH)) + return LIBGAMMA_DEVICE_ACCESS_FAILED; + + if (attr.st_gid == 0 /* root group */ || __test(S_IRGRP, S_IWGRP)) + return LIBGAMMA_DEVICE_RESTRICTED; + + + n = getgroups(NGROUPS_MAX, supplemental_groups); + if (n < 0) + return LIBGAMMA_ERRNO_SET; + + for (i = 0; i < n; i++) + if (supplemental_groups[i] == attr.st_gid) + break; + + if (i != n) + return LIBGAMMA_DEVICE_ACCESS_FAILED; + + errno = 0; + group = getgrgid(attr.st_gid); /* TODO: Not thread-safe. */ + libgamma_group_gid = attr.st_gid; + libgamma_group_name = group != NULL ? group->gr_name : NULL; + return LIBGAMMA_DEVICE_REQUIRE_GROUP; +#undef __test + } + + return LIBGAMMA_ERRNO_SET; +} + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + int rc = 0; + libgamma_drm_card_data_t* restrict data; + char pathname[PATH_MAX]; + + (void) site; + + /* Check for partition index overflow. */ + if (partition > INT_MAX) + return LIBGAMMA_NO_SUCH_PARTITION; + + /* Allocate and initialise graphics card data. */ + this->data = NULL; + data = malloc(sizeof(libgamma_drm_card_data_t)); + if (data == NULL) + return LIBGAMMA_ERRNO_SET; + data->fd = -1; + data->res = NULL; + + /* Get the pathname for the graphics card. */ + snprintf(pathname, sizeof(pathname) / sizeof(char), + DRM_DEV_NAME, DRM_DIR_NAME, (int)partition); + + /* Acquire access to the graphics card. */ + data->fd = open(pathname, O_RDWR | O_CLOEXEC); + if (data->fd < 0) + { + rc = figure_out_card_open_error(pathname); + goto fail_data; + } + + /* Acquire mode resources. */ + data->res = drmModeGetResources(data->fd); + if (data->res == NULL) + { + rc = LIBGAMMA_ACQUIRING_MODE_RESOURCES_FAILED; + goto fail_fd; + } + + /* Get the number of CRTC:s that are available in the partition. */ + if (data->res->count_crtcs < 0) + { + rc = LIBGAMMA_NEGATIVE_CRTC_COUNT; + goto fail_res; + } + this->crtcs_available = (size_t)(data->res->count_crtcs); + return 0; + + fail_res: + drmModeFreeResources(data->res); + fail_fd: + close(data->fd); + fail_data: + free(data); + return rc; +} + + +/** + * Release all connectors and encoders. + * + * @param this The graphics card data. + */ +static void release_connectors_and_encoders(libgamma_drm_card_data_t* restrict this) +{ + size_t i, n; + if (this->encoders != NULL) + for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) + if (this->encoders[i] != NULL) + drmModeFreeEncoder(this->encoders[i]); + free(this->encoders); + this->encoders = NULL; + + if (this->connectors != NULL) + for (i = 0, n = (size_t)(this->res->count_connectors); i < n; i++) + if (this->connectors[i] != NULL) + drmModeFreeConnector(this->connectors[i]); + free(this->connectors); + this->connectors = NULL; +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_linux_drm_partition_destroy(libgamma_partition_state_t* restrict this) +{ + libgamma_drm_card_data_t* restrict data = this->data; + release_connectors_and_encoders(data); + if (data->res != NULL) + drmModeFreeResources(data->res); + if (data->fd >= 0) + close(data->fd); + free(data); +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_partition_restore(libgamma_partition_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + libgamma_drm_card_data_t* restrict card; + uint32_t crtc_id; + + if (crtc >= partition->crtcs_available) + return LIBGAMMA_NO_SUCH_CRTC; + + card = partition->data; + crtc_id = card->res->crtcs[crtc]; + this->data = (void*)(size_t)crtc_id; + return 0; +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + +/** + * Find the connector that a CRTC belongs to. + * + * @param this The CRTC state. + * @param error Output of the error value to store of error report + * fields for data that requires the connector. +'* @return The CRTC's conncetor, `NULL` on error. + */ +static drmModeConnector* find_connector(libgamma_crtc_state_t* restrict this, int* restrict error) +{ + uint32_t crtc_id = (uint32_t)(size_t)(this->data); + libgamma_drm_card_data_t* restrict card = this->partition->data; + size_t i, n = (size_t)(card->res->count_connectors); + /* Open connectors and encoders if not already opened. */ + if (card->connectors == NULL) + { + /* We use calloc so all non-loaded elements are `NULL` after an error. */ + if ((card->connectors = calloc(n, sizeof(drmModeConnector*))) == NULL) + goto fail; + if ((card->encoders = calloc(n, sizeof(drmModeEncoder*))) == NULL) + goto fail; + for (i = 0; i < n; i++) + if (((card->connectors[i] = drmModeGetConnector(card->fd, card->res->connectors[i])) == NULL) || + ((card->encoders[i] = drmModeGetEncoder(card->fd, card->connectors[i]->encoder_id)) == NULL)) + goto fail; + } + /* Find connector. */ + *error = 0; + for (i = 0; i < n; i++) + if (card->encoders[i]->crtc_id == crtc_id) + return card->connectors[i]; + *error = LIBGAMMA_CONNECTOR_UNKNOWN; + return NULL; + + fail: + *error = errno; + release_connectors_and_encoders(card); + return NULL; +} + + +/** + * Get the size of the gamma ramps for a CRTC. + * + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @return The value stored in `out->gamma_size_error`. + */ +static int get_gamma_ramp_size(libgamma_crtc_information_t* restrict out, const libgamma_crtc_state_t* restrict crtc) +{ + libgamma_drm_card_data_t* restrict card = crtc->partition->data; + uint32_t crtc_id = card->res->crtcs[crtc->crtc]; + drmModeCrtc* restrict crtc_info; + errno = 0; + crtc_info = drmModeGetCrtc(card->fd, crtc_id); + out->gamma_size_error = crtc_info == NULL ? errno : 0; + if (out->gamma_size_error == 0) + { + out->red_gamma_size = (size_t)(crtc_info->gamma_size); + out->green_gamma_size = (size_t)(crtc_info->gamma_size); + out->blue_gamma_size = (size_t)(crtc_info->gamma_size); + out->gamma_size_error = crtc_info->gamma_size < 2 ? LIBGAMMA_SINGLETON_GAMMA_RAMP : 0; + drmModeFreeCrtc(crtc_info); + } + return out->gamma_size_error; +} + + +/** + * Get the a monitor's subpixel order + * + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param connector The connector. + */ +static void get_subpixel_order(libgamma_crtc_information_t* restrict out, + const drmModeConnector* restrict connector) +{ +#define __select(value) \ + case DRM_MODE_SUBPIXEL_##value: \ + out->subpixel_order = LIBGAMMA_SUBPIXEL_ORDER_##value; \ + break + + switch (connector->subpixel) + { + __select (UNKNOWN); + __select (HORIZONTAL_RGB); + __select (HORIZONTAL_BGR); + __select (VERTICAL_RGB); + __select (VERTICAL_BGR); + __select (NONE); + default: + out->subpixel_order_error = LIBGAMMA_SUBPIXEL_ORDER_NOT_RECOGNISED; + break; + } + +#undef __select +} + + +/** + * Get a connector's type + * + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param connector The connector. + * @param connector_name_base Output for the basename of the connector. + */ +static void get_connector_type(libgamma_crtc_information_t* restrict out, + const drmModeConnector* restrict connector, + const char** restrict connector_name_base) +{ +#define __select(type, name) \ + case DRM_MODE_CONNECTOR_##type: \ + out->connector_type = LIBGAMMA_CONNECTOR_TYPE_##type; \ + *connector_name_base = name; \ + break + + switch (connector->connector_type) + { +#ifndef DRM_MODE_CONNECTOR_VIRTUAL +# define DRM_MODE_CONNECTOR_VIRTUAL 15 +#endif +#ifndef DRM_MODE_CONNECTOR_DSI +# define DRM_MODE_CONNECTOR_DSI 16 +#endif + __select (Unknown, "Unknown" ); + __select (VGA, "VGA" ); + __select (DVII, "DVI-I" ); + __select (DVID, "DVI-D" ); + __select (DVIA, "DVI-A" ); + __select (Composite, "Composite"); + __select (SVIDEO, "SVIDEO" ); + __select (LVDS, "LVDS" ); + __select (Component, "Component"); + __select (9PinDIN, "DIN" ); + __select (DisplayPort, "DP" ); + __select (HDMIA, "HDMI-A" ); + __select (HDMIB, "HDMI-B" ); + __select (TV, "TV" ); + __select (eDP, "eDP" ); + __select (VIRTUAL, "VIRTUAL" ); + __select (DSI, "DSI" ); + default: + out->connector_type_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; + out->connector_name_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; + break; + } + +#undef __select +} + + +/** + * Read information from the CRTC's conncetor. + * + * @param crtc The state of the CRTC whose information should be read. + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param connector The CRTC's connector. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Non-zero if at least on error occured. + */ +static int read_connector_data(libgamma_crtc_state_t* restrict crtc, libgamma_crtc_information_t* restrict out, + const drmModeConnector* restrict connector, int32_t fields) +{ + const char* connector_name_base = NULL; + + /* Get some information that does not require too much work. */ + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM | LIBGAMMA_CRTC_INFO_HEIGHT_MM | LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE | + LIBGAMMA_CRTC_INFO_ACTIVE | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER))) + { + /* Get whether or not a monitor is plugged in. */ + out->active = connector->connection == DRM_MODE_CONNECTED; + out->active_error = connector->connection == DRM_MODE_UNKNOWNCONNECTION ? LIBGAMMA_STATE_UNKNOWN : 0; + if (out->active == 0) + { + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM | LIBGAMMA_CRTC_INFO_HEIGHT_MM | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER))) + out->width_mm_error = out->height_mm_error = out->subpixel_order_error = LIBGAMMA_NOT_CONNECTED; + goto not_connected; + } + + /* Get viewport dimension. */ + out->width_mm = connector->mmWidth; + out->height_mm = connector->mmHeight; + + /* Get subpixel order. */ + get_subpixel_order(out, connector); + + not_connected: + + /* Get connector type. */ + get_connector_type(out, connector, &connector_name_base); + } + + /* Get the connector's name. */ + if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_NAME) && (out->connector_name_error == 0)) + { + libgamma_drm_card_data_t* restrict card = crtc->partition->data; + uint32_t type = connector->connector_type; + size_t i, n = (size_t)(card->res->count_connectors), c = 0; + + out->connector_name = malloc((strlen(connector_name_base) + 12) * sizeof(char)); + if (out->connector_name == NULL) + return (out->connector_name_error = errno); + + for (i = 0; (i < n) && (card->connectors[i] != connector); i++) + if (card->connectors[i]->connector_type == type) + c++; + sprintf(out->connector_name, "%s-" PRIu32, connector_name_base, (uint32_t)(c + 1)); + } + + /* Did something go wrong? */ + return out->subpixel_order_error | out->active_error | out->connector_name_error; +} + + +/** + * Get the extended display identification data for a monitor. + * + * @param crtc The CRTC state. + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param connector The CRTC's connector. + * @reutnr Non-zero on error. + */ +static int get_edid(libgamma_crtc_state_t* restrict crtc, + libgamma_crtc_information_t* restrict out, drmModeConnector* connector) +{ + libgamma_drm_card_data_t* restrict card = crtc->partition->data; + int prop_n = connector->count_props; + int prop_i; + drmModePropertyRes* restrict prop; + drmModePropertyBlobRes* restrict blob; + + for (prop_i = 0; prop_i < prop_n; prop_i++) + { + prop = drmModeGetProperty(card->fd, connector->props[prop_i]); + if (prop == NULL) + continue; + if (!strcmp("EDID", prop->name)) + { + blob = drmModeGetPropertyBlob(card->fd, (uint32_t)(connector->prop_values[prop_i])); + if (blob == NULL) + { + drmModeFreeProperty(prop); + return out->edid_error = LIBGAMMA_PROPERTY_VALUE_QUERY_FAILED; + } + if (blob->data != NULL) + { + out->edid_length = blob->length; + out->edid = malloc(out->edid_length * sizeof(unsigned char)); + if (out->edid == NULL) + out->edid_error = errno; + else + memcpy(out->edid, blob->data, (size_t)(out->edid_length) * sizeof(char)); + drmModeFreePropertyBlob(blob); + return out->edid == NULL; + } + drmModeFreePropertyBlob(blob); + } + drmModeFreeProperty(prop); + } + return out->edid_error = LIBGAMMA_EDID_NOT_FOUND; +} + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_linux_drm_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + int e = 0; + drmModeConnector* restrict connector; + int require_connector; + int free_edid; + int error; + + + /* Wipe all error indicators. */ + memset(this, 0, sizeof(libgamma_crtc_information_t)); + + /* We need to free the EDID after us if it is not explicitly requested. */ + free_edid = (fields & LIBGAMMA_CRTC_INFO_EDID) == 0; + + /* Figure out what fields we need to get the data for to get the data for other fields. */ + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID | LIBGAMMA_CRTC_INFO_GAMMA))) + fields |= LIBGAMMA_CRTC_INFO_EDID; + if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_NAME)) + fields |= LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE; + if (LIBGAMMA_CRTC_INFO_EDID | LIBGAMMA_CRTC_INFO_WIDTH_MM | LIBGAMMA_CRTC_INFO_HEIGHT_MM | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER) + fields |= LIBGAMMA_CRTC_INFO_ACTIVE; + + /* Figure out whether we require the connector to get all information we want. */ + require_connector = fields & (LIBGAMMA_CRTC_INFO_ACTIVE | LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE); + + if (require_connector == 0) + goto cont; + if ((connector = find_connector(crtc, &error)) == NULL) + { + e |= this->width_mm_error = this->height_mm_error + = this->connector_type = this->subpixel_order_error + = this->active_error = this->connector_name_error + = this->edid_error = this->gamma_error + = this->width_mm_edid_error = this->height_mm_edid_error = error; + goto cont; + } + e |= read_connector_data(crtc, this, connector, fields); + if ((fields & LIBGAMMA_CRTC_INFO_EDID) == 0) + goto cont; + if (this->active_error || (this->active == 0)) + { + e |= this->edid_error = this->gamma_error + = this->width_mm_edid_error = this->height_mm_edid_error + = LIBGAMMA_NOT_CONNECTED; + goto cont; + } + e |= get_edid(crtc, this, connector); + if (this->edid == NULL) + { + this->gamma_error = this->width_mm_edid_error = this->height_mm_edid_error = this->edid_error; + goto cont; + } + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID | LIBGAMMA_CRTC_INFO_GAMMA))) + e |= libgamma_parse_edid(this, fields); + cont: + e |= (fields & LIBGAMMA_CRTC_INFO_GAMMA_SIZE) ? get_gamma_ramp_size(this, crtc) : 0; + this->gamma_depth = 16; + e |= this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); + + /* Free the EDID after us. */ + if (free_edid) + { + free(this->edid); + this->edid = NULL; + } + + return e ? -1 : 0; +#undef _E +} + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ + libgamma_drm_card_data_t* restrict card = this->partition->data; + int r; +#ifdef DEBUG + if ((ramps->red_size != ramps->green_size) || + (ramps->red_size != ramps->blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + r = drmModeCrtcGetGamma(card->fd, (uint32_t)(size_t)(this->data), (uint32_t)(ramps->red_size), + ramps->red, ramps->green, ramps->blue); + return r ? LIBGAMMA_GAMMA_RAMP_READ_FAILED : 0; +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ + libgamma_drm_card_data_t* restrict card = this->partition->data; + int r; +#ifdef DEBUG + if ((ramps.red_size != ramps.green_size) || + (ramps.red_size != ramps.blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + r = drmModeCrtcSetGamma(card->fd, (uint32_t)(size_t)(this->data), + (uint32_t)(ramps.red_size), ramps.red, ramps.green, ramps.blue); + if (r) + switch (errno) + { + case EACCES: + case EAGAIN: + case EIO: + /* Permission denied errors must be ignored, because we do not + * have permission to do this while a display server is active. + * We are also checking for some other error codes just in case. */ + case EBUSY: + case EINPROGRESS: + /* It is hard to find documentation for DRM (in fact all of this is + * just based on the functions names and some testing,) perhaps we + * could get this if we are updating to fast. */ + break; + case EBADF: + case ENODEV: + case ENXIO: + /* XXX: I have not actually tested removing my graphics card or, + * monitor but I imagine either of these is what would happen. */ + return LIBGAMMA_GRAPHICS_CARD_REMOVED; + + default: + return LIBGAMMA_ERRNO_SET; + } + return 0; +} + diff --git a/src/lib/gamma-linux-drm.h b/src/lib/gamma-linux-drm.h new file mode 100644 index 0000000..3d244aa --- /dev/null +++ b/src/lib/gamma-linux-drm.h @@ -0,0 +1,162 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_LINUX_DRM_H +#define LIBGAMMA_GAMMA_LINUX_DRM_H + +#ifndef HAVE_LIBGAMMA_METHOD_LINUX_DRM +# error Including gamma-linux-drm.h without HAVE_LIBGAMMA_METHOD_LINUX_DRM +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_linux_drm_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_linux_drm_site_destroy(libgamma_site_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_linux_drm_partition_destroy(libgamma_partition_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_linux_drm_crtc_destroy(libgamma_crtc_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_linux_drm_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_linux_drm_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps); + + +#endif + diff --git a/src/lib/gamma-quartz-cg.c b/src/lib/gamma-quartz-cg.c new file mode 100644 index 0000000..3832ca5 --- /dev/null +++ b/src/lib/gamma-quartz-cg.c @@ -0,0 +1,353 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# error Compiling gamma-quartz-cg.c without HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +#endif + +#include "gamma-quartz-cg.h" + +#include "libgamma-error.h" + +#ifdef FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# include "fake-quartz-cg.h" +#else +# include <CoreGraphics/CGDirectDisplay.h> +# define close_fake_quartz_cg() /* For compatibility with "fake-quartz-cg.h". */ +#endif + +#include <stdlib.h> +#include <errno.h> + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_quartz_cg_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ + this->crtc_information = LIBGAMMA_CRTC_INFO_GAMMA_SIZE + | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH; + this->default_site_known = 1; + this->multiple_sites = 0; + this->multiple_partitions = 0; + this->multiple_crtcs = 1; + this->partitions_are_graphics_cards = 0; + this->site_restore = 1; + this->partition_restore = 1; + this->crtc_restore = 0; + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 0; + this->fixed_gamma_depth = 1; +#ifdef FAKE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + this->fake = 1; +# ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + this->real = 1; +# else + this->real = 0; +# endif +#else + this->fake = 0; + this->real = 1; +#endif +} + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ + if (site != NULL) + return LIBGAMMA_NO_SUCH_SITE; + + this->partitions_available = 1; + return 0; +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_quartz_cg_site_destroy(libgamma_site_state_t* restrict this) +{ + (void) this; + close_fake_quartz_cg(); +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_site_restore(libgamma_site_state_t* restrict this) +{ + (void) this; + CGDisplayRestoreColorSyncSettings(); + return 0; +} + + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + uint32_t cap = 4, n; + CGDirectDisplayID* crtcs; + CGDirectDisplayID* crtcs_old; + CGError r; + + (void) site; + + this->data = NULL; + + if (partition != 0) + return LIBGAMMA_NO_SUCH_PARTITION; + + crtcs = malloc((size_t)cap * sizeof(CGDirectDisplayID)); + if (crtcs == NULL) + return LIBGAMMA_ERRNO_SET; + + for (;;) + { + r = CGGetOnlineDisplayList(cap, crtcs, &n); + if (r != kCGErrorSuccess) + { + free(crtcs); + return LIBGAMMA_LIST_CRTCS_FAILED; + } + if (n < cap) + break; + if (cap == 0) /* We could also test ~0, but it is still too many. */ + { + free(crtcs); + return LIBGAMMA_IMPOSSIBLE_AMOUNT; + } + crtcs_old = crtcs; + crtcs = realloc(crtcs, (size_t)cap * sizeof(CGDirectDisplayID)); + if (crtcs) + { + free(crtcs_old); + return LIBGAMMA_ERRNO_SET; + } + } + + this->data = crtcs; + this->crtcs_available = (size_t)n; + return 0; +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_quartz_cg_partition_destroy(libgamma_partition_state_t* restrict this) +{ + free(this->data); +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_partition_restore(libgamma_partition_state_t* restrict this) +{ + return libgamma_quartz_cg_site_restore(this->site); +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + (void) this; + if (crtc >= partition->crtcs_available) + return LIBGAMMA_NO_SUCH_CRTC; + return 0; +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_quartz_cg_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_quartz_cg_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#define SUPPORTED_FIELDS (LIBGAMMA_CRTC_INFO_GAMMA_SIZE | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH) + +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + + this->edid_error = _E(LIBGAMMA_CRTC_INFO_EDID); + this->width_mm_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM); + this->height_mm_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM); + this->width_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID); + this->height_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID); + if ((fields & LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + CGDirectDisplayID* crtcs = crtc->partition->data; + CGDirectDisplayID crtc_id = crtcs[crtc->crtc]; + size_t gamma_size = CGDisplayGammaTableCapacity(crtc_id);; + this->red_gamma_size = (size_t)gamma_size; + this->green_gamma_size = this->red_gamma_size; + this->blue_gamma_size = this->red_gamma_size; + this->gamma_size_error = gamma_size < 2 ? LIBGAMMA_SINGLETON_GAMMA_RAMP : 0; + } + else + this->gamma_size_error = 0; + this->gamma_depth = -1; + this->gamma_depth_error = 0; + this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); + this->subpixel_order_error = _E(LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER); + this->active_error = _E(LIBGAMMA_CRTC_INFO_ACTIVE); + this->connector_name_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_NAME); + this->connector_type_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE); + this->gamma_error = _E(LIBGAMMA_CRTC_INFO_GAMMA); + +#undef _E + + return this->gamma_size_error ? -1 : (fields & ~SUPPORTED_FIELDS) ? -1 : 0; + +#undef SUPPORTED_FIELDS +} + + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps) +{ + CGDirectDisplayID* restrict crtcs = this->partition->data; + CGDirectDisplayID crtc_id = crtcs[this->crtc]; + uint32_t gamma_size_out; + CGError r; +#ifdef DEBUG + if ((ramps->red_size != ramps->green_size) || + (ramps->red_size != ramps->blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + r = CGGetDisplayTransferByTable(crtc_id, (uint32_t)(ramps->red_size), + ramps->red, ramps->green, ramps->blue, &gamma_size_out); + if (r != kCGErrorSuccess) + return LIBGAMMA_GAMMA_RAMP_READ_FAILED; + if (gamma_size_out != ramps->red_size) + return LIBGAMMA_GAMMA_RAMP_SIZE_CHANGED; + return 0; +} + + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps) +{ + CGDirectDisplayID* restrict crtcs = this->partition->data; + CGDirectDisplayID crtc_id = crtcs[this->crtc]; + CGError r; +#ifdef DEBUG + if ((ramps.red_size != ramps.green_size) || + (ramps.red_size != ramps.blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + r = CGSetDisplayTransferByTable(crtc_id, (uint32_t)(ramps.red_size), + ramps.red, ramps.green, ramps.blue); + return r == kCGErrorSuccess ? 0 : LIBGAMMA_GAMMA_RAMP_WRITE_FAILED; +} + diff --git a/src/lib/gamma-quartz-cg.h b/src/lib/gamma-quartz-cg.h new file mode 100644 index 0000000..90f5244 --- /dev/null +++ b/src/lib/gamma-quartz-cg.h @@ -0,0 +1,162 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_QUARTZ_CG_H +#define LIBGAMMA_GAMMA_QUARTZ_CG_H + +#ifndef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# error Including gamma-quartz-cg.h without HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_quartz_cg_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_quartz_cg_site_destroy(libgamma_site_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_quartz_cg_partition_destroy(libgamma_partition_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) __attribute__((pure)); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_quartz_cg_crtc_destroy(libgamma_crtc_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_quartz_cg_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_quartz_cg_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps); + + +#endif + diff --git a/src/lib/gamma-w32-gdi.c b/src/lib/gamma-w32-gdi.c new file mode 100644 index 0000000..f8c00ee --- /dev/null +++ b/src/lib/gamma-w32-gdi.c @@ -0,0 +1,333 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_W32_GDI +# error Compiling gamma-w32-gdi.c without HAVE_LIBGAMMA_METHOD_W32_GDI +#endif + +#include "gamma-w32-gdi.h" + +#include "libgamma-error.h" + +#ifndef WINVER +# define WINVER 0x0500 +#endif +#ifdef FAKE_LIBGAMMA_METHOD_W32_GDI +# include "fake-w32-gdi.h" +#else +# include <windows.h> +# include <wingdi.h> +#endif + +#include <errno.h> + +#define GAMMA_RAMP_SIZE 256 + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_w32_gdi_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ + this->crtc_information = LIBGAMMA_CRTC_INFO_GAMMA_SIZE + | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH + | LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT; + this->default_site_known = 1; + this->multiple_sites = 0; + this->multiple_partitions = 0; + this->multiple_crtcs = 1; + this->partitions_are_graphics_cards = 0; + this->site_restore = 0; + this->partition_restore = 0; + this->crtc_restore = 0; + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 1; + this->fixed_gamma_depth = 1; +#ifdef FAKE_LIBGAMMA_METHOD_W32_GDI + this->fake = 1; +# ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + this->real = 1; +# else + this->real = 0; +# endif +#else + this->fake = 0; + this->real = 1; +#endif +} + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ + if (site != NULL) + return LIBGAMMA_NO_SUCH_SITE; + + this->partitions_available = 1; + return 0; +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_w32_gdi_site_destroy(libgamma_site_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_site_restore(libgamma_site_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + DWORD n = 0; + DISPLAY_DEVICE display; + + (void) site; + + if (partition != 0) + return LIBGAMMA_NO_SUCH_PARTITION; + + /* Count CRTC:s by iteration over all possible identifiers + until we reach on that does not exist. */ + display.cb = sizeof(DISPLAY_DEVICE); + while (EnumDisplayDevices(NULL, n, &display, 0)) + if (n++, n == 0) + return LIBGAMMA_IMPOSSIBLE_AMOUNT; + this->crtcs_available = (size_t)n; + return 0; +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_w32_gdi_partition_destroy(libgamma_partition_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_partition_restore(libgamma_partition_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + DISPLAY_DEVICE display; + HDC context; + + (void) partition; + + this->data = NULL; + + display.cb = sizeof(DISPLAY_DEVICE); /* Windows's API mandates this... */ + /* Get identifier for selected CRTC. */ + if (!EnumDisplayDevices(NULL, (DWORD)crtc, &display, 0)) + return LIBGAMMA_NO_SUCH_CRTC; + /* Check that the connector is enabled, + * newer versions of Windows will always pass. */ + if (!(display.StateFlags & DISPLAY_DEVICE_ACTIVE)) + return LIBGAMMA_CONNECTOR_DISABLED; + /* Acquire CRTC connection. */ + context = CreateDC(TEXT("DISPLAY"), display.DeviceName, NULL, NULL); + if (context == NULL) + return LIBGAMMA_OPEN_CRTC_FAILED; + this->data = context; + return 0; +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_w32_gdi_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + if (this->data) + ReleaseDC(NULL, this->data); +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_w32_gdi_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#define KNOWN_FIELDS (LIBGAMMA_CRTC_INFO_GAMMA_SIZE | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH | LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT) + +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + + this->edid_error = _E(LIBGAMMA_CRTC_INFO_EDID); + this->width_mm_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM); + this->height_mm_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM); + this->width_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID); + this->height_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID); + this->red_gamma_size = GAMMA_RAMP_SIZE; + this->green_gamma_size = GAMMA_RAMP_SIZE; + this->blue_gamma_size = GAMMA_RAMP_SIZE; + this->gamma_size_error = 0; + this->gamma_depth = 16; + this->gamma_depth_error = 0; + if ((fields & LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT)) + this->gamma_support = GetDeviceCaps(crtc->data, COLORMGMTCAPS) == CM_GAMMA_RAMP; + this->gamma_support_error = 0; + this->subpixel_order_error = _E(LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER); + this->active_error = _E(LIBGAMMA_CRTC_INFO_ACTIVE); + this->connector_name_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_NAME); + this->connector_type_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE); + this->gamma_error = _E(LIBGAMMA_CRTC_INFO_GAMMA); + +#undef _E + + return (fields & ~KNOWN_FIELDS) ? -1 : 0; + +#undef KNOWN_FIELDS +} + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ +#ifdef DEBUG + if ((ramps-> red_size != GAMMA_RAMP_SIZE) || + (ramps->green_size != GAMMA_RAMP_SIZE) || + (ramps-> blue_size != GAMMA_RAMP_SIZE)) + return LIBGAMMA_WRONG_GAMMA_RAMP_SIZE; +#endif + if (!GetDeviceGammaRamp(this->data, ramps->red)) + return LIBGAMMA_GAMMA_RAMP_READ_FAILED; + return 0; +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ +#ifdef DEBUG + if ((ramps. red_size != GAMMA_RAMP_SIZE) || + (ramps.green_size != GAMMA_RAMP_SIZE) || + (ramps. blue_size != GAMMA_RAMP_SIZE)) + return LIBGAMMA_WRONG_GAMMA_RAMP_SIZE; +#endif + if (!SetDeviceGammaRamp(this->data, ramps.red)) + return LIBGAMMA_GAMMA_RAMP_WRITE_FAILED; + return 0; +} + diff --git a/src/lib/gamma-w32-gdi.h b/src/lib/gamma-w32-gdi.h new file mode 100644 index 0000000..0e17720 --- /dev/null +++ b/src/lib/gamma-w32-gdi.h @@ -0,0 +1,162 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_W32_GDI_H +#define LIBGAMMA_GAMMA_W32_GDI_H + +#ifndef HAVE_LIBGAMMA_METHOD_W32_GDI +# error Including gamma-w32-gdi.h without HAVE_LIBGAMMA_METHOD_W32_GDI +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_w32_gdi_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_w32_gdi_site_destroy(libgamma_site_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_w32_gdi_partition_destroy(libgamma_partition_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_w32_gdi_crtc_destroy(libgamma_crtc_state_t* restrict this); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_w32_gdi_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_w32_gdi_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps); + + +#endif + diff --git a/src/lib/gamma-x-randr.c b/src/lib/gamma-x-randr.c new file mode 100644 index 0000000..9870f6b --- /dev/null +++ b/src/lib/gamma-x-randr.c @@ -0,0 +1,916 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_X_RANDR +# error Compiling gamma-x-randr.c without HAVE_LIBGAMMA_METHOD_X_RANDR +#endif + +#include "gamma-x-randr.h" + +#include "libgamma-error.h" +#include "edid.h" + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <stdint.h> +#ifdef DEBUG +# include <stdio.h> +#endif + +#include <xcb/xcb.h> +#include <xcb/randr.h> + + +/** + * The major version of RandR the library expects. + */ +#define RANDR_VERSION_MAJOR 1 + +/** + * The minor version of RandR the library expects. + */ +#define RANDR_VERSION_MINOR 3 + + + +/** + * Data structure for partition data. + */ +typedef struct libgamma_x_randr_partition_data +{ + /** + * Mapping from CRTC indices to CRTC identifiers. + */ + xcb_randr_crtc_t* crtcs; + + /** + * Mapping from output indices to output identifiers. + */ + xcb_randr_output_t* outputs; + + /** + * The number of outputs available. + */ + size_t outputs_count; + + /** + * Mapping from CRTC indices to output indices. + * CRTC's without an output (should be impossible) + * have the value `SIZE_MAX` which is impossible + * for an existing mapping. + */ + size_t* crtc_to_output; + + /** + * Screen configuration timestamp. + */ + xcb_timestamp_t config_timestamp; + +} libgamma_x_randr_partition_data_t; + + + +/** + * Translate an xcb error into a libgamma error. + * + * @param error_code The xcb error. + * @param default_error The libgamma error to use if the xcb error is not recognised. + * @return The libgamma error. + */ +static int translate_error_(int error_code, int default_error) +{ + switch (error_code) + { + case XCB_CONN_ERROR: return errno = ECONNABORTED, LIBGAMMA_ERRNO_SET; + case XCB_CONN_CLOSED_EXT_NOTSUPPORTED: return errno = ENOPROTOOPT, LIBGAMMA_ERRNO_SET; + case XCB_CONN_CLOSED_MEM_INSUFFICIENT: return errno = ENOMEM, LIBGAMMA_ERRNO_SET; + case XCB_CONN_CLOSED_REQ_LEN_EXCEED: return errno = EMSGSIZE, LIBGAMMA_ERRNO_SET; + case XCB_CONN_CLOSED_PARSE_ERR: return LIBGAMMA_NO_SUCH_SITE; + case XCB_CONN_CLOSED_INVALID_SCREEN: return LIBGAMMA_NO_SUCH_PARTITION; + case XCB_CONN_CLOSED_FDPASSING_FAILED: return errno = EIO, LIBGAMMA_ERRNO_SET; + default: + return default_error; + } +} + + +/** + * Translate an xcb error into a libgamma error. + * + * @param error_code The xcb error. + * @param default_error The libgamma error to use if the xcb error is not recognised. + * @param return_errno Whether an `errno` value may be returned. + * @return The libgamma error. + */ +static int translate_error(int error_code, int default_error, int return_errno) +{ + int r = translate_error_(error_code, default_error); + return return_errno ? (r > 0 ? errno : r) : r; +} + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_x_randr_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ + char* display = getenv("DISPLAY"); + this->crtc_information = LIBGAMMA_CRTC_INFO_EDID + | LIBGAMMA_CRTC_INFO_WIDTH_MM + | LIBGAMMA_CRTC_INFO_HEIGHT_MM + | LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID + | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID + | LIBGAMMA_CRTC_INFO_GAMMA_SIZE + | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH + | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER + | LIBGAMMA_CRTC_INFO_CONNECTOR_NAME + | LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE + | LIBGAMMA_CRTC_INFO_GAMMA; + this->default_site_known = (display && *display) ? 1 : 0; + this->multiple_sites = 1; + this->multiple_partitions = 1; + this->multiple_crtcs = 1; + this->partitions_are_graphics_cards = 0; + this->site_restore = 0; + this->partition_restore = 0; + this->crtc_restore = 0; + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 0; + this->fixed_gamma_depth = 1; + this->real = 1; + this->fake = 0; +} + + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Waggregate-return" + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ + xcb_generic_error_t* error = NULL; + xcb_connection_t* restrict connection; + xcb_randr_query_version_cookie_t cookie; + xcb_randr_query_version_reply_t* restrict reply; + const xcb_setup_t* restrict setup; + xcb_screen_iterator_t iter; + + this->data = connection = xcb_connect(site, NULL); + if (connection == NULL) + return LIBGAMMA_NO_SUCH_SITE; + + cookie = xcb_randr_query_version(connection, RANDR_VERSION_MAJOR, RANDR_VERSION_MINOR); + reply = xcb_randr_query_version_reply(connection, cookie, &error); + + if ((error != NULL) || (reply == NULL)) + { + free(reply); + xcb_disconnect(connection); + if (error != NULL) + return translate_error(error->error_code, LIBGAMMA_PROTOCOL_VERSION_QUERY_FAILED, 0); + return LIBGAMMA_PROTOCOL_VERSION_QUERY_FAILED; + } + + if ((reply->major_version != RANDR_VERSION_MAJOR) || + (reply->minor_version < RANDR_VERSION_MINOR)) + { +#ifdef DEBUG + fprintf(stderr, "libgamma: RandR protocol version: %u.%u", reply->major_version, reply->minor_version); +#endif + free(reply); + xcb_disconnect(connection); + return LIBGAMMA_PROTOCOL_VERSION_NOT_SUPPORTED; + } + + free(reply); + + if ((setup = xcb_get_setup(connection)) == NULL) + { + xcb_disconnect(connection); + return LIBGAMMA_LIST_PARTITIONS_FAILED; + } + iter = xcb_setup_roots_iterator(setup); + this->partitions_available = (size_t)(iter.rem); + + return iter.rem < 0 ? LIBGAMMA_NEGATIVE_PARTITION_COUNT : 0; +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_x_randr_site_destroy(libgamma_site_state_t* restrict this) +{ + xcb_disconnect((xcb_connection_t*)(this->data)); +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_site_restore(libgamma_site_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + +/** + * Duplicate a memory area. + * + * @param ptr The memory aree. + * @param bytes The size, in bytes, of the memory area. + * @return A duplication of the memory, `NULL` if zero-length or on error. + */ +static inline void* memdup(void* restrict ptr, size_t bytes) +{ + char* restrict rc; + if (bytes == 0) + return NULL; + if ((rc = malloc(bytes)) == NULL) + return NULL; + memcpy(rc, ptr, bytes); + return rc; +} + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + int fail_rc = LIBGAMMA_ERRNO_SET; + xcb_connection_t* restrict connection = site->data; + const xcb_setup_t* restrict setup = xcb_get_setup(connection); + xcb_screen_t* restrict screen = NULL; + xcb_generic_error_t* error = NULL; + xcb_screen_iterator_t iter; + xcb_randr_get_screen_resources_current_cookie_t cookie; + xcb_randr_get_screen_resources_current_reply_t* restrict reply; + xcb_randr_crtc_t* restrict crtcs; + xcb_randr_output_t* restrict outputs; + libgamma_x_randr_partition_data_t* restrict data; + size_t i; + + if (setup == NULL) + return LIBGAMMA_LIST_PARTITIONS_FAILED; + + for (i = 0; iter.rem > 0; i++, xcb_screen_next(&iter)) + if (i == partition) + { + screen = iter.data; + break; + } + if (iter.rem == 0) + return LIBGAMMA_NO_SUCH_PARTITION; + + if (screen == NULL) + return LIBGAMMA_NULL_PARTITION; + + cookie = xcb_randr_get_screen_resources_current(connection, screen->root); + reply = xcb_randr_get_screen_resources_current_reply(connection, cookie, &error); + if (error != NULL) + return translate_error(error->error_code, LIBGAMMA_LIST_CRTCS_FAILED, 0); + + this->crtcs_available = reply->num_crtcs; + crtcs = xcb_randr_get_screen_resources_current_crtcs(reply); + outputs = xcb_randr_get_screen_resources_current_outputs(reply); + if ((crtcs == NULL) || (outputs == NULL)) + { + free(reply); + return LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED; + } + + /* We use `calloc` because we want `data`'s pointers to be `NULL` if not allocated at `fail`. */ + data = calloc(1, sizeof(libgamma_x_randr_partition_data_t)); + if (data == NULL) + goto fail; + + /* Copy the CRTC:s, just so we do not have to keep the reply in memory. */ + data->crtcs = memdup(crtcs, (size_t)(reply->num_crtcs) * sizeof(xcb_randr_crtc_t)); + if ((data->crtcs == NULL) && (reply->num_crtcs > 0)) + goto fail; + + /* Copy the outputs as well. */ + data->outputs = memdup(outputs, (size_t)(reply->num_outputs) * sizeof(xcb_randr_output_t)); + if ((data->outputs == NULL) && (reply->num_outputs > 0)) + goto fail; + + data->outputs_count = (size_t)(reply->num_outputs); + + data->crtc_to_output = malloc((size_t)(reply->num_crtcs) * sizeof(size_t)); + if (data->crtc_to_output == NULL) + goto fail; + for (i = 0; i < (size_t)(reply->num_crtcs); i++) + data->crtc_to_output[i] = SIZE_MAX; + for (i = 0; i < (size_t)(reply->num_outputs); i++) + { + xcb_randr_get_output_info_cookie_t out_cookie; + xcb_randr_get_output_info_reply_t* out_reply; + uint16_t j; + + out_cookie = xcb_randr_get_output_info(connection, outputs[i], reply->config_timestamp); + out_reply = xcb_randr_get_output_info_reply(connection, out_cookie, &error); + if (error != NULL) + { + fail_rc = translate_error(error->error_code, LIBGAMMA_OUTPUT_INFORMATION_QUERY_FAILED, 0); + goto fail; + } + + for (j = 0; j < reply->num_crtcs; j++) + if (crtcs[j] == out_reply->crtc) + { + data->crtc_to_output[j] = i; + break; + } + + free(out_reply); + } + + data->config_timestamp = reply->config_timestamp; + this->data = data; + free(reply); + return 0; + + fail: + if (data != NULL) + { + free(data->crtcs); + free(data->outputs); + free(data->crtc_to_output); + free(data); + } + free(reply); + return fail_rc; +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_x_randr_partition_destroy(libgamma_partition_state_t* restrict this) +{ + libgamma_x_randr_partition_data_t* restrict data = this->data; + free(data->crtcs); + free(data->outputs); + free(data->crtc_to_output); + free(data); +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_partition_restore(libgamma_partition_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + libgamma_x_randr_partition_data_t* restrict screen_data = partition->data; + xcb_randr_crtc_t* restrict crtc_ids = screen_data->crtcs; + if (crtc >= partition->crtcs_available) + return LIBGAMMA_NO_SUCH_CRTC; + this->data = crtc_ids + crtc; + return 0; +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_x_randr_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Get the gamma ramp size of a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @return Non-zero on error. + */ +static int get_gamma_ramp_size(libgamma_crtc_information_t* restrict out, libgamma_crtc_state_t* restrict crtc) +{ + xcb_connection_t* restrict connection = crtc->partition->site->data; + xcb_randr_crtc_t* restrict crtc_id = crtc->data; + xcb_randr_get_crtc_gamma_size_cookie_t cookie; + xcb_randr_get_crtc_gamma_size_reply_t* restrict reply; + xcb_generic_error_t* error; + + out->gamma_size_error = 0; + cookie = xcb_randr_get_crtc_gamma_size(connection, *crtc_id); + reply = xcb_randr_get_crtc_gamma_size_reply(connection, cookie, &error); + if (error != NULL) + return out->gamma_size_error = translate_error(error->error_code, LIBGAMMA_GAMMA_RAMPS_SIZE_QUERY_FAILED, 1); + if (reply->size < 2) + out->gamma_size_error = LIBGAMMA_SINGLETON_GAMMA_RAMP; + out->red_gamma_size = out->green_gamma_size = out->blue_gamma_size = reply->size; + free(reply); + return out->gamma_size_error; +} + + +/** + * Read information from the CRTC's output. + * + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param output The CRTC's output information. + * @return Non-zero if at least on error occured. + */ +static int read_output_data(libgamma_crtc_information_t* restrict out, xcb_randr_get_output_info_reply_t* restrict output) +{ + switch (output->connection) + { + case XCB_RANDR_CONNECTION_CONNECTED: + out->active = 1; + out->width_mm = output->mm_width; + out->height_mm = output->mm_height; +#define __select(value) \ + case XCB_RENDER_SUB_PIXEL_##value: out->subpixel_order = LIBGAMMA_SUBPIXEL_ORDER_##value; break + switch (output->subpixel_order) + { + __select (UNKNOWN); + __select (HORIZONTAL_RGB); + __select (HORIZONTAL_BGR); + __select (VERTICAL_RGB); + __select (VERTICAL_BGR); + __select (NONE); + default: + out->subpixel_order_error = LIBGAMMA_SUBPIXEL_ORDER_NOT_RECOGNISED; + break; + } +#undef __select + return 0; + + case XCB_RANDR_CONNECTION_DISCONNECTED: + out->active = 0; + out->width_mm_error = LIBGAMMA_NOT_CONNECTED; + out->height_mm_error = LIBGAMMA_NOT_CONNECTED; + out->subpixel_order_error = LIBGAMMA_NOT_CONNECTED; + return 0; + + default: + out->active = 0; + out->active_error = LIBGAMMA_STATE_UNKNOWN; + out->width_mm_error = LIBGAMMA_NOT_CONNECTED; + out->height_mm_error = LIBGAMMA_NOT_CONNECTED; + out->subpixel_order_error = LIBGAMMA_NOT_CONNECTED; + return -1; + } +} + + +/** + * Determine the connector type from the connector name. + * + * @param this The CRTC information to use and extend. + * @param Non-zero on error. + */ +static int get_connector_type(libgamma_crtc_information_t* restrict this) +{ + if ((this->connector_type_error = this->connector_name_error)) + return -1; + +#define __select(name, type) \ + if (strstr(this->connector_name, name "-") == this->connector_name) \ + return this->connector_type = LIBGAMMA_CONNECTOR_TYPE_##type, 0 + + __select ("None", Unknown); + __select ("VGA", VGA); + __select ("DVI-I", DVII); + __select ("DVI-D", DVID); + __select ("DVI-A", DVIA); + __select ("Composite", Composite); + __select ("S-Video", SVIDEO); + __select ("Component", Component); + __select ("LFP", LFP); + __select ("Proprietary", Unknown); + __select ("HDMI", HDMI); + __select ("DisplayPort", DisplayPort); + +#undef __select + + this->connector_name_error = LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED; + return -1; +} + + +/** + * Get the output name of a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param output The CRTC's output's information. + * @return Non-zero on error. + */ +static int get_output_name(libgamma_crtc_information_t* restrict out, xcb_randr_get_output_info_reply_t* restrict output) +{ + char* restrict store; + uint8_t* restrict name; + uint16_t length; + size_t i; + + name = xcb_randr_get_output_info_name(output); + length = output->name_len; /* There is no NUL-termination. */ + if (name == NULL) + { + out->connector_name_error = LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED; + return -1; + } + + store = malloc(((size_t)length + 1) * sizeof(char)); + if (store == NULL) + { + out->connector_name_error = errno; + return -1; + } + + /* char is guaranteed to be (u)int_least8_t, but it is only guaranteed to be (u)int8_t + * on POSIX, so to be truly portable we will not assume that char is (u)int8_t. */ + for (i = 0; i < (size_t)length; i++) + store[i] = (char)(name[i]); + store[length] = '\0'; + + return 0; +} + + +/** + * Get the Extended Display Information Data of the monitor connected to the connector of a CRTC. + * + * @param out Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param output The CRTC's output. + * @return Non-zero on error. + */ +static int get_edid(libgamma_crtc_information_t* restrict out, + libgamma_crtc_state_t* restrict crtc, xcb_randr_output_t output) +{ + xcb_connection_t* restrict connection = crtc->partition->site->data; + xcb_randr_list_output_properties_cookie_t prop_cookie; + xcb_randr_list_output_properties_reply_t* restrict prop_reply; + xcb_atom_t* atoms; + xcb_atom_t* atoms_end; + xcb_generic_error_t* error; + + /* Acquire a list of all properties of the output. */ + prop_cookie = xcb_randr_list_output_properties(connection, output); + prop_reply = xcb_randr_list_output_properties_reply(connection, prop_cookie, &error); + + if (error != NULL) + return out->edid_error = translate_error(error->error_code, LIBGAMMA_LIST_PROPERTIES_FAILED, 1); + + /* Extract the properties form the data structure that holds them, */ + atoms = xcb_randr_list_output_properties_atoms(prop_reply); + /* and get the last one so that we can iterate over them nicely. */ + atoms_end = atoms + xcb_randr_list_output_properties_atoms_length(prop_reply); + + if (atoms == NULL) + { + free(prop_reply); + return out->edid_error = LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED;; + } + + /* For each property */ + for (; atoms != atoms_end; atoms++) + { + xcb_get_atom_name_cookie_t atom_name_cookie; + xcb_get_atom_name_reply_t* restrict atom_name_reply; + char* restrict atom_name; + int atom_name_len; + xcb_randr_get_output_property_cookie_t atom_cookie; + xcb_randr_get_output_property_reply_t* restrict atom_reply; + unsigned char* restrict atom_data; + int length; + + /* Acquire the atom name. */ + atom_name_cookie = xcb_get_atom_name(connection, *atoms); + atom_name_reply = xcb_get_atom_name_reply(connection, atom_name_cookie, &error); + if (error) + continue; + + /* Extract the atom name from the data structure that holds it. */ + atom_name = xcb_get_atom_name_name(atom_name_reply); + /* As well as the length of the name; it is not NUL-termianted.*/ + atom_name_len = xcb_get_atom_name_name_length(atom_name_reply); + + if (/* Check for errors. */ + (atom_name == NULL) || /* (atom_name_len < 1) || */ + /* Check that the length is the expected length for the EDID property. */ + (atom_name_len != 4) || + /* Check that the property is the EDID property. */ + (atom_name[0] != 'E') || (atom_name[1] != 'D') || (atom_name[2] != 'I') || (atom_name[3] != 'D')) + { + free(atom_name_reply); + continue; + } + + /* Acquire the property's value, we know that it is either 128 or 256 byte long. */ + atom_cookie = xcb_randr_get_output_property(connection, output, *atoms, + XCB_GET_PROPERTY_TYPE_ANY, 0, 256, 0, 0); + atom_reply = xcb_randr_get_output_property_reply(connection, atom_cookie, &error); + /* (*) EDID version 1.0 through 1.4 define it as 128 bytes long, + * but version 2.0 define it as 256 bytes long. However, + * version 2.0 is rare(?) and has been deprecated and replaced + * by version 1.3 (I guess that is with a new version epoch, + * but I do not know.) */ + if (error) + { + free(atom_name_reply); + free(prop_reply); + return out->edid_error = LIBGAMMA_PROPERTY_VALUE_QUERY_FAILED; + } + + /* Extract the property's value, */ + atom_data = xcb_randr_get_output_property_data(atom_reply); + /* and its actual length. */ + length = xcb_randr_get_output_property_data_length(atom_reply); + if ((atom_data == NULL) || (length < 1)) + { + free(atom_reply); + free(atom_name_reply); + free(prop_reply); + return out->edid_error = LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED; + } + + /* Store the EDID. */ + out->edid = malloc((size_t)length * sizeof(unsigned char)); + if (out->edid == NULL) + out->edid_error = errno; + else + memcpy(out->edid, atom_data, (size_t)length * sizeof(unsigned char)); + + free(atom_reply); + free(atom_name_reply); + free(prop_reply); + + return out->edid_error; + } + + return out->edid_error = LIBGAMMA_EDID_NOT_FOUND; +} + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`.. + */ +int libgamma_x_randr_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + int e = 0; + xcb_randr_get_output_info_reply_t* restrict output_info = NULL; + xcb_randr_output_t output; + int free_edid; + + /* Wipe all error indicators. */ + memset(this, 0, sizeof(libgamma_crtc_information_t)); + + /* We need to free the EDID after us if it is not explicitly requested. */ + free_edid = (fields & LIBGAMMA_CRTC_INFO_EDID) == 0; + + /* Figure out what fields we need to get the data for to get the data for other fields. */ + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID | LIBGAMMA_CRTC_INFO_GAMMA))) + fields |= LIBGAMMA_CRTC_INFO_EDID; + if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE)) + fields |= LIBGAMMA_CRTC_INFO_CONNECTOR_NAME; + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM | LIBGAMMA_CRTC_INFO_HEIGHT_MM | LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER))) + fields |= LIBGAMMA_CRTC_INFO_ACTIVE; + + /* Jump if the output information is not required. */ + if ((fields & (LIBGAMMA_CRTC_INFO_ACTIVE | LIBGAMMA_CRTC_INFO_CONNECTOR_NAME)) == 0) + goto cont; + + /* Get connector and connector information. */ + { + xcb_connection_t* restrict connection = crtc->partition->site->data; + libgamma_x_randr_partition_data_t* restrict screen_data = crtc->partition->data; + size_t output_index = screen_data->crtc_to_output[crtc->crtc]; + xcb_randr_get_output_info_cookie_t cookie; + xcb_generic_error_t* error; + if (output_index == SIZE_MAX) + { + e |= this->edid_error = this->gamma_error = this->width_mm_edid_error + = this->height_mm_edid_error = this->connector_type_error + = this->connector_name_error = this->subpixel_order_error + = this->width_mm_error = this->height_mm_error + = this->active_error = LIBGAMMA_CONNECTOR_UNKNOWN; + goto cont; + } + output = screen_data->outputs[output_index]; + cookie = xcb_randr_get_output_info(connection, output, screen_data->config_timestamp); + output_info = xcb_randr_get_output_info_reply(connection, cookie, &error); + if (error != NULL) + { + e |= this->edid_error = this->gamma_error = this->width_mm_edid_error + = this->height_mm_edid_error = this->connector_type_error + = this->connector_name_error = this->subpixel_order_error + = this->width_mm_error = this->height_mm_error + = this->active_error = LIBGAMMA_OUTPUT_INFORMATION_QUERY_FAILED; + goto cont; + } + } + + e |= get_output_name(this, output_info); + if ((fields & LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE)) + e |= get_connector_type(this); + e |= read_output_data(this, output_info); + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM | LIBGAMMA_CRTC_INFO_HEIGHT_MM))) + e |= this->width_mm_error | this->height_mm_error; + e |= (fields & LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER) ? this->subpixel_order_error : 0; + + if ((fields & LIBGAMMA_CRTC_INFO_EDID) == 0) + goto cont; + if (this->active == 0) + { + e |= this->edid_error = this->gamma_error = this->width_mm_edid_error + = this->height_mm_edid_error = LIBGAMMA_NOT_CONNECTED; + goto cont; + } + e |= get_edid(this, crtc, output); + if (this->edid == NULL) + { + this->gamma_error = this->width_mm_edid_error = this->height_mm_edid_error = this->edid_error; + goto cont; + } + if ((fields & (LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID | LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID | LIBGAMMA_CRTC_INFO_GAMMA))) + e |= libgamma_parse_edid(this, fields); + + cont: + e |= (fields & LIBGAMMA_CRTC_INFO_GAMMA_SIZE) ? get_gamma_ramp_size(this, crtc) : 0; + this->gamma_depth = 16; + e |= this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); + + /* Free the EDID after us. */ + if (free_edid) + { + free(this->edid); + this->edid = NULL; + } + + free(output_info); + return e ? -1 : 0; +#undef _E +} + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ + xcb_connection_t* restrict connection = this->partition->site->data; + xcb_randr_get_crtc_gamma_cookie_t cookie; + xcb_randr_get_crtc_gamma_reply_t* restrict reply; + xcb_generic_error_t* error; + uint16_t* restrict red; + uint16_t* restrict green; + uint16_t* restrict blue; + +#ifdef DEBUG + if ((ramps->red_size != ramps->green_size) || + (ramps->red_size != ramps->blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + + cookie = xcb_randr_get_crtc_gamma(connection, *(xcb_randr_crtc_t*)(this->data)); + reply = xcb_randr_get_crtc_gamma_reply(connection, cookie, &error); + + if (error != NULL) + return translate_error(error->error_code, LIBGAMMA_GAMMA_RAMP_READ_FAILED, 0); + + red = xcb_randr_get_crtc_gamma_red(reply); + green = xcb_randr_get_crtc_gamma_green(reply); + blue = xcb_randr_get_crtc_gamma_blue(reply); + memcpy(ramps->red, red, ramps->red_size * sizeof(uint16_t)); + memcpy(ramps->green, green, ramps->green_size * sizeof(uint16_t)); + memcpy(ramps->blue, blue, ramps->blue_size * sizeof(uint16_t)); + + free(reply); + return 0; +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ + xcb_connection_t* restrict connection = this->partition->site->data; + xcb_void_cookie_t cookie; + xcb_generic_error_t* restrict error; +#ifdef DEBUG + if ((ramps.red_size != ramps.green_size) || + (ramps.red_size != ramps.blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + cookie = xcb_randr_set_crtc_gamma_checked(connection, *(xcb_randr_crtc_t*)(this->data), + (uint16_t)(ramps.red_size), ramps.red, ramps.green, ramps.blue); + if ((error = xcb_request_check(connection, cookie)) != NULL) + return translate_error(error->error_code, LIBGAMMA_GAMMA_RAMP_WRITE_FAILED, 0); + return 0; +} + + +# pragma GCC diagnostic pop + diff --git a/src/lib/gamma-x-randr.h b/src/lib/gamma-x-randr.h new file mode 100644 index 0000000..dc1ecdc --- /dev/null +++ b/src/lib/gamma-x-randr.h @@ -0,0 +1,162 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_X_RANDR_H +#define LIBGAMMA_GAMMA_X_RANDR_H + +#ifndef HAVE_LIBGAMMA_METHOD_X_RANDR +# error Including gamma-x-randr.h without HAVE_LIBGAMMA_METHOD_X_RANDR +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_x_randr_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_x_randr_site_destroy(libgamma_site_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_x_randr_partition_destroy(libgamma_partition_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_x_randr_crtc_destroy(libgamma_crtc_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_x_randr_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_randr_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps); + + +#endif + diff --git a/src/lib/gamma-x-vidmode.c b/src/lib/gamma-x-vidmode.c new file mode 100644 index 0000000..a73f36f --- /dev/null +++ b/src/lib/gamma-x-vidmode.c @@ -0,0 +1,292 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef HAVE_LIBGAMMA_METHOD_X_VIDMODE +# error Compiling gamma-x-vidmode.c without HAVE_LIBGAMMA_METHOD_X_VIDMODE +#endif + +#include "gamma-x-vidmode.h" + +#include "libgamma-error.h" + +#include <X11/Xlib.h> +#include <X11/extensions/xf86vmode.h> + +#include <stdlib.h> +#include <errno.h> + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_x_vidmode_method_capabilities(libgamma_method_capabilities_t* restrict this) +{ + char* restrict display = getenv("DISPLAY"); + this->crtc_information = LIBGAMMA_CRTC_INFO_GAMMA_SIZE + | LIBGAMMA_CRTC_INFO_GAMMA_DEPTH; + this->default_site_known = (display && *display); + this->multiple_sites = 1; + this->multiple_partitions = 1; + this->multiple_crtcs = 1; + this->partitions_are_graphics_cards = 0; + this->site_restore = 0; + this->partition_restore = 0; + this->crtc_restore = 0; + this->identical_gamma_sizes = 1; + this->fixed_gamma_size = 0; + this->fixed_gamma_depth = 1; + this->real = 1; + this->fake = 0; +} + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site) +{ + Display* restrict connection = XOpenDisplay(site); + int _major, _minor, screens; + if ((this->data = connection) == NULL) + return LIBGAMMA_OPEN_SITE_FAILED; + if (!XF86VidModeQueryVersion(connection, &_major, &_minor)) + return LIBGAMMA_PROTOCOL_VERSION_QUERY_FAILED; + if ((screens = ScreenCount(connection)) < 0) + return LIBGAMMA_NEGATIVE_PARTITION_COUNT; + this->partitions_available = (size_t)screens; + return 0; +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_x_vidmode_site_destroy(libgamma_site_state_t* restrict this) +{ + XCloseDisplay((Display*)(this->data)); +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_site_restore(libgamma_site_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + if (partition >= site->partitions_available) + return LIBGAMMA_NO_SUCH_PARTITION; + this->crtcs_available = 1; + return 0; +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_x_vidmode_partition_destroy(libgamma_partition_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_partition_restore(libgamma_partition_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + (void) this; + (void) partition; + return crtc == 0 ? 0 : LIBGAMMA_NO_SUCH_CRTC; +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_x_vidmode_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + (void) this; +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + (void) this; + return errno = ENOTSUP, LIBGAMMA_ERRNO_SET; +} + + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_x_vidmode_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#define _E(FIELD) ((fields & FIELD) ? LIBGAMMA_CRTC_INFO_NOT_SUPPORTED : 0) + + this->edid_error = _E(LIBGAMMA_CRTC_INFO_EDID); + this->width_mm_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM); + this->height_mm_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM); + this->width_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID); + this->height_mm_edid_error = _E(LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID); + this->gamma_size_error = 0; + if ((fields & LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT)) + { + Display* restrict connection = crtc->partition->site->data; + int stops; + if (!XF86VidModeGetGammaRampSize(connection, (int)(crtc->partition->partition), &stops)) + this->gamma_size_error = LIBGAMMA_GAMMA_RAMPS_SIZE_QUERY_FAILED; + else if (stops < 2) + this->gamma_size_error = LIBGAMMA_SINGLETON_GAMMA_RAMP; + else + this->red_gamma_size = this->green_gamma_size = this->blue_gamma_size = (size_t)stops; + } + this->gamma_depth = 16; + this->gamma_depth_error = 0; + this->gamma_support_error = _E(LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT); + this->subpixel_order_error = _E(LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER); + this->active_error = _E(LIBGAMMA_CRTC_INFO_ACTIVE); + this->connector_name_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_NAME); + this->connector_type_error = _E(LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE); + this->gamma_error = _E(LIBGAMMA_CRTC_INFO_GAMMA); + +#undef _E + + return (fields & ~(LIBGAMMA_CRTC_INFO_GAMMA_DEPTH | LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) ? -1 : this->gamma_size_error; +} + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ +#ifdef DEBUG + if ((ramps->red_size != ramps->green_size) || + (ramps->red_size != ramps->blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + if (!XF86VidModeGetGammaRamp((Display*)(this->partition->site->data), (int)(this->partition->partition), + (int)(ramps->red_size), ramps->red, ramps->green, ramps->blue)) + return LIBGAMMA_GAMMA_RAMP_READ_FAILED; + return 0; +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ +#ifdef DEBUG + if ((ramps.red_size != ramps.green_size) || + (ramps.red_size != ramps.blue_size)) + return LIBGAMMA_MIXED_GAMMA_RAMP_SIZE; +#endif + if (!XF86VidModeSetGammaRamp((Display*)(this->partition->site->data), (int)(this->partition->partition), + (int)(ramps.red_size), ramps.red, ramps.green, ramps.blue)) + return LIBGAMMA_GAMMA_RAMP_WRITE_FAILED; + return 0; +} + diff --git a/src/lib/gamma-x-vidmode.h b/src/lib/gamma-x-vidmode.h new file mode 100644 index 0000000..8378726 --- /dev/null +++ b/src/lib/gamma-x-vidmode.h @@ -0,0 +1,162 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_GAMMA_X_VIDMODE_H +#define LIBGAMMA_GAMMA_X_VIDMODE_H + +#ifndef HAVE_LIBGAMMA_METHOD_X_VIDMODE +# error Including gamma-x-vidmode.h without HAVE_LIBGAMMA_METHOD_X_VIDMODE +#endif + + +#include "libgamma-method.h" + + +/** + * Return the capabilities of the adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + */ +void libgamma_x_vidmode_method_capabilities(libgamma_method_capabilities_t* restrict this); + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_site_initialise(libgamma_site_state_t* restrict this, + char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_x_vidmode_site_destroy(libgamma_site_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_x_vidmode_partition_destroy(libgamma_partition_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) __attribute__((const)); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_x_vidmode_crtc_destroy(libgamma_crtc_state_t* restrict this) __attribute__((const)); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_x_vidmode_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_x_vidmode_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps); + + +#endif + diff --git a/src/lib/libgamma-error.c.gpp b/src/lib/libgamma-error.c.gpp new file mode 100644 index 0000000..d443f74 --- /dev/null +++ b/src/lib/libgamma-error.c.gpp @@ -0,0 +1,133 @@ +/* -*- c -*- */ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#include "libgamma-error.h" + + +#include <stddef.h> +#include <sys/types.h> +#include <string.h> +#include <stdio.h> +#include <errno.h> + + + +£>set -u +£>cd src/extract +£>export PATH=".:${PATH}" + + + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned. + */ +gid_t libgamma_group_gid = 0; + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned, + * `NULL` if the name of the group `libgamma_group_gid` cannot be determined. + */ +const char* libgamma_group_name = NULL; + + + +/** + * Prints an error to stderr in a `perror` fashion, + * however this function will not translate the `libgamma` + * errors into human-readable strings, it will simply + * print the name of the error. If the value `error_code` + * is the value of `LIBGAMMA_ERRNO_SET`, `perror` will be + * used to print the current error stored in `errno`. + * If `error_code` is non-negative (an `errno` value`), that + * value will be stored in `errno` and `perror` will be + * used to print it. Additionally, if the `error_code` is + * the value of `LIBGAMMA_DEVICE_REQUIRE_GROUP` the + * required group will be printed with its numerical value + * and, if known, its name. + * + * @param name The text to add at the beginning. + * @param value The error code, may be an `errno` value. + */ +void libgamma_perror(const char* name, int error_code) +{ + if (error_code >= 0) + { + errno = error_code; + perror(name); + } + else if (error_code == LIBGAMMA_ERRNO_SET) + perror(name); + else if (error_code == LIBGAMMA_DEVICE_REQUIRE_GROUP) + { + const char* error = libgamma_name_of_error(error_code); + long int gid = (long int)libgamma_group_gid; + if (libgamma_group_name == NULL) + fprintf(stderr, "%s: %s: %ld\n", name, error, gid); + else + fprintf(stderr, "%s: %s: %s (%lid)\n", name, error, libgamma_group_name, gid); + } + else if (error_code < LIBGAMMA_ERROR_MIN) + fprintf(stderr, "%s: (?)\n", name); + else + fprintf(stderr, "%s: %s\n", name, libgamma_name_of_error(error_code)); +} + + +/** + * Returns the name of the definition associated with a `libgamma` error code. + * + * @param value The error code. + * @return The name of the definition associated with the error code, + * `NULL` if the error code does not exist. The return string + * should not be `free`:d. + */ +const char* libgamma_name_of_error(int value) +{ + static const char* error_names[] = + { +£>for error in $(libgamma-error-extract --list); do + "£{error}", +£>done + }; + + if ((value < LIBGAMMA_ERROR_MIN) || (value >= 0)) + return NULL; + + return error_names[-value - 1]; +} + + +/** + * Return the value of a `libgamma` error definition refered to by name. + * + * @param name The name of the definition associated with the error code. + * @return The error code, zero if the name does is `NULL` + * or does not refer to a `libgamma` error. + */ +int libgamma_value_of_error(const char* name) +{ + if (name == NULL) + return 0; + +£>for error in $(libgamma-error-extract --list); do + if (!strcmp(name, "£{error}")) return £{error}; +£>done + + return 0; +} + diff --git a/src/lib/libgamma-error.h b/src/lib/libgamma-error.h new file mode 100644 index 0000000..06a7077 --- /dev/null +++ b/src/lib/libgamma-error.h @@ -0,0 +1,332 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_ERROR_H +#define LIBGAMMA_ERROR_H + +#if !defined(LIBGAMMA_CONFIG_H) && !defined(DEBUG) +# error libgamma-error.h should not be included directly, include libgamma.h instead +#endif + +#include <sys/types.h> + + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned. + */ +extern gid_t libgamma_group_gid; + +/** + * Group that the user needs to be a member of if `LIBGAMMA_DEVICE_REQUIRE_GROUP` is returned, + * `NULL` if the name of the group `libgamma_group_gid` cannot be determined. + */ +extern const char* libgamma_group_name; + + +/** + * The selected adjustment method does not exist + * or has been excluded at compile-time. + */ +#define LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD (-1) + +/** + * `errno` has be set with a standard error number + * to indicate the what has gone wrong. + */ +#define LIBGAMMA_ERRNO_SET (-2) + +/** + * The selected site does not exist. + */ +#define LIBGAMMA_NO_SUCH_SITE (-3) + +/** + * The selected partition does not exist. + */ +#define LIBGAMMA_NO_SUCH_PARTITION (-4) + +/** + * The selected CRTC does not exist. + */ +#define LIBGAMMA_NO_SUCH_CRTC (-5) + +/** + * Counter overflowed when counting the number of available items. + */ +#define LIBGAMMA_IMPOSSIBLE_AMOUNT (-6) + +/** + * The selected connector is disabled, it does not have a CRTC. + */ +#define LIBGAMMA_CONNECTOR_DISABLED (-7) + +/** + * The selected CRTC could not be opened, reason unknown. + */ +#define LIBGAMMA_OPEN_CRTC_FAILED (-8) + +/** + * The CRTC information field is not supported by the adjustment method. + */ +#define LIBGAMMA_CRTC_INFO_NOT_SUPPORTED (-9) + +/** + * Failed to read the current gamma ramps for the selected CRTC, reason unknown. + */ +#define LIBGAMMA_GAMMA_RAMP_READ_FAILED (-10) + +/** + * Failed to write the current gamma ramps for the selected CRTC, reason unknown. + */ +#define LIBGAMMA_GAMMA_RAMP_WRITE_FAILED (-11) + +/** + * The specified ramp sizes does not match the ramps sizes returned by the + * adjustment methods in response to the query/command. + */ +#define LIBGAMMA_GAMMA_RAMP_SIZE_CHANGED (-12) + +/** + * The specified ramp sizes are not identical which is required by the adjustment method. + * (Only returned in debug mode.) + */ +#define LIBGAMMA_MIXED_GAMMA_RAMP_SIZE (-13) + +/** + * The specified ramp sizes are not supported by the adjustment method. + * (Only returned in debug mode.) + */ +#define LIBGAMMA_WRONG_GAMMA_RAMP_SIZE (-14) + +/** + * The adjustment method reported that the gamma ramps size is 1, or perhaps even zero or negative. + */ +#define LIBGAMMA_SINGLETON_GAMMA_RAMP (-15) + +/** + * The adjustment method failed to list available CRTC:s, reason unknown. + */ +#define LIBGAMMA_LIST_CRTCS_FAILED (-16) + +/** + * Failed to acquire mode resources from the adjustment method. + */ +#define LIBGAMMA_ACQUIRING_MODE_RESOURCES_FAILED (-17) + +/** + * The adjustment method reported that a negative number of partitions exists in the site. + */ +#define LIBGAMMA_NEGATIVE_PARTITION_COUNT (-18) + +/** + * The adjustment method reported that a negative number of CRTC:s exists in the partition. + */ +#define LIBGAMMA_NEGATIVE_CRTC_COUNT (-19) + +/** + * Device cannot be access becauses of insufficient permissions. + */ +#define LIBGAMMA_DEVICE_RESTRICTED (-20) + +/** + * Device cannot be access, reason unknown. + */ +#define LIBGAMMA_DEVICE_ACCESS_FAILED (-21) + +/** + * Device cannot be access, membership of the `libgamma_group_gid` + * (named by `libgamma_group_name` (can be `NULL`, if so `errno` may + * have been set to tell why)) is required. + */ +#define LIBGAMMA_DEVICE_REQUIRE_GROUP (-22) + +/** + * The graphics card appear to have been removed. + */ +#define LIBGAMMA_GRAPHICS_CARD_REMOVED (-23) + +/** + * The state of the requested information is unknown. + */ +#define LIBGAMMA_STATE_UNKNOWN (-24) + +/** + * Failed to determine which connector the CRTC belongs to. + */ +#define LIBGAMMA_CONNECTOR_UNKNOWN (-25) + +/** + * The detected connector type is not listed in this library and has to be updated. + */ +#define LIBGAMMA_CONNECTOR_TYPE_NOT_RECOGNISED (-26) + +/** + * The detected subpixel order is not listed in this library and has to be updated. + */ +#define LIBGAMMA_SUBPIXEL_ORDER_NOT_RECOGNISED (-27) + +/** + * The length of the EDID does not match that of any supported EDID structure revision. + */ +#define LIBGAMMA_EDID_LENGTH_UNSUPPORTED (-28) + +/** + * The magic number in the EDID does not match that of any supported EDID structure revision. + */ +#define LIBGAMMA_EDID_WRONG_MAGIC_NUMBER (-29) + +/** + * The EDID structure revision used by the monitor is not supported. + */ +#define LIBGAMMA_EDID_REVISION_UNSUPPORTED (-30) + +/** + * The gamma characteristics field in the EDID is left unspecified. + * (This could be considered a non-error.) + */ +#define LIBGAMMA_GAMMA_NOT_SPECIFIED (-31) + +/** + * The checksum in the EDID is incorrect, all request information has been provided + * by you cannot count on it. + */ +#define LIBGAMMA_EDID_CHECKSUM_ERROR (-32) + +/** + * Both of the errors `LIBGAMMA_GAMMA_NOT_SPECIFIED` and + * `LIBGAMMA_EDID_CHECKSUM_ERROR` have occurred. + */ +#define LIBGAMMA_GAMMA_NOT_SPECIFIED_AND_EDID_CHECKSUM_ERROR (-33) + +/** + * Failed to query the gamma ramps size from the adjustment method, reason unknown. + */ +#define LIBGAMMA_GAMMA_RAMPS_SIZE_QUERY_FAILED (-34) + +/** + * The selected partition could not be opened, reason unknown. + */ +#define LIBGAMMA_OPEN_PARTITION_FAILED (-35) + +/** + * The selected site could not be opened, reason unknown. + */ +#define LIBGAMMA_OPEN_SITE_FAILED (-36) + +/** + * Failed to query the adjustment method for its protocol version, reason unknown. + */ +#define LIBGAMMA_PROTOCOL_VERSION_QUERY_FAILED (-37) + +/** + * The adjustment method's version of its protocol is not supported. + */ +#define LIBGAMMA_PROTOCOL_VERSION_NOT_SUPPORTED (-38) + +/** + * The adjustment method failed to list available partitions, reason unknown. + */ +#define LIBGAMMA_LIST_PARTITIONS_FAILED (-39) + +/** + * Partition exists by index, but the partition at that index does not exist. + */ +#define LIBGAMMA_NULL_PARTITION (-40) + +/** + * There is not monitor connected to the connector of the selected CRTC. + */ +#define LIBGAMMA_NOT_CONNECTED (-41) + +/** + * Data extraction from a reply from the adjustment method failed, reason unknown. + */ +#define LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED (-42) + +/** + * No EDID property was found on the output. + */ +#define LIBGAMMA_EDID_NOT_FOUND (-43) + +/** + * Failed to list properties on the output, reason unknown. + */ +#define LIBGAMMA_LIST_PROPERTIES_FAILED (-44) + +/** + * Failed to query a property's value from the output, reason unknown. + */ +#define LIBGAMMA_PROPERTY_VALUE_QUERY_FAILED (-45) + +/** + * A request for information on an output failed, reason unknown. + */ +#define LIBGAMMA_OUTPUT_INFORMATION_QUERY_FAILED (-46) + + + +/** + * The number of the libgamma error with the lowest number. + * If this is lower than the number your program thinks it + * should be sould update your program for new errors. + */ +#define LIBGAMMA_ERROR_MIN (-46) + + + +/** + * Prints an error to stderr in a `perror` fashion, + * however this function will not translate the `libgamma` + * errors into human-readable strings, it will simply + * print the name of the error. If the value `error_code` + * is the value of `LIBGAMMA_ERRNO_SET`, `perror` will be + * used to print the current error stored in `errno`. + * If `error_code` is non-negative (an `errno` value`), that + * value will be stored in `errno` and `perror` will be + * used to print it. Additionally, if the `error_code` is + * the value of `LIBGAMMA_DEVICE_REQUIRE_GROUP` the + * required group will be printed with its numerical value + * and, if known, its name. + * + * @param name The text to add at the beginning. + * @param value The error code, may be an `errno` value. + */ +void libgamma_perror(const char* name, int error_code); + +/** + * Returns the name of the definition associated with a `libgamma` error code. + * + * @param value The error code. + * @return The name of the definition associated with the error code, + * `NULL` if the error code does not exist. The return string + * should not be `free`:d. + */ +const char* libgamma_name_of_error(int value) __attribute__((const)); + +/** + * Return the value of a `libgamma` error definition refered to by name. + * + * @param name The name of the definition associated with the error code. + * @return The error code, zero if the name does is `NULL` + * or does not refer to a `libgamma` error. + */ +int libgamma_value_of_error(const char* name) __attribute__((const)); + + + +#endif + diff --git a/src/lib/libgamma-facade.c b/src/lib/libgamma-facade.c new file mode 100644 index 0000000..c94d9e3 --- /dev/null +++ b/src/lib/libgamma-facade.c @@ -0,0 +1,1644 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#include "libgamma-facade.h" + +#include "libgamma-error.h" +#include "libgamma-method.h" +#include "gamma-helper.h" +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY +# include "gamma-dummy.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR +# include "gamma-x-randr.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE +# include "gamma-x-vidmode.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM +# include "gamma-linux-drm.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI +# include "gamma-w32-gdi.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS +# include "gamma-quartz-cg.h" +# ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_LIBGAMMA_METHODS +# endif +#endif + +#include <unistd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + + +#ifndef HAVE_LIBGAMMA_METHODS +# define HAVE_NO_LIBGAMMA_METHODS +#endif + + +#ifdef HAVE_NO_LIBGAMMA_METHODS +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wsuggest-attribute=const" +#endif + + + +#ifdef HAVE_LIBGAMMA_METHODS +# ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM +/** + * Test whether a file descriptor refers to a VT. + * + * @param fd The file descriptor. + * @return Whether the file descriptor refers to a VT. + */ +static int libgamma_is_vt_proper(int fd) +{ + char buf[32]; + char digit0; + + if (ttyname_r(fd, buf, sizeof(buf) / sizeof(char))) + return 0; + + if (strstr(buf, "/dev/tty") != buf) + return 0; + + digit0 = buf[strlen("/dev/tty")]; + return ('1' <= digit0) && (digit0 <= '9'); +} +# endif + + +/** + * Test the availability of an adjustment method. + * + * @param method The adjustment method. + * @param operation Allowed values: + * 0: Pass if the environment suggests it will work but is not fake. + * 1: Pass if the environment suggests it will work. + * 2: Pass if real and not fake. + * 3: Pass if real. + * 4: Always pass. + * Other values invoke undefined behaviour. + * @return Whether the test passed. + */ +static int libgamma_list_method_test(int method, int operation) +{ + libgamma_method_capabilities_t caps; + libgamma_method_capabilities(&caps, method); + + switch (operation) + { + case 0: /* Methods that the environment suggests will work, excluding fake. */ + if (caps.fake) + return 0; + /* Fall through. */ + + case 1: /* Methods that the environment suggests will work, including fake. */ + if (caps.real == 0) + return 0; +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + if (method == LIBGAMMA_METHOD_LINUX_DRM) + return libgamma_is_vt_proper(STDIN_FILENO) || + libgamma_is_vt_proper(STDOUT_FILENO) || + libgamma_is_vt_proper(STDERR_FILENO); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + if (method == LIBGAMMA_METHOD_DUMMY) + return 0; +#endif + return caps.default_site_known; + + case 2: /* All real non-fake methods. */ + return caps.real && (caps.fake == 0); + + case 3: /* All real methods. */ + return caps.real; + + default: /* All methods. */ + return 1; + } +} +#endif + + +/** + * List available adjustment methods by their order of preference based on the environment. + * + * @param methods Output array of methods, should be able to hold `LIBGAMMA_METHOD_COUNT` elements + * @param buf_size The number of elements that fits in `methods`, it should be `LIBGAMMA_METHOD_COUNT`, + * This is used to avoid writing outside the output buffer if this library adds new + * adjustment methods without the users of the library recompiling. + * @param operation Allowed values: + * 0: Methods that the environment suggests will work, excluding fake. + * 1: Methods that the environment suggests will work, including fake. + * 2: All real non-fake methods. + * 3: All real methods. + * 4: All methods. + * Other values invoke undefined behaviour. + * @return The number of element that have been stored in `methods`, or should + * have been stored if the buffer was large enought. + */ +size_t libgamma_list_methods(int* restrict methods, size_t buf_size, int operation) +{ +#ifdef HAVE_NO_LIBGAMMA_METHODS + (void) methods; + (void) operation; + return 0; +#else + size_t n = 0; + +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + if (libgamma_list_method_test(LIBGAMMA_METHOD_X_RANDR, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_X_RANDR; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + if (libgamma_list_method_test(LIBGAMMA_METHOD_X_VIDMODE, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_X_VIDMODE; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + if (libgamma_list_method_test(LIBGAMMA_METHOD_LINUX_DRM, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_LINUX_DRM; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + if (libgamma_list_method_test(LIBGAMMA_METHOD_W32_GDI, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_W32_GDI; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + if (libgamma_list_method_test(LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + if (libgamma_list_method_test(LIBGAMMA_METHOD_DUMMY, operation) && (n++ < buf_size)) + methods[n - 1] = LIBGAMMA_METHOD_DUMMY; +#endif + + return n; +#endif +} + + +/** + * Check whether an adjustment method is available, non-existing (invalid) methods will be + * identified as not available under the rationale that the library may be out of date. + * + * @param method The adjustment method. + * @return Whether the adjustment method is available. + */ +int libgamma_is_method_available(int method) +{ +#ifdef HAVE_NO_LIBGAMMA_METHODS + (void) methods; + return 0; +#else + switch (method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: +#endif + return 1; + + default: + return 0; + } +#endif +} + + +/** + * Return the capabilities of an adjustment method. + * + * @param this The data structure to fill with the method's capabilities. + * @param method The adjustment method (display server and protocol.) + */ +void libgamma_method_capabilities(libgamma_method_capabilities_t* restrict this, int method) +{ + memset(this, 0, sizeof(libgamma_method_capabilities_t)); + + switch (method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + libgamma_dummy_method_capabilities(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + libgamma_x_randr_method_capabilities(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + libgamma_x_vidmode_method_capabilities(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + libgamma_linux_drm_method_capabilities(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + libgamma_w32_gdi_method_capabilities(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + libgamma_quartz_cg_method_capabilities(this); + break; +#endif + + default: + /* Method does not exists/excluded at compile-time. + We will assume that this is not done... */ + break; + } +} + + +/** + * Return the capabilities of an adjustment method. + * + * @param method The adjustment method (display server and protocol.) + * @return The default site, `NULL` if it cannot be determined or + * if multiple sites are not supported by the adjustment + * method. This value should not be free:d. + */ +char* libgamma_method_default_site(int method) +{ + const char* restrict var = libgamma_method_default_site_variable(method); + char* restrict env; + + if (var == NULL) + return NULL; + + env = getenv(var); + if ((env == NULL) || (*env == '\0')) + return NULL; + + return env; +} + + +/** + * Return the capabilities of an adjustment method. + * + * @param method The adjustment method (display server and protocol.) + * @return The environ variables that is used to determine the + * default site. `NULL` if there is none, that is, if + * the method does not support multiple sites. + * This value should not be free:d. + */ +const char* libgamma_method_default_site_variable(int method) +{ + switch (method) + { +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return "DISPLAY"; +#endif + +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return "DISPLAY"; +#endif + + default: + return NULL; + } +} + + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param method The adjustment method (display server and protocol.) + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_site_initialise(libgamma_site_state_t* restrict this, + int method, char* restrict site) +{ + this->method = method; + this->site = site; + + switch (method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_site_initialise(this, site); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_site_initialise(this, site); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_site_initialise(this, site); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_site_initialise(this, site); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_site_initialise(this, site); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_site_initialise(this, site); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_site_destroy(libgamma_site_state_t* restrict this) +{ + switch (this->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + libgamma_dummy_site_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + libgamma_x_randr_site_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + libgamma_x_vidmode_site_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + libgamma_linux_drm_site_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + libgamma_w32_gdi_site_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + libgamma_quartz_cg_site_destroy(this); + break; +#endif + + default: + /* Method does not exists/excluded at compile-time. + We will assume that this is not done... */ + break; + } + free(this->site); +} + + +/** + * Release all resources held by a site state + * and free the site state pointer. + * + * @param this The site state. + */ +void libgamma_site_free(libgamma_site_state_t* restrict this) +{ + libgamma_site_destroy(this); + free(this); +} + + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_site_restore(libgamma_site_state_t* restrict this) +{ + switch (this->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_site_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_site_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_site_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_site_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_site_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_site_restore(this); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition) +{ + this->site = site; + this->partition = partition; + + switch (site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_partition_initialise(this, site, partition); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_partition_initialise(this, site, partition); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_partition_initialise(this, site, partition); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_partition_initialise(this, site, partition); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_partition_initialise(this, site, partition); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_partition_initialise(this, site, partition); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_partition_destroy(libgamma_partition_state_t* restrict this) +{ + switch (this->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + libgamma_dummy_partition_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + libgamma_x_randr_partition_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + libgamma_x_vidmode_partition_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + libgamma_linux_drm_partition_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + libgamma_w32_gdi_partition_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + libgamma_quartz_cg_partition_destroy(this); + break; +#endif + + default: + /* Method does not exists/excluded at compile-time. + We will assume that this is not done... */ + break; + } +} + + +/** + * Release all resources held by a partition state + * and free the partition state pointer. + * + * @param this The partition state. + */ +void libgamma_partition_free(libgamma_partition_state_t* restrict this) +{ + libgamma_partition_destroy(this); + free(this); +} + + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_partition_restore(libgamma_partition_state_t* restrict this) +{ + switch (this->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_partition_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_partition_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_partition_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_partition_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_partition_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_partition_restore(this); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc) +{ + this->partition = partition; + this->crtc = crtc; + + switch (partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_initialise(this, partition, crtc); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_crtc_initialise(this, partition, crtc); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_crtc_initialise(this, partition, crtc); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_crtc_initialise(this, partition, crtc); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_crtc_initialise(this, partition, crtc); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_crtc_initialise(this, partition, crtc); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_crtc_destroy(libgamma_crtc_state_t* restrict this) +{ + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + libgamma_dummy_crtc_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + libgamma_x_randr_crtc_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + libgamma_x_vidmode_crtc_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + libgamma_linux_drm_crtc_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + libgamma_w32_gdi_crtc_destroy(this); + break; +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + libgamma_quartz_cg_crtc_destroy(this); + break; +#endif + + default: + /* Method does not exists/excluded at compile-time. + We will assume that this is not done... */ + break; + } +} + + +/** + * Release all resources held by a CRTC state + * and free the CRTC state pointer. + * + * @param this The CRTC state. + */ +void libgamma_crtc_free(libgamma_crtc_state_t* restrict this) +{ + libgamma_crtc_destroy(this); + free(this); +} + + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_restore(libgamma_crtc_state_t* restrict this) +{ + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_crtc_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_crtc_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_crtc_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_crtc_restore(this); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_crtc_restore(this); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields) +{ +#ifdef HAVE_NO_LIBGAMMA_METHODS + (void) fields; +#endif + + this->edid = NULL; + this->connector_name = NULL; + + switch (crtc->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_get_crtc_information(this, crtc, fields); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_get_crtc_information(this, crtc, fields); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_get_crtc_information(this, crtc, fields); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_get_crtc_information(this, crtc, fields); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_get_crtc_information(this, crtc, fields); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_get_crtc_information(this, crtc, fields); +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + +/** + * Release all resources in an information data structure for a CRTC. + * + * @param this The CRTC information. + */ +void libgamma_crtc_information_destroy(libgamma_crtc_information_t* restrict this) +{ + free(this->edid); + free(this->connector_name); +} + + +/** + * Release all resources in an information data structure for a CRTC + * and free the data structure pointer. + * + * @param this The CRTC information. + */ +void libgamma_crtc_information_free(libgamma_crtc_information_t* restrict this) +{ + libgamma_crtc_information_destroy(this); + free(this); +} + + +/** + * Convert a raw representation of an EDID to a lowercase hexadecimal representation. + * + * @param edid The EDID in raw representation. + * @param length The length of `edid`. + * @retrun The EDID in lowercase hexadecimal representation, + * `NULL` on allocation error, `errno` will be set accordingly. + */ +char* libgamma_behex_edid_lowercase(const unsigned char* restrict edid, size_t length) +{ + char* restrict out = malloc((length * 2 + 1) * sizeof(char)); + size_t i; + + if (out == NULL) + return NULL; + + for (i = 0; i < length; i++) + { + out[i * 2 + 0] = "0123456789abcdef"[(edid[i] >> 4) & 15]; + out[i * 2 + 1] = "0123456789abcdef"[(edid[i] >> 0) & 15]; + } + out[length * 2] = '\0'; + + return out; +} + + +/** + * Convert a raw representation of an EDID to an uppercase hexadecimal representation. + * + * @param edid The EDID in raw representation. + * @param length The length of `edid`. + * @retrun The EDID in uppercase hexadecimal representation, + * NULL` on allocation error, `errno` will be set accordingly. + */ +char* libgamma_behex_edid_uppercase(const unsigned char* restrict edid, size_t length) +{ + char* restrict out = malloc((length * 2 + 1) * sizeof(char)); + size_t i; + + if (out == NULL) + return NULL; + + for (i = 0; i < length; i++) + { + out[i * 2 + 0] = "0123456789ABCDEF"[(edid[i] >> 4) & 15]; + out[i * 2 + 1] = "0123456789ABCDEF"[(edid[i] >> 0) & 15]; + } + out[length * 2] = '\0'; + + return out; +} + + +/** + * Convert an hexadecimal representation of an EDID to a raw representation. + * + * @param edid The EDID in hexadecimal representation. + * @retrun The EDID in raw representation, it will be half the length + * of `edid` (the input value). `NULL` on allocation error or + * if the EDID is malformated, `errno` will be set accordingly. + */ +unsigned char* libgamma_unhex_edid(const char* restrict edid) +{ +#define not_range(lower, V, upper) ((V < lower) || (upper < V)) +#define is_not_hex(V) (not_range('0', V, '9') && not_range('a', V, 'f') && not_range('A', V, 'F')) + + unsigned char* restrict out = NULL; + size_t n = strlen(edid); + size_t i; + + if ((n & 1)) + return errno = EINVAL, NULL; + + out = malloc(n / 2 * sizeof(unsigned char)); + if (out == NULL) + return NULL; + + for (i = 0; i < n; i++) + { + char a = edid[i * 2 + 0]; + char b = edid[i * 2 + 1]; + + if (is_not_hex(a) || is_not_hex(b)) + { + free(out); + return errno = EINVAL, NULL; + } + + a = (char)((a & 15) + (a > '9' ? 9 : 0)); + b = (char)((b & 15) + (b > '9' ? 9 : 0)); + + out[i] = (unsigned char)((a << 4) | b); + } + + return out; + +#undef is_hex +#undef not_range +} + + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps) +{ +#ifdef HAVE_NO_LIBGAMMA_METHODS + (void) ramps; +#endif + + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_get_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_crtc_get_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_crtc_get_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_crtc_get_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_crtc_get_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + { + libgamma_gamma_ramps_any_t ramps_; + ramps_.bits16 = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, 16, -1, + libgamma_crtc_get_gamma_ramps); + } +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) +{ +#ifdef HAVE_NO_LIBGAMMA_METHODS + (void) ramps; +#endif + + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_set_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_RANDR + case LIBGAMMA_METHOD_X_RANDR: + return libgamma_x_randr_crtc_set_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_X_VIDMODE + case LIBGAMMA_METHOD_X_VIDMODE: + return libgamma_x_vidmode_crtc_set_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + case LIBGAMMA_METHOD_LINUX_DRM: + return libgamma_linux_drm_crtc_set_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_W32_GDI + case LIBGAMMA_METHOD_W32_GDI: + return libgamma_w32_gdi_crtc_set_gamma_ramps(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + { + libgamma_gamma_ramps_any_t ramps_; + ramps_.bits16 = ramps; + return libgamma_translated_ramp_set(this, ramps_, 16, -1, + libgamma_crtc_set_gamma_ramps); + } +#endif + + default: + return LIBGAMMA_NO_SUCH_ADJUSTMENT_METHOD; + } +} + + + +/** + * Get current the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t* restrict ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_get_gamma_ramps32(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.bits32 = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, 32, -1, + libgamma_crtc_get_gamma_ramps); +#endif + + default: + ramps_.bits32 = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, 32, 16, + libgamma_crtc_get_gamma_ramps); + } +} + + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_set_gamma_ramps32(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.bits32 = ramps; + return libgamma_translated_ramp_set(this, ramps_, 32, -1, + libgamma_crtc_set_gamma_ramps); +#endif + + default: + ramps_.bits32 = ramps; + return libgamma_translated_ramp_set(this, ramps_, 32, 16, + libgamma_crtc_set_gamma_ramps); + } +} + + + +/** + * Get current the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t* restrict ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_get_gamma_ramps64(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.bits64 = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, 64, -1, + libgamma_crtc_get_gamma_ramps); +#endif + + default: + ramps_.bits64 = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, 64, 16, + libgamma_crtc_get_gamma_ramps); + } +} + + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_set_gamma_ramps64(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.bits64 = ramps; + return libgamma_translated_ramp_set(this, ramps_, 64, -1, + libgamma_crtc_set_gamma_ramps); +#endif + + default: + ramps_.bits64 = ramps; + return libgamma_translated_ramp_set(this, ramps_, 64, 16, + libgamma_crtc_set_gamma_ramps); + } +} + + + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_get_gamma_rampsf(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_crtc_get_gamma_rampsf(this, ramps); +#endif + + default: + ramps_.float_single = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, -1, 16, + libgamma_crtc_get_gamma_ramps); + } +} + + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps) +{ + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_set_gamma_rampsf(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + return libgamma_quartz_cg_crtc_set_gamma_rampsf(this, ramps); +#endif + + default: + { + libgamma_gamma_ramps_any_t ramps_; + ramps_.float_single = ramps; + return libgamma_translated_ramp_set(this, ramps_, -1, 16, + libgamma_crtc_set_gamma_ramps); + } + } +} + + + +/** + * Get current the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t* restrict ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_get_gamma_rampsd(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.float_double = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, -2, -1, + libgamma_crtc_get_gamma_ramps); +#endif + + default: + ramps_.float_double = *ramps; + return libgamma_translated_ramp_get(this, &ramps_, -2, 16, + libgamma_crtc_get_gamma_ramps); + } +} + + +/** + * Set the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t ramps) +{ + libgamma_gamma_ramps_any_t ramps_; + switch (this->partition->site->method) + { +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + case LIBGAMMA_METHOD_DUMMY: + return libgamma_dummy_crtc_set_gamma_rampsd(this, ramps); +#endif +#ifdef HAVE_LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS + case LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS: + ramps_.float_double = ramps; + return libgamma_translated_ramp_set(this, ramps_, -2, -1, + libgamma_crtc_set_gamma_ramps); +#endif + + default: + ramps_.float_double = ramps; + return libgamma_translated_ramp_set(this, ramps_, -2, 16, + libgamma_crtc_set_gamma_ramps); + } +} + + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_fun* red_function, + libgamma_gamma_ramps_fun* green_function, + libgamma_gamma_ramps_fun* blue_function) +{ + libgamma_crtc_information_t info; + libgamma_gamma_ramps_t ramps; + size_t i, n; + int e; + + if (libgamma_get_crtc_information(&info, this, LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + e = info.gamma_size_error; + if (e < 0) + return e; + return errno = e, LIBGAMMA_ERRNO_SET; + } + + n = ramps. red_size = info. red_gamma_size; + n += ramps.green_size = info.green_gamma_size; + n += ramps. blue_size = info. blue_gamma_size; + + ramps. red = malloc(n * sizeof(uint16_t)); + ramps.green = ramps. red + ramps. red_size; + ramps. blue = ramps.green + ramps.green_size; + if (ramps.red == NULL) + return LIBGAMMA_ERRNO_SET; + + for (i = 0, n = ramps.red_size; i < n; i++) + ramps.red[i] = red_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.green_size; i < n; i++) + ramps.green[i] = green_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.blue_size; i < n; i++) + ramps.blue[i] = blue_function((float)i / (float)(n - 1)); + + e = libgamma_crtc_set_gamma_ramps(this, ramps); + free(ramps.red); + return e; +} + + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps32_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_fun* red_function, + libgamma_gamma_ramps32_fun* green_function, + libgamma_gamma_ramps32_fun* blue_function) +{ + libgamma_crtc_information_t info; + libgamma_gamma_ramps32_t ramps; + size_t i, n; + int e; + + if (libgamma_get_crtc_information(&info, this, LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + e = info.gamma_size_error; + if (e < 0) + return e; + return errno = e, LIBGAMMA_ERRNO_SET; + } + + n = ramps. red_size = info. red_gamma_size; + n += ramps.green_size = info.green_gamma_size; + n += ramps. blue_size = info. blue_gamma_size; + + ramps. red = malloc(n * sizeof(uint32_t)); + ramps.green = ramps. red + ramps. red_size; + ramps. blue = ramps.green + ramps.green_size; + if (ramps.red == NULL) + return LIBGAMMA_ERRNO_SET; + + for (i = 0, n = ramps.red_size; i < n; i++) + ramps.red[i] = red_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.green_size; i < n; i++) + ramps.green[i] = green_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.blue_size; i < n; i++) + ramps.blue[i] = blue_function((float)i / (float)(n - 1)); + + e = libgamma_crtc_set_gamma_ramps32(this, ramps); + free(ramps.red); + return e; +} + + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps64_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_fun* red_function, + libgamma_gamma_ramps64_fun* green_function, + libgamma_gamma_ramps64_fun* blue_function) +{ + libgamma_crtc_information_t info; + libgamma_gamma_ramps64_t ramps; + size_t i, n; + int e; + + if (libgamma_get_crtc_information(&info, this, LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + e = info.gamma_size_error; + if (e < 0) + return e; + return errno = e, LIBGAMMA_ERRNO_SET; + } + + n = ramps. red_size = info. red_gamma_size; + n += ramps.green_size = info.green_gamma_size; + n += ramps. blue_size = info. blue_gamma_size; + + ramps. red = malloc(n * sizeof(uint64_t)); + ramps.green = ramps. red + ramps. red_size; + ramps. blue = ramps.green + ramps.green_size; + if (ramps.red == NULL) + return LIBGAMMA_ERRNO_SET; + + for (i = 0, n = ramps.red_size; i < n; i++) + ramps.red[i] = red_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.green_size; i < n; i++) + ramps.green[i] = green_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.blue_size; i < n; i++) + ramps.blue[i] = blue_function((float)i / (float)(n - 1)); + + e = libgamma_crtc_set_gamma_ramps64(this, ramps); + free(ramps.red); + return e; +} + + +/** + * Set the gamma ramps for a CRTC, `float` function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsf_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_fun* red_function, + libgamma_gamma_rampsf_fun* green_function, + libgamma_gamma_rampsf_fun* blue_function) +{ + libgamma_crtc_information_t info; + libgamma_gamma_rampsf_t ramps; + size_t i, n; + int e; + + if (libgamma_get_crtc_information(&info, this, LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + e = info.gamma_size_error; + if (e < 0) + return e; + return errno = e, LIBGAMMA_ERRNO_SET; + } + + n = ramps. red_size = info. red_gamma_size; + n += ramps.green_size = info.green_gamma_size; + n += ramps. blue_size = info. blue_gamma_size; + + ramps. red = malloc(n * sizeof(float)); + ramps.green = ramps. red + ramps. red_size; + ramps. blue = ramps.green + ramps.green_size; + if (ramps.red == NULL) + return LIBGAMMA_ERRNO_SET; + + for (i = 0, n = ramps.red_size; i < n; i++) + ramps.red[i] = red_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.green_size; i < n; i++) + ramps.green[i] = green_function((float)i / (float)(n - 1)); + + for (i = 0, n = ramps.blue_size; i < n; i++) + ramps.blue[i] = blue_function((float)i / (float)(n - 1)); + + e = libgamma_crtc_set_gamma_rampsf(this, ramps); + free(ramps.red); + return e; +} + + +/** + * Set the gamma ramps for a CRTC, `double` function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsd_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_fun* red_function, + libgamma_gamma_rampsd_fun* green_function, + libgamma_gamma_rampsd_fun* blue_function) +{ + libgamma_crtc_information_t info; + libgamma_gamma_rampsd_t ramps; + size_t i, n; + int e; + + if (libgamma_get_crtc_information(&info, this, LIBGAMMA_CRTC_INFO_GAMMA_SIZE)) + { + e = info.gamma_size_error; + if (e < 0) + return e; + return errno = e, LIBGAMMA_ERRNO_SET; + } + + n = ramps. red_size = info. red_gamma_size; + n += ramps.green_size = info.green_gamma_size; + n += ramps. blue_size = info. blue_gamma_size; + + ramps. red = malloc(n * sizeof(double)); + ramps.green = ramps. red + ramps. red_size; + ramps. blue = ramps.green + ramps.green_size; + if (ramps.red == NULL) + return LIBGAMMA_ERRNO_SET; + + for (i = 0, n = ramps.red_size; i < n; i++) + ramps.red[i] = red_function((double)i / (double)(n - 1)); + + for (i = 0, n = ramps.green_size; i < n; i++) + ramps.green[i] = green_function((double)i / (double)(n - 1)); + + for (i = 0, n = ramps.blue_size; i < n; i++) + ramps.blue[i] = blue_function((double)i / (double)(n - 1)); + + e = libgamma_crtc_set_gamma_rampsd(this, ramps); + free(ramps.red); + return e; +} + + + +#ifdef HAVE_NO_LIBGAMMA_METHODS +# pragma GCC diagnostic pop +#endif + diff --git a/src/lib/libgamma-facade.h b/src/lib/libgamma-facade.h new file mode 100644 index 0000000..fdf46ae --- /dev/null +++ b/src/lib/libgamma-facade.h @@ -0,0 +1,510 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_FACADE_H +#define LIBGAMMA_FACADE_H + +#if !defined(LIBGAMMA_CONFIG_H) && !defined(DEBUG) +# error libgamma-facade.h should not be included directly, include libgamma.h instead +#endif + + +#include "libgamma-method.h" + +#include <stddef.h> +#include <stdint.h> + + + +/** + * Mapping function from [0, 1] float encoding value to [0, 2¹⁶ − 1] integer output value. + * + * @param encoding [0, 1] float encoding value. + * @return [0, 2¹⁶ − 1] integer output value. + */ +typedef uint16_t libgamma_gamma_ramps_fun(float encoding); + +/** + * Mapping function from [0, 1] float encoding value to [0, 2³² − 1] integer output value. + * + * @param encoding [0, 1] float encoding value. + * @return [0, 2³² − 1] integer output value. + */ +typedef uint32_t libgamma_gamma_ramps32_fun(float encoding); + +/** + * Mapping function from [0, 1] float encoding value to [0, 2⁶⁴ − 1] integer output value. + * + * @param encoding [0, 1] float encoding value. + * @return [0, 2⁶⁴ − 1] integer output value. + */ +typedef uint64_t libgamma_gamma_ramps64_fun(float encoding); + +/** + * Mapping function from [0, 1] float encoding value to [0, 1] float output value. + * + * @param encoding [0, 1] float encoding value. + * @return [0, 1] float output value. + */ +typedef float libgamma_gamma_rampsf_fun(float encoding); + +/** + * Mapping function from [0, 1] double precision float encoding + * value to [0, 1] double precision float output value. + * + * @param encoding [0, 1] float encoding value. + * @return [0, 1] float output value. + */ +typedef double libgamma_gamma_rampsd_fun(double encoding); + + + +/** + * List available adjustment methods by their order of preference based on the environment. + * + * @param methods Output array of methods, should be able to hold `LIBGAMMA_METHOD_COUNT` elements + * @param buf_size The number of elements that fits in `methods`, it should be `LIBGAMMA_METHOD_COUNT`, + * This is used to avoid writing outside the output buffer if this library adds new + * adjustment methods without the users of the library recompiling. + * @param operation Allowed values: + * 0: Methods that the environment suggests will work, excluding fake. + * 1: Methods that the environment suggests will work, including fake. + * 2: All real non-fake methods. + * 3: All real methods. + * 4: All methods. + * Other values invoke undefined behaviour. + * @return The number of element that have been stored in `methods`, or should + * have been stored if the buffer was large enought. + */ +size_t libgamma_list_methods(int* restrict methods, size_t buf_size, int operation); + +/** + * Check whether an adjustment method is available, non-existing (invalid) methods will be + * identified as not available under the rationale that the library may be out of date. + * + * @param method The adjustment method. + * @return Whether the adjustment method is available. + */ +int libgamma_is_method_available(int method) __attribute__((const)); + +/** + * Return the capabilities of an adjustment method. + * + * @param this The data structure to fill with the method's capabilities + * @param method The adjustment method (display server and protocol). + */ +void libgamma_method_capabilities(libgamma_method_capabilities_t* restrict this, int method); + +/** + * Return the capabilities of an adjustment method. + * + * @param method The adjustment method (display server and protocol.) + * @return The default site, `NULL` if it cannot be determined or + * if multiple sites are not supported by the adjustment + * method. This value should not be free:d. + */ +char* libgamma_method_default_site(int method); + +/** + * Return the capabilities of an adjustment method. + * + * @param method The adjustment method (display server and protocol.) + * @return The environ variables that is used to determine the + * default site. `NULL` if there is none, that is, if + * the method does not support multiple sites. + * This value should not be free:d. + */ +const char* libgamma_method_default_site_variable(int method) __attribute__((const)); + + +/** + * Initialise an allocated site state. + * + * @param this The site state to initialise. + * @param method The adjustment method (display server and protocol.) + * @param site The site identifier, unless it is `NULL` it must a + * `free`:able. One the state is destroyed the library + * will attempt to free it. There you should not free + * it yourself, and it must not be a string constant + * or allocate on the stack. Note however that it will + * not be free:d if this function fails. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_site_initialise(libgamma_site_state_t* restrict this, + int method, char* restrict site); + +/** + * Release all resources held by a site state. + * + * @param this The site state. + */ +void libgamma_site_destroy(libgamma_site_state_t* restrict this); + +/** + * Release all resources held by a site state + * and free the site state pointer. + * + * @param this The site state. + */ +void libgamma_site_free(libgamma_site_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a site to the system settings. + * + * @param this The site state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_site_restore(libgamma_site_state_t* restrict this); + + +/** + * Initialise an allocated partition state. + * + * @param this The partition state to initialise. + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_partition_initialise(libgamma_partition_state_t* restrict this, + libgamma_site_state_t* restrict site, size_t partition); + +/** + * Release all resources held by a partition state. + * + * @param this The partition state. + */ +void libgamma_partition_destroy(libgamma_partition_state_t* restrict this); + +/** + * Release all resources held by a partition state + * and free the partition state pointer. + * + * @param this The partition state. + */ +void libgamma_partition_free(libgamma_partition_state_t* restrict this); + +/** + * Restore the gamma ramps all CRTC:s with a partition to the system settings. + * + * @param this The partition state. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_partition_restore(libgamma_partition_state_t* restrict this); + + +/** + * Initialise an allocated CRTC state. + * + * @param this The CRTC state to initialise. + * @param partition The partition state for the partition that the CRTC belongs to. + * @param crtc The the index of the CRTC within the site. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_initialise(libgamma_crtc_state_t* restrict this, + libgamma_partition_state_t* restrict partition, size_t crtc); + +/** + * Release all resources held by a CRTC state. + * + * @param this The CRTC state. + */ +void libgamma_crtc_destroy(libgamma_crtc_state_t* restrict this); + +/** + * Release all resources held by a CRTC state + * and free the CRTC state pointer. + * + * @param this The CRTC state. + */ +void libgamma_crtc_free(libgamma_crtc_state_t* restrict this); + +/** + * Restore the gamma ramps for a CRTC to the system settings for that CRTC. + * + * @param this The CRTC state + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_restore(libgamma_crtc_state_t* restrict this); + + +/** + * Read information about a CRTC. + * + * @param this Instance of a data structure to fill with the information about the CRTC. + * @param crtc The state of the CRTC whose information should be read. + * @param fields OR:ed identifiers for the information about the CRTC that should be read. + * @return Zero on success, -1 on error. On error refer to the error reports in `this`. + */ +int libgamma_get_crtc_information(libgamma_crtc_information_t* restrict this, + libgamma_crtc_state_t* restrict crtc, int32_t fields); + +/** + * Release all resources in an information data structure for a CRTC. + * + * @param this The CRTC information. + */ +void libgamma_crtc_information_destroy(libgamma_crtc_information_t* restrict this); + +/** + * Release all resources in an information data structure for a CRTC + * and free the data structure pointer. + * + * @param this The CRTC information. + */ +void libgamma_crtc_information_free(libgamma_crtc_information_t* restrict this); + +/** + * Convert a raw representation of an EDID to a lowercase hexadecimal representation. + * + * @param edid:const unsigned char* The EDID in raw representation. + * @param length:size_t The length of `edid`. + * @return :char* The EDID in lowercase hexadecimal representation, + * `NULL` on allocation error, `errno` will be set accordingly. + */ +#define libgamma_behex_edid(edid, length) \ + libgamma_behex_edid_lowercase(edid, length) + +/** + * Convert a raw representation of an EDID to a lowercase hexadecimal representation. + * + * @param edid The EDID in raw representation. + * @param length The length of `edid`. + * @retrun The EDID in lowercase hexadecimal representation, + * `NULL` on allocation error, `errno` will be set accordingly. + */ +char* libgamma_behex_edid_lowercase(const unsigned char* restrict edid, size_t length); + +/** + * Convert a raw representation of an EDID to an uppercase hexadecimal representation. + * + * @param edid The EDID in raw representation. + * @param length The length of `edid`. + * @retrun The EDID in uppercase hexadecimal representation, + * NULL` on allocation error, `errno` will be set accordingly. + */ +char* libgamma_behex_edid_uppercase(const unsigned char* restrict edid, size_t length); + +/** + * Convert an hexadecimal representation of an EDID to a raw representation. + * + * @param edid The EDID in hexadecimal representation. + * @retrun The EDID in raw representation, it will be half the length + * of `edid` (the input value). `NULL` on allocation error or + * if the EDID is malformated, `errno` will be set accordingly. + */ +unsigned char* libgamma_unhex_edid(const char* restrict edid); + + +/** + * Get current the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_t ramps) __attribute__((hot)); + + +/** + * Get current the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps32(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_t ramps); + + +/** + * Get current the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps64(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_t ramps); + + +/** + * Set the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t ramps); + +/** + * Get current the gamma ramps for a CRTC, `float` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_rampsf(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_t* restrict ramps); + + +/** + * Get current the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to fill with the current values. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_get_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t* restrict ramps); + +/** + * Set the gamma ramps for a CRTC, `double` version. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsd(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_t ramps); + + +/** + * Set the gamma ramps for a CRTC, 16-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps_fun* red_function, + libgamma_gamma_ramps_fun* green_function, + libgamma_gamma_ramps_fun* blue_function) __attribute__((cold)); + +/** + * Set the gamma ramps for a CRTC, 32-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps32_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps32_fun* red_function, + libgamma_gamma_ramps32_fun* green_function, + libgamma_gamma_ramps32_fun* blue_function) __attribute__((cold)); + +/** + * Set the gamma ramps for a CRTC, 64-bit gamma-depth function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_ramps64_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_ramps64_fun* red_function, + libgamma_gamma_ramps64_fun* green_function, + libgamma_gamma_ramps64_fun* blue_function) __attribute__((cold)); + +/** + * Set the gamma ramps for a CRTC, `float` function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsf_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsf_fun* red_function, + libgamma_gamma_rampsf_fun* green_function, + libgamma_gamma_rampsf_fun* blue_function) __attribute__((cold)); + +/** + * Set the gamma ramps for a CRTC, `double` function version. + * + * Note that this will probably involve the library allocating temporary data. + * + * @param this The CRTC state. + * @param ramps The gamma ramps to apply. + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library. + */ +int libgamma_crtc_set_gamma_rampsd_f(libgamma_crtc_state_t* restrict this, + libgamma_gamma_rampsd_fun* red_function, + libgamma_gamma_rampsd_fun* green_function, + libgamma_gamma_rampsd_fun* blue_function) __attribute__((cold)); + + +#endif + diff --git a/src/lib/libgamma-method.c b/src/lib/libgamma-method.c new file mode 100644 index 0000000..4c81549 --- /dev/null +++ b/src/lib/libgamma-method.c @@ -0,0 +1,274 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#include "libgamma-method.h" + + +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps_initialise(libgamma_gamma_ramps_t* restrict this) +{ + size_t n = this->red_size + this->green_size + this->blue_size; + this->red = malloc(n * sizeof(uint16_t)); + this->green = this-> red + this-> red_size; + this->blue = this->green + this->green_size; + return this->red ? 0 : -1; +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps_destroy(libgamma_gamma_ramps_t* restrict this) +{ + free(this->red); +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps_free(libgamma_gamma_ramps_t* restrict this) +{ + free(this->red); + free(this); +} + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps32_initialise(libgamma_gamma_ramps32_t* restrict this) +{ + size_t n = this->red_size + this->green_size + this->blue_size; + this->red = malloc(n * sizeof(uint32_t)); + this->green = this-> red + this-> red_size; + this->blue = this->green + this->green_size; + return this->red ? 0 : -1; +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps32_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps32_destroy(libgamma_gamma_ramps32_t* restrict this) +{ + free(this->red); +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps32_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps32_free(libgamma_gamma_ramps32_t* restrict this) +{ + free(this->red); + free(this); +} + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps64_initialise(libgamma_gamma_ramps64_t* restrict this) +{ + size_t n = this->red_size + this->green_size + this->blue_size; + this->red = malloc(n * sizeof(uint64_t)); + this->green = this-> red + this-> red_size; + this->blue = this->green + this->green_size; + return this->red ? 0 : -1; +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps64_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps64_destroy(libgamma_gamma_ramps64_t* restrict this) +{ + free(this->red); +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps64_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps64_free(libgamma_gamma_ramps64_t* restrict this) +{ + free(this->red); + free(this); +} + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_rampsf_initialise(libgamma_gamma_rampsf_t* restrict this) +{ + size_t n = this->red_size + this->green_size + this->blue_size; + this->red = malloc(n * sizeof(float)); + this->green = this-> red + this-> red_size; + this->blue = this->green + this->green_size; + return this->red ? 0 : -1; +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsf_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsf_destroy(libgamma_gamma_rampsf_t* restrict this) +{ + free(this->red); +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsf_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsf_free(libgamma_gamma_rampsf_t* restrict this) +{ + free(this->red); + free(this); +} + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_rampsd_initialise(libgamma_gamma_rampsd_t* restrict this) +{ + size_t n = this->red_size + this->green_size + this->blue_size; +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + /* Valgrind complains about us reading uninitialize memory if we just use malloc. */ + this->red = calloc(n, sizeof(double)); +#else + this->red = malloc(n * sizeof(double)); +#endif + this->green = this-> red + this-> red_size; + this->blue = this->green + this->green_size; + return this->red == NULL ? -1 : 0; +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsd_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsd_destroy(libgamma_gamma_rampsd_t* restrict this) +{ + free(this->red); +} + + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsd_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsd_free(libgamma_gamma_rampsd_t* restrict this) +{ + free(this->red); + free(this); +} + diff --git a/src/lib/libgamma-method.h b/src/lib/libgamma-method.h new file mode 100644 index 0000000..8496631 --- /dev/null +++ b/src/lib/libgamma-method.h @@ -0,0 +1,1154 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_METHOD_H +#define LIBGAMMA_METHOD_H + +#if !defined(LIBGAMMA_CONFIG_H) && !defined(DEBUG) +# error libgamma-method.h should not be included directly, include libgamma.h instead +#endif + + +#include <stddef.h> +#include <stdint.h> + + + +/** + * The identifier for the dummy adjustment method. + * This method can be configured and is useful for + * testing your program's ability to handle errors. + */ +#define LIBGAMMA_METHOD_DUMMY 0 + +/** + * The identifier for the adjustment method with + * uses the RandR protocol under the X display server. + */ +#define LIBGAMMA_METHOD_X_RANDR 1 + +/** + * The identifier for the adjustment method with + * uses the VidMode protocol under the X display server. + * This is an older alternative to RandR that can + * work on some drivers that are not supported by RandR, + * however it can only control the primary CRTC per + * screen (partition). + */ +#define LIBGAMMA_METHOD_X_VIDMODE 2 + +/** + * The identifier for the Direct Rendering Manager + * adjustment method that is available in Linux + * (built in to the Linux kernel with a userland + * library for access) and is a part of the + * Direct Rendering Infrastructure. This adjustment + * method all work when you are in non-graphical + * mode; however a display server cannnot be + * started while this is running, but it can be + * started while a display server is running. + */ +#define LIBGAMMA_METHOD_LINUX_DRM 3 + +/** + * The identifier for the Graphics Device Interface + * adjustment method that is available in Windows. + * This method is not well tested; it can be compiled + * to be available under X.org using a translation layer. + */ +#define LIBGAMMA_METHOD_W32_GDI 4 + +/** + * The identifier for the CoreGraphics adjustment + * method that is available in Mac OS X that can + * adjust gamma ramps under the Quartz display server. + * This method is not well tested; it can be compiled + * to be available under X.org using a translation layer. + */ +#define LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS 5 + + +/** + * The index of the last gamma method, neither it + * nor any index before it may actually be supported + * as it could have been disabled at compile-time + */ +#define LIBGAMMA_METHOD_MAX 5 + +/** + * The number adjustment methods provided by this library. + * Note however that this includes adjstment methods that + * have been removed at compile-time. + */ +#define LIBGAMMA_METHOD_COUNT (LIBGAMMA_METHOD_MAX + 1) + + + +/** + * Capabilities of adjustment methods + */ +typedef struct libgamma_method_capabilities +{ + /** + * OR of the CRTC information fields in `libgamma_crtc_information_t` + * that may (but can fail) be read successfully. + */ + int32_t crtc_information; + + /** + * Whether the default site is known, if true the site is integrated + * to the system or can be determined using environment variables. + */ + unsigned default_site_known : 1; + + /** + * Whether the adjustment method supports multiple sites rather + * than just the default site. + */ + unsigned multiple_sites : 1; + + /** + * Whether the adjustment method supports multiple partitions + * per site. + */ + unsigned multiple_partitions : 1; + + /** + * Whether the adjustment method supports multiple CRTC:s + * per partition per site. + */ + unsigned multiple_crtcs : 1; + + /** + * Whether the partition to graphics card is a bijection. + */ + unsigned partitions_are_graphics_cards : 1; + + /** + * Whether the adjustment method supports `libgamma_site_restore`. + */ + unsigned site_restore : 1; + + /** + * Whether the adjustment method supports `libgamma_partition_restore`. + */ + unsigned partition_restore : 1; + + /** + * Whether the adjustment method supports `libgamma_crtc_restore`. + */ + unsigned crtc_restore : 1; + + /** + * Whether the `red_gamma_size`, `green_gamma_size` and `blue_gamma_size` + * fields in `libgamma_crtc_information_t` will always have the same + * values as each other for the adjustment method. + */ + unsigned identical_gamma_sizes : 1; + + /** + * Whether the `red_gamma_size`, `green_gamma_size` and `blue_gamma_size` + * fields in `libgamma_crtc_information_t` will always be filled with the + * same value for the adjustment method. + */ + unsigned fixed_gamma_size : 1; + + /** + * Whether the `gamma_depth` field in `libgamma_crtc_information_t` + * will always be filled with the same value for the adjustment method. + */ + unsigned fixed_gamma_depth : 1; + + /** + * Whether the adjustment method will actually perform adjustments. + */ + unsigned real : 1; + + /** + * Whether the adjustment method is implement using a translation layer. + */ + unsigned fake : 1; + +} libgamma_method_capabilities_t; + + +/** + * Site state + * + * On operating systems that integrate a graphical environment + * there is usally just one site. However, one systems with + * pluggable graphics, like Unix-like systems such as GNU/Linux + * and the BSD:s, there can usually be any (feasible) number of + * sites. In X.org parlance they are called displays. + */ +typedef struct libgamma_site_state +{ + /** + * Adjustment method implementation specific data. + * You as a user of this library should not touch this. + */ + void* data; + + /** + * This field specifies, for the methods if this library, + * which adjustment method (display server and protocol) + * is used to adjust the gamma ramps. + */ + int method; + + /** + * The site identifier. It can either be `NULL` or a string. + * `NULL` indicates the default site. On systems like the + * Unix-like systems, where the graphics are pluggable, this + * is usally resolved by an environment variable, such as + * "DISPLAY" for X.org. + */ + char* site; + + /** + * The number of partitions that is available on this site. + * Probably the majority of display server only one partition + * per site. However, X.org can, and traditional used to have + * on multi-headed environments, multiple partitions per site. + * In X.org partitions are called 'screens'. It is not to be + * confused with monitor. A screen is a collection of monitors, + * and the mapping from monitors to screens is a surjection. + * On hardware-level adjustment methods, such as Direct + * Rendering Manager, a partition is a graphics card. + */ + size_t partitions_available; + +} libgamma_site_state_t; + + +/** + * Partition state. + * + * Probably the majority of display server only one partition + * per site. However, X.org can, and traditional used to have + * on multi-headed environments, multiple partitions per site. + * In X.org partitions are called 'screens'. It is not to be + * confused with monitor. A screen is a collection of monitors, + * and the mapping from monitors to screens is a surjection. + * On hardware-level adjustment methods, such as Direct + * Rendering Manager, a partition is a graphics card. + */ +typedef struct libgamma_partition_state +{ + /** + * Adjustment method implementation specific data. + * You as a user of this library should not touch this. + */ + void* data; + + /** + * The site this partition belongs to. + */ + libgamma_site_state_t* site; + + /** + * The index of the partition. + */ + size_t partition; + + /** + * The number of CRTC:s that are available under this + * partition. Note that the CRTC:s are not necessarily + * online. + */ + size_t crtcs_available; + +} libgamma_partition_state_t; + + +/** + * Cathode ray tube controller state. + * + * The CRTC controls the gamma ramps for the + * monitor that is plugged in to the connector + * that the CRTC belongs to. + */ +typedef struct libgamma_crtc_state +{ + /** + * Adjustment method implementation specific data. + * You as a user of this library should not touch this. + */ + void* data; + + /** + * The partition this CRTC belongs to. + */ + libgamma_partition_state_t* partition; + + /** + * The index of the CRTC within its partition. + */ + size_t crtc; + +} libgamma_crtc_state_t; + + +/** + * Types for connectors. + */ +typedef enum libgamma_connector_type + { + /** + * The adjustment method does not know the connector's type + * (This could be considered an error). + */ + LIBGAMMA_CONNECTOR_TYPE_Unknown, + + /** + * Video Graphics Array (VGA). + */ + LIBGAMMA_CONNECTOR_TYPE_VGA, + + /** + * Digital Visual Interface, integrated (DVI-I). + */ + LIBGAMMA_CONNECTOR_TYPE_DVII, + + /** + * Digital Visual Interface, digital only (DVI-D). + */ + LIBGAMMA_CONNECTOR_TYPE_DVID, + + /** + * Digital Visual Interface, analogue only (DVI-A). + */ + LIBGAMMA_CONNECTOR_TYPE_DVIA, + + /** + * Composite video. + */ + LIBGAMMA_CONNECTOR_TYPE_Composite, + + /** + * Separate Video (S-video). + */ + LIBGAMMA_CONNECTOR_TYPE_SVIDEO, + + /** + * Low-voltage differential signaling (LVDS). + */ + LIBGAMMA_CONNECTOR_TYPE_LVDS, + + /** + * Component video, usally separate cables for each channel. + */ + LIBGAMMA_CONNECTOR_TYPE_Component, + + /** + * 9 pin DIN (Deutsches Institut für Normung) connector. + */ + LIBGAMMA_CONNECTOR_TYPE_9PinDIN, + + /** + * DisplayPort. + */ + LIBGAMMA_CONNECTOR_TYPE_DisplayPort, + + /** + * High-Definition Multimedia Interface (HDMI), unknown type. + */ + LIBGAMMA_CONNECTOR_TYPE_HDMI, + + /** + * High-Definition Multimedia Interface, type A (HDMI-A). + */ + LIBGAMMA_CONNECTOR_TYPE_HDMIA, + + /** + * High-Definition Multimedia Interface, type B (HDMI-B). + */ + LIBGAMMA_CONNECTOR_TYPE_HDMIB, + + /** + * Television, unknown connector. + */ + LIBGAMMA_CONNECTOR_TYPE_TV, + + /** + * Embedded DisplayPort (eDP). + */ + LIBGAMMA_CONNECTOR_TYPE_eDP, + + /** + * A virtual connector. + */ + LIBGAMMA_CONNECTOR_TYPE_VIRTUAL, + + /** + * Display Serial Interface (DSI). + */ + LIBGAMMA_CONNECTOR_TYPE_DSI, + + /** + * LFP connector. + * (If you know what this is add it to Wikipedia.) + */ + LIBGAMMA_CONNECTOR_TYPE_LFP + + } libgamma_connector_type_t; + +/** + * The number of values defined in `libgamma_connector_type_t`. + */ +#define LIBGAMMA_CONNECTOR_TYPE_COUNT 19 + +/** + * Orders for subpixels. Currently the possible values are + * very biased to LCD, Plasma and monochrome monitors. + */ +typedef enum libgamma_subpixel_order + { + /** + * The adjustment method does not know the order of the subpixels. + * (This could be considered an error.) + */ + LIBGAMMA_SUBPIXEL_ORDER_UNKNOWN, + + /** + * There are no subpixels in the monitor. + */ + LIBGAMMA_SUBPIXEL_ORDER_NONE, + + /** + * The subpixels are ordered red, green and then blue, from left to right. + */ + LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_RGB, + + /** + * The subpixels are ordered blue, green and then red, from left to right. + */ + LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_BGR, + + /** + * The subpixels are ordered red, green and then blue, from the top down. + */ + LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_RGB, + + /** + * The subpixels are ordered blue, green and then red, from the top down. + */ + LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_BGR + + } libgamma_subpixel_order_t; + +/** + * The number of values defined in `libgamma_subpixel_order_t`. + */ +#define LIBGAMMA_SUBPIXEL_ORDER_COUNT 6 + + +/** + * For a `libgamma_crtc_information_t` fill in the + * values for `edid` and `edid_length` and report errors to `edid_error`. + */ +#define LIBGAMMA_CRTC_INFO_EDID (1 << 0) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `width_mm` and report errors to `width_mm_error`. + */ +#define LIBGAMMA_CRTC_INFO_WIDTH_MM (1 << 1) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `height_mm` and report errors to `height_mm_error`. + */ +#define LIBGAMMA_CRTC_INFO_HEIGHT_MM (1 << 2) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `width_mm_edid` and report errors to `width_mm_edid_error`. + */ +#define LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID (1 << 3) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `height_mm_edid` and report errors to `height_mm_edid_error`. + */ +#define LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID (1 << 4) + +/** + * For a `libgamma_crtc_information_t` fill in the + * values for `red_gamma_size`, `green_gamma_size` and `blue_gamma_size`. + * and report errors to `gamma_size_error` + */ +#define LIBGAMMA_CRTC_INFO_GAMMA_SIZE (1 << 5) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `gamma_depth` and report errors to `gamma_depth_error`. + */ +#define LIBGAMMA_CRTC_INFO_GAMMA_DEPTH (1 << 6) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `gamma_support` and report errors to `gamma_support_error`. + */ +#define LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT (1 << 7) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `subpixel_order` and report errors to `subpixel_order_error`. + */ +#define LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER (1 << 8) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `active` and report errors to `active_error`. + */ +#define LIBGAMMA_CRTC_INFO_ACTIVE (1 << 9) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `connector_name` and report errors to `connector_name_error`. + */ +#define LIBGAMMA_CRTC_INFO_CONNECTOR_NAME (1 << 10) + +/** + * For a `libgamma_crtc_information_t` fill in the + * value for `connector_type` and report errors to `connector_type_error`. + */ +#define LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE (1 << 11) + +/** + * For a `libgamma_crtc_information_t` fill in the + * values for `gamma_red`, `gamma_green` and `gamma_blue` + * and report errors to `connector_type_error`. + */ +#define LIBGAMMA_CRTC_INFO_GAMMA (1 << 12) + +/** + * The number of `LIBGAMMA_CRTC_INFO_*` values defined. + */ +#define LIBGAMMA_CRTC_INFO_COUNT 13 + + +/** + * Cathode ray tube controller information data structure. + */ +typedef struct libgamma_crtc_information +{ + /** + * The Extended Display Identification Data associated with + * the attached monitor. This is raw byte array that is usually + * 128 bytes long. It is not NUL-terminate, rather its length + * is stored in `edid_size`. + */ + unsigned char* edid; + + /** + * The length of `edid`. + */ + size_t edid_length; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int edid_error; + + + /** + * The phyical width, in millimetres, of the viewport of the + * attached monitor, as reported by the adjustment method. This + * value may be incorrect, which is a known issue with the X + * server where it is the result of the X server attempting + * the estimate the size on its own. + * Zero means that its is not applicable, which is the case + * for projectors. + */ + size_t width_mm; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int width_mm_error; + + + /** + * The phyical height, in millimetres, of the viewport of the + * attached monitor, as reported by the adjustment method. This + * value may be incorrect, which is a known issue with the X + * server where it is the result of the X server attempting + * the estimate the size on its own. + * Zero means that its is not applicable, which is the case + * for projectors. + */ + size_t height_mm; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int height_mm_error; + + + /** + * The phyical width, in millimetres, of the viewport of the + * attached monitor, as reported by it the monitor's Extended + * Display Information Data. This value can only contain whole + * centimetres, which means that the result is always zero + * modulus ten. However, this could change with revisions of + * the EDID structure. + * Zero means that its is not applicable, which is the case + * for projectors. + */ + size_t width_mm_edid; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int width_mm_edid_error; + + + /** + * The phyical height, in millimetres, of the viewport of the + * attached monitor, as reported by it the monitor's Extended + * Display Information Data. This value can only contain whole + * centimetres, which means that the result is always zero + * modulus ten. However, this could change with revisions of + * the EDID structure. + * Zero means that its is not applicable, which is the case + * for projectors. + */ + size_t height_mm_edid; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int height_mm_edid_error; + + + /** + * The size of the encoding axis of the red gamma ramp. + */ + size_t red_gamma_size; + + /** + * The size of the encoding axis of the green gamma ramp. + */ + size_t green_gamma_size; + + /** + * The size of the encoding axis of the blue gamma ramp. + */ + size_t blue_gamma_size; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int gamma_size_error; + + + /** + * The bit-depth of the value axes of gamma ramps, + * -1 for single precision floating point, and -2 for + * double precision floating point. + */ + signed gamma_depth; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int gamma_depth_error; + + + /** + * Non-zero gamma ramp adjustments are supported. + */ + int gamma_support; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int gamma_support_error; + + + /** + * The layout of the subpixels. + * You cannot count on this value — especially for CRT:s — + * but it is provided anyway as a means of distinguishing monitors. + */ + libgamma_subpixel_order_t subpixel_order; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int subpixel_order_error; + + + /** + * Whether there is a monitors connected to the CRTC. + */ + int active; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int active_error; + + + /** + * The name of the connector as designated by the display + * server or as give by this library in case the display + * server lacks this feature. + */ + char* connector_name; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int connector_name_error; + + + /** + * The type of the connector that is associated with the CRTC. + */ + libgamma_connector_type_t connector_type; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int connector_type_error; + + + /** + * The gamma characteristics of the monitor as reported + * in its Extended Display Information Data. The value + * holds the value for the red channel. If you do not have + * and more accurate measurement of the gamma for the + * monitor this could be used to give a rought gamma + * correction; simply divide the value with 2.2 and use + * the result for the red channel in the gamma correction. + */ + float gamma_red; + + /** + * The gamma characteristics of the monitor as reported + * in its Extended Display Information Data. The value + * holds the value for the green channel. If you do not have + * and more accurate measurement of the gamma for the + * monitor this could be used to give a rought gamma + * correction; simply divide the value with 2.2 and use + * the result for the green channel in the gamma correction. + */ + float gamma_green; + + /** + * The gamma characteristics of the monitor as reported + * in its Extended Display Information Data. The value + * holds the value for the blue channel. If you do not have + * and more accurate measurement of the gamma for the + * monitor this could be used to give a rought gamma + * correction; simply divide the value with 2.2 and use + * the result for the blue channel in the gamma correction. + */ + float gamma_blue; + + /** + * Zero on success, positive it holds the value `errno` had + * when the reading failed, otherwise (negative) the value + * of an error identifier provided by this library. + */ + int gamma_error; + +} libgamma_crtc_information_t; + + + +/** + * Gamma ramp structure for 16-bit gamma ramps. + */ +typedef struct libgamma_gamma_ramps +{ + /** + * The size of `red`. + */ + size_t red_size; + + /** + * The size of `green`. + */ + size_t green_size; + + /** + * The size of `blue`. + */ + size_t blue_size; + + /** + * The gamma ramp for the red channel. + */ + uint16_t* red; + + /** + * The gamma ramp for the green channel. + */ + uint16_t* green; + + /** + * The gamma ramp for the blue channel. + */ + uint16_t* blue; + +} libgamma_gamma_ramps_t; + + +/** + * Gamma ramp structure for 32-bit gamma ramps. + */ +typedef struct libgamma_gamma_ramps32 +{ + /** + * The size of `red`. + */ + size_t red_size; + + /** + * The size of `green`. + */ + size_t green_size; + + /** + * The size of `blue`. + */ + size_t blue_size; + + /** + * The gamma ramp for the red channel. + */ + uint32_t* red; + + /** + * The gamma ramp for the green channel. + */ + uint32_t* green; + + /** + * The gamma ramp for the blue channel. + */ + uint32_t* blue; + +} libgamma_gamma_ramps32_t; + + +/** + * Gamma ramp structure for 64-bit gamma ramps. + */ +typedef struct libgamma_gamma_ramps64 +{ + /** + * The size of `red`. + */ + size_t red_size; + + /** + * The size of `green`. + */ + size_t green_size; + + /** + * The size of `blue`. + */ + size_t blue_size; + + /** + * The gamma ramp for the red channel. + */ + uint64_t* red; + + /** + * The gamma ramp for the green channel. + */ + uint64_t* green; + + /** + * The gamma ramp for the blue channel. + */ + uint64_t* blue; + +} libgamma_gamma_ramps64_t; + + +/** + * Gamma ramp structure for `float` gamma ramps. + */ +typedef struct libgamma_gamma_rampsf +{ + /** + * The size of `red`. + */ + size_t red_size; + + /** + * The size of `green`. + */ + size_t green_size; + + /** + * The size of `blue`. + */ + size_t blue_size; + + /** + * The gamma ramp for the red channel. + */ + float* red; + + /** + * The gamma ramp for the green channel. + */ + float* green; + + /** + * The gamma ramp for the blue channel. + */ + float* blue; + +} libgamma_gamma_rampsf_t; + + +/** + * Gamma ramp structure for `double` gamma ramps. + */ +typedef struct libgamma_gamma_rampsd +{ + /** + * The size of `red`. + */ + size_t red_size; + + /** + * The size of `green`. + */ + size_t green_size; + + /** + * The size of `blue`. + */ + size_t blue_size; + + /** + * The gamma ramp for the red channel. + */ + double* red; + + /** + * The gamma ramp for the green channel. + */ + double* green; + + /** + * The gamma ramp for the blue channel. + */ + double* blue; + +} libgamma_gamma_rampsd_t; + + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps_initialise(libgamma_gamma_ramps_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps_destroy(libgamma_gamma_ramps_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps_free(libgamma_gamma_ramps_t* restrict this); + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps32_initialise(libgamma_gamma_ramps32_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps32_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps32_destroy(libgamma_gamma_ramps32_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps32_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps32_free(libgamma_gamma_ramps32_t* restrict this); + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_ramps64_initialise(libgamma_gamma_ramps64_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps64_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps64_destroy(libgamma_gamma_ramps64_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_ramps64_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_ramps64_free(libgamma_gamma_ramps64_t* restrict this); + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps. + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_rampsf_initialise(libgamma_gamma_rampsf_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsf_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsf_destroy(libgamma_gamma_rampsf_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsf_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsf_free(libgamma_gamma_rampsf_t* restrict this); + + +/** + * Initialise a gamma ramp in the proper way that allows all adjustment + * methods to read from and write to it without causing segmentation violation. + * + * The input must have `red_size`, `green_size` and `blue_size` set to the + * sizes of the gamma ramps that should be allocated. + * + * @param this The gamma ramps + * @return Zero on success, -1 on allocation error, `errno` will be set accordingly. + */ +int libgamma_gamma_rampsd_initialise(libgamma_gamma_rampsd_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsd_initialise` or otherwise + * initialises in the proper manner. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsd_destroy(libgamma_gamma_rampsd_t* restrict this); + +/** + * Release resources that are held by a gamma ramp strcuture that + * has been allocated by `libgamma_gamma_rampsd_initialise` or otherwise + * initialises in the proper manner, as well as release the pointer + * to the structure. + * + * @param this The gamma ramps. + */ +void libgamma_gamma_rampsd_free(libgamma_gamma_rampsd_t* restrict this); + + + +#endif + diff --git a/src/lib/libgamma.h b/src/lib/libgamma.h new file mode 100644 index 0000000..9a5b9be --- /dev/null +++ b/src/lib/libgamma.h @@ -0,0 +1,30 @@ +/** + * libgamma — Display server abstraction layer for gamma ramp adjustments + * Copyright © 2014 Mattias Andrée (maandree@member.fsf.org) + * + * This library 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. + * + * This library 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 this library. If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef LIBGAMMA_H +#define LIBGAMMA_H + + +#include "libgamma-config.h" /* Must be first. */ + +#include "libgamma-method.h" +#include "libgamma-facade.h" +#include "libgamma-error.h" + + +#endif + |