Commit | Line | Data |
---|---|---|
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 | ||
15 | extern 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 | ||
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 && !HAVE_ANDROID */ | |
139 | ||
140 | ||
141 | /* These functions are the same with Xlib, Cocoa and Android: | |
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 | } |