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