diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/blueshift_iccprofile.c | 85 |
1 files changed, 78 insertions, 7 deletions
diff --git a/src/blueshift_iccprofile.c b/src/blueshift_iccprofile.c index ef04701..68635d2 100644 --- a/src/blueshift_iccprofile.c +++ b/src/blueshift_iccprofile.c @@ -45,7 +45,6 @@ static xcb_generic_error_t* error; */ int main(int argc, char** argv) { - const xcb_setup_t* setup; xcb_screen_iterator_t iter; int screen_count; xcb_screen_t* screens; @@ -55,21 +54,41 @@ int main(int argc, char** argv) (void) argv; + /* To get all ICC profiles, which are binary encoded, we have + to connect to the display and for each screen look for + properties maching the pattern "_ICC_PROFILE(|_[0-9]*)". + But we should also do it without being case sensitive, + because it is not well defined how the casing should be. + The _ICC_PROFILE atom is the profile for the first CRTC + (with the primary one being the first) within the screen. + _ICC_PROFILE_0 is not a valid atom for a profile, + _ICC_PROFILE_1 is for the secondard, and _ICC_PROFILE_2 + is for the tertiary, and so on. + */ + + /* Get X connection */ + /* This acquires a connection to the + X display indicated by the DISPLAY + environ variable. */ connection = xcb_connect(NULL, NULL); /* Get screen information */ - setup = xcb_get_setup(connection); - iter = xcb_setup_roots_iterator(setup); + /* Acquire a list of all screens in the displaym */ + iter = xcb_setup_roots_iterator(xcb_get_setup(connection)); + /* count the list, */ screen_count = iter.rem; + /* and start at the first screen. */ screens = iter.data; for (screen_i = 0; screen_i < screen_count; screen_i++) { + /* For each screen */ xcb_screen_t* screen = screens + screen_i; + xcb_list_properties_cookie_t list_cookie; xcb_list_properties_reply_t* list_reply; xcb_atom_t* atoms; @@ -78,19 +97,27 @@ int main(int argc, char** argv) /* Get root window properties */ + /* Acquire a list of all properties on the current screen's root window. + global properties are set here, as well as monitor specific properties + that are actual monitor properties. */ list_cookie = xcb_list_properties(connection, screen->root); list_reply = xcb_list_properties_reply(connection, list_cookie, &error); if (error) { + /* If we were not successful lets print an error + message and close the connection to the display. */ fprintf(stderr, "Screen root window property list query returned %i\n", error->error_code); xcb_disconnect(connection); return 1; } + /* Extract the properties for the data structure that holds them, */ atoms = xcb_list_properties_atoms(list_reply); + /* and get the last one so that we can iterate over them nicely. */ atoms_end = atoms + xcb_list_properties_atoms_length(list_reply); + /* For each property */ for (; atoms != atoms_end; atoms++) { xcb_get_atom_name_cookie_t name_cookie; @@ -105,62 +132,91 @@ int main(int argc, char** argv) /* Get root window property name */ + /* Acquire the the atom name. */ name_cookie = xcb_get_atom_name(connection, *atoms); name_reply = xcb_get_atom_name_reply(connection, name_cookie, &error); if (error) { + /* If we were not successful lets print an error + message, free the property list and close the + connection to the display. */ fprintf(stderr, "Screen root window property name query returned %i\n", error->error_code); free(list_reply); xcb_disconnect(connection); return 1; } + /* Extract the atom name from the data structure that holds it. */ name_ = xcb_get_atom_name_name(name_reply); + /* As well as the length of the name; it is not NUL-termianted.*/ len = xcb_get_atom_name_name_length(name_reply); - name = alloca((len + 1) * sizeof(char)); + /* NUL-terminate the atom name, */ + name = alloca((len + 1) * sizeof(char)); /* It is allocated on the stack, so it should not be free:d */ memcpy(name, name_, len * sizeof(char)); *(name + len) = 0; + /* and free the version that is not NUL-terminated. */ free(name_reply); /* Check property name pattern */ + /* Read the atom name */ if (!strcasecmp(name, "_icc_profile")) + /* _ICC_PROFILE is for monitor 0 */ monitor = 0; else if (strcasestr(name, "_icc_profile_") == name) { + /* Skip to the part that should be numerical */ name += strlen("_icc_profile_"); monitor = 0; if (*name == '\0') + /* Invalid: no index */ continue; + /* Parse index */ while (*name) { char c = *name++; + /* with strict format matching. */ if (('0' <= c) && (c <= '9')) monitor = monitor * 10 - (c & 15); else + /* Not numerical: did not match */ goto monitor_bad; } + /* Convert from negative to possitive. */ monitor = -monitor; - goto monitor_ok; + /* Check that it is not zero, zero is + not a valid index, it should just be + _ICC_PROFILE in such case. */ + if (monitor > 0) + goto monitor_ok; monitor_bad: + /* Atom name ultimately did not match the, pattern + ignore it, it may be for something else, but it + is propably just invalid. */ continue; } else + /* Atom name does not match the pattern, + ignore it, it is for something else. */ continue; /* Get root window property value */ monitor_ok: + /* Acquire the property's value */ prop_cookie = xcb_get_property(connection, 0, screen->root, *atoms, XCB_GET_PROPERTY_TYPE_ANY, 0, 0); prop_reply = xcb_get_property_reply(connection, prop_cookie, &error); if (error) { + /* If we were not successful lets print an error + message, free the property and property list + and close the connection to the display. */ fprintf(stderr, "Screen root window property value query returned %i\n", error->error_code); free(prop_reply); free(list_reply); @@ -168,14 +224,17 @@ int main(int argc, char** argv) return 1; } + /* Get the length of the property's value */ len = prop_reply->bytes_after; - free(prop_reply); prop_cookie = xcb_get_property(connection, 0, screen->root, *atoms, XCB_GET_PROPERTY_TYPE_ANY, 0, len); prop_reply = xcb_get_property_reply(connection, prop_cookie, &error); if (error) { + /* If we were not successful lets print an error + message, free the property and property list + and close the connection to the display. */ fprintf(stderr, "Screen root window property value query returned %i\n", error->error_code); free(prop_reply); free(list_reply); @@ -183,31 +242,43 @@ int main(int argc, char** argv) return 1; } + /* Encode the property's value hexadecimally */ { + /* Allocate memories on the stack to fill with property's + value in with hexadecimal encoding and NUL-termination. */ char* value = alloca((2 * len + 1) * sizeof(char)); + /* Get the property's value. */ char* value_ = xcb_get_property_value(prop_reply); int i; + /* Recode */ for (i = 0; i < len; i++) { *(value + i * 2 + 0) = "0123456789abcdef"[(*(value_ + i) >> 4) & 15]; *(value + i * 2 + 1) = "0123456789abcdef"[(*(value_ + i) >> 0) & 15]; } + /* NUL-terminate */ *(value + 2 * len) = 0; + /* Print screen, monitor and profile. */ printf("%i: %i: %s\n", screen_i, monitor, value); } + /* Free the property resources. */ free(prop_reply); } + /* Free the list is properties. */ free(list_reply); } + /* Flush standard output to be sure that everything was printed, + should not be necessary, but it is best to be on the safe side. */ fflush(stdout); - /* Free resources **/ + /* Free resources */ + /* Close connection to the display. */ xcb_disconnect(connection); return 0; } |