Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit c4ace10a6ecd3e376ea677dd583e9a554101098b 0 parents
Jared Candelaria authored
Showing with 176 additions and 0 deletions.
  1. +12 −0 README
  2. +164 −0 idler.c
12 README
@@ -0,0 +1,12 @@
+This program will patiently wait until you've stopped moving before executing another program.
+
+Its command line options include:
+ -h Prints out how to use the program
+ -t timeout Tell the program how long to wait before considering you idle (in seconds)
+
+The code is pretty readable. I used OpenBSD's sudo(8)'s idea for checking for a valid file. I'm sure
+there are thousands of programs like these but I wanted something small to act like a screen saver launcher.
+I also wanted to write it in Haskell but such is life.
+
+You can have this program run a script that will set your irssi status, then lock the screen, then unset your
+status if you want. Or do anything that relies on idle times, which makes sense.
164 idler.c
@@ -0,0 +1,164 @@
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <X11/Xlib.h>
+#include <X11/extensions/scrnsaver.h>
+
+#include <err.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#define PROG "idler"
+/* Low enough to not overflow and
+ * large enough for anybody. Quote me. */
+#define LIM 4000000
+
+void
+usage(void)
+{
+ errx(1, "usage: %s [-h | -t timeout_seconds] command\n", PROG);
+}
+
+void *
+xmalloc(size_t s)
+{
+ void *p = malloc(s);
+
+ if (!p)
+ err(1, NULL);
+
+ return p;
+}
+
+int
+proper_file(const char *file)
+{
+ struct stat f;
+
+ if (stat(file, &f))
+ return 0;
+
+ return (S_ISREG(f.st_mode)); /* && (f.st_mode & 0000111)); */
+}
+
+/* Taken from OpenBSD's sudo(8). */
+/* Thanks Todd C. Miller! */
+int
+valid_command(const char *file)
+{
+ char *p, *save, *path, command[PATH_MAX];
+ int len, ret;
+
+ if (strchr(file, '/'))
+ return proper_file(file);
+
+ if ((p = getenv("PATH")) == NULL)
+ return 0;
+
+ len = (int)strlen(p);
+ save = path = xmalloc((unsigned)len + 1);
+ strncpy(path, p, (unsigned)len);
+ path[len] = '\0';
+
+ ret = 0;
+ for (p = path; p; path = p + 1) {
+ if ((p = strchr(path, ':')))
+ *p = '\0';
+
+ len = snprintf(command, PATH_MAX, "%s/%s", path, file);
+ if (len <= 0 || len >= sizeof(command))
+ errx(1, "%s: file name too long", file);
+
+ if (proper_file(command)) {
+ ret = 1;
+ break;
+ }
+ }
+ free(save);
+
+ return ret;
+}
+
+void
+launch(char *file, char **command)
+{
+ switch (fork()) {
+ case -1:
+ err(1, NULL);
+ case 0:
+ execvp(file, command);
+ default:
+ wait(NULL);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ XScreenSaverInfo *info;
+ Display *d;
+ Window w;
+
+ Time timeout, saved_timeout;
Jared Candelaria Owner
jcande added a note

The actual type for XScreenSaverInfo.idle is an unsigned long. Having timeout be an int (whose value is well below overflowing and is positive) should be ok. saved_timeout should, however, be an unsigned long.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ char c;
+
+ info = XScreenSaverAllocInfo();
+ d = XOpenDisplay(NULL);
+ w = DefaultRootWindow(d);
+
+ errno = 0;
+ /* Default timeout of 10 minutes. */
+ timeout = 600000;
+
+ while ((c = getopt(argc, argv, "+ht:")) != -1) {
+ switch(c) {
+ case 't':
+ timeout = (int)strtol(optarg, NULL, 10);
+ if (errno || timeout < 0 || timeout > LIM)
+ errx(1, "%s: invalid timeout", optarg);
+ /* Convert timeout into milliseconds. */
+ timeout *= 1000;
+ break;
+ case 'h':
+ default:
+ usage();
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc == 0)
+ errx(1, "must specify a command");
+
+ if (!valid_command(argv[0]))
+ errx(1, "%s: command not found", argv[0]);
+
+ daemon(0, 0);
+
+ saved_timeout = 0;
+ for (;;) {
+ XScreenSaverQueryInfo(d, w, info);
+
+ if (info->idle > timeout && saved_timeout == 0) {
+ saved_timeout = info->idle;
+ launch(argv[0], argv);
+ } else
+ usleep(1000);
+
+ /* Make sure we only run once per idle period. */
+ if (info->idle < saved_timeout)
+ saved_timeout = 0;
+ }
+ /* NOT REACHED */
+
+ XCloseDisplay(d);
+ XFree(info);
+
+ return 0;
+}
Jared Candelaria
Owner

The actual type for XScreenSaverInfo.idle is an unsigned long. Having timeout be an int (whose value is well below overflowing and is positive) should be ok. saved_timeout should, however, be an unsigned long.

Please sign in to comment.
Something went wrong with that request. Please try again.