1 /*****************************************************************************
3 * xsublim -- Submit. Conform. Obey. *
5 * Copyright (c) 1999 Greg Knauss (greg@eod.com) *
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) *
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 *
19 * Stare into the subliminal for as long as you can... *
21 *****************************************************************************/
24 /* Warnings *******************************************************************
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.
31 /* Arguments ******************************************************************
33 -font font Font to use
34 -delayShow ms Microsecs for display of each word
35 -delayWord ms Microsecs for blank between words
36 -delayPhraseMin ms Microsecs for min blank between phrases
37 -delayPhraseMax ms Microsecs for max blank between phrases
38 -random Show phrases in random order (Default)
39 -no-random Show phrases in listed order
40 -screensaver Wait for an active screensaver (Default)
41 -no-screensaver Draw over active windows
42 -outline Draw a contrasting outline around words (Default)
43 -no-outline Draw words without an outline
44 -center Draw words in the center of the screen (Default)
45 -no-center Draw words randomly around the screen
49 /* Defines *******************************************************************/
50 #define XSUBLIM_NAME "XSublim"
51 #define XSUBLIM_TEXT_COUNT 1000
52 #define XSUBLIM_TEXT_LENGTH 128
53 #define XSUBLIM_TEXT_OUTLINE 1
54 #define XSUBLIM_ARG_DELAYSHOW "delayShow"
55 #define XSUBLIM_ARG_DELAYWORD "delayWord"
56 #define XSUBLIM_ARG_DELAYPHRASEMIN "delayPhraseMin"
57 #define XSUBLIM_ARG_DELAYPHRASEMAX "delayPhraseMax"
58 #define XSUBLIM_ARG_RANDOM "random"
59 #define XSUBLIM_ARG_FILE "file"
60 #define XSUBLIM_ARG_SCREENSAVER "screensaver"
61 #define XSUBLIM_ARG_OUTLINE "outline"
62 #define XSUBLIM_ARG_CENTER "center"
63 #define XSUBLIM_ARG_FONT "font"
64 #define XSUBLIM_ARG_PHRASES "phrases"
71 /* Includes ******************************************************************/
76 #include <X11/Intrinsic.h>
77 #include <X11/IntrinsicP.h>
78 #include <X11/CoreP.h>
79 #include <X11/Shell.h>
80 #include <X11/StringDefs.h>
81 #include <X11/Xutil.h>
82 #include <X11/keysym.h>
83 #include <X11/Xatom.h>
86 #include <X11/Xproto.h>
88 #include <X11/SGIScheme.h>
93 #include "resources.h"
96 /* Globals *******************************************************************/
100 char* progclass = XSUBLIM_NAME;
103 ".background: #000000",
104 ".foreground: #FFFFFF",
105 "*" XSUBLIM_ARG_PHRASES ":"
109 "OBEY. OBEY. OBEY.\\n"
118 "Despair quietly.\\n"
120 "You are being watched.\\n"
121 "You will be punished.\\n"
122 "You serve no purpose.\\n"
123 "Your contributions are ignored.\\n"
124 "They are laughing at you.\\n"
125 "They lied to you.\\n"
126 "They read your mail.\\n"
131 "You are a prisoner.\\n"
132 "You are helpless.\\n"
133 "You are diseased.\\n"
134 "Fear the unknown.\\n"
135 "Happiness follows obedience.\\n"
136 "Ignorance is strength.\\n"
138 "Freedom is slavery.\\n"
139 "Abandon all hope.\\n"
140 "You will be assimilated.\\n"
141 "Resistance is futile.\\n"
142 "Resistance is useless.\\n"
145 "What's that smell?\\n"
146 "All praise the company.\\n"
148 "*" XSUBLIM_ARG_FONT ": -*-utopia-*-r-*-*-*-600-*-*-p-*-*-*",
149 "*" XSUBLIM_ARG_DELAYSHOW ": 40000",
150 "*" XSUBLIM_ARG_DELAYWORD ": 100000",
151 "*" XSUBLIM_ARG_DELAYPHRASEMIN ": 5000000",
152 "*" XSUBLIM_ARG_DELAYPHRASEMAX ": 20000000",
153 "*" XSUBLIM_ARG_RANDOM ": true",
154 "*" XSUBLIM_ARG_SCREENSAVER ": true",
155 "*" XSUBLIM_ARG_OUTLINE": true",
156 "*" XSUBLIM_ARG_CENTER": true",
159 XrmOptionDescRec options[] =
161 {"-" XSUBLIM_ARG_FONT, "." XSUBLIM_ARG_FONT,
163 {"-" XSUBLIM_ARG_DELAYSHOW, "." XSUBLIM_ARG_DELAYSHOW,
165 {"-" XSUBLIM_ARG_DELAYWORD, "." XSUBLIM_ARG_DELAYWORD,
167 {"-" XSUBLIM_ARG_DELAYPHRASEMIN,"." XSUBLIM_ARG_DELAYPHRASEMIN,
169 {"-" XSUBLIM_ARG_DELAYPHRASEMAX,"." XSUBLIM_ARG_DELAYPHRASEMAX,
171 {"-" XSUBLIM_ARG_RANDOM, "." XSUBLIM_ARG_RANDOM,
172 XrmoptionNoArg,"true"},
173 {"-no-" XSUBLIM_ARG_RANDOM, "." XSUBLIM_ARG_RANDOM,
174 XrmoptionNoArg,"false"},
175 {"-" XSUBLIM_ARG_FILE, "." XSUBLIM_ARG_FILE,
177 {"-" XSUBLIM_ARG_SCREENSAVER, "." XSUBLIM_ARG_SCREENSAVER,
178 XrmoptionNoArg,"true"},
179 {"-no-" XSUBLIM_ARG_SCREENSAVER,"." XSUBLIM_ARG_SCREENSAVER,
180 XrmoptionNoArg,"false"},
181 {"-" XSUBLIM_ARG_OUTLINE, "." XSUBLIM_ARG_OUTLINE,
182 XrmoptionNoArg,"true"},
183 {"-no-" XSUBLIM_ARG_OUTLINE, "." XSUBLIM_ARG_OUTLINE,
184 XrmoptionNoArg,"false"},
185 {"-" XSUBLIM_ARG_CENTER, "." XSUBLIM_ARG_CENTER,
186 XrmoptionNoArg,"true"},
187 {"-no-" XSUBLIM_ARG_CENTER, "." XSUBLIM_ARG_CENTER,
188 XrmoptionNoArg,"false"},
192 static int Xsublim_Sig_Last;
195 /* Functions *****************************************************************/
197 /* Defer signals to protect the server grab ================================ */
198 void xsublim_Sig_Catch(int sig_Number)
200 /* BSD needs this reset each time, and it shouldn't hurt anything
202 signal(sig_Number,xsublim_Sig_Catch);
203 Xsublim_Sig_Last = sig_Number;
206 /* Get the screensaver's window ============================================ */
207 static XErrorHandler Xsublim_Ss_Handler = NULL;
208 static int Xsublim_Ss_Status;
210 /* This was all basically swiped from driver/remote.c and util/vroot.h */
211 static int xsublim_Ss_Handler(Display* handle_Display,
212 XErrorEvent* handle_Error)
214 if (handle_Error->error_code == BadWindow)
216 Xsublim_Ss_Status = BadWindow;
219 if (Xsublim_Ss_Handler == NULL)
221 fprintf(stderr,"%x: ",progname);
224 return (*Xsublim_Ss_Handler)(handle_Display,handle_Error);
226 static Window xsublim_Ss_GetWindow(Display* ss_Display)
229 Window win_RootReturn;
237 unsigned long prop_Count;
238 unsigned long prop_Bytes;
241 static Atom XA_SCREENSAVER_VERSION = -1;
242 static Atom __SWM_VROOT;
244 /* Assume bad things */
249 if (XA_SCREENSAVER_VERSION == -1)
251 XA_SCREENSAVER_VERSION = XInternAtom(ss_Display,
252 "_SCREENSAVER_VERSION",FALSE);
253 __SWM_VROOT = XInternAtom(ss_Display,"__SWM_VROOT",FALSE);
256 /* Find a screensaver window */
257 win_Root = RootWindowOfScreen(DefaultScreenOfDisplay(ss_Display));
258 if (XQueryTree(ss_Display,win_Root,&win_RootReturn,&win_Parent,
259 &win_Child,&child_Count) != FALSE)
262 (win_Root == win_RootReturn) &&
264 (win_Child != NULL) &&
267 for (child_Index = 0;child_Index < child_Count;
270 XSync(ss_Display,FALSE);
271 Xsublim_Ss_Status = 0;
273 XSetErrorHandler(xsublim_Ss_Handler);
275 prop_Status = XGetWindowProperty(ss_Display,
276 win_Child[child_Index],XA_SCREENSAVER_VERSION,
277 0,200,FALSE,XA_STRING,&prop_Type,&prop_Format,
278 &prop_Count,&prop_Bytes,
279 (unsigned char**)&prop_Value);
280 XSync(ss_Display,FALSE);
281 XSetErrorHandler(Xsublim_Ss_Handler);
282 if (prop_Value != NULL)
286 if (Xsublim_Ss_Status == BadWindow)
288 prop_Status = BadWindow;
290 if ((prop_Status == Success) &&
293 /* See if it's a virtual root */
296 XGetWindowProperty(ss_Display,
297 win_Child[child_Index],__SWM_VROOT,0,
298 1,FALSE,XA_WINDOW,&prop_Type,
299 &prop_Format,&prop_Count,&prop_Bytes,
300 (unsigned char**)&prop_Value);
301 if (prop_Value != NULL)
305 if ((prop_Status == Success) &&
309 win_Child[child_Index];
315 if (win_Child != NULL)
322 /* Main ==================================================================== */
323 static XErrorHandler Xsublim_Sh_Handler = NULL;
324 static int Xsublim_Sh_Status = 0;
326 static int xsublim_Sh_Handler(Display* handle_Display,
327 XErrorEvent* handle_Error)
329 if (handle_Error->error_code == BadMatch)
331 Xsublim_Sh_Status = BadMatch;
334 if (Xsublim_Sh_Handler == NULL)
336 fprintf(stderr,"%s: ",progname);
339 return (*Xsublim_Sh_Handler)(handle_Display,handle_Error);
341 int main(int argc,char* argv[])
369 #if defined(SIGDANGER)
375 Display* disp_Display;
377 XWindowAttributes attr_Win;
378 XGCValues gc_ValFore;
379 XGCValues gc_ValBack;
382 XFontStruct* font_Font;
385 "-*-character-*-r-*-*-*-600-*-*-p-*-*-*",
386 "-*-helvetica-*-r-*-*-*-600-*-*-p-*-*-*",
387 "-*-lucida-*-r-*-*-*-600-*-*-p-*-*-*",
388 "-*-times-*-r-*-*-*-600-*-*-p-*-*-*",
389 "-*-*-*-r-*-sans-*-600-*-*-p-*-*-*",
390 "-*-*-*-r-*-*-*-600-*-*-m-*-*-*",
392 "-*-helvetica-*-r-*-*-*-240-*-*-p-*-*-*",
393 "-*-lucida-*-r-*-*-*-240-*-*-p-*-*-*",
394 "-*-times-*-r-*-*-*-240-*-*-p-*-*-*",
395 "-*-*-*-r-*-sans-*-240-*-*-p-*-*-*",
396 "-*-*-*-r-*-*-*-240-*-*-m-*-*-*",
406 char* text_List[XSUBLIM_TEXT_COUNT];
407 int text_Used[XSUBLIM_TEXT_COUNT];
408 char text_Text[XSUBLIM_TEXT_LENGTH+1];
426 int text_OutlineIndex;
427 XImage* image_Image = NULL;
431 int image_Height = 0;
435 int arg_FlagScreensaver;
439 int arg_DelayPhraseMin;
440 int arg_DelayPhraseMax;
443 /* Set-up ---------------------------------------------------------- */
446 Xsublim_Sig_Last = -1;
447 for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
449 signal(sig_Number,xsublim_Sig_Catch);
453 srandom((int)time((time_t*)0));
455 /* Handle all the X nonsense */
457 SgiUseSchemes("none");
459 for (arg_Count = 0;options[arg_Count].option != NULL;arg_Count++)
463 app_App = XtAppInitialize(&app,progclass,options,arg_Count,&argc,argv,
472 int count = (sizeof(options)/sizeof(*options))-1;
473 fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
474 fprintf (stderr, "Options include: ");
475 for (i = 0; i < count; i++)
477 char *sw = options [i].option;
478 Bool argp = (options [i].argKind == XrmoptionSepArg);
479 int size = strlen (sw) + (argp ? 6 : 0) + 2;
482 fprintf (stderr, "\n\t\t ");
486 fprintf (stderr, "%s", sw);
487 if (argp) fprintf (stderr, " <arg>");
488 if (i != count-1) fprintf (stderr, ", ");
490 fprintf (stderr, ".\n");
494 disp_Display = XtDisplay(app_App);
495 db = XtDatabase(disp_Display);
496 XtGetApplicationNameAndClass(disp_Display,&progname,&progclass);
497 win_Root = RootWindowOfScreen(XtScreen(app_App));
498 XtDestroyWidget(app_App);
500 /* Get the arguments */
501 arg_FlagCenter = get_boolean_resource(XSUBLIM_ARG_CENTER,"Boolean");
502 arg_FlagOutline = get_boolean_resource(XSUBLIM_ARG_OUTLINE,"Boolean");
503 arg_FlagScreensaver = get_boolean_resource(XSUBLIM_ARG_SCREENSAVER,
505 arg_FlagRandom = get_boolean_resource(XSUBLIM_ARG_RANDOM,"Boolean");
506 arg_DelayShow = get_integer_resource(XSUBLIM_ARG_DELAYSHOW,"Integer");
507 arg_DelayWord = get_integer_resource(XSUBLIM_ARG_DELAYWORD,"Integer");
508 arg_DelayPhraseMin = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMIN,
510 arg_DelayPhraseMax = get_integer_resource(XSUBLIM_ARG_DELAYPHRASEMAX,
512 if (arg_DelayPhraseMax < arg_DelayPhraseMin)
514 arg_DelayPhraseMax = arg_DelayPhraseMin;
517 /* Get the phrases */
521 memset(text_Used,0,sizeof(text_Used));
522 arg_Text = get_string_resource(XSUBLIM_ARG_PHRASES,"Phrases");
523 if (arg_Text != NULL)
525 arg_Text = strdup(arg_Text);
526 while (((text_Phrase = strtok(arg_Text,"\n")) != NULL) &&
527 (text_Count < XSUBLIM_TEXT_COUNT))
530 text_List[text_Count] = text_Phrase;
534 text_List[text_Count] = NULL;
537 fprintf(stderr,"%s: No text to display\n",progname);
542 font_Font = XLoadQueryFont(disp_Display,
543 get_string_resource(XSUBLIM_ARG_FONT,"Font"));
545 while ((font_Font == NULL) && (font_List[font_Index] != NULL))
547 font_Font = XLoadQueryFont(disp_Display,font_List[font_Index]);
550 if (font_Font == NULL)
552 fprintf(stderr,"%s: Couldn't load a font\n",progname);
557 XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
558 gc_ValFore.font = font_Font->fid;
559 gc_ValFore.foreground = get_pixel_resource("foreground","Foreground",
560 disp_Display,attr_Win.colormap);
561 gc_ValFore.background = get_pixel_resource("background","Background",
562 disp_Display,attr_Win.colormap);
563 gc_ValFore.subwindow_mode = IncludeInferiors;
564 gc_GcFore = XCreateGC(disp_Display,win_Root,
565 (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValFore);
566 gc_ValBack.font = font_Font->fid;
567 gc_ValBack.foreground = get_pixel_resource("background","Background",
568 disp_Display,attr_Win.colormap);
569 gc_ValBack.background = get_pixel_resource("foreground","Foreground",
570 disp_Display,attr_Win.colormap);
571 gc_ValBack.subwindow_mode = IncludeInferiors;
572 gc_GcBack = XCreateGC(disp_Display,win_Root,
573 (GCFont|GCForeground|GCBackground|GCSubwindowMode),&gc_ValBack);
575 /* Loop ------------------------------------------------------------ */
576 while (Xsublim_Sig_Last == -1)
578 /* Once-per-phrase stuff ----------------------------------- */
580 /* If we're waiting for a screensaver... */
581 if (arg_FlagScreensaver != FALSE)
583 /* Find the screensaver's window */
584 win_Root = xsublim_Ss_GetWindow(disp_Display);
592 /* Pick the next phrase */
593 if (arg_FlagRandom != FALSE)
595 text_Item = random()%text_Count;
598 while (text_Used[text_Item] != FALSE)
602 if (text_Index == text_Count)
605 memset(text_Used,0,sizeof(text_Used));
607 if (text_List[text_Item] == NULL)
612 text_Used[text_Item] = TRUE;
613 strncpy(text_Text,text_List[text_Item],
614 XSUBLIM_TEXT_LENGTH);
615 text_Phrase = text_Text;
617 /* Run through the phrase */
618 while (((text_Word = strtok(text_Phrase," \t")) != NULL) &&
619 (Xsublim_Sig_Last == -1))
623 /* Once-per-word stuff ----------------------------- */
625 /* Find the text's position */
626 XGetWindowAttributes(disp_Display,win_Root,&attr_Win);
627 text_Length = strlen(text_Word);
628 text_Width = XTextWidth(font_Font,text_Word,
629 text_Length)+XSUBLIM_TEXT_OUTLINE*2;
630 text_Height = font_Font->ascent+font_Font->descent+1+
631 XSUBLIM_TEXT_OUTLINE*2;
632 if (arg_FlagCenter == FALSE)
634 text_X = random()%(attr_Win.width-text_Width);
635 text_Y = random()%(attr_Win.height-
640 text_X = (attr_Win.width/2)-(text_Width/2);
641 text_Y = (attr_Win.height/2)-(text_Height/2);
644 /* Find the image's position (and pad it out slightly,
645 otherwise bits of letter get left behind -- are
646 there boundry issues I don't know about?) */
649 image_Width = text_Width+32;
650 image_Height = text_Height;
659 if (image_X+image_Width > attr_Win.width)
661 image_Width = attr_Win.width-image_X;
663 if (image_Y+image_Height > attr_Win.height)
665 image_Height = attr_Win.height-image_Y;
668 /* Influence people for our own ends --------------- */
670 /* Grab the server -- we can't let anybody draw over
672 XSync(disp_Display,FALSE);
673 XGrabServer(disp_Display);
674 XSync(disp_Display,FALSE);
676 /* Set up an error handler that ignores BadMatches --
677 since the screensaver can take its window away at
678 any time, any call that uses it might choke */
679 Xsublim_Sh_Status = 0;
681 XSetErrorHandler(xsublim_Sh_Handler);
683 /* Save the current background */
684 image_Image = XGetImage(disp_Display,win_Root,image_X,
685 image_Y,image_Width,image_Height,~0L,ZPixmap);
687 /* If we've successfully saved the background... */
688 if (image_Image != NULL)
690 if (Xsublim_Sh_Status == 0)
692 /* Draw the outline */
693 if (arg_FlagOutline != FALSE)
695 for (text_OutlineIndex = 0;
697 text_OutlineIndex].outline_X
698 != 0;text_OutlineIndex++)
712 XSUBLIM_TEXT_OUTLINE,
718 XSUBLIM_TEXT_OUTLINE,
725 XDrawString(disp_Display,win_Root,
727 text_Y+(font_Font->ascent),text_Word,
730 if (Xsublim_Sh_Status == 0)
733 XSync(disp_Display,FALSE);
734 if (Xsublim_Sig_Last == -1)
736 usleep(arg_DelayShow);
739 /* Restore the background */
740 XPutImage(disp_Display,win_Root,
741 gc_GcFore,image_Image,0,0,image_X,
742 image_Y,image_Width,image_Height);
745 /* Free the image (and it's goddamned structure
746 -- the man page for XCreateImage() lies,
748 XDestroyImage(image_Image);
752 /* Restore the error handler, ungrab the server */
753 XSync(disp_Display, FALSE);
754 XSetErrorHandler(Xsublim_Sh_Handler);
755 XUngrabServer(disp_Display);
756 XSync(disp_Display, FALSE);
758 /* Pause between words */
759 if (Xsublim_Sig_Last == -1)
761 usleep(arg_DelayWord);
765 /* Pause between phrases */
766 if (Xsublim_Sig_Last == -1)
768 usleep(random()%(arg_DelayPhraseMax-
769 arg_DelayPhraseMin+1)+arg_DelayPhraseMin);
773 /* Exit ------------------------------------------------------------ */
774 for (sig_Number = 0;sig_Signal[sig_Number] != -1;sig_Number++)
776 signal(sig_Number,SIG_DFL);
778 kill(getpid(),Xsublim_Sig_Last);