1 /* xscreensaver, Copyright (c) 2006 Jamie Zawinski <jwz@jwz.org>
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
12 /* This is the Cocoa shim for webcollage.
14 It runs the webcollage perl script
15 (in "WebCollage.saver/Contents/Resources/webcollage")
16 at the end of a pipe; each time that script updates the image file on
17 disk it prints the file name, and this program loads and displays that
20 The script uses "WebCollage.saver/Contents/Resources/webcollage-helper"
21 to paste the images together in the usual way.
27 #import <Cocoa/Cocoa.h>
29 #include "screenhack.h"
35 XWindowAttributes xgwa;
45 subproc_cb (XtPointer closure, int *source, XtInputId *id)
47 /* state *st = (state *) closure; */
48 /* st->input_available_p = True; */
52 /* whether there is data available to be read on the file descriptor
55 input_available_p (int fd)
57 struct timeval tv = { 0, };
60 /* This breaks on BSD, which uses bzero() in the definition of FD_ZERO */
63 memset (&fds, 0, sizeof(fds));
66 return select (fd+1, &fds, NULL, NULL, &tv);
71 display_image (state *st, const char *file)
73 NSImage *image = [[NSImage alloc]
74 initWithContentsOfFile:
75 [NSString stringWithCString: file
76 encoding: kCFStringEncodingUTF8]];
79 fprintf (stderr, "%s: failed to load \"%s\"\n", progname, file);
83 [image drawAtPoint: NSMakePoint (0, 0)
84 fromRect: NSMakeRect (0, 0, [image size].width, [image size].height)
85 operation: NSCompositeCopy
94 /* This mess is because popen() doesn't give us the pid.
105 int timeout = get_integer_resource (st->dpy, "timeout", "Timeout");
106 int delay = get_integer_resource (st->dpy, "delay", "Delay");
107 float opacity = get_float_resource (st->dpy, "opacity", "Opacity");
108 char *filter = get_string_resource (st->dpy, "filter", "Filter");
109 char *filter2 = get_string_resource (st->dpy, "filter2", "Filter2");
111 av[ac++] = "webcollage";
115 sprintf (buf, "%dx%d", st->xgwa.width, st->xgwa.height);
116 av[ac++] = strdup (buf);
118 av[ac++] = "-timeout"; sprintf (buf, "%d", timeout);
119 av[ac++] = strdup (buf);
120 av[ac++] = "-delay"; sprintf (buf, "%d", delay);
121 av[ac++] = strdup (buf);
122 av[ac++] = "-opacity"; sprintf (buf, "%.2f", opacity);
123 av[ac++] = strdup (buf);
125 if (filter && *filter) {
126 av[ac++] = "-filter";
129 if (filter2 && *filter2) {
130 av[ac++] = "-filter2";
138 fprintf (stderr, "%s: launching:", progname);
140 for (i = 0; i < ac; i++)
141 fprintf (stderr, " %s", av[i]);
142 fprintf (stderr, "\n");
148 perror ("error creating pipe:");
155 switch ((int) (forked = fork ()))
159 sprintf (buf, "%s: couldn't fork", progname);
167 close (in); /* don't need this one */
169 if (dup2 (out, stdout_fd) < 0) /* pipe stdout */
171 perror ("could not dup() a new stdout:");
175 execvp (av[0], av); /* shouldn't return. */
179 /* Ignore "no such file or directory" errors, unless verbose.
180 Issue all other exec errors, though. */
181 sprintf (buf, "%s: %s", progname, av[0]);
185 exit (1); /* exits fork */
190 st->pipe_fd = fdopen (in, "r");
191 close (out); /* don't need this one */
195 if (! st->pipe_fd) abort();
199 XtAppAddInput (XtDisplayToApplicationContext (st->dpy),
200 fileno (st->pipe_fd),
201 (XtPointer) (XtInputReadMask | XtInputExceptMask),
202 subproc_cb, (XtPointer) st);
205 fprintf (stderr, "%s: subprocess pid: %d\n", progname, st->pid);
210 webcollage_init (Display *dpy, Window window)
212 state *st = (state *) calloc (1, sizeof(*st));
215 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
217 st->delay = 1000000; /* check once a second */
226 webcollage_draw (Display *dpy, Window window, void *closure)
228 state *st = (state *) closure;
233 if (! input_available_p (fileno (st->pipe_fd)))
237 int n = read (fileno (st->pipe_fd),
242 XtRemoveInput (st->pipe_id);
244 // #### sometimes hangs -- pclose (st->pipe_fd);
248 fprintf (stderr, "%s: subprocess has exited: bailing.\n", progname);
250 return st->delay * 10;
254 char *s = strchr (buf, '\n');
257 const char *target = "COCOA LOAD ";
258 if (!strncmp (target, buf, strlen(target))) {
259 const char *file = buf + strlen(target);
260 display_image (st, file);
268 webcollage_reshape (Display *dpy, Window window, void *closure,
269 unsigned int w, unsigned int h)
275 webcollage_event (Display *dpy, Window window, void *closure, XEvent *event)
282 webcollage_free (Display *dpy, Window window, void *closure)
284 state *st = (state *) closure;
286 // Dammit dammit dammit! Why won't this shit die when we pclose it!
287 // killpg (0, SIGTERM);
291 fprintf (stderr, "%s: kill %d\n", progname, st->pid);
292 if (kill (st->pid, SIGTERM) < 0) {
293 fprintf (stderr, "%s: kill (%d, TERM): ", progname, st->pid);
300 XtRemoveInput (st->pipe_id);
303 fclose (st->pipe_fd);
309 waitpid (-1, &wait_status, 0);
315 static const char *webcollage_defaults [] = {
316 ".background: black",
317 ".foreground: white",
327 static XrmOptionDescRec webcollage_options [] = {
328 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
329 { "-delay", ".delay", XrmoptionSepArg, 0 },
330 { "-opacity", ".opacity", XrmoptionSepArg, 0 },
331 { "-filter", ".filter", XrmoptionSepArg, 0 },
332 { "-filter2", ".filter2", XrmoptionSepArg, 0 },
337 XSCREENSAVER_MODULE ("WebCollage", webcollage)