xss

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

Neale Pickett  ·  2008-12-14

magic.c

  1/* magic -- "Magic" (qix) screen saver hack
  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 <stdlib.h>
 19#include <unistd.h>
 20#include <stdio.h>
 21#include <time.h>
 22#include <X11/Xlib.h>
 23#include "obj.h"
 24
 25#define FPS 17                  /* Frames Per Second */
 26#define TRAILPCT 50             /* Percentage of width to cover */
 27#define MAXDELTAPML 14          /* Maximum velocity per-mil width */
 28#define MINDELTAPML 2           /* Minimum verocity per-mil width */
 29#define MINCOLORDELTA 40        /* Minimum color steps per line */
 30#define MAXCOLORDELTA 150       /* Maximum color steps per line */
 31
 32#define nsec (1000000000 / FPS)
 33#define max(a,b) (((a) > (b)) ? (a) : (b))
 34
 35
 36#define randint(x) (random() % (x))
 37#define rand(l, h) (randint(h-l) + l)
 38
 39#define sum(a, b, v, m)     \
 40  if (b < -v) {             \
 41    v *= -1;                \
 42    a = v - b;              \
 43  } else if (m - b <= v) {  \
 44    v *= -1;                \
 45    a = v + b;              \
 46  } else {                  \
 47    a = v + b;              \
 48  }
 49
 50int
 51main(int argc, char * const argv[])
 52{
 53  Display  *display;
 54  Window    w      = (Window)0;
 55  GC        egc    = (GC)0;
 56  XSegment *lines  = NULL;
 57  char     *winstr = NULL;
 58  int       i;
 59
 60  for (i = 1; i < argc; i += 1) {
 61    if (0 == strcmp(argv[i], "-window-id")) {
 62      /* For compatibility with xscreensaver.  We just ignore it. */
 63    } else if (winstr) {
 64      w = (Window)-1;
 65      break;
 66    } else {
 67      winstr = argv[i];
 68    }
 69  }
 70  if (! winstr) winstr = getenv("XSS_WINDOW");
 71  if (winstr) {
 72    char *end;
 73
 74    if (winstr[0] == '0' && winstr[1] == 'x') {
 75      w = (Window)strtol(winstr + 2, &end, 16);
 76    } else {
 77      w = (Window)strtol(winstr, &end, 10);
 78    }
 79    if ('\0' != *end) {
 80      w = (Window)-1;
 81    }
 82  }
 83  if ((Window)-1 == w) {
 84    (void)fprintf(stderr, "Usage: %s [WINDOW_ID]\n", argv[0]);
 85    return 64;                  /* EX_USAGE */
 86  }
 87
 88  if (! (display = XOpenDisplay(NULL))) {
 89    (void)fprintf(stderr, "cannot open display");
 90    return 69;                  /* EX_UNAVAILABLE */
 91  }
 92
 93  try {
 94    int            screen = DefaultScreen(display);
 95    Window         root   = RootWindow(display, screen);
 96    Colormap       cmap   = DefaultColormap(display, screen);
 97    XSegment       velocity;
 98    int            width, height, nlines;
 99    unsigned short red, green, blue; /* because color.red is reset to the color you got */
100    int            dred, dgreen, dblue;
101    GC             gc;
102    XColor         color;
103
104    if (w) {
105      XWindowAttributes wa;
106
107      XGetWindowAttributes(display, w, &wa);
108      width = wa.width;
109      height = wa.height;
110    } else {
111      XSetWindowAttributes wa;
112
113      zero(wa);
114
115      wa.override_redirect = 1;
116      wa.background_pixel = BlackPixel(display, screen);
117      width = DisplayWidth(display, screen) / 3;
118      height = DisplayHeight(display, screen) / 3;
119      w = XCreateWindow(display, root,
120                        0, 0,
121                        width, height, 0,
122                        CopyFromParent, CopyFromParent, CopyFromParent,
123                        CWBackPixel,
124                        &wa);
125      XMapWindow(display, w);
126    }
127
128    srandom((unsigned int)time(NULL));
129
130    {
131      int u, l;
132
133      u = width * MAXDELTAPML / 1000;
134      l = max(width * MINDELTAPML / 1000, 1);
135      velocity.x1 = (short)rand(l, u);
136      velocity.y1 = (short)rand(l, u);
137      velocity.x2 = (short)rand(l, u);
138      velocity.y2 = (short)rand(l, u);
139    }
140
141    nlines = (width * TRAILPCT) / (max(velocity.y1, velocity.y2) * 100);
142    lines = (XSegment *)calloc(nlines, sizeof(XSegment));
143
144    lines[0].x1 = (short)randint(width);
145    lines[0].y1 = (short)randint(height);
146    lines[0].x2 = (short)randint(width);
147    lines[0].y2 = (short)randint(height);
148
149
150    /* Allocate graphics contexts */
151    {
152      XGCValues      values;
153
154      values.background = values.foreground = BlackPixel(display, screen);
155      egc = XCreateGC(display, w, GCBackground | GCForeground, &values);
156
157      red = color.red = (unsigned short)randint(65536);
158      green = color.green = (unsigned short)randint(65536);
159      blue = color.blue = (unsigned short)randint(65536);
160      dred = rand(MINCOLORDELTA, MAXCOLORDELTA);
161      dgreen = rand(MINCOLORDELTA, MAXCOLORDELTA);
162      dblue = rand(MINCOLORDELTA, MAXCOLORDELTA);
163
164      if (! XAllocColor(display, cmap, &color)) break;
165      values.foreground = color.pixel;
166      gc = XCreateGC(display, w, GCBackground | GCForeground, &values);
167    }
168
169    for (i = 0; ;) {
170      XSegment        segments[2];
171      struct timespec req = {0, nsec};
172      int             j   = (i + 1) % nlines;
173
174      /* Erase old line */
175      (void)memcpy(segments + 0, lines + j, sizeof(XSegment));
176      (void)memcpy(segments + 1, lines + j, sizeof(XSegment));
177      segments[1].x1 = width - segments[0].x1;
178      segments[1].x2 = width - segments[0].x2;
179      (void)XDrawSegments(display, (Drawable)w, egc, segments, 2);
180
181      /* Calculate new line */
182      sum(lines[j].x1, lines[i].x1, velocity.x1, width);
183      sum(lines[j].y1, lines[i].y1, velocity.y1, height);
184      sum(lines[j].x2, lines[i].x2, velocity.x2, width);
185      sum(lines[j].y2, lines[i].y2, velocity.y2, height);
186
187      /* Draw new line */
188      (void)memcpy(segments + 0, lines + j, sizeof(XSegment));
189      (void)memcpy(segments + 1, lines + j, sizeof(XSegment));
190      segments[1].x1 = width - segments[0].x1;
191      segments[1].x2 = width - segments[0].x2;
192      (void)XDrawSegments(display, (Drawable)w, gc, segments, 2);
193
194      /* Change color */
195      {
196        unsigned long pixel = color.pixel;
197
198        sum(color.red = red, red, dred, 65536);
199        sum(color.green = green, green, dgreen, 65536);
200        sum(color.blue = blue, blue, dblue, 65536);
201
202        if (! XAllocColor(display, cmap, &color)) break;
203        if (! XSetForeground(display, gc, color.pixel)) break;
204        if (! XFreeColors(display, cmap, &pixel, 1, 0)) break;
205      }
206      XSync(display, True);
207
208      (void)nanosleep(&req, NULL);
209
210      i = j;
211    }
212
213    (void)XFreeGC(display, gc);
214  }
215
216  if (lines) {
217    free(lines);
218  }
219
220  if (display) {
221    if (egc) {
222      (void)XFreeGC(display, egc);
223    }
224    (void)XCloseDisplay(display);
225  }
226
227  except {
228    (void)fprintf(stderr, "Error: %s\n", exception);
229    return 69;                  /* EX_UNAVAILABLE */
230  }
231  return 0;
232}