diff --git a/Makefile b/Makefile index 5a0894a..05a1031 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ CFLAGS = -Wall -LDLIBS = -lX11 -lXss +LDLIBS = -lX11 -all: xss +all: xss xsswin + +xss: LDLIBS += -lXss diff --git a/README b/README new file mode 100644 index 0000000..046072f --- /dev/null +++ b/README @@ -0,0 +1,53 @@ +== xss == + +xss uses the nearly 20-year-old MIT-SCREEN-SAVER extension to launch a +program when the X server turns on the built-in screen saver. + +xsswin makes a full-screen black window and runs some other program, +passing along the window ID in the environment ($XSS_WINDOW) and +possibly as an argument (XSS_WINDOW gets replaced with the id). + + +Examples +-------- + +Tell the X server to launch the screen saver after 90 seconds idle: + + xset s 90 + + +Run like xautolock: + + xss xlock -mode qix & + + +Run like xscreensaver (no locking): + + xss xsswin /usr/lib/xscreensaver/flurry -window-id XSS_WINDOW + + +Shell script to run an xscreensaver hack and xtrlock at the same time: + + #! /bin/sh + xsswin /usr/lib/xscreensaver/qix -window-id XSS_WINDOW & + pid=$! + xtrlock + kill $pid + + +History +------- + +AIX apparently had something also called `xss` which did almost exactly +what my xss does, but had some command-line options. + +I'm not aware of anything else like `xsswin`. + +I lifted some code from `beforelight` from the X11 distribution, and +from `slock` from [suckless.org](http://suckless.org/). Both have a +BSD/X11-like license. + + +------ + +Neale Pickett diff --git a/xss.c b/xss.c index 4e434b1..5fa434e 100644 --- a/xss.c +++ b/xss.c @@ -15,17 +15,16 @@ * along with this program. If not, see . */ -#include #include #include #include #include -#include #include -#include #include +#include "obj.h" + int child = 0; void @@ -39,30 +38,22 @@ int main(int argc, char *argv[]) { Display *display = NULL; - char *errtxt = "bummer dude."; - Pixmap blank; - int ss_event, ss_error; - Window root; - XEvent event; if (argc < 2) { fprintf(stderr, "Usage: %s PROGRAM [ARGUMENT ...]\n", argv[0]); - exit(1); + return 64; /* EX_USAGE */ } signal(SIGCHLD, sigchld); - do { - display = XOpenDisplay(NULL); - if (! display) { - errtxt = "Cannot open display"; - break; - } - root = DefaultRootWindow(display); + try { + int ss_event, ss_error; + XEvent event; + + if (! (display = XOpenDisplay(NULL))) raise("cannot open display"); if (! XScreenSaverQueryExtension(display, &ss_event, &ss_error)) { - errtxt = "X server does not support MIT-SCREEN-SAVER extension."; - break; + raise("X server does not support MIT-SCREEN-SAVER extension."); } - XScreenSaverSelectInput(display, root, ScreenSaverNotifyMask); + XScreenSaverSelectInput(display, DefaultRootWindow(display), ScreenSaverNotifyMask); while (! XNextEvent(display, &event)) { if (event.type == ss_event) { XScreenSaverNotifyEvent *sevent = (XScreenSaverNotifyEvent *)&event; @@ -79,16 +70,15 @@ main(int argc, char *argv[]) } } } - errtxt = NULL; } while (0); if (display) { - (void)XFreePixmap(display, blank); (void)XCloseDisplay(display); } - if (errtxt) { - fprintf(stderr, "Error: %s\n", errtxt); - return 1; + + except { + fprintf(stderr, "Error: %s\n", exception); + return 69; /* EX_UNAVAILABLE */ } return 0; diff --git a/xsswin.c b/xsswin.c new file mode 100644 index 0000000..66e531a --- /dev/null +++ b/xsswin.c @@ -0,0 +1,104 @@ +/* xsswin -- create a screensaver window + * Copyright (C) 2008 Neale Pickett + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include + +#include "obj.h" + +int +main(int argc, char * const argv[]) +{ + Display *display; + Cursor invisible; + Pixmap pmap; + Window w; + + if (argc < 2) { + fprintf(stderr, "Usage: %s PROGRAM [ARGUMENT ...]\n", argv[0]); + return 64; /* EX_USAGE */ + } + + try { + int screen; + XSetWindowAttributes wa; + Window root; + XColor black; + int child; + + zero(wa); + zero(black); + + if (! (display = XOpenDisplay(NULL))) raise("cannot open display"); + screen = DefaultScreen(display); + root = RootWindow(display, screen); + + wa.override_redirect = 1; + wa.background_pixel = BlackPixel(display, screen); + w = XCreateWindow(display, root, + 0, 0, + DisplayWidth(display, screen), DisplayHeight(display, screen), 0, + CopyFromParent, InputOutput, CopyFromParent, + CWOverrideRedirect | CWBackPixel, + &wa); + XAllocColor(display, DefaultColormap(display, screen), &black); + pmap = XCreateBitmapFromData(display, w, "\0", 1, 1); + invisible = XCreatePixmapCursor(display, pmap, pmap, &black, &black, 0, 0); + XDefineCursor(display, w, invisible); + XMapRaised(display, w); + XSync(display, False); + + child = fork(); + if (0 == child) { + char *nargv[argc + 1]; + char id[50]; + int i; + + (void)snprintf(id, sizeof(id), "0x%lx", (unsigned long)w); + (void)setenv("XSS_WINDOW", id, 1); + for (i = 0; i < argc; i += 1) { + if (0 == strcmp(argv[i], "XSS_WINDOW")) { + nargv[i] = id; + } else { + nargv[i] = argv[i]; + } + } + nargv[argc] = NULL; + (void)execvp(nargv[1], nargv + 1); + perror("exec"); + exit(1); + } + + /* XXX: maybe important to also watch for X events? */ + (void)waitpid(-1, NULL, 0); + } + + if (display) { + (void)XUndefineCursor(display, w); + (void)XFreePixmap(display, pmap); + (void)XCloseDisplay(display); + } + + except { + fprintf(stderr, "Error: %s\n", exception); + return 69; /* EX_UNAVAILABLE */ + } + return 0; +}