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