1 /* xscreensaver, Copyright (c) 1997, 2005 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 a kludge that lets xscreensaver work with SGI demos that expect
13 to be run from `haven'. It runs the program given on the command line,
14 then waits for an X window to be created whose name is that of the
15 program. Then, it resizes that window to fill the screen. Run it
18 xscreensaver-sgigl /usr/demos/bin/ep -S
19 xscreensaver-sgigl -n ant /usr/demos/General_Demos/ant/RUN
20 xscreensaver-sgigl -n atlantis /usr/demos/General_Demos/atlantis/RUN
21 xscreensaver-sgigl -n /usr/demos/General_Demos/powerflip/powerflip \
22 /usr/demos/General_Demos/powerflip/RUN
24 Except that doesn't really work. You have to do this instead:
26 xscreensaver-sgigl -n ant ant.sh
31 cd /usr/demos/General_Demos/ant
34 There's no way to make this work with powerflip at all, since it doesn't
35 take a -S option to run in the foreground.
38 /* #### Another way to do this would be:
39 instead of exec'ing the hack, fork it; then wait for that fork to die.
40 If it dies, but the window ID is still valid, then that means the
41 sub-process has forked itself (as those fuckwits at SGI are wont to do.)
42 In that case, this process should go to sleep, and set up a signal handler
43 that will destroy the X window when it is killed. That way, the caller
44 is given a foreground pid which, when killed, will cause the hack to die
45 (by a roundabout mechanism.)
47 This would all be so much simpler if those assholes would just:
49 1: get out of the habit of writing programs that magically background
52 2: give the fucking programs arguments which control the window size
53 instead of always making 100x100 windows!
55 I won't even dream of having a "-root" option that understood virtual-roots;
56 that would just be too outlandish to even dream about.
59 static char *progname;
67 #include <X11/Xutil.h>
68 #include <X11/Xmu/Error.h>
71 #undef RootWindowOfScreen
73 #undef DefaultRootWindow
77 BadWindow_ehandler (Display *dpy, XErrorEvent *error)
79 if (error->error_code == BadWindow ||
80 error->error_code == BadMatch ||
81 error->error_code == BadDrawable)
85 fprintf (stderr, "\nX error in %s:\n", progname);
86 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
89 fprintf (stderr, " (nonfatal.)\n");
96 main(int ac, char **av)
105 Bool verbose = False;
112 s = strrchr(progname, '/');
113 if (s) progname = s+1;
118 "usage: %s [ -v ] [ -n window-name ] program arguments...\n",
123 if (ac > 2 && !strcmp(av[1], "-v"))
130 if (ac > 2 && !strcmp(av[1], "-n"))
137 n1 = strrchr(av[1], '/');
142 dpy = XOpenDisplay(0);
145 fprintf(stderr, "%s: couldn't open display\n", progname);
149 screen = DefaultScreenOfDisplay(dpy);
150 root = XRootWindowOfScreen (screen);
151 vroot = VirtualRootWindowOfScreen (screen);
153 XSelectInput (dpy, root, SubstructureNotifyMask);
155 XSelectInput (dpy, vroot, SubstructureNotifyMask);
157 XSetErrorHandler (BadWindow_ehandler);
160 fprintf(stderr, "%s: selected SubstructureNotifyMask on 0x%x / 0x%x\n",
161 progname, root, vroot);
166 fprintf(stderr, "%s: pid is %d\n", progname, parent);
168 switch ((int) (forked = fork ()))
172 sprintf (buf, "%s: couldn't fork", progname);
179 time_t start = time((time_t) 0);
183 fprintf(stderr, "%s: forked pid is %d\n", progname, getpid());
187 XNextEvent(dpy, &event);
189 if (event.xany.type == CreateNotify)
192 Window w = event.xcreatewindow.window;
195 XFetchName(dpy, w, &name);
198 /* Try again to see if the name has been set later... */
201 XFetchName(dpy, w, &name);
205 ((n1 && !strcmp(name, n1)) ||
206 (n2 && !strcmp(name, n2))))
209 fprintf(stderr, "%s: resizing 0x%x\n", progname, w);
211 /* Make sure the window allows itself to be resized. */
212 XGetWMNormalHints (dpy, w, &h, &ls);
214 h.max_width = WidthOfScreen(screen)+128;
215 h.max_height = HeightOfScreen(screen)+128;
216 XSetWMNormalHints (dpy, w, &h);
218 XMoveResizeWindow(dpy, w, 0, 0,
219 WidthOfScreen(screen),
220 HeightOfScreen(screen));
223 if (vroot && vroot != root &&
224 event.xcreatewindow.parent == root)
228 "%s: reparenting 0x%x from 0x%x to 0x%x\n",
229 progname, w, root, vroot);
230 XReparentWindow(dpy, w, vroot, 0, 0);
237 exit(0); /* Note that this only exits a child fork. */
241 if (start + 5 < time((time_t) 0))
244 "%s: timed out: no window named \"%s\" has been created\n",
245 progname, (n2 ? n2 : n1));
248 kill(parent, SIGTERM);
254 default: /* foreground */
256 close (ConnectionNumber (dpy)); /* close display fd */
257 execvp (av[1], av+1); /* shouldn't return. */
258 sprintf (buf, "%s: execvp(\"%s\") failed", progname, av[1]);