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