1 /* xscreensaver, Copyright (c) 1997-2013 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Wendy, let me explain something to you. Whenever you come in here and
12 * interrupt me, you're BREAKING my CONCENTRATION. You're DISTRACTING me!
13 * And it will then take me time to get back to where I was. You understand?
14 * Now, we're going to make a new rule. When you come in here and you hear
15 * me typing, or whether you DON'T hear me typing, or whatever the FUCK you
16 * hear me doing; when I'm in here, it means that I am working, THAT means
17 * don't come in! Now, do you think you can handle that?
21 #include "screenhack.h"
23 static const char *source = "All work and no play makes Jack a dull boy. ";
24 /* If you're here because you're thinking about making the above string be
25 customizable, then you don't get the joke. You loser. */
30 XWindowAttributes xgwa;
35 int columns, rows; /* characters */
36 int left, right; /* characters */
37 int char_width, line_height; /* pixels */
38 int x, y; /* characters */
40 int hspace; /* pixels */
41 int vspace; /* pixels */
55 xjack_reshape (Display *dpy, Window window, void *closure,
56 unsigned int w, unsigned int h)
58 struct state *st = (struct state *) closure;
59 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
60 st->columns = (st->xgwa.width - st->hspace - st->hspace) / st->char_width;
61 st->rows = (st->xgwa.height - st->vspace - st->vspace) / st->line_height;
65 /* If the window is stupidly small, just truncate. */
66 if (st->rows < 4) st->rows = 4;
67 if (st->columns < 12) st->columns = 12;
69 if (st->y > st->rows) st->y = st->rows-1;
70 if (st->x > st->columns) st->x = st->columns-2;
72 if (st->right > st->columns) st->right = st->columns;
73 if (st->left > st->columns-20) st->left = st->columns-20;
74 if (st->left < 0) st->left = 0;
76 XClearWindow (st->dpy, st->window);
81 xjack_init (Display *dpy, Window window)
83 struct state *st = (struct state *) calloc (1, sizeof(*st));
90 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
91 fontname = get_string_resource (st->dpy, "font", "Font");
93 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
95 if (st->xgwa.width <= 480)
96 fontname = "-*-courier-medium-r-*-*-*-180-*-*-m-*-*-*";
98 st->font = XLoadQueryFont (st->dpy, fontname);
101 st->font = XLoadQueryFont (st->dpy, "-*-*-medium-r-*-*-*-240-*-*-m-*-*-*");
103 st->font = XLoadQueryFont (st->dpy,
104 "-*-courier-medium-r-*-*-*-180-*-*-m-*-*-*");
106 st->font = XLoadQueryFont (st->dpy, "-*-*-*-r-*-*-*-240-*-*-m-*-*-*");
109 fprintf(stderr, "no big fixed-width font like \"%s\"\n", fontname);
113 gcv.font = st->font->fid;
114 gcv.foreground = get_pixel_resource (st->dpy, st->xgwa.colormap,
115 "foreground", "Foreground");
116 gcv.background = get_pixel_resource (st->dpy, st->xgwa.colormap,
117 "background", "Background");
118 st->gc = XCreateGC (st->dpy, st->window,
119 (GCFont | GCForeground | GCBackground), &gcv);
123 ? st->font->per_char['n'-st->font->min_char_or_byte2].rbearing
124 : st->font->min_bounds.rbearing);
125 st->line_height = st->font->ascent + st->font->descent + 1;
127 xjack_reshape (dpy, window, st, st->xgwa.width, st->xgwa.height);
129 st->left = 0xFF & (random() % ((st->columns / 2)+1));
130 st->right = st->left + (0xFF & (random() % (st->columns - st->left)
132 if (st->right < st->left + 10) st->right = st->left + 10;
133 if (st->right > st->columns) st->right = st->columns;
138 if (st->xgwa.width > 200 && st->xgwa.height > 200)
139 st->hspace = st->vspace = 40;
145 xjack_scroll (struct state *st)
148 if (st->subscrolling)
150 int inc = st->line_height / 7;
151 XCopyArea (st->dpy, st->window, st->window, st->gc,
153 st->xgwa.width, st->xgwa.height - inc,
156 /* See? It's OK. He saw it on the television. */
157 XClearArea (st->dpy, st->window,
158 0, st->xgwa.height - inc, st->xgwa.width, inc,
161 st->subscrolling -= inc;
162 if (st->subscrolling <= 0)
163 st->subscrolling = 0;
164 if (st->subscrolling == 0)
166 if (st->scrolling > 0)
170 return st->delay / 1000;
172 else if (st->scrolling)
173 st->subscrolling = st->line_height;
177 else if (st->y >= st->rows-1)
184 xjack_pine (struct state *st)
186 /* See also http://catalog.com/hopkins/unix-haters/login.html */
187 const char *n1 = "NFS server overlook not responding, still trying...";
188 const char *n2 = "NFS server overlook ok.";
189 int prev = st->pining;
192 st->pining = 1 + (random() % 3);
197 XDrawString (st->dpy, st->window, st->gc,
198 (st->x * st->char_width) + st->hspace,
199 ((st->y * st->line_height) + st->vspace
203 if (st->x >= st->columns) st->x = 0, st->y++;
213 XDrawString (st->dpy, st->window, st->gc,
214 (st->x * st->char_width) + st->hspace,
215 ((st->y * st->line_height) + st->vspace
219 if (st->x >= st->columns) st->x = 0, st->y++;
228 xjack_draw (Display *dpy, Window window, void *closure)
230 struct state *st = (struct state *) closure;
231 int this_delay = st->delay;
236 return xjack_scroll (st);
238 return xjack_pine (st);
240 for (s2 = st->s; *s2 && *s2 != ' '; s2++)
243 if (st->break_para ||
245 (st->x + word_length) >= st->right))
255 if (st->mode == 1 || st->mode == 2)
257 /* 1 = left margin goes southwest; 2 = southeast */
258 st->left += (st->mode == 1 ? 1 : -1);
259 if (st->left >= st->right - 10)
261 if ((st->right < (st->columns - 10)) && (random() & 1))
262 st->right += (0xFF & (random() % (st->columns - st->right)));
266 else if (st->left <= 0)
272 else if (st->mode == 3 || st->mode == 4)
274 /* 3 = right margin goes southeast; 4 = southwest */
275 st->right += (st->mode == 3 ? 1 : -1);
276 if (st->right >= st->columns)
278 st->right = st->columns;
281 else if (st->right <= st->left + 10)
285 if (st->y >= st->rows-1) /* bottom of page */
287 # if 0 /* Nah, this looks bad. */
289 /* scroll by 1-5 lines */
290 st->scrolling = (random() % 5 ? 0 : (0xFF & (random() % 5))) + 1;
295 /* but sometimes scroll by a whole page */
296 if (0 == (random() % 100))
297 st->scrolling += st->rows;
302 return xjack_scroll (st);
309 int xshift = 0, yshift = 0;
310 if (0 == random() % 50)
312 xshift = random() % ((st->char_width / 3) + 1); /* mis-strike */
313 yshift = random() % ((st->line_height / 6) + 1);
314 if (0 == (random() % 3))
322 if (0 == (random() % 250)) /* introduce adjascent-key typo */
324 static const char * const typo[] = {
325 "asqw", "ASQW", "bgvhn", "cxdfv", "dserfcx", "ewsdrf",
326 "Jhuikmn", "kjiol,m", "lkop;.,", "mnjk,", "nbhjm", "oiklp09",
327 "pol;(-0", "redft54", "sawedxz", "uyhji87", "wqase32",
328 "yuhgt67", ".,l;/", 0 };
330 while (typo[i] && typo[i][0] != c)
333 c = typo[i][0xFF & ((random() % strlen(typo[i]+1)) + 1)];
337 if (c >= 'a' && c <= 'z' && (st->caps || 0 == (random() % 350)))
340 if (c == 'O' && random() & 1)
345 XDrawString (st->dpy, st->window, st->gc,
346 (st->x * st->char_width) + st->hspace + xshift,
347 ((st->y * st->line_height) + st->vspace + st->font->ascent
350 if (xshift == 0 && yshift == 0 && (0 == (random() & 3000)))
359 if ((tolower(c) != tolower(*st->s))
360 ? (0 == (random() % 10)) /* backup to correct */
361 : (0 == (random() % 400))) /* fail to advance */
366 st->delay += (0xFFFF & (st->delay +
367 (random() % (st->delay * 10))));
374 if (0 == random() % 200)
376 if (random() & 1 && st->s != source)
377 st->s--; /* duplicate character */
379 st->s++; /* skip character */
385 st->caps = (0 == random() % 40); /* capitalize sentence */
387 if (0 == (random() % 10) || /* randomly break paragraph */
389 ((0 == (random() % 10)) || st->sentences > 20)))
391 st->break_para = True;
395 if (random() & 1) /* mode=0 50% of the time */
398 st->mode = (0xFF & (random() % 5));
400 if (0 == (random() % 2)) /* re-pick margins */
402 st->left = 0xFF & (random() % (st->columns / 3));
403 st->right = (st->columns -
404 (0xFF & (random() % (st->columns / 3))));
406 if (0 == random() % 3) /* sometimes be wide */
407 st->right = st->left + ((st->right - st->left) / 2);
410 if (st->right - st->left <= 10) /* introduce sanity */
413 st->right = st->columns;
416 if (st->right - st->left > 50) /* if wide, shrink and move */
418 st->left += (0xFF & (random() % ((st->columns - 50) + 1)));
419 st->right = st->left + (0xFF & ((random() % 40) + 10));
424 st->right - st->left < 25 &&
428 if (st->right > st->columns)
429 st->left -= (st->right - st->columns);
432 if (st->right - st->left < 5)
433 st->left = st->right - 5;
436 if (st->right - st->left < 5)
437 st->right = st->left + 5;
444 if (0 == random() % 3)
445 this_delay += (0xFFFFFF & ((random() % (st->delay * 5)) + 1));
448 this_delay += (0xFFFFFF & ((random() % (st->delay * 15)) + 1));
452 (0 == (random() % 1000)) &&
454 return xjack_pine (st);
460 xjack_event (Display *dpy, Window window, void *closure, XEvent *event)
462 struct state *st = (struct state *) closure;
463 if (event->xany.type == ButtonPress)
473 xjack_free (Display *dpy, Window window, void *closure)
475 struct state *st = (struct state *) closure;
480 static const char *xjack_defaults [] = {
481 ".background: #FFF0B4",
482 ".foreground: #000000",
485 ".font: American Typewriter 24",
487 ".font: -*-courier-medium-r-*-*-*-240-*-*-m-*-*-*",
493 static XrmOptionDescRec xjack_options [] = {
494 { "-delay", ".delay", XrmoptionSepArg, 0 },
495 { "-font", ".font", XrmoptionSepArg, 0 },
499 XSCREENSAVER_MODULE ("XJack", xjack)