diff options
-rw-r--r-- | README | 12 | ||||
-rw-r--r-- | src/haiku.c | 2 | ||||
-rw-r--r-- | src/settings.c | 3 | ||||
-rw-r--r-- | src/state.c | 141 | ||||
-rw-r--r-- | src/state.h | 9 |
5 files changed, 161 insertions, 6 deletions
@@ -127,11 +127,15 @@ SIGNALS order they where selected. ENVIRONMENT + XDG_RUNTIME_DIR + This environment variable names the directory in which + the state file is stored. If unset or empty, /run is + used. + RADHARC_STATE - The pathname to the state file, will be - determined automatically if not set. - If not set, you may only have one instance - running per display server instance. + The pathname to the state file, will be determined + automatically if not set. If not set, you may only + have one instance running per display server instance. RATIONALE Your location is determined use GeoClue because it clunky, diff --git a/src/haiku.c b/src/haiku.c index d38fc9a..5c9e5c7 100644 --- a/src/haiku.c +++ b/src/haiku.c @@ -73,7 +73,7 @@ random_haiku(const char *str, ... /*, NULL */) */ void haiku(const char *s) { -#define HAIKU(...) do { fprintf(stderr, "\n%s", random_haiku(__VA_ARGS__, NULL)); return; } while (0) +#define HAIKU(...) do { fprintf(stderr, "%s", random_haiku(__VA_ARGS__, NULL)); return; } while (0) /* Yeah, I now most of these are in 5–7–5 syllables, * rather than 5–7–5 mora. But really, how cares. */ diff --git a/src/settings.c b/src/settings.c index fc527e7..6ee5130 100644 --- a/src/settings.c +++ b/src/settings.c @@ -229,12 +229,13 @@ parse_command_line(int argc, char *argv[], struct settings *settings) if (!location_set && !(settings->temp)) { fprintf(stderr, - "%s: The -l option is mandatory, unless single value -t is used." + "%s: The -l option is mandatory, unless single value -t is used. " "See `man 1 radharc` for more information.\n", !argv0 ? "radharc" : argv0); exit(2); } + return; fail: haiku(argv0 ? argv0 : "radharc"); exit(1); diff --git a/src/state.c b/src/state.c index bad38eb..20427b8 100644 --- a/src/state.c +++ b/src/state.c @@ -16,6 +16,14 @@ */ #include "state.h" #include "solar.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> + +#include <libgamma.h> + +#define t(...) do { if (!(__VA_ARGS__)) goto fail; } while (0) @@ -35,3 +43,136 @@ get_darkness(double elevation) return NIGHT; } + +/** + * Compare two display server environment strings. + * + * @param a_ One of the string. + * @param b_ The other string. + * @return -1, 0, or +1. + */ +static int +displayenvcmp(const void *a_, const void *b_) +{ +#define S(V, CD) ((V = ((CD)[1] == 'r' ? strrchr : strchr)(V, (CD)[0]))) +#ifdef __GNUC__ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdiscarded-qualifiers" +#endif + char *a = a_; + char *b = b_; +#ifdef __GNUC__ +# pragma GCC diagnostic pop +#endif + char *p = strchr(a, '=') + 1; + char *q = strchr(b, '=') + 1; + int rc; + + if ((*p != '/') && S(p, ":r") && S(p, ".l")) *p = '\0'; else p = NULL; + if ((*q != '/') && S(p, ":r") && S(p, ".l")) *q = '\0'; else q = NULL; + + rc = strcmp(a, b); + + if (*p) *p = '.'; + if (*q) *q = '.'; + return rc; +#undef S +} + + +/** + * Make an display string safe for a pathname. + * + * @param str The string. + * @return A safe version of the string, `NULL` on error. + */ +static char * +escape_display(const char* str) +{ + char *r, *w, *rc = malloc((2 * strlen(str) + 1) * sizeof(char *)); + int s = 0; + if (!rc) return NULL; + for (r = w = strchr(rc, '=') + 1; *r; r++) { + if (!s || (*r != '/')) { + if (strchr("@=/", *r)) *w++ = '@'; + *w++ = (*r == '/' ? 's' : *r); + s = (*r == '/'); + } + } + if (s) w[-2] = '\0'; + return rc; +} + + +/** + * The string of display servers. + * + * @param settings The settings. + * @return The string, `NULL` on error. + */ +static char * +get_display_string(struct settings *settings) +{ + const char *var, *val; + char *r, *d = NULL, *rc = NULL, **displays; + size_t i, n = 0, len = 0; + int method, saved_errno; + + t (displays = malloc(settings->monitors_n * sizeof(char *))); + for (i = 0; i < settings->monitors_n; i++) + if ((settings->monitors_arg[i] == 'd') && strchr(settings->monitors_id[i], '=')) + len += 1 + strlen(displays[n++] = settings->monitors_id[i]); + if (n) goto custom; + + if (!libgamma_list_methods(&method, 1, 0)) { + fprintf(stderr, "No display was found.\n" + "DRM support missing.\n" + "Can you even see?\n"); + return errno = 0, NULL; + } + + var = libgamma_method_default_site_variable(method); + val = libgamma_method_default_site(method); + if (!val) return strdup(""); + t (d = malloc((3 + strlen(var) + strlen(val)) * sizeof(char))); + stpcpy(stpcpy(stpcpy(stpcpy(d, "."), var), "="), val); + t (rc = escape_display(d)); + return rc; + +custom: + qsort(displays, n, sizeof(*displays), displayenvcmp); + t (r = rc = malloc((2 * len + 1) * sizeof(char))); + for (i = 0; i < n; i++) { + t (d = escape_display(displays[i])); + r = stpcpy(stpcpy(r, "."), d), free(d), d = NULL; + } + return rc; + +fail: + saved_errno = errno, free(rc), free(d), errno = saved_errno; + return NULL; +} + + +/** + * Set $RADHARC_STATE. + * + * @param settings The settings. + * @return 0 on success, -1 on error. + */ +int +get_state_pathname(struct settings *settings) +{ + const char *dir = getenv("XGD_RUNTIME_DIR"); + char *display; + char *env; + int rc = -1, saved_errno; + t (display = get_display_string(settings)); + if (!dir || !*dir) dir = "/run"; + t (env = malloc((strlen(dir) + sizeof("/radharc/") + strlen(display)) * sizeof(char))); + stpcpy(stpcpy(stpcpy(env, dir), "/radharc/"), display); + rc = setenv("RADHARC_STATE", env, 1); +fail: + return saved_errno = errno, free(env), free(display), errno = saved_errno, rc; +} + diff --git a/src/state.h b/src/state.h index cd4cef6..bcb271b 100644 --- a/src/state.h +++ b/src/state.h @@ -14,6 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include "settings.h" @@ -63,3 +64,11 @@ enum darkness { */ enum darkness get_darkness(double elevation); +/** + * Set $RADHARC_STATE. + * + * @param settings The settings. + * @return 0 on success, -1 on error. + */ +int get_state_pathname(struct settings *settings); + |