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