1 /* xscreensaver, Copyright (c) 1991-1994 Jamie Zawinski <jwz@mcom.com>
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
14 /* ========================================================================
15 * First we wait until the keyboard and mouse become idle for the specified
16 * amount of time. We do this by periodically checking with the XIdle
19 * Then, we map a full screen black window.
21 * We place a __SWM_VROOT property on this window, so that newly-started
22 * clients will think that this window is a "virtual root" window.
24 * If there is an existing "virtual root" window (one that already had
25 * an __SWM_VROOT property) then we remove that property from that window.
26 * Otherwise, clients would see that window (the real virtual root) instead
27 * of ours (the impostor.)
29 * Then we pick a random program to run, and start it. Two assumptions
30 * are made about this program: that it has been specified with whatever
31 * command-line options are necessary to make it run on the root window;
32 * and that it has been compiled with vroot.h, so that it is able to find
33 * the root window when a virtual-root window manager (or this program) is
36 * Then, we wait for keyboard or mouse events to be generated on the window.
37 * When they are, we kill the inferior process, unmap the window, and restore
38 * the __SWM_VROOT property to the real virtual root window if there was one.
40 * While we are waiting, we also set up timers so that, after a certain
41 * amount of time has passed, we can start a different screenhack. We do
42 * this by killing the running child process with SIGTERM, and then starting
43 * a new one in the same way.
45 * If there was a real virtual root, meaning that we removed the __SWM_VROOT
46 * property from it, meaning we must (absolutely must) restore it before we
47 * exit, then we set up signal handlers for most signals (SIGINT, SIGTERM,
48 * etc.) that do this. Most Xlib and Xt routines are not reentrant, so it
49 * is not generally safe to call them from signal handlers; however, this
50 * program spends most of its time waiting, so the window of opportunity
51 * when code could be called reentrantly is fairly small; and also, the worst
52 * that could happen is that the call would fail. If we've gotten one of
53 * these signals, then we're on our way out anyway. If we didn't restore the
54 * __SWM_VROOT property, that would be very bad, so it's worth a shot. Note
55 * that this means that, if you're using a virtual-root window manager, you
56 * can really fuck up the world by killing this process with "kill -9".
58 * This program accepts ClientMessages of type SCREENSAVER; these messages
59 * may contain the atom ACTIVATE or DEACTIVATE, meaning to turn the
60 * screensaver on or off now, regardless of the idleness of the user,
61 * and a few other things. The included "xscreensaver_command" program
62 * sends these messsages.
64 * If we don't have the XIdle extension, then we do the XAutoLock trick:
65 * notice every window that gets created, and wait 30 seconds or so until
66 * its creating process has settled down, and then select KeyPress events on
67 * those windows which already select for KeyPress events. It's important
68 * that we not select KeyPress on windows which don't select them, because
69 * that would interfere with event propagation. This will break if any
70 * program changes its event mask to contain KeyRelease or PointerMotion
71 * more than 30 seconds after creating the window, but that's probably
74 * The reason that we can't select KeyPresses on windows that don't have
75 * them already is that, when dispatching a KeyPress event, X finds the
76 * lowest (leafmost) window in the hierarchy on which *any* client selects
77 * for KeyPress, and sends the event to that window. This means that if a
78 * client had a window with subwindows, and expected to receive KeyPress
79 * events on the parent window instead of the subwindows, then that client
80 * would malfunction if some other client selected KeyPress events on the
81 * subwindows. It is an incredible misdesign that one client can make
82 * another client malfunction in this way.
84 * To detect mouse motion, we periodically wake up and poll the mouse
85 * position and button/modifier state, and notice when something has
86 * changed. We make this check every five seconds by default, and since the
87 * screensaver timeout has a granularity of one minute, this makes the
88 * chance of a false positive very small. We could detect mouse motion in
89 * the same way as keyboard activity, but that would suffer from the same
90 * "client changing event mask" problem that the KeyPress events hack does.
91 * I think polling is more reliable.
93 * None of this crap happens if we're using the XIdle extension, so install
94 * it if the description above sounds just too flaky to live. It is, but
95 * those are your choices.
97 * A third idle-detection option could be implement (but is not): when running
98 * on the console display ($DISPLAY is `localhost`:0) and we're on a machine
99 * where /dev/tty and /dev/mouse have reasonable last-modification times, we
100 * could just stat those. But the incremental benefit of implementing this
101 * is really small, so forget I said anything.
104 * - Have a second terminal handy.
105 * - Be careful where you set your breakpoints, you don't want this to
106 * stop under the debugger with the keyboard grabbed or the blackout
108 * - you probably can't set breakpoints in functions that are called on
109 * the other side of a call to fork() -- if your clients are dying
110 * with signal 5, Trace/BPT Trap, you're losing in this way.
111 * - If you aren't using XIdle, don't leave this stopped under the
112 * debugger for very long, or the X input buffer will get huge because
113 * of the keypress events it's selecting for. This can make your X
114 * server wedge with "no more input buffers."
116 * ========================================================================
125 #include <X11/Xlib.h>
126 #include <X11/Xatom.h>
127 #include <X11/Intrinsic.h>
131 #include <X11/extensions/xidle.h>
134 #include "xscreensaver.h"
136 #if defined(SVR4) || defined(SYSV) || defined(VMS)
137 # define srandom(i) srand((unsigned int)(i))
140 extern void srandom P((int)); /* srand() is in stdlib.h... */
144 extern char *get_string_resource P((char *, char *));
145 extern Bool get_boolean_resource P((char *, char *));
146 extern int get_integer_resource P((char *, char *));
147 extern unsigned int get_minutes_resource P((char *, char *));
148 extern unsigned int get_seconds_resource P((char *, char *));
150 extern Visual *get_visual_resource P((Display *, char *, char *));
151 extern int get_visual_depth P((Display *, Visual *));
153 extern void notice_events_timer P((XtPointer closure, void *timer));
154 extern void cycle_timer P((void *junk1, XtPointer junk2));
155 extern void activate_lock_timer P((void *junk1, XtPointer junk2));
156 extern void sleep_until_idle P((Bool until_idle_p));
158 extern void ensure_no_screensaver_running P((void));
159 extern void initialize_screensaver_window P((void));
160 extern void disable_builtin_screensaver P((void));
162 extern void hack_environment P((void));
163 extern void grab_keyboard_and_mouse P((void));
164 extern void ungrab_keyboard_and_mouse P((void));
166 extern void save_argv P((int argc, char **argv));
169 char *screensaver_version;
181 Widget toplevel_shell;
188 extern Time passwd_timeout;
190 extern Time pointer_timeout;
191 extern Time notice_events_timeout;
192 extern XtIntervalId lock_id, cycle_id;
196 Bool lock_p, locked_p;
198 extern char **screenhacks;
199 extern int screenhacks_count;
201 extern int nice_inferior;
202 extern Window screensaver_window;
203 extern Cursor cursor;
204 extern Colormap cmap, cmap2;
205 extern Bool fade_p, unfade_p;
206 extern int fade_seconds, fade_ticks;
207 extern Bool install_cmap_p;
208 extern Bool locking_disabled_p;
209 extern char *nolock_reason;
210 extern Bool demo_mode_p;
211 extern Bool dbox_up_p;
212 extern int next_mode_p;
214 static time_t initial_delay;
216 extern Atom XA_VROOT, XA_XSETROOT_ID;
217 extern Atom XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
219 static Atom XA_SCREENSAVER;
220 static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
221 static Atom XA_EXIT, XA_RESTART, XA_DEMO, XA_LOCK;
223 #ifdef NO_MOTIF /* kludge */
224 Bool demo_mode_p = 0;
227 Time passwd_timeout = 0;
233 # define demo_mode() abort()
235 extern void demo_mode P((void));
238 static XrmOptionDescRec options [] = {
239 { "-timeout", ".timeout", XrmoptionSepArg, 0 },
240 { "-idelay", ".initialDelay",XrmoptionSepArg, 0 },
241 { "-cycle", ".cycle", XrmoptionSepArg, 0 },
242 { "-visual", ".visualID", XrmoptionSepArg, 0 },
243 { "-lock-timeout", ".lockTimeout", XrmoptionSepArg, 0 },
244 { "-verbose", ".verbose", XrmoptionNoArg, "on" },
245 { "-silent", ".verbose", XrmoptionNoArg, "off" },
246 { "-xidle", ".xidle", XrmoptionNoArg, "on" },
247 { "-no-xidle", ".xidle", XrmoptionNoArg, "off" },
248 { "-lock", ".lock", XrmoptionNoArg, "on" },
249 { "-no-lock", ".lock", XrmoptionNoArg, "off" }
252 static char *defaults[] = {
254 #include "XScreenSaver.ad.h"
256 #include "XScreenSaver_ad.h"
265 xscreensaver %s, copyright (c) 1991-1994 by Jamie Zawinski <jwz@mcom.com>.\n\
266 The standard Xt command-line options are accepted; other options include:\n\
268 -timeout <minutes> when the screensaver should activate\n\
269 -cycle <minutes> how long to let each hack run\n\
270 -idelay <seconds> how long to sleep before startup\n\
271 -demo enter interactive demo mode on startup\n\
274 -xidle use the XIdle server extension\n\
276 -lock require a password before deactivating\n\
278 -lock-timeout <minutes> grace period before locking; default 0\n\
279 -help this message\n\
281 Use the `xscreensaver-command' program to control a running screensaver.\n\
283 The *programs, *colorPrograms, and *monoPrograms resources control which\n\
284 graphics demos will be launched by the screensaver. See the man page for\n\
286 screensaver_version);
289 printf("Support for locking was not enabled at compile-time.\n");
292 printf("Support for demo mode was not enabled at compile-time.\n");
295 printf("Support for the XIdle extension was not enabled at compile-time.\n");
304 get_screenhacks P((void))
307 int i, hacks_size = 10;
309 data[0] = get_string_resource ("programs", "Programs");
310 data[1] = ((CellsOfScreen (screen) <= 2)
311 ? get_string_resource ("monoPrograms", "MonoPrograms")
312 : get_string_resource ("colorPrograms", "ColorPrograms"));
314 if (! data[0]) data[0] = data[1], data[1] = 0;
316 screenhacks = (char **) malloc (sizeof (char *) * hacks_size);
317 screenhacks_count = 0;
319 for (i = 0; data[i]; i++)
323 int size = strlen (d);
327 if (d[j] == ' ' || d[j] == '\t' || d[j] == '\n' || d[j] == 0)
332 if (hacks_size <= screenhacks_count)
333 screenhacks = (char **) realloc (screenhacks,
334 (hacks_size = hacks_size * 2) *
336 screenhacks [screenhacks_count++] = d + j;
337 while (d[j] != 0 && d[j] != '\n')
340 while (j > start && (d[j-1] == ' ' || d[j-1] == '\t'))
347 /* shrink all whitespace to one space, for the benefit of the "demo"
348 mode display. We only do this when we can easily tell that the
349 whitespace is not significant (no shell metachars).
351 for (i = 0; i < screenhacks_count; i++)
353 char *s = screenhacks [i];
357 for (j = 0; j < L; j++)
361 case '\'': case '"': case '`': case '\\':
367 for (s2 = s+j+1; *s2 == ' ' || *s2 == '\t'; s2++)
370 for (s2 = s + j + 1; *s2; s2++)
379 if (screenhacks_count)
381 /* Shrink down the screenhacks array to be only as big as it needs to.
382 This doesn't really matter at all. */
383 screenhacks = (char **)
384 realloc (screenhacks, ((screenhacks_count + 1) * sizeof(char *)));
385 screenhacks [screenhacks_count] = 0;
396 get_resources P((void))
398 /* Note: we can't use the resource ".visual" because Xt is SO FUCKED. */
399 visual = get_visual_resource (dpy, "visualID", "VisualID");
400 timeout = 1000 * get_minutes_resource ("timeout", "Time");
401 cycle = 1000 * get_minutes_resource ("cycle", "Time");
402 lock_timeout = 1000 * get_minutes_resource ("lockTimeout", "Time");
403 nice_inferior = get_integer_resource ("nice", "Nice");
404 verbose_p = get_boolean_resource ("verbose", "Boolean");
405 lock_p = get_boolean_resource ("lock", "Boolean");
406 install_cmap_p = get_boolean_resource ("installColormap", "Boolean");
407 fade_p = get_boolean_resource ("fade", "Boolean");
408 unfade_p = get_boolean_resource ("unfade", "Boolean");
409 fade_seconds = get_seconds_resource ("fadeSeconds", "Time");
410 fade_ticks = get_integer_resource ("fadeTicks", "Integer");
411 shell = get_string_resource ("bourneShell", "BourneShell");
412 initial_delay = get_seconds_resource ("initialDelay", "Time");
413 pointer_timeout = 1000 * get_seconds_resource ("pointerPollTime", "Time");
414 notice_events_timeout = 1000 * get_seconds_resource ("windowCreationTimeout",
417 passwd_timeout = 1000 * get_seconds_resource ("passwdTimeout", "Time");
418 if (passwd_timeout == 0) passwd_timeout = 30000;
420 if (timeout < 10000) timeout = 10000;
421 if (cycle != 0 && cycle < 2000) cycle = 2000;
422 if (pointer_timeout == 0) pointer_timeout = 5000;
423 if (notice_events_timeout == 0) notice_events_timeout = 10000;
424 if (fade_seconds == 0 || fade_ticks == 0) fade_p = False;
425 if (! fade_p) unfade_p = False;
427 visual_depth = get_visual_depth (dpy, visual);
429 if (visual_depth <= 1 || CellsOfScreen (screen) <= 2)
430 install_cmap_p = False;
433 locking_disabled_p = True;
434 nolock_reason = "not compiled with locking support";
438 fprintf (stderr, "%s: %snot compiled with support for locking.\n",
439 progname, (verbose_p ? "## " : ""));
441 #else /* ! NO_LOCKING */
442 if (lock_p && locking_disabled_p)
444 fprintf (stderr, "%s: %slocking is disabled (%s).\n", progname,
445 (verbose_p ? "## " : ""), nolock_reason);
448 #endif /* ! NO_LOCKING */
450 /* don't set use_xidle unless it is explicitly specified */
451 if (get_string_resource ("xidle", "Boolean"))
452 use_xidle = get_boolean_resource ("xidle", "Boolean");
454 #ifdef HAVE_XIDLE /* pick a default */
465 long now = time ((time_t *) 0);
466 char *str = (char *) ctime (&now);
467 char *nl = (char *) strchr (str, '\n');
468 if (nl) *nl = 0; /* take off that dang newline */
474 # define hack_uid_warn()
475 #else /* !NO_SETUID */
476 extern void hack_uid P((void));
477 extern void hack_uid_warn P((void));
478 #endif /* NO_SETUID */
482 extern Bool unlock_p P((Widget));
483 extern Bool lock_init P((void));
486 static void initialize P((int argc, char **argv));
487 static void main_loop P((void));
498 initialize (argc, argv);
505 initialize_connection (int argc, char **argv)
507 initialize_connection (argc, argv)
512 toplevel_shell = XtAppInitialize (&app, progclass,
513 options, XtNumber (options),
514 &argc, argv, defaults, 0, 0);
516 dpy = XtDisplay (toplevel_shell);
517 screen = XtScreen (toplevel_shell);
518 db = XtDatabase (dpy);
519 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
521 if (argc == 2 && !strcmp (argv[1], "-help"))
525 fprintf (stderr, "%s: unknown option %s\n", progname, argv [1]);
531 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
532 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
533 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION", False);
534 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
535 XA_XSETROOT_ID = XInternAtom (dpy, "_XSETROOT_ID", False);
536 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
537 XA_DEACTIVATE = XInternAtom (dpy, "DEACTIVATE", False);
538 XA_RESTART = XInternAtom (dpy, "RESTART", False);
539 XA_CYCLE = XInternAtom (dpy, "CYCLE", False);
540 XA_NEXT = XInternAtom (dpy, "NEXT", False);
541 XA_PREV = XInternAtom (dpy, "PREV", False);
542 XA_EXIT = XInternAtom (dpy, "EXIT", False);
543 XA_DEMO = XInternAtom (dpy, "DEMO", False);
544 XA_LOCK = XInternAtom (dpy, "LOCK", False);
547 extern void init_sigchld P((void));
550 initialize (argc, argv)
554 Bool initial_demo_mode_p = False;
555 screensaver_version = (char *) malloc (5);
556 memcpy (screensaver_version, screensaver_id + 17, 4);
557 screensaver_version [4] = 0;
558 progname = argv[0]; /* reset later; this is for the benefit of lock_init() */
561 locking_disabled_p = True;
562 nolock_reason = "not compiled with locking support";
564 locking_disabled_p = False;
565 if (! lock_init ()) /* before hack_uid() for proper permissions */
567 locking_disabled_p = True;
568 nolock_reason = "error getting password";
573 progclass = "XScreenSaver";
575 /* remove -demo switch before saving argv */
578 for (i = 1; i < argc; i++)
579 while (!strcmp ("-demo", argv [i]))
582 initial_demo_mode_p = True;
583 for (j = i; j < argc; j++)
584 argv [j] = argv [j+1];
587 if (argc <= i) break;
590 save_argv (argc, argv);
591 initialize_connection (argc, argv);
592 ensure_no_screensaver_running ();
596 %s %s, copyright (c) 1991-1994 by Jamie Zawinski <jwz@mcom.com>.\n\
597 pid = %d.\n", progname, screensaver_version, getpid ());
598 ensure_no_screensaver_running ();
600 demo_mode_p = initial_demo_mode_p;
601 screensaver_window = 0;
603 initialize_screensaver_window ();
604 srandom ((int) time ((time_t *) 0));
612 int first_event, first_error;
613 if (! XidleQueryExtension (dpy, &first_event, &first_error))
616 "%s: display %s does not support the XIdle extension.\n",
617 progname, DisplayString (dpy));
621 fprintf (stderr, "%s: not compiled with support for XIdle.\n",
629 disable_builtin_screensaver ();
631 if (initial_demo_mode_p)
632 /* If the user wants demo mode, don't wait around before doing it. */
643 printf ("%s: waiting for %d second%s...", progname,
644 initial_delay, (initial_delay == 1 ? "" : "s"));
647 sleep (initial_delay);
653 printf ("%s: selecting events on extant windows...", progname);
656 notice_events_timer ((XtPointer)
657 RootWindowOfScreen (XtScreen (toplevel_shell)),
665 extern void suspend_screenhack P((Bool suspend_p));
673 sleep_until_idle (True);
680 printf ("%s: user is idle; waking up at %s.\n", progname,
683 spawn_screenhack (True);
685 cycle_id = XtAppAddTimeOut (app, cycle, (XtPointer)cycle_timer, 0);
688 if (lock_p && lock_timeout == 0)
690 if (lock_p && !locked_p)
691 /* locked_p might be true already because of ClientMessage */
692 lock_id = XtAppAddTimeOut (app,lock_timeout,
693 (XtPointer)activate_lock_timer,0);
698 sleep_until_idle (False); /* until not idle */
704 if (locking_disabled_p) abort ();
707 /* We used to ungrab the keyboard here, before calling unlock_p()
708 to pop up the dialog box. This left the keyboard ungrabbed
709 for a small window, during an insecure state. Bennett Todd
710 was seeing the bahavior that, when the load was high, he could
711 actually get characters through to a shell under the saver
712 window (he accidentally typed his password there...)
714 So the ungrab has been moved down into pop_passwd_dialog()
715 just after the server is grabbed, closing this window
718 /* ungrab_keyboard_and_mouse (); */
720 suspend_screenhack (True);
721 XUndefineCursor (dpy, screensaver_window);
723 printf ("%s: prompting for password.\n", progname);
724 val = unlock_p (toplevel_shell);
725 if (verbose_p && val == False)
726 printf ("%s: password incorrect!\n", progname);
728 XDefineCursor (dpy, screensaver_window, cursor);
729 suspend_screenhack (False);
731 /* I think this grab is now redundant, but it shouldn't hurt. */
732 grab_keyboard_and_mouse ();
743 XtRemoveTimeOut (cycle_id);
749 XtRemoveTimeOut (lock_id);
754 printf ("%s: user is active; going to sleep at %s.\n", progname,
763 handle_clientmessage (event, until_idle_p)
768 if (event->xclient.message_type != XA_SCREENSAVER)
771 str = XGetAtomName (dpy, event->xclient.message_type);
772 fprintf (stderr, "%s: %sunrecognised ClientMessage type %s received\n",
773 progname, (verbose_p ? "## " : ""),
774 (str ? str : "(null)"));
775 if (str) XFree (str);
777 if (event->xclient.format != 32)
779 fprintf (stderr, "%s: %sClientMessage of format %d received, not 32\n",
780 progname, (verbose_p ? "## " : ""), event->xclient.format);
782 type = event->xclient.data.l[0];
783 if (type == XA_ACTIVATE)
788 printf ("%s: ACTIVATE ClientMessage received.\n", progname);
792 "%s: %sClientMessage ACTIVATE received while already active.\n",
793 progname, (verbose_p ? "## " : ""));
795 else if (type == XA_DEACTIVATE)
800 printf ("%s: DEACTIVATE ClientMessage received.\n", progname);
804 "%s: %sClientMessage DEACTIVATE received while inactive.\n",
805 progname, (verbose_p ? "## " : ""));
807 else if (type == XA_CYCLE)
812 printf ("%s: CYCLE ClientMessage received.\n", progname);
814 XtRemoveTimeOut (cycle_id);
820 "%s: %sClientMessage CYCLE received while inactive.\n",
821 progname, (verbose_p ? "## " : ""));
823 else if (type == XA_NEXT || type == XA_PREV)
826 printf ("%s: %s ClientMessage received.\n", progname,
827 (type == XA_NEXT ? "NEXT" : "PREV"));
828 next_mode_p = 1 + (type == XA_PREV);
833 XtRemoveTimeOut (cycle_id);
840 else if (type == XA_EXIT)
842 /* Ignore EXIT message if the screen is locked. */
843 if (until_idle_p || !locked_p)
846 printf ("%s: EXIT ClientMessage received.\n", progname);
856 fprintf (stderr, "%s: %sEXIT ClientMessage received while locked.\n",
857 progname, (verbose_p ? "## " : ""));
859 else if (type == XA_RESTART)
861 /* The RESTART message works whether the screensaver is active or not,
862 unless the screen is locked, in which case it doesn't work.
864 if (until_idle_p || !locked_p)
867 printf ("%s: RESTART ClientMessage received.\n", progname);
877 fprintf(stderr, "%s: %sRESTART ClientMessage received while locked.\n",
878 progname, (verbose_p ? "## " : ""));
880 else if (type == XA_DEMO)
884 "%s: %snot compiled with support for DEMO mode\n",
885 progname, (verbose_p ? "## " : ""));
890 printf ("%s: DEMO ClientMessage received.\n", progname);
895 "%s: %sDEMO ClientMessage received while active.\n",
896 progname, (verbose_p ? "## " : ""));
899 else if (type == XA_LOCK)
902 fprintf (stderr, "%s: %snot compiled with support for LOCK mode\n",
903 progname, (verbose_p ? "## " : ""));
905 if (locking_disabled_p)
907 "%s: %sLOCK ClientMessage received, but locking is disabled.\n",
908 progname, (verbose_p ? "## " : ""));
911 "%s: %sLOCK ClientMessage received while already locked.\n",
912 progname, (verbose_p ? "## " : ""));
917 printf ("%s: LOCK ClientMessage received;%s locking.\n",
918 progname, until_idle_p ? " activating and" : "");
920 if (lock_id) /* we're doing it now, so lose the timeout */
922 XtRemoveTimeOut (lock_id);
934 str = XGetAtomName (dpy, type);
937 "%s: %sunrecognised screensaver ClientMessage %s received\n",
938 progname, (verbose_p ? "## " : ""), str);
941 "%s: %sunrecognised screensaver ClientMessage 0x%x received\n",
942 progname, (verbose_p ? "## " : ""),
943 event->xclient.data.l[0]);
944 if (str) XFree (str);