http://ftp.x.org/contrib/applications/xscreensaver-3.21.tar.gz
[xscreensaver] / hacks / xsublim.c
1 /*****************************************************************************
2  *                                                                           *
3  * xsublim -- Submit.  Conform.  Obey.                                       *
4  *                                                                           *
5  * Copyright (c) 1999 Greg Knauss (greg@eod.com)                             *
6  *                                                                           *
7  * Thanks to Jamie Zawinski, whose suggestions and advice made what was a    *
8  * boring little program into a less boring (and a _lot_ less little)        *
9  * program.                                                                  *
10  *                                                                           *
11  * Permission to use, copy, modify, distribute, and sell this software and   *
12  * its documentation for any purpose is hereby granted without fee, provided *
13  * that the above copyright notice appear in all copies and that both that   *
14  * copyright notice and this permission notice appear in supporting          *
15  * documentation.  No representations are made about the suitability of this *
16  * software for any purpose.  It is provided "as is" without express or      *
17  * implied warranty.                                                         *
18  *                                                                           *
19  * Stare into the subliminal for as long as you can...                       *
20  *                                                                           *
21  *****************************************************************************/
22
23
24 /* Warnings *******************************************************************
25
26         Please don't end this process with a SIGKILL.  If it's got the X server
27         grabbed when you do, you'll never get it back and it won't be my fault.
28 */
29
30
31 /* Changelog ******************************************************************
32
33         1.0.1  19990716  Assume that XGetImage()/XDestroyImage() don't leak,
34                           which they apparently don't.  I have no idea how I
35                           convinced myself that they did.  Huh.  (greg@eod.com)
36         1.0.0  19990716  Initial release
37 */
38
39
40 /* Arguments ******************************************************************
41
42         -font font           Font to use
43         -delayShow ms        Microsecs for display of each word
44         -delayWord ms        Microsecs for blank between words
45         -delayPhraseMin ms   Microsecs for min blank between phrases
46         -delayPhraseMax ms   Microsecs for max blank between phrases
47         -random              Show phrases in random order (Default)
48         -no-random           Show phrases in listed order
49         -screensaver         Wait for an active screensaver (Default)
50         -no-screensaver      Draw over active windows       
51         -outline             Draw a contrasting outline around words (Default)
52         -no-outline          Draw words without an outline
53         -center              Draw words in the center of the screen (Default)
54         -no-center           Draw words randomly around the screen
55 */
56
57
58 /* Defines *******************************************************************/
59 #define XSUBLIM_NAME               "XSublim"
60 #define XSUBLIM_TEXT_COUNT         1000
61 #define XSUBLIM_TEXT_LENGTH        128
62 #define XSUBLIM_TEXT_OUTLINE       1
63 #define XSUBLIM_ARG_DELAYSHOW      "delayShow"
64 #define XSUBLIM_ARG_DELAYWORD      "delayWord"
65 #define XSUBLIM_ARG_DELAYPHRASEMIN "delayPhraseMin"
66 #define XSUBLIM_ARG_DELAYPHRASEMAX "delayPhraseMax"
67 #define XSUBLIM_ARG_RANDOM         "random"
68 #define XSUBLIM_ARG_FILE           "file"
69 #define XSUBLIM_ARG_SCREENSAVER    "screensaver"
70 #define XSUBLIM_ARG_OUTLINE        "outline"
71 #define XSUBLIM_ARG_CENTER         "center"
72 #define XSUBLIM_ARG_FONT           "font"
73 #define XSUBLIM_ARG_PHRASES        "phrases"
74 #ifndef TRUE
75 #define FALSE 0
76 #define TRUE  1
77 #endif
78
79
80 /* Includes ******************************************************************/
81 #include <stdio.h>
82 #include <stdlib.h>
83 #include <string.h>
84 #include <signal.h>
85 #include <X11/Intrinsic.h>
86 #include <X11/IntrinsicP.h>
87 #include <X11/CoreP.h>
88 #include <X11/Shell.h>
89 #include <X11/StringDefs.h>
90 #include <X11/Xutil.h>
91 #include <X11/keysym.h>
92 #include <X11/Xatom.h>
93 #include <X11/Xlib.h>
94 #include <X11/Xos.h>
95 #include <X11/Xproto.h>
96 #if defined(__sgi)
97 #include <X11/SGIScheme.h>
98 #endif
99
100 #include "yarandom.h"
101 #include "usleep.h"
102 #include "resources.h"
103
104
105 /* Globals *******************************************************************/
106 char*        progname;
107 XtAppContext app;
108 XrmDatabase  db;
109 char*        progclass = XSUBLIM_NAME;
110 char*        defaults[] =
111 {
112         ".background:                     #000000",
113         ".foreground:                     #FFFFFF",
114         "*" XSUBLIM_ARG_PHRASES ":"
115          "Submit.\\n"
116          "Conform.\\n"
117          "Obey.\\n"
118          "OBEY. OBEY. OBEY.\\n"
119          "Consume.\\n"
120          "Be silent.\\n"
121          "Fear.\\n"
122          "Waste.\\n"
123          "Money.\\n"
124          "Watch TV.\\n"
125          "Hate yourself.\\n"
126          "Buy needlessly.\\n"
127          "Despair quietly.\\n"
128          "God hates you.\\n"
129          "You are being watched.\\n"
130          "You will be punished.\\n"
131          "You serve no purpose.\\n"
132          "Your contributions are ignored.\\n"
133          "They are laughing at you.\\n"
134          "They lied to you.\\n"
135          "They read your mail.\\n"
136          "They know.\\n"
137          "Surrender.\\n"
138          "You will fail.\\n"
139          "Never question.\\n"
140          "You are a prisoner.\\n"
141          "You are helpless.\\n"
142          "You are diseased.\\n"
143          "Fear the unknown.\\n"
144          "Happiness follows obedience.\\n"
145          "Ignorance is strength.\\n"
146          "War is peace.\\n"
147          "Freedom is slavery.\\n"
148          "Abandon all hope.\\n"
149          "You will be assimilated.\\n"
150          "Resistance is futile.\\n"
151          "Resistance is useless.\\n"
152          "Life is pain.\\n"
153          "No escape.\\n"
154          "What's that smell?\\n"
155          "All praise the company.\\n"
156          "Fnord.\\n",
157         "*" XSUBLIM_ARG_FONT ":           -*-utopia-*-r-*-*-*-600-*-*-p-*-*-*",
158         "*" XSUBLIM_ARG_DELAYSHOW ":      40000",
159         "*" XSUBLIM_ARG_DELAYWORD ":      100000",
160         "*" XSUBLIM_ARG_DELAYPHRASEMIN ": 5000000",
161         "*" XSUBLIM_ARG_DELAYPHRASEMAX ": 20000000",
162         "*" XSUBLIM_ARG_RANDOM ":         true",
163         "*" XSUBLIM_ARG_SCREENSAVER ":    true",
164         "*" XSUBLIM_ARG_OUTLINE":         true",
165         "*" XSUBLIM_ARG_CENTER":          true",
166         NULL
167 };
168 XrmOptionDescRec options[] =
169 {
170         {"-" XSUBLIM_ARG_FONT,          "." XSUBLIM_ARG_FONT,
171          XrmoptionSepArg,0},
172         {"-" XSUBLIM_ARG_DELAYSHOW,     "." XSUBLIM_ARG_DELAYSHOW,
173          XrmoptionSepArg,0},
174         {"-" XSUBLIM_ARG_DELAYWORD,     "." XSUBLIM_ARG_DELAYWORD,
175          XrmoptionSepArg,0},
176         {"-" XSUBLIM_ARG_DELAYPHRASEMIN,"." XSUBLIM_ARG_DELAYPHRASEMIN,
177          XrmoptionSepArg,0},
178         {"-" XSUBLIM_ARG_DELAYPHRASEMAX,"." XSUBLIM_ARG_DELAYPHRASEMAX,
179          XrmoptionSepArg,0},
180         {"-" XSUBLIM_ARG_RANDOM,        "." XSUBLIM_ARG_RANDOM,
181          XrmoptionNoArg,"true"},
182         {"-no-" XSUBLIM_ARG_RANDOM,     "." XSUBLIM_ARG_RANDOM,
183          XrmoptionNoArg,"false"},
184         {"-" XSUBLIM_ARG_FILE,          "." XSUBLIM_ARG_FILE,
185          XrmoptionSepArg,0 },
186         {"-" XSUBLIM_ARG_SCREENSAVER,   "." XSUBLIM_ARG_SCREENSAVER,
187          XrmoptionNoArg,"true"},
188         {"-no-" XSUBLIM_ARG_SCREENSAVER,"." XSUBLIM_ARG_SCREENSAVER,
189          XrmoptionNoArg,"false"},
190         {"-" XSUBLIM_ARG_OUTLINE,       "." XSUBLIM_ARG_OUTLINE,
191          XrmoptionNoArg,"true"},
192         {"-no-" XSUBLIM_ARG_OUTLINE,    "." XSUBLIM_ARG_OUTLINE,
193          XrmoptionNoArg,"false"},
194         {"-" XSUBLIM_ARG_CENTER,        "." XSUBLIM_ARG_CENTER,
195          XrmoptionNoArg,"true"},
196         {"-no-" XSUBLIM_ARG_CENTER,     "." XSUBLIM_ARG_CENTER,
197          XrmoptionNoArg,"false"},
198         {NULL,                          NULL,
199          0,              0 }
200 };
201 static int Xsublim_Sig_Last;
202
203
204 /* Functions *****************************************************************/
205
206 /* Defer signals to protect the server grab ================================ */
207 void xsublim_Sig_Catch(int sig_Number)
208 {
209         /* BSD needs this reset each time, and it shouldn't hurt anything
210            else */
211         signal(sig_Number,xsublim_Sig_Catch);
212         Xsublim_Sig_Last = sig_Number;
213 }
214
215 /* Get the screensaver's window ============================================ */
216 static XErrorHandler Xsublim_Ss_Handler = NULL;
217 static int           Xsublim_Ss_Status;
218
219 /* This was all basically swiped from driver/remote.c and util/vroot.h */
220 static int xsublim_Ss_Handler(Display* handle_Display,
221             XErrorEvent* handle_Error)
222 {
223         if (handle_Error->error_code == BadWindow)
224         {
225                 Xsublim_Ss_Status = BadWindow;
226                 return 0;
227         }
228         if (Xsublim_Ss_Handler == NULL)
229         {
230                 fprintf(stderr,"%x: ",progname);
231                 abort();
232         }
233         return (*Xsublim_Ss_Handler)(handle_Display,handle_Error);
234 }
235 static Window xsublim_Ss_GetWindow(Display* ss_Display)
236 {
237         Window        win_Root;
238         Window        win_RootReturn;
239         Window        win_Parent;
240         Window*       win_Child;
241         Window        win_Win;
242         int           child_Count;
243         int           child_Index;
244         Atom          prop_Type;
245         int           prop_Format;
246         unsigned long prop_Count;
247         unsigned long prop_Bytes;
248         char*         prop_Value;
249         int           prop_Status;
250         static Atom   XA_SCREENSAVER_VERSION = -1;
251         static Atom   __SWM_VROOT;
252
253         /* Assume bad things */
254         win_Win = 0;
255         win_Child = NULL;
256
257         /* Find the atoms */
258         if (XA_SCREENSAVER_VERSION == -1)
259         {
260                 XA_SCREENSAVER_VERSION = XInternAtom(ss_Display,
261                  "_SCREENSAVER_VERSION",FALSE);
262                 __SWM_VROOT = XInternAtom(ss_Display,"__SWM_VROOT",FALSE);
263         }
264
265         /* Find a screensaver window */
266         win_Root = RootWindowOfScreen(DefaultScreenOfDisplay(ss_Display));
267         if (XQueryTree(ss_Display,win_Root,&win_RootReturn,&win_Parent,
268          &win_Child,&child_Count) != FALSE)
269         {
270                 if (
271                  (win_Root == win_RootReturn) &&
272                  (win_Parent == 0) &&
273                  (win_Child != NULL) &&
274                  (child_Count > 0))
275                 {
276                         for (child_Index = 0;child_Index < child_Count;
277                          child_Index++)
278                         {
279                                 XSync(ss_Display,FALSE);
280                                 Xsublim_Ss_Status = 0;
281                                 Xsublim_Ss_Handler =
282                                  XSetErrorHandler(xsublim_Ss_Handler);
283                                 prop_Value = NULL;
284                                 prop_Status = XGetWindowProperty(ss_Display,
285                                  win_Child[child_Index],XA_SCREENSAVER_VERSION,
286                                  0,200,FALSE,XA_STRING,&prop_Type,&prop_Format,
287                                  &prop_Count,&prop_Bytes,
288                                  (unsigned char**)&prop_Value);
289                                 XSync(ss_Display,FALSE);
290                                 XSetErrorHandler(Xsublim_Ss_Handler);
291                                 if (prop_Value != NULL)
292                                 {
293                                         XFree(prop_Value);
294                                 }
295                                 if (Xsublim_Ss_Status == BadWindow)
296                                 {
297                                         prop_Status = BadWindow;
298                                 }
299                                 if ((prop_Status == Success) &&
300                                  (prop_Type != None))
301                                 {
302                                         /* See if it's a virtual root */
303                                         prop_Value = NULL;
304                                         prop_Status =
305                                          XGetWindowProperty(ss_Display,
306                                          win_Child[child_Index],__SWM_VROOT,0,
307                                          1,FALSE,XA_WINDOW,&prop_Type,
308                                          &prop_Format,&prop_Count,&prop_Bytes,
309                                          (unsigned char**)&prop_Value);
310                                         if (prop_Value != NULL)
311                                         {
312                                                 XFree(prop_Value);
313                                         }
314                                         if ((prop_Status == Success) &&
315                                          (prop_Type != None))
316                                         {
317                                                 win_Win =
318                                                  win_Child[child_Index];
319                                         }
320                                 }
321                         }
322                 }
323         }
324         if (win_Child != NULL)
325         {
326                 XFree(win_Child);
327         }
328         return win_Win;
329 }
330
331 /* Main ==================================================================== */
332 static XErrorHandler Xsublim_Sh_Handler = NULL;
333 static int           Xsublim_Sh_Status = 0;
334
335 static int xsublim_Sh_Handler(Display* handle_Display,
336             XErrorEvent* handle_Error)
337 {
338         if (handle_Error->error_code == BadMatch)
339         {
340                 Xsublim_Sh_Status = BadMatch;
341                 return 0;
342         }
343         if (Xsublim_Sh_Handler == NULL)
344         {
345                 fprintf(stderr,"%s: ",progname);
346                 abort();
347         }
348         return (*Xsublim_Sh_Handler)(handle_Display,handle_Error);
349 }
350 int main(int argc,char* argv[])
351 {
352         int               sig_Number;
353         int               sig_Signal[] =
354         {
355                 SIGHUP,
356                 SIGINT,
357                 SIGQUIT,
358                 SIGILL,
359                 SIGTRAP,
360                 SIGIOT,
361                 SIGABRT,
362 #if defined(SIGEMT)
363                 SIGEMT,
364 #endif
365                 SIGFPE,
366                 SIGBUS,
367                 SIGSEGV,
368 #if defined(SIGSYS)
369                 SIGSYS,
370 #endif
371                 SIGTERM,
372 #if defined(SIGXCPU)
373                 SIGXCPU,
374 #endif
375 #if defined(SIGXFSZ)
376                 SIGXFSZ,
377 #endif
378 #if defined(SIGDANGER)
379                 SIGDANGER,
380 #endif
381                 -1
382         };
383         Widget            app_App;
384         Display*          disp_Display;
385         Window            win_Root;
386         XWindowAttributes attr_Win;
387         XGCValues         gc_ValFore;
388         XGCValues         gc_ValBack;
389         GC                gc_GcFore;
390         GC                gc_GcBack;
391         XFontStruct*      font_Font;
392         char*             font_List[] =
393         {
394                 "-*-character-*-r-*-*-*-600-*-*-p-*-*-*",
395                 "-*-helvetica-*-r-*-*-*-600-*-*-p-*-*-*",
396                 "-*-lucida-*-r-*-*-*-600-*-*-p-*-*-*",
397                 "-*-times-*-r-*-*-*-600-*-*-p-*-*-*",
398                 "-*-*-*-r-*-sans-*-600-*-*-p-*-*-*",
399                 "-*-*-*-r-*-*-*-600-*-*-m-*-*-*",
400
401                 "-*-helvetica-*-r-*-*-*-240-*-*-p-*-*-*",
402                 "-*-lucida-*-r-*-*-*-240-*-*-p-*-*-*",
403                 "-*-times-*-r-*-*-*-240-*-*-p-*-*-*",
404                 "-*-*-*-r-*-sans-*-240-*-*-p-*-*-*",
405                 "-*-*-*-r-*-*-*-240-*-*-m-*-*-*",
406                 "fixed",
407                 NULL
408         };
409         int               font_Index;
410         int               text_Length;
411         int               text_X;
412         int               text_Y;
413         int               text_Width;
414         int               text_Height;
415         char*             text_List[XSUBLIM_TEXT_COUNT];
416         int               text_Used[XSUBLIM_TEXT_COUNT];
417         char              text_Text[XSUBLIM_TEXT_LENGTH+1];
418         char*             text_Phrase;
419         char*             text_Word;
420         int               text_Index;
421         int               text_Item;
422         int               text_Count;
423         struct
424         {
425                 int outline_X;
426                 int outline_Y;
427         }                 text_Outline[] =
428         {
429                 { -1,-1 },
430                 {  1,-1 },
431                 { -1, 1 },
432                 {  1, 1 },
433                 {  0, 0 }
434         };
435         int               text_OutlineIndex;
436         XImage*           image_Image = NULL;
437         int               image_X = 0;
438         int               image_Y = 0;
439         int               image_Width = 0;
440         int               image_Height = 0;
441         int               arg_Count;
442         int               arg_FlagCenter;
443         int               arg_FlagOutline;
444         int               arg_FlagScreensaver;
445         int               arg_FlagRandom;
446         int               arg_DelayShow;
447         int               arg_DelayWord;
448         int               arg_DelayPhraseMin;
449         int               arg_DelayPhraseMax;
450         char*             arg_Text;
451
452         /* Set-up ---------------------------------------------------------- */
453
454         /* Catch signals */
455         Xsublim_Sig_Last = -1;
456         for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
457         {
458                 signal(sig_Number,xsublim_Sig_Catch);
459         }
460
461         /* Randomize -- only need to do this here because this program
462            doesn't use the `screenhack.h' or `lockmore.h' APIs. */
463 # undef ya_rand_init
464         ya_rand_init ((int) time ((time_t *) 0));
465
466         /* Handle all the X nonsense */
467 #if defined(__sgi)
468         SgiUseSchemes("none");
469 #endif
470         for (arg_Count = 0;options[arg_Count].option != NULL;arg_Count++)
471         {
472                 ;
473         }
474         app_App = XtAppInitialize(&app,progclass,options,arg_Count,&argc,argv,
475          defaults,0,0);
476
477         /* jwz */
478         if (argc > 1)
479           {
480             int x = 18;
481             int end = 78;
482             int i;
483             int count = (sizeof(options)/sizeof(*options))-1;
484             fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
485             fprintf (stderr, "Options include: ");
486             for (i = 0; i < count; i++)
487               {
488                 char *sw = options [i].option;
489                 Bool argp = (options [i].argKind == XrmoptionSepArg);
490                 int size = strlen (sw) + (argp ? 6 : 0) + 2;
491                 if (x + size >= end)
492                   {
493                     fprintf (stderr, "\n\t\t ");
494                     x = 18;
495                   }
496                 x += size;
497                 fprintf (stderr, "%s", sw);
498                 if (argp) fprintf (stderr, " <arg>");
499                 if (i != count-1) fprintf (stderr, ", ");
500               }
501             fprintf (stderr, ".\n");
502             exit (-1);
503           }
504
505         disp_Display = XtDisplay(app_App);
506         db = XtDatabase(disp_Display);
507         XtGetApplicationNameAndClass(disp_Display,&progname,&progclass);
508         win_Root = RootWindowOfScreen(XtScreen(app_App));
509         XtDestroyWidget(app_App);
510
511         /* Get the arguments */
512         arg_FlagCenter = get_boolean_resource(XSUBLIM_ARG_CENTER,"Boolean");
513         arg_FlagOutline = get_boolean_resource(XSUBLIM_ARG_OUTLINE,"Boolean");
514         arg_FlagScreensaver = get_boolean_resource(XSUBLIM_ARG_SCREENSAVER,
515          "Boolean");
516         arg_FlagRandom = get_boolean_resource(XSUBLIM_ARG_RANDOM,"Boolean");
517         arg_DelayShow = get_integer_resource(XSUBLIM_ARG_DELAYSHOW,"Integer");
518         arg_DelayWord = get_integer_resource(XSUBLIM_ARG_DELAYWORD,"Integer");
519         arg_DelayPhraseMin = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMIN,
520          "Integer");
521         arg_DelayPhraseMax = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMAX,
522          "Integer");
523         if (arg_DelayPhraseMax < arg_DelayPhraseMin)
524         {
525                 arg_DelayPhraseMax = arg_DelayPhraseMin;
526         }
527
528         /* Get the phrases */
529         text_Index = 0;
530         text_Item = 0;
531         text_Count = 0;
532         memset(text_Used,0,sizeof(text_Used));
533         arg_Text = get_string_resource(XSUBLIM_ARG_PHRASES,"Phrases");
534         if (arg_Text != NULL)
535         {
536                 arg_Text = strdup(arg_Text);
537                 while (((text_Phrase = strtok(arg_Text,"\n")) != NULL) &&
538                  (text_Count < XSUBLIM_TEXT_COUNT))
539                 {
540                         arg_Text = NULL;
541                         text_List[text_Count] = text_Phrase;
542                         text_Count++;
543                 }
544         }
545         text_List[text_Count] = NULL;
546         if (text_Count == 0)
547         {
548                 fprintf(stderr,"%s: No text to display\n",progname);
549                 exit(-1);
550         }
551
552         /* Load the font */
553         font_Font = XLoadQueryFont(disp_Display,
554          get_string_resource(XSUBLIM_ARG_FONT,"Font"));
555         font_Index = 0;
556         while ((font_Font == NULL) && (font_List[font_Index] != NULL))
557         {
558                 font_Font = XLoadQueryFont(disp_Display,font_List[font_Index]);
559                 font_Index++;
560         }
561         if (font_Font == NULL)
562         {
563                 fprintf(stderr,"%s: Couldn't load a font\n",progname);
564                 exit(-1);
565         }
566
567         /* Create the GCs */
568         XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
569         gc_ValFore.font = font_Font->fid;
570         gc_ValFore.foreground = get_pixel_resource("foreground","Foreground",
571          disp_Display,attr_Win.colormap);
572         gc_ValFore.background = get_pixel_resource("background","Background",
573          disp_Display,attr_Win.colormap);
574         gc_ValFore.subwindow_mode = IncludeInferiors;
575         gc_GcFore = XCreateGC(disp_Display,win_Root,
576          (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValFore);
577         gc_ValBack.font = font_Font->fid;
578         gc_ValBack.foreground = get_pixel_resource("background","Background",
579          disp_Display,attr_Win.colormap);
580         gc_ValBack.background = get_pixel_resource("foreground","Foreground",
581          disp_Display,attr_Win.colormap);
582         gc_ValBack.subwindow_mode = IncludeInferiors;
583         gc_GcBack = XCreateGC(disp_Display,win_Root,
584          (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValBack);
585
586         /* Loop ------------------------------------------------------------ */
587         while (Xsublim_Sig_Last == -1)
588         {
589                 /* Once-per-phrase stuff ----------------------------------- */
590
591                 /* If we're waiting for a screensaver... */
592                 if (arg_FlagScreensaver != FALSE)
593                 {
594                         /* Find the screensaver's window */
595                         win_Root = xsublim_Ss_GetWindow(disp_Display);
596                         if (win_Root == 0)
597                         {
598                                 usleep(30000000);
599                                 continue;
600                         }
601                 }
602
603                 /* Pick the next phrase */
604                 if (arg_FlagRandom != FALSE)
605                 {
606                         text_Item = random()%text_Count;
607                         text_Index = 0;
608                 }
609                 while (text_Used[text_Item] != FALSE)
610                 {
611                         text_Index++;
612                         text_Item++;
613                         if (text_Index == text_Count)
614                         {
615                                 text_Index = 0;
616                                 memset(text_Used,0,sizeof(text_Used));
617                         }
618                         if (text_List[text_Item] == NULL)
619                         {
620                                 text_Item = 0;
621                         }
622                 }
623                 text_Used[text_Item] = TRUE;
624                 strncpy(text_Text,text_List[text_Item],
625                  XSUBLIM_TEXT_LENGTH);
626                 text_Phrase = text_Text;
627
628                 /* Run through the phrase */
629                 while (((text_Word = strtok(text_Phrase," \t")) != NULL) &&
630                  (Xsublim_Sig_Last == -1))
631                 {
632                         text_Phrase = NULL;
633
634                         /* Once-per-word stuff ----------------------------- */
635
636                         /* Find the text's position */
637                         XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
638                         text_Length = strlen(text_Word);
639                         text_Width = XTextWidth(font_Font,text_Word,
640                          text_Length)+XSUBLIM_TEXT_OUTLINE*2;
641                         text_Height = font_Font->ascent+font_Font->descent+1+
642                          XSUBLIM_TEXT_OUTLINE*2;
643                         if (arg_FlagCenter == FALSE)
644                         {
645                                 text_X = random()%(attr_Win.width-text_Width);
646                                 text_Y = random()%(attr_Win.height-
647                                  text_Height);
648                         }
649                         else
650                         {
651                                 text_X = (attr_Win.width/2)-(text_Width/2);
652                                 text_Y = (attr_Win.height/2)-(text_Height/2);
653                         }
654
655                         /* Find the image's position (and pad it out slightly,
656                            otherwise bits of letter get left behind -- are
657                            there boundry issues I don't know about?) */
658                         image_X = text_X-16;
659                         image_Y = text_Y;
660                         image_Width = text_Width+32;
661                         image_Height = text_Height;
662                         if (image_X < 0)
663                         {
664                                 image_X = 0;
665                         }
666                         if (image_Y < 0)
667                         {
668                                 image_Y = 0;
669                         }
670                         if (image_X+image_Width > attr_Win.width)
671                         {
672                                 image_Width = attr_Win.width-image_X;
673                         }
674                         if (image_Y+image_Height > attr_Win.height)
675                         {
676                                 image_Height = attr_Win.height-image_Y;
677                         }
678
679                         /* Influence people for our own ends --------------- */
680
681                         /* Grab the server -- we can't let anybody draw over
682                            us */
683                         XSync(disp_Display,FALSE);
684                         XGrabServer(disp_Display);
685                         XSync(disp_Display,FALSE);
686
687                         /* Set up an error handler that ignores BadMatches --
688                            since the screensaver can take its window away at
689                            any time, any call that uses it might choke */
690                         Xsublim_Sh_Status = 0;
691                         Xsublim_Sh_Handler =
692                          XSetErrorHandler(xsublim_Sh_Handler);
693
694                         /* Save the current background */
695                         image_Image = XGetImage(disp_Display,win_Root,image_X,
696                          image_Y,image_Width,image_Height,~0L,ZPixmap);
697
698                         /* If we've successfully saved the background... */
699                         if (image_Image != NULL)
700                         {
701                                 if (Xsublim_Sh_Status == 0)
702                                 {
703                                         /* Draw the outline */
704                                         if (arg_FlagOutline != FALSE)
705                                         {
706                                                 for (text_OutlineIndex = 0;
707                                                  text_Outline[
708                                                  text_OutlineIndex].outline_X
709                                                  != 0;text_OutlineIndex++)
710                                                 {
711                                                         /* Y'know, eight
712                                                            character tabs and
713                                                            descriptive variable
714                                                            names become
715                                                            annoying at some
716                                                            point... */
717                                                         XDrawString(
718                                                          disp_Display,
719                                                          win_Root,gc_GcBack,
720                                                          text_X+text_Outline[
721                                                          text_OutlineIndex].
722                                                          outline_X*
723                                                          XSUBLIM_TEXT_OUTLINE,
724                                                          text_Y+
725                                                          (font_Font->ascent)+
726                                                          text_Outline[
727                                                          text_OutlineIndex].
728                                                          outline_Y*
729                                                          XSUBLIM_TEXT_OUTLINE,
730                                                          text_Word,
731                                                          text_Length);
732                                                 }
733                                         }
734
735                                         /* Draw the word */
736                                         XDrawString(disp_Display,win_Root,
737                                          gc_GcFore,text_X,
738                                          text_Y+(font_Font->ascent),text_Word,
739                                          text_Length);
740                                 }
741                                 if (Xsublim_Sh_Status == 0)
742                                 {
743                                         /* Wait a bit */
744                                         XSync(disp_Display,FALSE);
745                                         if (Xsublim_Sig_Last == -1)
746                                         {
747                                                 usleep(arg_DelayShow);
748                                         }
749         
750                                         /* Restore the background */
751                                         XPutImage(disp_Display,win_Root,
752                                          gc_GcFore,image_Image,0,0,image_X,
753                                          image_Y,image_Width,image_Height);
754                                 }
755
756                                 /* Free the image */
757                                 XDestroyImage(image_Image);
758                         }
759
760                         /* Restore the error handler, ungrab the server */
761                         XSync(disp_Display, FALSE);
762                         XSetErrorHandler(Xsublim_Sh_Handler);
763                         XUngrabServer(disp_Display);
764                         XSync(disp_Display, FALSE);
765
766                         /* Pause between words */
767                         if (Xsublim_Sig_Last == -1)
768                         {
769                                 usleep(arg_DelayWord);
770                         }
771                 }
772
773                 /* Pause between phrases */
774                 if (Xsublim_Sig_Last == -1)
775                 {
776                         usleep(random()%(arg_DelayPhraseMax-
777                          arg_DelayPhraseMin+1)+arg_DelayPhraseMin);
778                 }
779         }
780
781         /* Exit ------------------------------------------------------------ */
782         for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
783         {
784                 signal(sig_Number,SIG_DFL);
785         }
786         kill(getpid(),Xsublim_Sig_Last);
787
788         return 0;
789 }