Added missing newline in NEDsim error message.
[screensavers] / screenhack / resources.c
CommitLineData
3144ee8a
AT
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
15extern char *progname;
16
17
18#if !defined(HAVE_COCOA) && !defined(HAVE_ANDROID)
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
26extern char *progclass;
27extern XrmDatabase XtDatabase (Display *);
28
29static 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
40char *
41get_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
62Bool
63get_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
88int
89get_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
121double
122get_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 && !HAVE_ANDROID */
139
140
141/* These functions are the same with Xlib, Cocoa and Android:
142 */
143
144
145unsigned int
146get_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
202int
203parse_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
243static unsigned int
244get_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
254unsigned int
255get_seconds_resource (Display *dpy, char *res_name, char *res_class)
256{
257 return get_time_resource (dpy, res_name, res_class, True);
258}
259
260unsigned int
261get_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 */
275Bool
276screenhack_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}