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