aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@member.fsf.org>2016-01-04 03:56:13 +0100
committerMattias Andrée <maandree@member.fsf.org>2016-01-04 03:56:13 +0100
commit929fddac2b95656a962fd3e7c53dbd1907f914d6 (patch)
treec0f2963c1675abf43e1507cbb039060aeafb7d44
parenthaiku (diff)
downloadradharc-929fddac2b95656a962fd3e7c53dbd1907f914d6.tar.gz
radharc-929fddac2b95656a962fd3e7c53dbd1907f914d6.tar.bz2
radharc-929fddac2b95656a962fd3e7c53dbd1907f914d6.tar.xz
automatic selection of RADHARC_STATE
Signed-off-by: Mattias Andrée <maandree@member.fsf.org>
-rw-r--r--README12
-rw-r--r--src/haiku.c2
-rw-r--r--src/settings.c3
-rw-r--r--src/state.c141
-rw-r--r--src/state.h9
5 files changed, 161 insertions, 6 deletions
diff --git a/README b/README
index 4260b90..be663a0 100644
--- a/README
+++ b/README
@@ -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);
+