diff options
Diffstat (limited to '')
| -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;  } | 
