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