xss

Screensaver utilities for the X Windowing System
git clone https://git.woozle.org/neale/xss.git

Neale Pickett  ·  2008-04-21

xss.c

  1/* xss -- xautolock replacement using MIT-SCREEN-SAVER (it doesn't poll)
  2 * Copyright (C) 2008  Neale Pickett <neale@woozle.org>
  3 *
  4 * This program is free software: you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation, either version 3 of the License, or (at
  7 * your option) any later version.
  8 *
  9 * This program is distributed in the hope that it will be useful, but
 10 * WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12 * General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 */
 17
 18#include <sys/wait.h>
 19#include <unistd.h>
 20#include <signal.h>
 21#include <stdio.h>
 22
 23#include <X11/Xlib.h>
 24#include <X11/Xatom.h>
 25#include <X11/extensions/scrnsaver.h>
 26
 27#include "obj.h"
 28
 29int child = 0;
 30
 31void
 32sigchld(int signum)
 33{
 34  (void)waitpid(-1, NULL, WNOHANG);
 35  child = 0;
 36}
 37
 38int
 39main(int argc, char *argv[])
 40{
 41  Display *display   = NULL;
 42  int      screen;
 43  int      bigwindow = 0;
 44
 45  if ((argc > 1) && (0 == (strcmp(argv[1], "-w")))) {
 46    bigwindow = 1;
 47  }
 48  if (argc - bigwindow < 2) {
 49    (void)fprintf(stderr, "Usage: %s [-w] PROGRAM [ARGUMENT ...]\n", argv[0]);
 50    (void)fprintf(stderr, "\n");
 51    (void)fprintf(stderr, "-w    Map X server window, export $XSS_WINDOW.  This window\n");
 52    (void)fprintf(stderr, "      will be unmapped by any keypress or mouse movement.\n");
 53    return 64;                  /* EX_USAGE */
 54  }
 55  signal(SIGCHLD, sigchld);
 56
 57  try {
 58    int     ss_event, ss_error;
 59    XEvent  event;
 60    Window  root;
 61    char   *nargv[argc+1];
 62    char    id[50];
 63    int     i;
 64
 65    if (! (display = XOpenDisplay(NULL))) raise("cannot open display");
 66    screen = DefaultScreen(display);
 67    if (! XScreenSaverQueryExtension(display, &ss_event, &ss_error)) {
 68      raise("X server does not support MIT-SCREEN-SAVER extension.");
 69    }
 70    if (! XScreenSaverRegister(display, screen, (XID)getpid(), XA_INTEGER)) {
 71      raise("cannot register screen saver, is another one already running?");
 72    }
 73    root = RootWindow(display, screen);
 74    XScreenSaverSelectInput(display, root, ScreenSaverNotifyMask);
 75
 76    {
 77      XSetWindowAttributes wa;
 78      XScreenSaverInfo     info;
 79      Pixmap               pmap;
 80      XColor               black;
 81
 82      pmap = XCreateBitmapFromData(display, root, "\0", 1, 1);
 83      black.pixel = BlackPixel(display, screen);
 84      wa.cursor = XCreatePixmapCursor(display, pmap, pmap, &black, &black, 0, 0);
 85      wa.background_pixel = BlackPixel(display, screen);
 86      if (! (XFreePixmap(display, pmap))) break;
 87      XScreenSaverSetAttributes(display, root,
 88                                bigwindow?0:-1, bigwindow?0:-1,
 89                                bigwindow?DisplayWidth(display, screen):1,
 90                                bigwindow?DisplayHeight(display, screen):1,
 91                                0,
 92                                CopyFromParent, CopyFromParent,
 93                                CopyFromParent,
 94                                CWBackPixel | CWCursor,
 95                                &wa);
 96      XScreenSaverQueryInfo(display, (Drawable)root, &info);
 97      (void)snprintf(id, sizeof(id), "0x%lx", (unsigned long)info.window);
 98      (void)setenv("XSS_WINDOW", id, 1);
 99    }
100
101    for (i = 0; i < argc; i += 1) {
102      if (bigwindow && (0 == strcmp(argv[i], "XSS_WINDOW"))) {
103        nargv[i] = id;
104      } else {
105        nargv[i] = argv[i];
106      }
107    }
108    nargv[argc] = NULL;
109
110    while (! XNextEvent(display, &event)) {
111      if (ss_event == event.type) {
112        XScreenSaverNotifyEvent *sevent = (XScreenSaverNotifyEvent *)&event;
113
114        if (ScreenSaverOn == sevent->state) {
115          if (! child) {
116            child = fork();
117            if (0 == child) {
118              (void)execvp(nargv[1+bigwindow], nargv+1+bigwindow);
119              perror("exec");
120              exit(1);
121            }
122          } else {
123          }
124        }
125      }
126    }
127  } while (0);
128
129  if (display) {
130    (void)XScreenSaverUnregister(display, screen);
131    (void)XCloseDisplay(display);
132  }
133
134  except {
135    (void)fprintf(stderr, "Error: %s\n", exception);
136    return 69;                  /* EX_UNAVAILABLE */
137  }
138
139  return 0;
140}