1 /* xscreensaver, Copyright (c) 1992-2010 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
11 * And remember: X Windows is to graphics hacking as roman numerals are to
12 * the square root of pi.
15 /* This file contains simple code to open a window or draw on the root.
16 The idea being that, when writing a graphics hack, you can just link
17 with this .o to get all of the uninteresting junk out of the way.
19 Create a few static global procedures and variables:
21 static void *YOURNAME_init (Display *, Window);
23 Return an opaque structure representing your drawing state.
25 static unsigned long YOURNAME_draw (Display *, Window, void *closure);
28 The `closure' arg is your drawing state, that you created in `init'.
29 Return the number of microseconds to wait until the next frame.
31 This should return in some small fraction of a second.
32 Do not call `usleep' or loop excessively. For long loops, use a
35 static void YOURNAME_reshape (Display *, Window, void *closure,
36 unsigned int width, unsigned int height);
38 Called when the size of the window changes with the new size.
40 static Bool YOURNAME_event (Display *, Window, void *closure,
43 Called when a keyboard or mouse event arrives.
44 Return True if you handle it in some way, False otherwise.
46 static void YOURNAME_free (Display *, Window, void *closure);
48 Called when you are done: free everything you've allocated,
49 including your private `state' structure.
51 NOTE: this is called in windowed-mode when the user typed
52 'q' or clicks on the window's close box; but when
53 xscreensaver terminates this screenhack, it does so by
54 killing the process with SIGSTOP. So this callback is
57 static char YOURNAME_defaults [] = { "...", "...", ... , 0 };
59 This variable is an array of strings, your default resources.
60 Null-terminate the list.
62 static XrmOptionDescRec YOURNAME_options[] = { { ... }, ... { 0,0,0,0 } }
64 This variable describes your command-line options.
65 Null-terminate the list.
67 Finally , invoke the XSCREENSAVER_MODULE() macro to tie it all together.
71 - Make sure that all functions in your module are static (check this
72 by running "nm -g" on the .o file).
74 - Do not use global variables: all such info must be stored in the
75 private `state' structure.
77 - Do not use static function-local variables, either. Put it in `state'.
79 Assume that there are N independent runs of this code going in the
80 same address space at the same time: they must not affect each other.
82 - Don't forget to write an XML file to describe the user interface
83 of your screen saver module. See .../hacks/config/README for details.
89 #include <X11/Intrinsic.h>
90 #include <X11/IntrinsicP.h>
91 #include <X11/CoreP.h>
92 #include <X11/Shell.h>
93 #include <X11/StringDefs.h>
94 #include <X11/keysym.h>
95 /* #include <libosso.h> */
96 #include <dbus/dbus.h>
97 #include <dbus/dbus-glib.h>
100 # include <X11/SGIScheme.h> /* for SgiUseSchemes() */
105 # include <X11/Xmu/Error.h>
107 # include <Xmu/Error.h>
113 #include "screenhackI.h"
118 #ifndef _XSCREENSAVER_VROOT_H_
119 # error Error! You have an old version of vroot.h! Check -I args.
120 #endif /* _XSCREENSAVER_VROOT_H_ */
123 # define isupper(c) ((c) >= 'A' && (c) <= 'Z')
126 # define _tolower(c) ((c) - 'A' + 'a')
130 /* This is defined by the SCREENHACK_MAIN() macro via screenhack.h.
132 extern struct xscreensaver_function_table *xscreensaver_function_table;
135 const char *progname; /* used by hacks in error messages */
136 const char *progclass; /* used by ../utils/resources.c */
137 Bool mono_p; /* used by hacks */
140 static XrmOptionDescRec default_options [] = {
141 { "-root", ".root", XrmoptionNoArg, "True" },
142 { "-window", ".root", XrmoptionNoArg, "False" },
143 { "-mono", ".mono", XrmoptionNoArg, "True" },
144 { "-install", ".installColormap", XrmoptionNoArg, "True" },
145 { "-noinstall",".installColormap", XrmoptionNoArg, "False" },
146 { "-visual", ".visualID", XrmoptionSepArg, 0 },
147 { "-window-id", ".windowID", XrmoptionSepArg, 0 },
148 { "-fps", ".doFPS", XrmoptionNoArg, "True" },
149 { "-no-fps", ".doFPS", XrmoptionNoArg, "False" },
152 { "-pair", ".pair", XrmoptionNoArg, "True" },
153 # endif /* DEBUG_PAIR */
157 static char *default_defaults[] = {
159 "*geometry: 600x480", /* this should be .geometry, but nooooo... */
161 "*installColormap: false",
163 "*visualID: default",
165 "*desktopGrabber: xscreensaver-getimage %s",
169 static XrmOptionDescRec *merged_options;
170 static int merged_options_size;
171 static char **merged_defaults;
177 struct xscreensaver_function_table *ft = xscreensaver_function_table;
179 const XrmOptionDescRec *options = ft->options;
180 const char * const *defaults = ft->defaults;
181 const char *progclass = ft->progclass;
183 int def_opts_size, opts_size;
184 int def_defaults_size, defaults_size;
186 for (def_opts_size = 0; default_options[def_opts_size].option;
189 for (opts_size = 0; options[opts_size].option; opts_size++)
192 merged_options_size = def_opts_size + opts_size;
193 merged_options = (XrmOptionDescRec *)
194 malloc ((merged_options_size + 1) * sizeof(*default_options));
195 memcpy (merged_options, default_options,
196 (def_opts_size * sizeof(*default_options)));
197 memcpy (merged_options + def_opts_size, options,
198 ((opts_size + 1) * sizeof(*default_options)));
200 for (def_defaults_size = 0; default_defaults[def_defaults_size];
203 for (defaults_size = 0; defaults[defaults_size]; defaults_size++)
205 merged_defaults = (char **)
206 malloc ((def_defaults_size + defaults_size + 1) * sizeof (*defaults));;
207 memcpy (merged_defaults, default_defaults,
208 def_defaults_size * sizeof(*defaults));
209 memcpy (merged_defaults + def_defaults_size, defaults,
210 (defaults_size + 1) * sizeof(*defaults));
212 /* This totally sucks. Xt should behave like this by default.
213 If the string in `defaults' looks like ".foo", change that
218 for (s = merged_defaults; *s; s++)
221 const char *oldr = *s;
222 char *newr = (char *) malloc(strlen(oldr) + strlen(progclass) + 3);
223 strcpy (newr, progclass);
233 /* Make the X errors print out the name of this program, so we have some
234 clue which one has a bug when they die under the screensaver.
238 screenhack_ehandler (Display *dpy, XErrorEvent *error)
240 fprintf (stderr, "\nX error in %s:\n", progname);
241 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
244 fprintf (stderr, " (nonfatal.)\n");
249 MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
251 return (event->xany.type == MapNotify &&
252 event->xvisibility.window == (Window) window);
256 static Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW;
258 /* Dead-trivial event handling: exits if "q" or "ESC" are typed.
259 Exit if the WM_PROTOCOLS WM_DELETE_WINDOW ClientMessage is received.
260 Returns False if the screen saver should now terminate.
263 screenhack_handle_event_1 (Display *dpy, XEvent *event)
265 switch (event->xany.type)
271 XLookupString (&event->xkey, &c, 1, &keysym, 0);
276 return False; /* exit */
277 else if (! (keysym >= XK_Shift_L && keysym <= XK_Hyper_R))
278 XBell (dpy, 0); /* beep for non-chord keys */
286 if (event->xclient.message_type != XA_WM_PROTOCOLS)
288 char *s = XGetAtomName(dpy, event->xclient.message_type);
289 if (!s) s = "(null)";
290 fprintf (stderr, "%s: unknown ClientMessage %s received!\n",
293 else if (event->xclient.data.l[0] != XA_WM_DELETE_WINDOW)
295 char *s1 = XGetAtomName(dpy, event->xclient.message_type);
296 char *s2 = XGetAtomName(dpy, event->xclient.data.l[0]);
297 if (!s1) s1 = "(null)";
298 if (!s2) s2 = "(null)";
299 fprintf (stderr, "%s: unknown ClientMessage %s[%s] received!\n",
304 return False; /* exit */
314 pick_visual (Screen *screen)
316 struct xscreensaver_function_table *ft = xscreensaver_function_table;
318 if (ft->pick_visual_hook)
320 Visual *v = ft->pick_visual_hook (screen);
324 return get_visual_resource (screen, "visualID", "VisualID", False);
328 /* Notice when the user has requested a different visual or colormap
329 on a pre-existing window (e.g., "-root -visual truecolor" or
330 "-window-id 0x2c00001 -install") and complain, since when drawing
331 on an existing window, we have no choice about these things.
334 visual_warning (Screen *screen, Window window, Visual *visual, Colormap cmap,
337 struct xscreensaver_function_table *ft = xscreensaver_function_table;
339 char *visual_string = get_string_resource (DisplayOfScreen (screen),
340 "visualID", "VisualID");
341 Visual *desired_visual = pick_visual (screen);
345 if (window == RootWindowOfScreen (screen))
346 strcpy (win, "root window");
348 sprintf (win, "window 0x%lx", (unsigned long) window);
351 sprintf (why, "-window-id 0x%lx", (unsigned long) window);
353 strcpy (why, "-root");
355 if (visual_string && *visual_string)
358 for (s = visual_string; *s; s++)
359 if (isupper (*s)) *s = _tolower (*s);
361 if (!strcmp (visual_string, "default") ||
362 !strcmp (visual_string, "default") ||
363 !strcmp (visual_string, "best"))
364 /* don't warn about these, just silently DWIM. */
366 else if (visual != desired_visual)
368 fprintf (stderr, "%s: ignoring `-visual %s' because of `%s'.\n",
369 progname, visual_string, why);
370 fprintf (stderr, "%s: using %s's visual 0x%lx.\n",
371 progname, win, XVisualIDFromVisual (visual));
373 free (visual_string);
376 if (visual == DefaultVisualOfScreen (screen) &&
377 has_writable_cells (screen, visual) &&
378 get_boolean_resource (DisplayOfScreen (screen),
379 "installColormap", "InstallColormap"))
381 fprintf (stderr, "%s: ignoring `-install' because of `%s'.\n",
383 fprintf (stderr, "%s: using %s's colormap 0x%lx.\n",
384 progname, win, (unsigned long) cmap);
387 if (ft->validate_visual_hook)
389 if (! ft->validate_visual_hook (screen, win, visual))
398 /* Bad Things Happen if stdin, stdout, and stderr have been closed
399 (as by the `sh incantation "attraction >&- 2>&-"). When you do
400 that, the X connection gets allocated to one of these fds, and
401 then some random library writes to stderr, and random bits get
402 stuffed down the X pipe, causing "Xlib: sequence lost" errors.
403 So, we cause the first three file descriptors to be open to
404 /dev/null if they aren't open to something else already. This
405 must be done before any other files are opened (or the closing
406 of that other file will again free up one of the "magic" first
409 We do this by opening /dev/null three times, and then closing
410 those fds, *unless* any of them got allocated as #0, #1, or #2,
411 in which case we leave them open. Gag.
413 Really, this crap is technically required of *every* X program,
414 if you want it to be robust in the face of "2>&-".
416 int fd0 = open ("/dev/null", O_RDWR);
417 int fd1 = open ("/dev/null", O_RDWR);
418 int fd2 = open ("/dev/null", O_RDWR);
419 if (fd0 > 2) close (fd0);
420 if (fd1 > 2) close (fd1);
421 if (fd2 > 2) close (fd2);
426 screenhack_table_handle_events (Display *dpy,
427 const struct xscreensaver_function_table *ft,
428 Window window, void *closure
430 , Window window2, void *closure2
434 XtAppContext app = XtDisplayToApplicationContext (dpy);
436 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
437 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
439 while (XPending (dpy))
442 XNextEvent (dpy, &event);
444 if (event.xany.type == ConfigureNotify)
446 if (event.xany.window == window)
447 ft->reshape_cb (dpy, window, closure,
448 event.xconfigure.width, event.xconfigure.height);
450 if (event.xany.window == window2)
451 ft->reshape_cb (dpy, window2, closure2,
452 event.xconfigure.width, event.xconfigure.height);
455 else if (event.xany.type == ClientMessage ||
456 (! (event.xany.window == window
457 ? ft->event_cb (dpy, window, closure, &event)
459 : event.xany.window == window2
460 ? ft->event_cb (dpy, window2, closure2, &event)
463 if (! screenhack_handle_event_1 (dpy, &event))
466 if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
467 XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
474 usleep_and_process_events (Display *dpy,
475 const struct xscreensaver_function_table *ft,
476 Window window, fps_state *fpst, void *closure,
479 , Window window2, fps_state *fpst2, void *closure2,
485 unsigned long quantum = 100000; /* 1/10th second */
494 if (fpst) fps_slept (fpst, quantum);
496 if (fpst2) fps_slept (fpst2, quantum);
500 if (! screenhack_table_handle_events (dpy, ft, window, closure
513 screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
515 fps_compute (fpst, 0);
521 run_screenhack_table (Display *dpy,
526 const struct xscreensaver_function_table *ft)
529 /* Kludge: even though the init_cb functions are declared to take 2 args,
530 actually call them with 3, for the benefit of xlockmore_init() and
533 void *(*init_cb) (Display *, Window, void *) =
534 (void *(*) (Display *, Window, void *)) ft->init_cb;
536 void (*fps_cb) (Display *, Window, fps_state *, void *) = ft->fps_cb;
538 void *closure = init_cb (dpy, window, ft->setup_arg);
539 fps_state *fpst = fps_init (dpy, window);
543 fps_state *fpst2 = 0;
544 if (window2) closure2 = init_cb (dpy, window2, ft->setup_arg);
545 if (window2) fpst2 = fps_init (dpy, window2);
548 if (! closure) /* if it returns nothing, it can't possibly be re-entrant. */
551 if (! fps_cb) fps_cb = screenhack_do_fps;
555 unsigned long delay = ft->draw_cb (dpy, window, closure);
557 unsigned long delay2 = 0;
558 if (window2) delay2 = ft->draw_cb (dpy, window2, closure2);
561 if (fpst) fps_cb (dpy, window, fpst, closure);
563 if (fpst2) fps_cb (dpy, window, fpst2, closure);
566 if (! usleep_and_process_events (dpy, ft,
567 window, fpst, closure, delay
569 , window2, fpst2, closure2, delay2
575 ft->free_cb (dpy, window, closure);
576 if (fpst) fps_free (fpst);
579 if (window2) ft->free_cb (dpy, window2, closure2);
580 if (window2) fps_free (fpst2);
586 make_shell (Screen *screen, Widget toplevel, int width, int height)
588 Display *dpy = DisplayOfScreen (screen);
589 Visual *visual = pick_visual (screen);
590 Boolean def_visual_p = (toplevel &&
591 visual == DefaultVisualOfScreen (screen));
593 if (width <= 0) width = 600;
594 if (height <= 0) height = 480;
599 XtVaSetValues (toplevel,
600 XtNmappedWhenManaged, False,
603 XtNinput, True, /* for WM_HINTS */
605 XtRealizeWidget (toplevel);
606 window = XtWindow (toplevel);
608 if (get_boolean_resource (dpy, "installColormap", "InstallColormap"))
611 XCreateColormap (dpy, window, DefaultVisualOfScreen (screen),
613 XSetWindowColormap (dpy, window, cmap);
620 Colormap cmap = XCreateColormap (dpy, VirtualRootWindowOfScreen(screen),
622 bg = get_pixel_resource (dpy, cmap, "background", "Background");
623 bd = get_pixel_resource (dpy, cmap, "borderColor", "Foreground");
625 new = XtVaAppCreateShell (progname, progclass,
626 topLevelShellWidgetClass, dpy,
627 XtNmappedWhenManaged, False,
629 XtNdepth, visual_depth (screen, visual),
633 XtNbackground, (Pixel) bg,
634 XtNborderColor, (Pixel) bd,
635 XtNinput, True, /* for WM_HINTS */
638 if (!toplevel) /* kludge for the second window in -pair mode... */
639 XtVaSetValues (new, XtNx, 0, XtNy, 550, NULL);
641 XtRealizeWidget (new);
649 init_window (Display *dpy, Widget toplevel, const char *title)
652 XWindowAttributes xgwa;
653 XtPopup (toplevel, XtGrabNone);
654 XtVaSetValues (toplevel, XtNtitle, title, NULL);
656 /* Select KeyPress, and announce that we accept WM_DELETE_WINDOW.
658 window = XtWindow (toplevel);
659 XGetWindowAttributes (dpy, window, &xgwa);
660 XSelectInput (dpy, window,
661 (xgwa.your_event_mask | KeyPressMask | KeyReleaseMask |
662 ButtonPressMask | ButtonReleaseMask));
663 XChangeProperty (dpy, window, XA_WM_PROTOCOLS, XA_ATOM, 32,
665 (unsigned char *) &XA_WM_DELETE_WINDOW, 1);
670 main (int argc, char **argv)
672 struct xscreensaver_function_table *ft = xscreensaver_function_table;
674 /* osso_context_t *osso; */
676 XWindowAttributes xgwa;
682 Widget toplevel2 = 0;
686 Window on_window = 0;
693 progname = argv[0]; /* reset later */
694 progclass = ft->progclass;
697 ft->setup_cb (ft, ft->setup_arg);
702 /* We have to do this on SGI to prevent the background color from being
703 overridden by the current desktop color scheme (we'd like our backgrounds
704 to be black, thanks.) This should be the same as setting the
705 "*useSchemes: none" resource, but it's not -- if that resource is
706 present in the `default_defaults' above, it doesn't work, though it
707 does work when passed as an -xrm arg on the command line. So screw it,
708 turn them off from C instead.
710 SgiUseSchemes ("none");
713 toplevel = XtAppInitialize (&app, progclass, merged_options,
714 merged_options_size, &argc, argv,
715 merged_defaults, 0, 0);
717 dpy = XtDisplay (toplevel);
719 XtGetApplicationNameAndClass (dpy,
721 (char **) &progclass);
723 /* half-assed way of avoiding buffer-overrun attacks. */
724 if (strlen (progname) >= 100) ((char *) progname)[100] = 0;
726 XSetErrorHandler (screenhack_ehandler);
728 XA_WM_PROTOCOLS = XInternAtom (dpy, "WM_PROTOCOLS", False);
729 XA_WM_DELETE_WINDOW = XInternAtom (dpy, "WM_DELETE_WINDOW", False);
732 char *v = (char *) strdup(strchr(screensaver_id, ' '));
733 char *s1, *s2, *s3, *s4;
734 s1 = (char *) strchr(v, ' '); s1++;
735 s2 = (char *) strchr(s1, ' ');
736 s3 = (char *) strchr(v, '('); s3++;
737 s4 = (char *) strchr(s3, ')');
740 sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
751 Bool help_p = (!strcmp(argv[1], "-help") ||
752 !strcmp(argv[1], "--help"));
753 fprintf (stderr, "%s\n", version);
754 for (s = progclass; *s; s++) fprintf(stderr, " ");
755 fprintf (stderr, " http://www.jwz.org/xscreensaver/\n\n");
758 fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
759 fprintf (stderr, "Options include: ");
760 for (i = 0; i < merged_options_size; i++)
762 char *sw = merged_options [i].option;
763 Bool argp = (merged_options [i].argKind == XrmoptionSepArg);
764 int size = strlen (sw) + (argp ? 6 : 0) + 2;
767 fprintf (stderr, "\n\t\t ");
771 fprintf (stderr, "%s", sw);
772 if (argp) fprintf (stderr, " <arg>");
773 if (i != merged_options_size - 1) fprintf (stderr, ", ");
776 fprintf (stderr, ".\n");
781 fprintf (stderr, "\nResources:\n\n");
782 for (i = 0; i < merged_options_size; i++)
784 const char *opt = merged_options [i].option;
785 const char *res = merged_options [i].specifier + 1;
786 const char *val = merged_options [i].value;
787 char *s = get_string_resource (dpy, (char *) res, (char *) res);
792 while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
796 fprintf (stderr, " %-16s %-18s ", opt, res);
797 if (merged_options [i].argKind == XrmoptionSepArg)
799 fprintf (stderr, "[%s]", (s ? s : "?"));
803 fprintf (stderr, "%s", (val ? val : "(null)"));
804 if (val && s && !strcasecmp (val, s))
805 fprintf (stderr, " [default]");
807 fprintf (stderr, "\n");
809 fprintf (stderr, "\n");
813 exit (help_p ? 0 : 1);
818 for (s = merged_defaults; *s; s++)
822 free (merged_options);
823 free (merged_defaults);
827 dont_clear = get_boolean_resource (dpy, "dontClearRoot", "Boolean");
828 mono_p = get_boolean_resource (dpy, "mono", "Boolean");
829 if (CellsOfScreen (DefaultScreenOfDisplay (dpy)) <= 2)
832 root_p = get_boolean_resource (dpy, "root", "Boolean");
835 char *s = get_string_resource (dpy, "windowID", "WindowID");
837 on_window = get_integer_resource (dpy, "windowID", "WindowID");
840 /* OSSO initialize */
841 /* osso = osso_initialize("org.maemo.xscreensaver", "0.5.11", TRUE, NULL); */
843 DBusGConnection *connection;
849 connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
855 window = (Window) on_window;
856 XtDestroyWidget (toplevel);
857 XGetWindowAttributes (dpy, window, &xgwa);
858 visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, True);
860 /* Select KeyPress and resize events on the external window.
862 xgwa.your_event_mask |= KeyPressMask | StructureNotifyMask;
863 XSelectInput (dpy, window, xgwa.your_event_mask);
865 /* Select ButtonPress and ButtonRelease events on the external window,
866 if no other app has already selected them (only one app can select
867 ButtonPress at a time: BadAccess results.)
869 if (! (xgwa.all_event_masks & (ButtonPressMask | ButtonReleaseMask)))
870 XSelectInput (dpy, window,
871 (xgwa.your_event_mask |
872 ButtonPressMask | ButtonReleaseMask));
876 window = VirtualRootWindowOfScreen (XtScreen (toplevel));
877 XtDestroyWidget (toplevel);
878 XGetWindowAttributes (dpy, window, &xgwa);
879 /* With RANDR, the root window can resize! */
880 XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
881 visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);
885 Widget new = make_shell (XtScreen (toplevel), toplevel,
886 toplevel->core.width,
887 toplevel->core.height);
890 XtDestroyWidget (toplevel);
894 init_window (dpy, toplevel, version);
895 window = XtWindow (toplevel);
896 XGetWindowAttributes (dpy, window, &xgwa);
899 if (get_boolean_resource (dpy, "pair", "Boolean"))
901 toplevel2 = make_shell (xgwa.screen, 0,
902 toplevel->core.width,
903 toplevel->core.height);
904 init_window (dpy, toplevel2, version);
905 window2 = XtWindow (toplevel2);
907 # endif /* DEBUG_PAIR */
912 unsigned int bg = get_pixel_resource (dpy, xgwa.colormap,
913 "background", "Background");
914 XSetWindowBackground (dpy, window, bg);
915 XClearWindow (dpy, window);
919 XSetWindowBackground (dpy, window2, bg);
920 XClearWindow (dpy, window2);
925 if (!root_p && !on_window)
926 /* wait for it to be mapped */
927 XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
931 /* This is the one and only place that the random-number generator is
932 seeded in any screenhack. You do not need to seed the RNG again,
933 it is done for you before your code is invoked. */
937 run_screenhack_table (dpy, window,
943 XtDestroyWidget (toplevel);
944 XtDestroyApplicationContext (app);