/* See LICENSE file for copyright and license details. */
#include "crtcinfo.h"
/**
* Conditionally print a CRTC information field
*
* @param type:data-type Data type for the value of the information field
* @param notation:string-literal %-pattern for `printf` (excluding the %) that is used for `type`
* @param do_print Whether the information should be included in the process's output
* @param description A description of the information field
* @param error The error of the information field
* @param value The value of the information field
*/
#define print_crtc_information_(type, notation)\
static void\
print_crtc_information_##type(int do_print, const char *description, int error, type value)\
{\
char buf[256];\
if (do_print) {\
if (error) {\
snprintf(buf, sizeof(buf) / sizeof(char), " (error) %s", description);\
libgamma_perror(buf, error);\
} else {\
printf(" %s: %" notation "\n", description, value);\
}\
}\
}
/**
* A single [a-z] word alternative to `const char*`, we need it for the
* function name of the string variant of `print_crtc_information_*`
*/
typedef const char *str;
/* Create `print_crtc_information_*` variants */
print_crtc_information_(size_t, "lu")
print_crtc_information_(signed, "i")
print_crtc_information_(int, "i")
#ifdef __GCC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdouble-promotion"
#endif
print_crtc_information_(float, "f")
#ifdef __GCC__
# pragma GCC diagnostic pop
#endif
print_crtc_information_(str, "s")
#undef print_crtc_information_
#define __case(VALUE) case VALUE: return #VALUE
/**
* Get a string representation of a subpixel order
*
* @param value The subpixel order
* @return String representation
*/
static const char *
subpixel_order_str(libgamma_subpixel_order_t value)
{
switch (value) {
__case (LIBGAMMA_SUBPIXEL_ORDER_UNKNOWN);
__case (LIBGAMMA_SUBPIXEL_ORDER_NONE);
__case (LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_RGB);
__case (LIBGAMMA_SUBPIXEL_ORDER_HORIZONTAL_BGR);
__case (LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_RGB);
__case (LIBGAMMA_SUBPIXEL_ORDER_VERTICAL_BGR);
default:
return "(unknown)";
}
}
/**
* Get a string representation of a connector type
*
* @param value The connector type
* @return String representation
*/
static const char *
connector_type_str(libgamma_connector_type_t value)
{
switch (value) {
__case (LIBGAMMA_CONNECTOR_TYPE_Unknown);
__case (LIBGAMMA_CONNECTOR_TYPE_VGA);
__case (LIBGAMMA_CONNECTOR_TYPE_DVI);
__case (LIBGAMMA_CONNECTOR_TYPE_DVII);
__case (LIBGAMMA_CONNECTOR_TYPE_DVID);
__case (LIBGAMMA_CONNECTOR_TYPE_DVIA);
__case (LIBGAMMA_CONNECTOR_TYPE_Composite);
__case (LIBGAMMA_CONNECTOR_TYPE_SVIDEO);
__case (LIBGAMMA_CONNECTOR_TYPE_LVDS);
__case (LIBGAMMA_CONNECTOR_TYPE_Component);
__case (LIBGAMMA_CONNECTOR_TYPE_9PinDIN);
__case (LIBGAMMA_CONNECTOR_TYPE_DisplayPort);
__case (LIBGAMMA_CONNECTOR_TYPE_HDMI);
__case (LIBGAMMA_CONNECTOR_TYPE_HDMIA);
__case (LIBGAMMA_CONNECTOR_TYPE_HDMIB);
__case (LIBGAMMA_CONNECTOR_TYPE_TV);
__case (LIBGAMMA_CONNECTOR_TYPE_eDP);
__case (LIBGAMMA_CONNECTOR_TYPE_VIRTUAL);
__case (LIBGAMMA_CONNECTOR_TYPE_DSI);
__case (LIBGAMMA_CONNECTOR_TYPE_LFP);
default:
return "(unknown)";
}
}
/**
* Get a string representation of a decision
*
* @param value The decision
* @return String representation
*/
static const char *
decision_str(libgamma_decision_t value)
{
switch (value) {
__case (LIBGAMMA_NO);
__case (LIBGAMMA_MAYBE);
__case (LIBGAMMA_YES);
default:
return "(unknown)";
}
}
#undef __case
/**
* The CRTC information for a CRTC
*
* @param crtc The CRTC
*/
void
crtc_information(libgamma_crtc_state_t *restrict crtc)
{
libgamma_method_capabilities_t caps;
libgamma_crtc_information_t info;
int fields, field;
char *edid_lc, *edid_uc;
unsigned char *edid_raw;
/* Get supported CRTC informations fields */
libgamma_method_capabilities(&caps, crtc->partition->site->method);
/* List unsupport information fields by testing them one by one */
for (fields = caps.crtc_information; field = fields & -fields, fields; fields ^= field) {
if (libgamma_get_crtc_information(&info, crtc, field))
printf("Could not read CRTC information field %i\n", field);
free(info.edid);
free(info.connector_name);
}
/* Get CRTC information, that is supported */
fields = caps.crtc_information;
if (libgamma_get_crtc_information(&info, crtc, fields))
printf("An error occurred while reading CRTC information\n");
/* Macros for printing CRTC information */
#define print2(TYPE, FIELD_ID, DESCRIPTION, FIELD_VAR, ERROR_VAR)\
print_crtc_information_##TYPE(fields & FIELD_ID, DESCRIPTION, info.ERROR_VAR, info.FIELD_VAR);
#define print(TYPE, FIELD_ID, DESCRIPTION, FIELD_VAR)\
print2(TYPE, FIELD_ID, DESCRIPTION, FIELD_VAR, FIELD_VAR##_error);
/* Print CRTC information */
printf("CRTC information:\n");
/* Print the EDID field */
if ((fields & LIBGAMMA_CRTC_INFO_EDID)) {
if (info.edid_error) {
libgamma_perror(" (error) EDID", info.edid_error);
} else {
edid_lc = libgamma_behex_edid(info.edid, info.edid_length);
edid_raw = libgamma_unhex_edid(edid_lc);
edid_uc = libgamma_behex_edid_uppercase(edid_raw, info.edid_length);
printf(" EDID: %s\n", edid_lc);
printf(" EDID (uppercase): %s\n", edid_uc);
printf(" EDID (length): %lu\n", info.edid_length);
free(edid_lc);
free(edid_raw);
free(edid_uc);
}
}
/* Print physical dimensions of the monitor */
print(size_t, LIBGAMMA_CRTC_INFO_WIDTH_MM, "width", width_mm);
print(size_t, LIBGAMMA_CRTC_INFO_HEIGHT_MM, "height", height_mm);
print(size_t, LIBGAMMA_CRTC_INFO_WIDTH_MM_EDID, "width per EDID", width_mm_edid);
print(size_t, LIBGAMMA_CRTC_INFO_HEIGHT_MM_EDID, "height per EDID", height_mm_edid);
/* Print gamma ramp information */
print2(size_t, LIBGAMMA_CRTC_INFO_GAMMA_SIZE, "red gamma ramp size", red_gamma_size, gamma_size_error);
print2(size_t, LIBGAMMA_CRTC_INFO_GAMMA_SIZE, "green gamma ramp size", green_gamma_size, gamma_size_error);
print2(size_t, LIBGAMMA_CRTC_INFO_GAMMA_SIZE, "blue gamma ramp size", blue_gamma_size, gamma_size_error);
print(signed, LIBGAMMA_CRTC_INFO_GAMMA_DEPTH, "gamma ramp depth", gamma_depth);
/* Print gamma ramp support */
if (fields & LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT) {
if (info.gamma_support_error)
libgamma_perror(" (error) gamma support", info.gamma_support_error);
else
printf(" gamma support: %s\n", decision_str(info.gamma_support));
}
/* Print subpixel order for the monitor */
if (fields & LIBGAMMA_CRTC_INFO_SUBPIXEL_ORDER) {
if (info.subpixel_order_error)
libgamma_perror(" (error) subpixel order", info.subpixel_order_error);
else
printf(" subpixel order: %s\n", subpixel_order_str(info.subpixel_order));
}
/* Print connector information */
print(int, LIBGAMMA_CRTC_INFO_ACTIVE, "active", active);
print(str, LIBGAMMA_CRTC_INFO_CONNECTOR_NAME, "connector name", connector_name);
if (fields & LIBGAMMA_CRTC_INFO_CONNECTOR_TYPE) {
if (info.connector_type_error)
libgamma_perror(" (error) subpixel order", info.connector_type_error);
else
printf(" subpixel order: %s\n", connector_type_str(info.connector_type));
}
/* Print the gamma characteristics of the monitor */
print2(float, LIBGAMMA_CRTC_INFO_GAMMA, "red gamma characteristics", gamma_red, gamma_error);
print2(float, LIBGAMMA_CRTC_INFO_GAMMA, "green gamma characteristics", gamma_green, gamma_error);
print2(float, LIBGAMMA_CRTC_INFO_GAMMA, "blue gamma characteristics", gamma_blue, gamma_error);
printf("\n");
#undef print
#undef print2
/* Release resouces */
free(info.edid);
free(info.connector_name);
}