http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[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 /* This was all basically swiped from driver/remote.c and util/vroot.h */
235 static Window xsublim_Ss_GetWindow(Display* ss_Display)
236 {
237   Screen *s = DefaultScreenOfDisplay (ss_Display);
238   Window root = XRootWindowOfScreen (s);
239   Window vroot = VirtualRootWindowOfScreen (s);
240   if (root == vroot)
241     return 0;
242   else
243     return vroot;
244 }
245
246 /* Main ==================================================================== */
247 static XErrorHandler Xsublim_Sh_Handler = NULL;
248 static int           Xsublim_Sh_Status = 0;
249
250 static int xsublim_Sh_Handler(Display* handle_Display,
251             XErrorEvent* handle_Error)
252 {
253         if (handle_Error->error_code == BadMatch)
254         {
255                 Xsublim_Sh_Status = BadMatch;
256                 return 0;
257         }
258         if (Xsublim_Sh_Handler == NULL)
259         {
260                 fprintf(stderr,"%s: ",progname);
261                 abort();
262         }
263         return (*Xsublim_Sh_Handler)(handle_Display,handle_Error);
264 }
265 int main(int argc,char* argv[])
266 {
267         int               sig_Number;
268         int               sig_Signal[] =
269         {
270                 SIGHUP,
271                 SIGINT,
272                 SIGQUIT,
273                 SIGILL,
274                 SIGTRAP,
275 #if defined(SIGIOT)
276                 SIGIOT,
277 #endif
278                 SIGABRT,
279 #if defined(SIGEMT)
280                 SIGEMT,
281 #endif
282                 SIGFPE,
283                 SIGBUS,
284                 SIGSEGV,
285 #if defined(SIGSYS)
286                 SIGSYS,
287 #endif
288                 SIGTERM,
289 #if defined(SIGXCPU)
290                 SIGXCPU,
291 #endif
292 #if defined(SIGXFSZ)
293                 SIGXFSZ,
294 #endif
295 #if defined(SIGDANGER)
296                 SIGDANGER,
297 #endif
298                 -1
299         };
300         Widget            app_App;
301         Display*          disp_Display;
302         Window            win_Root;
303         XWindowAttributes attr_Win;
304         XGCValues         gc_ValFore;
305         XGCValues         gc_ValBack;
306         GC                gc_GcFore;
307         GC                gc_GcBack;
308         XFontStruct*      font_Font;
309         char*             font_List[] =
310         {
311                 "-*-character-*-r-*-*-*-600-*-*-p-*-*-*",
312                 "-*-helvetica-*-r-*-*-*-600-*-*-p-*-*-*",
313                 "-*-lucida-*-r-*-*-*-600-*-*-p-*-*-*",
314                 "-*-times-*-r-*-*-*-600-*-*-p-*-*-*",
315                 "-*-*-*-r-*-sans-*-600-*-*-p-*-*-*",
316                 "-*-*-*-r-*-*-*-600-*-*-m-*-*-*",
317                 "-*-helvetica-*-r-*-*-*-240-*-*-p-*-*-*",
318                 "-*-lucida-*-r-*-*-*-240-*-*-p-*-*-*",
319                 "-*-times-*-r-*-*-*-240-*-*-p-*-*-*",
320                 "-*-*-*-r-*-sans-*-240-*-*-p-*-*-*",
321                 "-*-*-*-r-*-*-*-240-*-*-m-*-*-*",
322                 "fixed",
323                 NULL
324         };
325         int               font_Index;
326         int               text_Length;
327         int               text_X;
328         int               text_Y;
329         int               text_Width;
330         int               text_Height;
331         char*             text_List[XSUBLIM_TEXT_COUNT];
332         int               text_Used[XSUBLIM_TEXT_COUNT];
333         char              text_Text[XSUBLIM_TEXT_LENGTH+1];
334         char*             text_Phrase;
335         char*             text_Word;
336         int               text_Index;
337         int               text_Item;
338         int               text_Count;
339         struct
340         {
341                 int outline_X;
342                 int outline_Y;
343         }                 text_Outline[] =
344         {
345                 { -1,-1 },
346                 {  1,-1 },
347                 { -1, 1 },
348                 {  1, 1 },
349                 {  0, 0 }
350         };
351         int               text_OutlineIndex;
352         XImage*           image_Image = NULL;
353         int               image_X = 0;
354         int               image_Y = 0;
355         int               image_Width = 0;
356         int               image_Height = 0;
357         int               arg_Count;
358         int               arg_FlagCenter;
359         int               arg_FlagOutline;
360         int               arg_FlagScreensaver;
361         int               arg_FlagRandom;
362         int               arg_DelayShow;
363         int               arg_DelayWord;
364         int               arg_DelayPhraseMin;
365         int               arg_DelayPhraseMax;
366         char*             arg_Text;
367         char*             arg_Source;
368
369         /* Set-up ---------------------------------------------------------- */
370
371         /* Catch signals */
372         Xsublim_Sig_Last = -1;
373         for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
374         {
375                 signal(sig_Number,xsublim_Sig_Catch);
376         }
377
378         /* Randomize -- only need to do this here because this program
379            doesn't use the `screenhack.h' or `lockmore.h' APIs. */
380 # undef ya_rand_init
381         ya_rand_init (0);
382
383         /* Handle all the X nonsense */
384 #if defined(__sgi)
385         SgiUseSchemes("none");
386 #endif
387         for (arg_Count = 0;options[arg_Count].option != NULL;arg_Count++)
388         {
389                 ;
390         }
391         app_App = XtAppInitialize(&app,progclass,options,arg_Count,&argc,argv,
392          defaults,0,0);
393
394         /* jwz */
395         if (argc > 1)
396           {
397             int x = 18;
398             int end = 78;
399             int i;
400             int count = (sizeof(options)/sizeof(*options))-1;
401             fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
402             fprintf (stderr, "Options include: ");
403             for (i = 0; i < count; i++)
404               {
405                 char *sw = options [i].option;
406                 Bool argp = (options [i].argKind == XrmoptionSepArg);
407                 int size = strlen (sw) + (argp ? 6 : 0) + 2;
408                 if (x + size >= end)
409                   {
410                     fprintf (stderr, "\n\t\t ");
411                     x = 18;
412                   }
413                 x += size;
414                 fprintf (stderr, "%s", sw);
415                 if (argp) fprintf (stderr, " <arg>");
416                 if (i != count-1) fprintf (stderr, ", ");
417               }
418             fprintf (stderr, ".\n");
419             exit (-1);
420           }
421
422         disp_Display = XtDisplay(app_App);
423         db = XtDatabase(disp_Display);
424         XtGetApplicationNameAndClass(disp_Display,&progname,&progclass);
425         win_Root = RootWindowOfScreen(XtScreen(app_App));
426         XtDestroyWidget(app_App);
427
428         /* Get the arguments */
429         arg_FlagCenter = get_boolean_resource(XSUBLIM_ARG_CENTER,"Boolean");
430         arg_FlagOutline = get_boolean_resource(XSUBLIM_ARG_OUTLINE,"Boolean");
431         arg_FlagScreensaver = get_boolean_resource(XSUBLIM_ARG_SCREENSAVER,
432          "Boolean");
433         arg_FlagRandom = get_boolean_resource(XSUBLIM_ARG_RANDOM,"Boolean");
434         arg_DelayShow = get_integer_resource(XSUBLIM_ARG_DELAYSHOW,"Integer");
435         arg_DelayWord = get_integer_resource(XSUBLIM_ARG_DELAYWORD,"Integer");
436         arg_DelayPhraseMin = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMIN,
437          "Integer");
438         arg_DelayPhraseMax = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMAX,
439          "Integer");
440         if (arg_DelayPhraseMax < arg_DelayPhraseMin)
441         {
442                 arg_DelayPhraseMax = arg_DelayPhraseMin;
443         }
444
445         /* Get the phrases */
446         text_Index = 0;
447         text_Item = 0;
448         text_Count = 0;
449         memset(text_Used,0,sizeof(text_Used));
450         arg_Source = get_string_resource(XSUBLIM_ARG_FILE,"Filename");
451         if (arg_Source != NULL)
452         {
453                 FILE*       file_Fs;
454                 struct stat file_Stat;
455
456                 file_Fs = fopen(arg_Source,"rb");
457                 if (file_Fs == NULL)
458                 {
459                         fprintf(stderr,"%s: Could not open '%s'\n",progname,
460                          arg_Source);
461                         exit(-1);
462                 }
463                 if (fstat(fileno(file_Fs),&file_Stat) != 0)
464                 {
465                         fprintf(stderr,"%s: Could not stat '%s'\n",progname,
466                          arg_Source);
467                         exit(-1);
468                 }
469                 arg_Text = calloc(1,file_Stat.st_size+1);
470                 if (arg_Text != NULL)
471                 {
472                         if (fread(arg_Text,file_Stat.st_size,1,file_Fs) != 1)
473                         {
474                                 fprintf(stderr,"%s: Could not read '%s'\n",
475                                  progname,arg_Source);
476                                 exit(-1);
477                         }
478                 }
479                 fclose(file_Fs);
480         }
481         else
482         {
483                 arg_Source = get_string_resource(XSUBLIM_ARG_PROGRAM,
484                  "Executable");
485                 if (arg_Source != NULL)
486                 {
487                         char* exe_Command = calloc(1,strlen(arg_Source)+10);
488                         FILE* exe_Fs;
489
490                         if (exe_Command == NULL)
491                         {
492                                 fprintf(stderr,
493                                  "%s: Could not allocate space for '%s'\n",
494                                  progname,arg_Source);
495                                 exit(-1);
496                         }
497                         sprintf(exe_Command,"( %s ) 2>&1",arg_Source);
498
499                         exe_Fs = popen(exe_Command,"r");
500                         if (exe_Fs == NULL)
501                         {
502                                 fprintf(stderr,"%s: Could not run '%s'\n",
503                                  progname,arg_Source);
504                                 exit(-1);
505                         }
506                         arg_Text = calloc(1,XSUBLIM_PROGRAM_SIZE);
507                         if (arg_Text != NULL)
508                         {
509                                 if (fread(arg_Text,1,XSUBLIM_PROGRAM_SIZE,
510                                  exe_Fs) <= 0)
511                                 {
512                                         fprintf(stderr,
513                                          "%s: Could not read output of '%s'\n",
514                                          progname,arg_Source);
515                                         exit(-1);
516                                 }
517                                 if (
518                                  strstr(arg_Text,": not found") ||
519                                  strstr(arg_Text,": Not found") ||
520                                  strstr(arg_Text,": command not found") ||
521                                  strstr(arg_Text,": Command not found"))
522                                 {
523                                         fprintf(stderr,
524                                          "%s: Could not find '%s'\n",
525                                          progname,arg_Source);
526                                         exit(-1);
527                                 }
528                         }
529                         fclose(exe_Fs);
530                 }
531                 else
532                 {
533                         arg_Text =
534                          get_string_resource(XSUBLIM_ARG_PHRASES,"Phrases");
535                         if (arg_Text != NULL)
536                         {
537                                 arg_Text = strdup(arg_Text);
538                         }
539                 }
540         }
541         if (arg_Text != NULL)
542         {
543                 while (((text_Phrase = strtok(arg_Text,"\n")) != NULL) &&
544                  (text_Count < XSUBLIM_TEXT_COUNT))
545                 {
546                         arg_Text = NULL;
547                         text_List[text_Count] = text_Phrase;
548                         text_Count++;
549                 }
550                 text_List[text_Count] = NULL;
551         }
552         if (text_Count == 0)
553         {
554                 fprintf(stderr,"%s: No text to display\n",progname);
555                 exit(-1);
556         }
557
558         /* Load the font */
559         font_Font = XLoadQueryFont(disp_Display,
560          get_string_resource(XSUBLIM_ARG_FONT,"Font"));
561         font_Index = 0;
562         while ((font_Font == NULL) && (font_List[font_Index] != NULL))
563         {
564                 font_Font = XLoadQueryFont(disp_Display,font_List[font_Index]);
565                 font_Index++;
566         }
567         if (font_Font == NULL)
568         {
569                 fprintf(stderr,"%s: Couldn't load a font\n",progname);
570                 exit(-1);
571         }
572
573         /* Create the GCs */
574         XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
575         gc_ValFore.font = font_Font->fid;
576         gc_ValFore.foreground = get_pixel_resource("foreground","Foreground",
577          disp_Display,attr_Win.colormap);
578         gc_ValFore.background = get_pixel_resource("background","Background",
579          disp_Display,attr_Win.colormap);
580         gc_ValFore.subwindow_mode = IncludeInferiors;
581         gc_GcFore = XCreateGC(disp_Display,win_Root,
582          (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValFore);
583         gc_ValBack.font = font_Font->fid;
584         gc_ValBack.foreground = get_pixel_resource("background","Background",
585          disp_Display,attr_Win.colormap);
586         gc_ValBack.background = get_pixel_resource("foreground","Foreground",
587          disp_Display,attr_Win.colormap);
588         gc_ValBack.subwindow_mode = IncludeInferiors;
589         gc_GcBack = XCreateGC(disp_Display,win_Root,
590          (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValBack);
591
592         /* Loop ------------------------------------------------------------ */
593         while (Xsublim_Sig_Last == -1)
594         {
595                 /* Once-per-phrase stuff ----------------------------------- */
596
597                 /* If we're waiting for a screensaver... */
598                 if (arg_FlagScreensaver != FALSE)
599                 {
600                         /* Find the screensaver's window */
601                         win_Root = xsublim_Ss_GetWindow(disp_Display);
602                         if (win_Root == 0)
603                         {
604                                 usleep(30000000);
605                                 continue;
606                         }
607                 }
608
609                 /* Pick the next phrase */
610                 if (arg_FlagRandom != FALSE)
611                 {
612                         text_Item = random()%text_Count;
613                         text_Index = 0;
614                 }
615                 while (text_Used[text_Item] != FALSE)
616                 {
617                         text_Index++;
618                         text_Item++;
619                         if (text_Index == text_Count)
620                         {
621                                 text_Index = 0;
622                                 memset(text_Used,0,sizeof(text_Used));
623                         }
624                         if (text_List[text_Item] == NULL)
625                         {
626                                 text_Item = 0;
627                         }
628                 }
629                 text_Used[text_Item] = TRUE;
630                 strncpy(text_Text,text_List[text_Item],
631                  XSUBLIM_TEXT_LENGTH);
632                 text_Phrase = text_Text;
633
634                 /* Run through the phrase */
635                 while (((text_Word = strtok(text_Phrase," \t")) != NULL) &&
636                  (Xsublim_Sig_Last == -1))
637                 {
638                         text_Phrase = NULL;
639
640                         /* Once-per-word stuff ----------------------------- */
641
642                         /* Find the text's position */
643                         XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
644                         text_Length = strlen(text_Word);
645                         text_Width = XTextWidth(font_Font,text_Word,
646                          text_Length)+XSUBLIM_TEXT_OUTLINE*2;
647                         text_Height = font_Font->ascent+font_Font->descent+1+
648                          XSUBLIM_TEXT_OUTLINE*2;
649                         if (arg_FlagCenter == FALSE)
650                         {
651                                 text_X = random()%(attr_Win.width-text_Width);
652                                 text_Y = random()%(attr_Win.height-
653                                  text_Height);
654                         }
655                         else
656                         {
657                                 text_X = (attr_Win.width/2)-(text_Width/2);
658                                 text_Y = (attr_Win.height/2)-(text_Height/2);
659                         }
660
661                         /* Find the image's position (and pad it out slightly,
662                            otherwise bits of letter get left behind -- are
663                            there boundry issues I don't know about?) */
664                         image_X = text_X-16;
665                         image_Y = text_Y;
666                         image_Width = text_Width+32;
667                         image_Height = text_Height;
668                         if (image_X < 0)
669                         {
670                                 image_X = 0;
671                         }
672                         if (image_Y < 0)
673                         {
674                                 image_Y = 0;
675                         }
676                         if (image_X+image_Width > attr_Win.width)
677                         {
678                                 image_Width = attr_Win.width-image_X;
679                         }
680                         if (image_Y+image_Height > attr_Win.height)
681                         {
682                                 image_Height = attr_Win.height-image_Y;
683                         }
684
685                         /* Influence people for our own ends --------------- */
686
687                         /* Grab the server -- we can't let anybody draw over
688                            us */
689                         XSync(disp_Display,FALSE);
690                         XGrabServer(disp_Display);
691                         XSync(disp_Display,FALSE);
692
693                         /* Set up an error handler that ignores BadMatches --
694                            since the screensaver can take its window away at
695                            any time, any call that uses it might choke */
696                         Xsublim_Sh_Status = 0;
697                         Xsublim_Sh_Handler =
698                          XSetErrorHandler(xsublim_Sh_Handler);
699
700                         /* Save the current background */
701                         image_Image = XGetImage(disp_Display,win_Root,image_X,
702                          image_Y,image_Width,image_Height,~0L,ZPixmap);
703
704                         /* If we've successfully saved the background... */
705                         if (image_Image != NULL)
706                         {
707                                 if (Xsublim_Sh_Status == 0)
708                                 {
709                                         /* Draw the outline */
710                                         if (arg_FlagOutline != FALSE)
711                                         {
712                                                 for (text_OutlineIndex = 0;
713                                                  text_Outline[
714                                                  text_OutlineIndex].outline_X
715                                                  != 0;text_OutlineIndex++)
716                                                 {
717                                                         /* Y'know, eight
718                                                            character tabs and
719                                                            descriptive variable
720                                                            names become
721                                                            annoying at some
722                                                            point... */
723                                                         XDrawString(
724                                                          disp_Display,
725                                                          win_Root,gc_GcBack,
726                                                          text_X+text_Outline[
727                                                          text_OutlineIndex].
728                                                          outline_X*
729                                                          XSUBLIM_TEXT_OUTLINE,
730                                                          text_Y+
731                                                          (font_Font->ascent)+
732                                                          text_Outline[
733                                                          text_OutlineIndex].
734                                                          outline_Y*
735                                                          XSUBLIM_TEXT_OUTLINE,
736                                                          text_Word,
737                                                          text_Length);
738                                                 }
739                                         }
740
741                                         /* Draw the word */
742                                         XDrawString(disp_Display,win_Root,
743                                          gc_GcFore,text_X,
744                                          text_Y+(font_Font->ascent),text_Word,
745                                          text_Length);
746                                 }
747                                 if (Xsublim_Sh_Status == 0)
748                                 {
749                                         /* Wait a bit */
750                                         XSync(disp_Display,FALSE);
751                                         if (Xsublim_Sig_Last == -1)
752                                         {
753                                                 usleep(arg_DelayShow);
754                                         }
755         
756                                         /* Restore the background */
757                                         XPutImage(disp_Display,win_Root,
758                                          gc_GcFore,image_Image,0,0,image_X,
759                                          image_Y,image_Width,image_Height);
760                                 }
761
762                                 /* Free the image */
763                                 XDestroyImage(image_Image);
764                         }
765
766                         /* Restore the error handler, ungrab the server */
767                         XSync(disp_Display,FALSE);
768                         XSetErrorHandler(Xsublim_Sh_Handler);
769                         XUngrabServer(disp_Display);
770                         XSync(disp_Display,FALSE);
771
772                         /* Pause between words */
773                         if (Xsublim_Sig_Last == -1)
774                         {
775                                 usleep(arg_DelayWord);
776                         }
777                 }
778
779                 /* Pause between phrases */
780                 if (Xsublim_Sig_Last == -1)
781                 {
782                         usleep(random()%(arg_DelayPhraseMax-
783                          arg_DelayPhraseMin+1)+arg_DelayPhraseMin);
784                 }
785         }
786
787         /* Exit ------------------------------------------------------------ */
788         for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
789         {
790                 signal(sig_Number,SIG_DFL);
791         }
792         kill(getpid(),Xsublim_Sig_Last);
793
794         return 0;
795 }