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