From http://www.jwz.org/xscreensaver/xscreensaver-5.30.tar.gz
[xscreensaver] / utils / resources.c
1 /* xscreensaver, Copyright (c) 1992-2014 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include "utils.h"
13 #include "resources.h"
14
15 extern char *progname;
16
17
18 #ifndef HAVE_COCOA
19
20 #include <X11/Xresource.h>
21
22 /* These are the Xlib/Xrm versions of these functions.
23    The Cocoa versions are on OSX/XScreenSaverView.m.
24  */
25
26 extern char *progclass;
27 extern XrmDatabase XtDatabase (Display *);
28
29 static unsigned int get_time_resource (Display *dpy, 
30                                        char *res_name, char *res_class,
31                                        Bool sec_p);
32
33 #ifndef isupper
34 # define isupper(c)  ((c) >= 'A' && (c) <= 'Z')
35 #endif
36 #ifndef _tolower
37 # define _tolower(c)  ((c) - 'A' + 'a')
38 #endif
39
40 char *
41 get_string_resource (Display *dpy, char *res_name, char *res_class)
42 {
43   XrmValue value;
44   char  *type;
45   char full_name [1024], full_class [1024];
46   strcpy (full_name, progname);
47   strcat (full_name, ".");
48   strcat (full_name, res_name);
49   strcpy (full_class, progclass);
50   strcat (full_class, ".");
51   strcat (full_class, res_class);
52   if (XrmGetResource (XtDatabase (dpy), full_name, full_class, &type, &value))
53     {
54       char *str = (char *) malloc (value.size + 1);
55       strncpy (str, (char *) value.addr, value.size);
56       str [value.size] = 0;
57       return str;
58     }
59   return 0;
60 }
61
62 Bool 
63 get_boolean_resource (Display *dpy, char *res_name, char *res_class)
64 {
65   char *tmp, buf [100];
66   char *s = get_string_resource (dpy, res_name, res_class);
67   char *os = s;
68   if (! s) return 0;
69   for (tmp = buf; *s; s++)
70     *tmp++ = isupper (*s) ? _tolower (*s) : *s;
71   *tmp = 0;
72   free (os);
73
74   while (*buf &&
75          (buf[strlen(buf)-1] == ' ' ||
76           buf[strlen(buf)-1] == '\t'))
77     buf[strlen(buf)-1] = 0;
78
79   if (!strcmp (buf, "on") || !strcmp (buf, "true") || !strcmp (buf, "yes"))
80     return 1;
81   if (!strcmp (buf,"off") || !strcmp (buf, "false") || !strcmp (buf,"no"))
82     return 0;
83   fprintf (stderr, "%s: %s must be boolean, not %s.\n",
84            progname, res_name, buf);
85   return 0;
86 }
87
88 int 
89 get_integer_resource (Display *dpy, char *res_name, char *res_class)
90 {
91   int val;
92   char c, *s = get_string_resource (dpy, res_name, res_class);
93   char *ss = s;
94   if (!s) return 0;
95
96   while (*ss && *ss <= ' ') ss++;                       /* skip whitespace */
97
98   if (ss[0] == '0' && (ss[1] == 'x' || ss[1] == 'X'))   /* 0x: parse as hex */
99     {
100       if (1 == sscanf (ss+2, "%x %c", (unsigned int *) &val, &c))
101         {
102           free (s);
103           return val;
104         }
105     }
106   else                                                  /* else parse as dec */
107     {
108       if (1 == sscanf (ss, "%d %c", &val, &c))
109         {
110           free (s);
111           return val;
112         }
113     }
114
115   fprintf (stderr, "%s: %s must be an integer, not %s.\n",
116            progname, res_name, s);
117   free (s);
118   return 0;
119 }
120
121 double
122 get_float_resource (Display *dpy, char *res_name, char *res_class)
123 {
124   double val;
125   char c, *s = get_string_resource (dpy, res_name, res_class);
126   if (! s) return 0.0;
127   if (1 == sscanf (s, " %lf %c", &val, &c))
128     {
129       free (s);
130       return val;
131     }
132   fprintf (stderr, "%s: %s must be a float, not %s.\n",
133            progname, res_name, s);
134   free (s);
135   return 0.0;
136 }
137
138 #endif /* !HAVE_COCOA */
139
140
141 /* These functions are the same with Xlib and Cocoa:
142  */
143
144
145 unsigned int
146 get_pixel_resource (Display *dpy, Colormap cmap,
147                     char *res_name, char *res_class)
148 {
149   XColor color;
150   char *s = get_string_resource (dpy, res_name, res_class);
151   char *s2;
152   Bool ok = True;
153   if (!s) goto DEFAULT;
154
155   for (s2 = s + strlen(s) - 1; s2 > s; s2--)
156     if (*s2 == ' ' || *s2 == '\t')
157       *s2 = 0;
158     else
159       break;
160
161   if (! XParseColor (dpy, cmap, s, &color))
162     {
163       fprintf (stderr, "%s: can't parse color %s", progname, s);
164       ok = False;
165       goto DEFAULT;
166     }
167   if (! XAllocColor (dpy, cmap, &color))
168     {
169       fprintf (stderr, "%s: couldn't allocate color %s", progname, s);
170       ok = False;
171       goto DEFAULT;
172     }
173   free (s);
174   return (unsigned int) color.pixel;
175  DEFAULT:
176   if (s) free (s);
177
178   {
179     Bool black_p = (strlen(res_class) >= 10 &&
180                     !strcasecmp ("Background",
181                                  res_class + strlen(res_class) - 10));
182     if (!ok)
183       fprintf (stderr, ": using %s.\n", (black_p ? "black" : "white"));
184     color.flags = DoRed|DoGreen|DoBlue;
185     color.red = color.green = color.blue = (black_p ? 0 : 0xFFFF);
186     if (XAllocColor (dpy, cmap, &color))
187       return (unsigned int) color.pixel;
188     else
189       {
190         fprintf (stderr, "%s: couldn't allocate %s either!\n", progname,
191                  (black_p ? "black" : "white"));
192         /* We can't use BlackPixel/WhitePixel here, because we don't know
193            what screen we're allocating on (only an issue when running inside
194            the xscreensaver daemon: for hacks, DefaultScreen is fine.)
195          */
196         return 0;
197       }
198   }
199 }
200
201
202 int
203 parse_time (const char *string, Bool seconds_default_p, Bool silent_p)
204 {
205   unsigned int h, m, s;
206   char c;
207   if (3 == sscanf (string,   " %u : %2u : %2u %c", &h, &m, &s, &c))
208     ;
209   else if (2 == sscanf (string, " : %2u : %2u %c", &m, &s, &c) ||
210            2 == sscanf (string,    " %u : %2u %c", &m, &s, &c))
211     h = 0;
212   else if (1 == sscanf (string,       " : %2u %c", &s, &c))
213     h = m = 0;
214   else if (1 == sscanf (string,          " %u %c",
215                         (seconds_default_p ? &s : &m), &c))
216     {
217       h = 0;
218       if (seconds_default_p) m = 0;
219       else s = 0;
220     }
221   else
222     {
223       if (! silent_p)
224         fprintf (stderr, "%s: invalid time interval specification \"%s\".\n",
225                  progname, string);
226       return -1;
227     }
228   if (s >= 60 && (h != 0 || m != 0))
229     {
230       if (! silent_p)
231         fprintf (stderr, "%s: seconds > 59 in \"%s\".\n", progname, string);
232       return -1;
233     }
234   if (m >= 60 && h > 0)
235     {
236       if (! silent_p)
237         fprintf (stderr, "%s: minutes > 59 in \"%s\".\n", progname, string);
238       return -1;
239     }
240   return ((h * 60 * 60) + (m * 60) + s);
241 }
242
243 static unsigned int 
244 get_time_resource (Display *dpy, char *res_name, char *res_class, Bool sec_p)
245 {
246   int val;
247   char *s = get_string_resource (dpy, res_name, res_class);
248   if (!s) return 0;
249   val = parse_time (s, sec_p, False);
250   free (s);
251   return (val < 0 ? 0 : val);
252 }
253
254 unsigned int 
255 get_seconds_resource (Display *dpy, char *res_name, char *res_class)
256 {
257   return get_time_resource (dpy, res_name, res_class, True);
258 }
259
260 unsigned int 
261 get_minutes_resource (Display *dpy, char *res_name, char *res_class)
262 {
263   return get_time_resource (dpy, res_name, res_class, False);
264 }
265
266
267 /* A utility function for event-handler functions:
268    Returns True if the event is a simple click, Space, Tab, etc.
269    Returns False otherwise.
270    The idea here is that most hacks interpret to clicks or basic
271    keypresses as "change it up".
272
273    This isn't really the right file for this, but whatever.
274  */
275 Bool
276 screenhack_event_helper (Display *dpy, Window window, XEvent *event)
277 {
278   if (event->xany.type == KeyPress)
279     {
280       KeySym keysym;
281       char c = 0;
282       XLookupString (&event->xkey, &c, 1, &keysym, 0);
283       if (c == ' ' || c == '\t' || c == '\r' || c == '\n' ||
284           keysym == XK_Left || keysym == XK_Right ||
285           keysym == XK_Up || keysym == XK_Down ||
286           keysym == XK_Prior || keysym == XK_Next)
287         return True;
288     }
289   else if (event->xany.type == ButtonPress)
290     {
291       if (event->xbutton.button == 1)
292         return True;
293     }
294
295   return False;
296 }