8462d4e792999b6431539f793ad4d5f4f8d399fb
[xscreensaver] / hacks / screenhack.c
1 /* xscreensaver, Copyright (c) 1992, 1995, 1997
2  *  Jamie Zawinski <jwz@netscape.com>
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  *
12  * And remember: X Windows is to graphics hacking as roman numerals are to
13  * the square root of pi.
14  */
15
16 /* This file contains simple code to open a window or draw on the root.
17    The idea being that, when writing a graphics hack, you can just link
18    with this .o to get all of the uninteresting junk out of the way.
19
20    -  create a procedure `screenhack(dpy, window)'
21
22    -  create a variable `char *progclass' which names this program's
23       resource class.
24
25    -  create a variable `char defaults []' for the default resources, and
26       null-terminate it.
27
28    -  create a variable `XrmOptionDescRec options[]' for the command-line,
29       and null-terminate it.
30
31    And that's it...
32  */
33
34 #include <stdio.h>
35 #include <X11/Intrinsic.h>
36 #include <X11/IntrinsicP.h>
37 #include <X11/CoreP.h>
38 #include <X11/Shell.h>
39 #include <X11/StringDefs.h>
40 #ifdef HAVE_XMU
41 # ifndef VMS
42 #  include <X11/Xmu/Error.h>
43 # else /* VMS */
44 #  include <Xmu/Error.h>
45 # endif
46 #else
47 # include "xmu.h"
48 #endif
49 #include "screenhack.h"
50 #include "version.h"
51 #include "vroot.h"
52
53 char *progname;
54 XrmDatabase db;
55 Bool mono_p;
56
57 static XrmOptionDescRec default_options [] = {
58   { "-root",    ".root",                XrmoptionNoArg, "True" },
59   { "-window",  ".root",                XrmoptionNoArg, "False" },
60   { "-mono",    ".mono",                XrmoptionNoArg, "True" },
61   { "-install", ".installColormap",     XrmoptionNoArg, "True" },
62   { "-noinstall",".installColormap",    XrmoptionNoArg, "False" },
63   { "-visual",  ".visualID",            XrmoptionSepArg, 0 },
64   { 0, 0, 0, 0 }
65 };
66
67 static char *default_defaults[] = {
68   "*root:               false",
69   "*geometry:           600x480", /* this should be .geometry, but nooooo... */
70   "*mono:               false",
71   "*installColormap:    false",
72   "*visualID:           default",
73   0
74 };
75
76 static XrmOptionDescRec *merged_options;
77 static int merged_options_size;
78 static char **merged_defaults;
79
80 static void
81 merge_options (void)
82 {
83   int def_opts_size, opts_size;
84   int def_defaults_size, defaults_size;
85
86   for (def_opts_size = 0; default_options[def_opts_size].option;
87        def_opts_size++)
88     ;
89   for (opts_size = 0; options[opts_size].option; opts_size++)
90     ;
91
92   merged_options_size = def_opts_size + opts_size;
93   merged_options = (XrmOptionDescRec *)
94     malloc ((merged_options_size + 1) * sizeof(*default_options));
95   memcpy (merged_options, default_options,
96           (def_opts_size * sizeof(*default_options)));
97   memcpy (merged_options + def_opts_size, options,
98           ((opts_size + 1) * sizeof(*default_options)));
99
100   for (def_defaults_size = 0; default_defaults[def_defaults_size];
101        def_defaults_size++)
102     ;
103   for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
104     ;
105   merged_defaults = (char **)
106     malloc ((def_defaults_size + defaults_size + 1) * sizeof (*defaults));;
107   memcpy (merged_defaults, default_defaults,
108           def_defaults_size * sizeof(*defaults));
109   memcpy (merged_defaults + def_defaults_size, defaults,
110           (defaults_size + 1) * sizeof(*defaults));
111 }
112
113 \f
114 /* Make the X errors print out the name of this program, so we have some
115    clue which one has a bug when they die under the screensaver.
116  */
117
118 static int
119 screenhack_ehandler (Display *dpy, XErrorEvent *error)
120 {
121   fprintf (stderr, "\nX error in %s:\n", progname);
122   if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
123     exit (-1);
124   else
125     fprintf (stderr, " (nonfatal.)\n");
126   return 0;
127 }
128
129 static Bool
130 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
131 {
132   return (event->xany.type == MapNotify &&
133           event->xvisibility.window == (Window) window);
134 }
135
136
137 #ifdef USE_GL
138 extern Visual *get_gl_visual (Screen *, const char *, const char *);
139 #endif
140
141 #ifdef XLOCKMORE
142 extern void pre_merge_options (void);
143 #endif
144
145
146
147 int
148 main (int argc, char **argv)
149 {
150   XtAppContext app;
151   Widget toplevel;
152   Display *dpy;
153   Window window;
154   Visual *visual;
155   Colormap cmap;
156   Bool root_p;
157   XEvent event;
158   Boolean dont_clear /*, dont_map */;
159   char version[255];
160
161 #ifdef XLOCKMORE
162   pre_merge_options ();
163 #endif
164   merge_options ();
165   toplevel = XtAppInitialize (&app, progclass, merged_options,
166                               merged_options_size, &argc, argv,
167                               merged_defaults, 0, 0);
168   dpy = XtDisplay (toplevel);
169   db = XtDatabase (dpy);
170   XtGetApplicationNameAndClass (dpy, &progname, &progclass);
171   XSetErrorHandler (screenhack_ehandler);
172
173   {
174     char *v = (char *) strdup(strchr(screensaver_id, ' '));
175     char *s = (char *) strchr(v, ',');
176     *s = 0;
177     sprintf (version, "%s: from the XScreenSaver%s distribution.",
178              progclass, v);
179     free(v);
180   }
181
182   if (argc > 1)
183     {
184       const char *s;
185       int i;
186       int x = 18;
187       int end = 78;
188       Bool help_p = !strcmp(argv[1], "-help");
189       fprintf (stderr, "%s\n", version);
190       for (s = progclass; *s; s++) fprintf(stderr, " ");
191       fprintf (stderr, "  http://people.netscape.com/jwz/xscreensaver/\n\n");
192
193       if (!help_p)
194         fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
195       fprintf (stderr, "Options include: ");
196       for (i = 0; i < merged_options_size; i++)
197         {
198           char *sw = merged_options [i].option;
199           Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
200           int size = strlen (sw) + (argp ? 6 : 0) + 2;
201           if (x + size >= end)
202             {
203               fprintf (stderr, "\n\t\t ");
204               x = 18;
205             }
206           x += size;
207           fprintf (stderr, "%s", sw);
208           if (argp) fprintf (stderr, " <arg>");
209           if (i != merged_options_size - 1) fprintf (stderr, ", ");
210         }
211       fprintf (stderr, ".\n");
212       exit (help_p ? 0 : 1);
213     }
214
215   dont_clear = get_boolean_resource ("dontClearRoot", "Boolean");
216 /*dont_map = get_boolean_resource ("dontMapWindow", "Boolean"); */
217   mono_p = get_boolean_resource ("mono", "Boolean");
218   if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
219     mono_p = True;
220
221   root_p = get_boolean_resource ("root", "Boolean");
222   if (root_p)
223     {
224       XWindowAttributes xgwa;
225       window = RootWindowOfScreen (XtScreen (toplevel));
226       XtDestroyWidget (toplevel);
227       XGetWindowAttributes (dpy, window, &xgwa);
228       cmap = xgwa.colormap;
229       visual = xgwa.visual;
230     }
231   else
232     {
233       Boolean def_visual_p;
234       Screen *screen = XtScreen (toplevel);
235
236 #ifdef USE_GL
237       visual = get_gl_visual (screen, "visualID", "VisualID");
238 #else
239       visual = get_visual_resource (screen, "visualID", "VisualID", False);
240 #endif
241
242       if (toplevel->core.width <= 0)
243         toplevel->core.width = 600;
244       if (toplevel->core.height <= 0)
245         toplevel->core.height = 480;
246
247       def_visual_p = (visual == DefaultVisualOfScreen (screen));
248
249       if (!def_visual_p)
250         {
251           unsigned int bg, bd;
252           Widget new;
253
254           cmap = XCreateColormap (dpy, RootWindowOfScreen(screen),
255                                   visual, AllocNone);
256           bg = get_pixel_resource ("background", "Background", dpy, cmap);
257           bd = get_pixel_resource ("borderColor", "Foreground", dpy, cmap);
258
259           new = XtVaAppCreateShell (progname, progclass,
260                                     topLevelShellWidgetClass, dpy,
261                                     XtNmappedWhenManaged, False,
262                                     XtNvisual, visual,
263                                     XtNdepth, visual_depth (screen, visual),
264                                     XtNwidth, toplevel->core.width,
265                                     XtNheight, toplevel->core.height,
266                                     XtNcolormap, cmap,
267                                     XtNbackground, (Pixel) bg,
268                                     XtNborderColor, (Pixel) bd,
269                                     0);
270           XtDestroyWidget (toplevel);
271           toplevel = new;
272           XtRealizeWidget (toplevel);
273           window = XtWindow (toplevel);
274         }
275       else
276         {
277           XtVaSetValues (toplevel, XtNmappedWhenManaged, False, 0);
278           XtRealizeWidget (toplevel);
279           window = XtWindow (toplevel);
280
281           if (get_boolean_resource ("installColormap", "InstallColormap"))
282             {
283               cmap = XCreateColormap (dpy, window,
284                                    DefaultVisualOfScreen (XtScreen (toplevel)),
285                                       AllocNone);
286               XSetWindowColormap (dpy, window, cmap);
287             }
288           else
289             {
290               cmap = DefaultColormap (dpy, DefaultScreen (dpy));
291             }
292         }
293
294 /*
295       if (dont_map)
296         {
297           XtVaSetValues (toplevel, XtNmappedWhenManaged, False, 0);
298           XtRealizeWidget (toplevel);
299         }
300       else
301 */
302         {
303           XtPopup (toplevel, XtGrabNone);
304         }
305
306       XtVaSetValues(toplevel, XtNtitle, version, 0);
307     }
308
309   if (!dont_clear)
310     {
311       XSetWindowBackground (dpy, window,
312                             get_pixel_resource ("background", "Background",
313                                                 dpy, cmap));
314       XClearWindow (dpy, window);
315     }
316
317   if (!root_p)
318     /* wait for it to be mapped */
319     XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
320
321   XSync (dpy, False);
322   srandom ((int) time ((time_t *) 0));
323   screenhack (dpy, window); /* doesn't return */
324   return 0;
325 }