1 /* demo-Xm.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-2003, 2005 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #ifdef HAVE_MOTIF /* whole file */
26 # include <pwd.h> /* for getpwuid() */
32 # include <sys/utsname.h> /* for uname() */
33 #endif /* HAVE_UNAME */
37 #include <X11/Xproto.h> /* for CARD32 */
38 #include <X11/Xatom.h> /* for XA_INTEGER */
39 #include <X11/Intrinsic.h>
40 #include <X11/StringDefs.h>
42 /* We don't actually use any widget internals, but these are included
43 so that gdb will have debug info for the widgets... */
44 #include <X11/IntrinsicP.h>
45 #include <X11/ShellP.h>
53 # include <X11/Xmu/Error.h>
55 # include <Xmu/Error.h>
66 #include <Xm/LabelG.h>
67 #include <Xm/RowColumn.h>
68 #include <Xm/MessageB.h>
70 #ifdef HAVE_XMCOMBOBOX /* a Motif 2.0 widget */
71 # include <Xm/ComboBox.h>
72 # ifndef XmNtextField /* Lesstif 0.89.4 bug */
73 # undef HAVE_XMCOMBOBOX
75 # if (XmVersion < 2001) /* Lesstif has two personalities these days */
76 # undef HAVE_XMCOMBOBOX
78 #endif /* HAVE_XMCOMBOBOX */
82 #include "resources.h" /* for parse_time() */
83 #include "visual.h" /* for has_writable_cells() */
84 #include "remote.h" /* for xscreensaver_command() */
92 #define countof(x) (sizeof((x))/sizeof((*x)))
96 char *progclass = "XScreenSaver";
100 saver_preferences *a, *b;
103 static void *global_prefs_pair; /* I hate C so much... */
105 char *blurb (void) { return progname; }
107 extern Widget create_xscreensaver_demo (Widget parent);
108 extern const char *visual_menu[];
111 static char *short_version = 0;
114 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
115 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO;
116 Atom XA_ACTIVATE, XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
119 static void populate_demo_window (Widget toplevel,
120 int which, prefs_pair *pair);
121 static void populate_prefs_page (Widget top, prefs_pair *pair);
122 static int apply_changes_and_save (Widget widget);
123 static int maybe_reload_init_file (Widget widget, prefs_pair *pair);
124 static void await_xscreensaver (Widget widget);
127 /* Some random utility functions
131 name_to_widget (Widget widget, const char *name)
136 strcpy (name2+1, name);
138 while ((parent = XtParent (widget)))
140 return XtNameToWidget (widget, name2);
145 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
146 Takes a scroller, viewport, or list as an argument.
149 ensure_selected_item_visible (Widget list)
153 if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
158 XmNtopItemPosition, &top,
159 XmNvisibleItemCount, &visible,
161 if (pos_list[0] >= top + visible)
163 int pos = pos_list[0] - visible + 1;
164 if (pos < 0) pos = 0;
165 XmListSetPos (list, pos);
167 else if (pos_list[0] < top)
169 XmListSetPos (list, pos_list[0]);
173 XtFree ((char *) pos_list);
178 warning_dialog_dismiss_cb (Widget button, XtPointer client_data,
181 Widget shell = (Widget) client_data;
182 XtDestroyWidget (shell);
187 warning_dialog (Widget parent, const char *message, int center)
189 char *msg = strdup (message);
204 dialog = XmCreateWarningDialog (parent, "warning", av, ac);
206 w = XmMessageBoxGetChild (dialog, XmDIALOG_MESSAGE_LABEL);
207 if (w) XtUnmanageChild (w);
208 w = XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON);
209 if (w) XtUnmanageChild (w);
210 w = XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
211 if (w) XtUnmanageChild (w);
213 ok = XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON);
216 XtSetArg (av[ac], XmNnumColumns, 1); ac++;
217 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++;
218 XtSetArg (av[ac], XmNpacking, XmPACK_COLUMN); ac++;
219 XtSetArg (av[ac], XmNrowColumnType, XmWORK_AREA); ac++;
220 XtSetArg (av[ac], XmNspacing, 0); ac++;
221 container = XmCreateRowColumn (dialog, "container", av, ac);
227 char *s = strchr (head, '\n');
230 sprintf (name, "label%d", i++);
232 xmstr = XmStringCreate (head, XmSTRING_DEFAULT_CHARSET);
234 XtSetArg (av[ac], XmNlabelString, xmstr); ac++;
235 XtSetArg (av[ac], XmNmarginHeight, 0); ac++;
236 label = XmCreateLabelGadget (container, name, av, ac);
237 XtManageChild (label);
238 XmStringFree (xmstr);
248 XtManageChild (container);
249 XtRealizeWidget (dialog);
250 XtManageChild (dialog);
252 XtAddCallback (ok, XmNactivateCallback, warning_dialog_dismiss_cb, dialog);
259 run_cmd (Widget widget, Atom command, int arg)
264 apply_changes_and_save (widget);
265 status = xscreensaver_command (XtDisplay (widget),
266 command, arg, False, &err);
271 sprintf (buf, "Error:\n\n%s", err);
273 strcpy (buf, "Unknown error!");
274 warning_dialog (widget, buf, 100);
281 run_hack (Widget widget, int which, Bool report_errors_p)
283 if (which < 0) return;
284 apply_changes_and_save (widget);
286 run_cmd (widget, XA_DEMO, which + 1);
290 xscreensaver_command (XtDisplay (widget), XA_DEMO, which + 1, False, &s);
301 exit_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
303 apply_changes_and_save (XtParent (button));
309 wm_close_cb (Widget widget, GdkEvent *event, XtPointer data)
311 apply_changes_and_save (XtParent (button));
317 cut_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
320 warning_dialog (XtParent (button),
322 "cut unimplemented\n", 1);
327 copy_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
330 warning_dialog (XtParent (button),
332 "copy unimplemented\n", 1);
337 paste_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
340 warning_dialog (XtParent (button),
342 "paste unimplemented\n", 1);
347 about_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
350 char *s = strdup (screensaver_id + 4);
353 s2 = strchr (s, ',');
357 sprintf (buf, "%s\n%s\n"
359 "This is the Motif version of \"xscreensaver-demo\". The Motif\n"
360 "version is no longer maintained. Please use the GTK version\n"
361 "instead, which has many more features.\n"
363 "For xscreensaver updates, check http://www.jwz.org/xscreensaver/",
367 warning_dialog (XtParent (button), buf, 100);
372 doc_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
374 prefs_pair *pair = (prefs_pair *) client_data;
376 saver_preferences *p = pair->a;
379 if (!p->help_url || !*p->help_url)
381 warning_dialog (XtParent (button),
383 "No Help URL has been specified.\n", 100);
387 help_command = (char *) malloc (strlen (p->load_url_command) +
388 (strlen (p->help_url) * 4) + 20);
389 strcpy (help_command, "( ");
390 sprintf (help_command + strlen(help_command),
392 p->help_url, p->help_url, p->help_url, p->help_url);
393 strcat (help_command, " ) &");
394 system (help_command);
400 activate_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
402 run_cmd (XtParent (button), XA_ACTIVATE, 0);
407 lock_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
409 run_cmd (XtParent (button), XA_LOCK, 0);
414 kill_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
416 run_cmd (XtParent (button), XA_EXIT, 0);
421 restart_menu_cb (Widget button, XtPointer client_data, XtPointer ignored)
424 run_cmd (XtParent (button), XA_RESTART, 0);
426 button = XtParent (button);
427 apply_changes_and_save (button);
428 xscreensaver_command (XtDisplay (button), XA_EXIT, 0, False, NULL);
430 system ("xscreensaver -nosplash &");
433 await_xscreensaver (button);
437 await_xscreensaver (Widget widget)
441 Display *dpy = XtDisplay (widget);
444 while (!rversion && (--countdown > 0))
446 /* Check for the version of the running xscreensaver... */
447 server_xscreensaver_version (dpy, &rversion, 0, 0);
449 /* If it's not there yet, wait a second... */
460 /* Timed out, no screensaver running. */
463 Bool root_p = (geteuid () == 0);
467 "The xscreensaver daemon did not start up properly.\n"
472 __extension__ /* don't warn about "string length is greater than
473 the length ISO C89 compilers are required to
474 support" in the following expression... */
477 "You are running as root. This usually means that xscreensaver\n"
478 "was unable to contact your X server because access control is\n"
479 "turned on. Try running this command:\n"
481 " xhost +localhost\n"
483 "and then selecting `File / Restart Daemon'.\n"
485 "Note that turning off access control will allow anyone logged\n"
486 "on to this machine to access your screen, which might be\n"
487 "considered a security problem. Please read the xscreensaver\n"
488 "manual and FAQ for more information.\n"
490 "You shouldn't run X as root. Instead, you should log in as a\n"
491 "normal user, and `su' as necessary.");
493 strcat (buf, "Please check your $PATH and permissions.");
495 warning_dialog (XtParent (widget), buf, 1);
500 static int _selected_hack_number = -1;
503 selected_hack_number (Widget toplevel)
505 return _selected_hack_number;
510 demo_write_init_file (Widget widget, saver_preferences *p)
512 if (!write_init_file (XtDisplay (widget), p, short_version, False))
516 const char *f = init_file_name();
518 warning_dialog (widget,
519 "Error:\n\nCouldn't determine init file name!\n",
523 char *b = (char *) malloc (strlen(f) + 1024);
524 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
525 warning_dialog (widget, b, 100);
534 apply_changes_and_save (Widget widget)
536 prefs_pair *pair = global_prefs_pair;
537 saver_preferences *p = pair->a;
538 Widget list_widget = name_to_widget (widget, "list");
539 int which = selected_hack_number (widget);
541 Widget cmd = name_to_widget (widget, "cmdText");
542 Widget enabled = name_to_widget (widget, "enabled");
544 Widget vis = name_to_widget (widget, "combo");
545 # ifdef HAVE_XMCOMBOBOX
547 # else /* !HAVE_XMCOMBOBOX */
548 Widget menu = 0, *kids = 0, selected_item = 0;
551 # endif /* !HAVE_XMCOMBOBOX */
553 Bool enabled_p = False;
554 const char *visual = 0;
555 const char *command = 0;
560 if (which < 0) return -1;
562 # ifdef HAVE_XMCOMBOBOX
563 XtVaGetValues (vis, XmNtextField, &text, NULL);
565 /* If we can't get at the text field of this combo box, we're screwed. */
567 XtVaGetValues (text, XmNvalue, &visual, NULL);
569 # else /* !HAVE_XMCOMBOBOX */
570 XtVaGetValues (vis, XmNsubMenuId, &menu, NULL);
571 XtVaGetValues (menu, XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
572 XtVaGetValues (menu, XmNmenuHistory, &selected_item, NULL);
574 for (i = 0; i < nkids; i++)
575 if (kids[i] == selected_item)
578 visual = visual_menu[i];
579 # endif /* !HAVE_XMCOMBOBOX */
581 XtVaGetValues (enabled, XmNset, &enabled_p, NULL);
582 XtVaGetValues (cmd, XtNvalue, &command, NULL);
584 if (maybe_reload_init_file (widget, pair) != 0)
587 /* Sanity-check and canonicalize whatever the user typed into the combo box.
589 if (!strcasecmp (visual, "")) visual = "";
590 else if (!strcasecmp (visual, "any")) visual = "";
591 else if (!strcasecmp (visual, "default")) visual = "Default";
592 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
593 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
594 else if (!strcasecmp (visual, "best")) visual = "Best";
595 else if (!strcasecmp (visual, "mono")) visual = "Mono";
596 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
597 else if (!strcasecmp (visual, "gray")) visual = "Gray";
598 else if (!strcasecmp (visual, "grey")) visual = "Gray";
599 else if (!strcasecmp (visual, "color")) visual = "Color";
600 else if (!strcasecmp (visual, "gl")) visual = "GL";
601 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
602 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
603 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
604 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
605 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
606 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
607 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
608 else if (1 == sscanf (visual, " %lu %c", &id, &c)) ;
609 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
612 XBell (XtDisplay (widget), 0); /* unparsable */
614 /* #### gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");*/
617 ensure_selected_item_visible (list_widget);
619 if (!p->screenhacks[which]->visual)
620 p->screenhacks[which]->visual = strdup ("");
621 if (!p->screenhacks[which]->command)
622 p->screenhacks[which]->command = strdup ("");
624 if (p->screenhacks[which]->enabled_p != enabled_p ||
625 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
626 !!strcasecmp (p->screenhacks[which]->command, command))
628 /* Something was changed -- store results into the struct,
631 free (p->screenhacks[which]->visual);
632 free (p->screenhacks[which]->command);
633 p->screenhacks[which]->visual = strdup (visual);
634 p->screenhacks[which]->command = strdup (command);
635 p->screenhacks[which]->enabled_p = enabled_p;
637 return demo_write_init_file (widget, p);
640 /* No changes made */
645 run_this_cb (Widget button, XtPointer client_data, XtPointer ignored)
647 int which = selected_hack_number (XtParent (button));
648 if (which < 0) return;
649 if (0 == apply_changes_and_save (XtParent (button)))
650 run_hack (XtParent (button), which, True);
655 manual_cb (Widget button, XtPointer client_data, XtPointer ignored)
657 prefs_pair *pair = (prefs_pair *) client_data;
658 saver_preferences *p = pair->a;
659 Widget list_widget = name_to_widget (button, "list");
660 int which = selected_hack_number (button);
661 char *name, *name2, *cmd, *s;
662 if (which < 0) return;
663 apply_changes_and_save (button);
664 ensure_selected_item_visible (list_widget);
666 name = strdup (p->screenhacks[which]->command);
668 while (isspace (*name2)) name2++;
670 while (*s && !isspace (*s)) s++;
672 s = strrchr (name2, '/');
675 cmd = get_string_resource (XtDisplay (button), "manualCommand", "ManualCommand");
678 char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100);
680 sprintf (cmd2 + strlen (cmd2),
682 name2, name2, name2, name2);
683 strcat (cmd2, " ) &");
689 warning_dialog (XtParent (button),
690 "Error:\n\nno `manualCommand' resource set.",
699 run_next_cb (Widget button, XtPointer client_data, XtPointer ignored)
701 prefs_pair *pair = (prefs_pair *) client_data;
702 saver_preferences *p = pair->a;
704 Widget list_widget = name_to_widget (button, "list");
705 int which = selected_hack_number (button);
707 button = XtParent (button);
714 if (which >= p->screenhacks_count)
717 apply_changes_and_save (button);
719 XmListDeselectAllItems (list_widget); /* LessTif lossage */
720 XmListSelectPos (list_widget, which+1, True);
722 ensure_selected_item_visible (list_widget);
723 populate_demo_window (button, which, pair);
724 run_hack (button, which, False);
729 run_prev_cb (Widget button, XtPointer client_data, XtPointer ignored)
731 prefs_pair *pair = (prefs_pair *) client_data;
732 saver_preferences *p = pair->a;
734 Widget list_widget = name_to_widget (button, "list");
735 int which = selected_hack_number (button);
737 button = XtParent (button);
740 which = p->screenhacks_count - 1;
745 which = p->screenhacks_count - 1;
747 apply_changes_and_save (button);
749 XmListDeselectAllItems (list_widget); /* LessTif lossage */
750 XmListSelectPos (list_widget, which+1, True);
752 ensure_selected_item_visible (list_widget);
753 populate_demo_window (button, which, pair);
754 run_hack (button, which, False);
758 /* Helper for the text fields that contain time specifications:
759 this parses the text, and does error checking.
762 hack_time_text (Widget button, const char *line, Time *store, Bool sec_p)
767 value = parse_time ((char *) line, sec_p, True);
768 value *= 1000; /* Time measures in microseconds */
774 "Unparsable time format: \"%s\"\n",
776 warning_dialog (XtParent (button), b, 100);
785 prefs_ok_cb (Widget button, XtPointer client_data, XtPointer ignored)
787 prefs_pair *pair = (prefs_pair *) client_data;
789 saver_preferences *p = pair->a;
790 saver_preferences *p2 = pair->b;
791 Bool changed = False;
794 button = XtParent (button);
796 # define SECONDS(field, name) \
798 XtVaGetValues (name_to_widget (button, (name)), XtNvalue, &v, NULL); \
799 hack_time_text (button, v, (field), True)
801 # define MINUTES(field, name) \
803 XtVaGetValues (name_to_widget (button, (name)), XtNvalue, &v, NULL); \
804 hack_time_text (button, v, (field), False)
806 # define INTEGER(field, name) do { \
807 unsigned int value; \
809 XtVaGetValues (name_to_widget (button, (name)), XtNvalue, &v, NULL); \
812 else if (sscanf (v, "%u%c", &value, &c) != 1) \
815 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", v); \
816 warning_dialog (XtParent (button), b, 100); \
822 # define CHECKBOX(field, name) \
823 XtVaGetValues (name_to_widget (button, (name)), XmNset, &field, NULL)
825 MINUTES (&p2->timeout, "timeoutText");
826 MINUTES (&p2->cycle, "cycleText");
827 SECONDS (&p2->fade_seconds, "fadeSecondsText");
828 INTEGER (&p2->fade_ticks, "fadeTicksText");
829 MINUTES (&p2->lock_timeout, "lockText");
830 SECONDS (&p2->passwd_timeout, "passwdText");
831 CHECKBOX (p2->verbose_p, "verboseToggle");
832 CHECKBOX (p2->install_cmap_p, "cmapToggle");
833 CHECKBOX (p2->fade_p, "fadeToggle");
834 CHECKBOX (p2->unfade_p, "unfadeToggle");
835 CHECKBOX (p2->lock_p, "lockToggle");
842 # define COPY(field) \
843 if (p->field != p2->field) changed = True; \
849 COPY(passwd_timeout);
853 COPY(install_cmap_p);
859 populate_prefs_page (button, pair);
862 demo_write_init_file (button, p);
867 prefs_cancel_cb (Widget button, XtPointer client_data, XtPointer ignored)
869 prefs_pair *pair = (prefs_pair *) client_data;
872 populate_prefs_page (XtParent (button), pair);
877 list_select_cb (Widget list, XtPointer client_data, XtPointer call_data)
879 prefs_pair *pair = (prefs_pair *) client_data;
881 XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
882 int which = lcb->item_position - 1;
884 apply_changes_and_save (list);
885 populate_demo_window (list, which, pair);
887 if (lcb->reason == XmCR_DEFAULT_ACTION && which >= 0)
888 run_hack (list, which, True);
892 /* Populating the various widgets
896 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
899 format_time (char *buf, Time time)
902 unsigned int h = 0, m = 0;
913 sprintf (buf, "%u:%02u:%02u", h, m, s);
917 /* Finds the number of the last hack to run, and makes that item be
921 scroll_to_current_hack (Widget toplevel, prefs_pair *pair)
925 unsigned long nitems, bytesafter;
926 unsigned char *data = 0;
927 Display *dpy = XtDisplay (toplevel);
931 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
932 XA_SCREENSAVER_STATUS,
933 0, 3, False, XA_INTEGER,
934 &type, &format, &nitems, &bytesafter,
937 && type == XA_INTEGER
940 which = (int) data[2] - 1;
942 if (data) free (data);
947 list = name_to_widget (toplevel, "list");
948 apply_changes_and_save (toplevel);
950 XmListDeselectAllItems (list); /* LessTif lossage */
951 XmListSelectPos (list, which+1, True);
953 ensure_selected_item_visible (list);
954 populate_demo_window (toplevel, which, pair);
960 populate_hack_list (Widget toplevel, prefs_pair *pair)
962 saver_preferences *p = pair->a;
963 Widget list = name_to_widget (toplevel, "list");
964 screenhack **hacks = p->screenhacks;
967 for (h = hacks; *h; h++)
969 char *pretty_name = (h[0]->name
970 ? strdup (h[0]->name)
971 : make_hack_name (XtDisplay (toplevel), h[0]->command));
973 XmString xmstr = XmStringCreate (pretty_name, XmSTRING_DEFAULT_CHARSET);
974 XmListAddItem (list, xmstr, 0);
975 XmStringFree (xmstr);
978 XtAddCallback (list, XmNbrowseSelectionCallback, list_select_cb, pair);
979 XtAddCallback (list, XmNdefaultActionCallback, list_select_cb, pair);
984 populate_prefs_page (Widget top, prefs_pair *pair)
986 saver_preferences *p = pair->a;
989 format_time (s, p->timeout);
990 XtVaSetValues (name_to_widget (top, "timeoutText"), XmNvalue, s, NULL);
991 format_time (s, p->cycle);
992 XtVaSetValues (name_to_widget (top, "cycleText"), XmNvalue, s, NULL);
993 format_time (s, p->lock_timeout);
994 XtVaSetValues (name_to_widget (top, "lockText"), XmNvalue, s, NULL);
995 format_time (s, p->passwd_timeout);
996 XtVaSetValues (name_to_widget (top, "passwdText"), XmNvalue, s, NULL);
997 format_time (s, p->fade_seconds);
998 XtVaSetValues (name_to_widget (top, "fadeSecondsText"), XmNvalue, s, NULL);
999 sprintf (s, "%u", p->fade_ticks);
1000 XtVaSetValues (name_to_widget (top, "fadeTicksText"), XmNvalue, s, NULL);
1002 XtVaSetValues (name_to_widget (top, "verboseToggle"),
1003 XmNset, p->verbose_p, NULL);
1004 XtVaSetValues (name_to_widget (top, "cmapToggle"),
1005 XmNset, p->install_cmap_p, NULL);
1006 XtVaSetValues (name_to_widget (top, "fadeToggle"),
1007 XmNset, p->fade_p, NULL);
1008 XtVaSetValues (name_to_widget (top, "unfadeToggle"),
1009 XmNset, p->unfade_p, NULL);
1010 XtVaSetValues (name_to_widget (top, "lockToggle"),
1011 XmNset, p->lock_p, NULL);
1015 Bool found_any_writable_cells = False;
1016 Display *dpy = XtDisplay (top);
1017 int nscreens = ScreenCount(dpy);
1019 for (i = 0; i < nscreens; i++)
1021 Screen *s = ScreenOfDisplay (dpy, i);
1022 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1024 found_any_writable_cells = True;
1029 #ifdef HAVE_XF86VMODE_GAMMA
1030 found_any_writable_cells = True; /* if we can gamma fade, go for it */
1033 XtVaSetValues (name_to_widget (top, "fadeSecondsLabel"), XtNsensitive,
1034 found_any_writable_cells, NULL);
1035 XtVaSetValues (name_to_widget (top, "fadeTicksLabel"), XtNsensitive,
1036 found_any_writable_cells, NULL);
1037 XtVaSetValues (name_to_widget (top, "fadeSecondsText"), XtNsensitive,
1038 found_any_writable_cells, NULL);
1039 XtVaSetValues (name_to_widget (top, "fadeTicksText"), XtNsensitive,
1040 found_any_writable_cells, NULL);
1041 XtVaSetValues (name_to_widget (top, "cmapToggle"), XtNsensitive,
1042 found_any_writable_cells, NULL);
1043 XtVaSetValues (name_to_widget (top, "fadeToggle"), XtNsensitive,
1044 found_any_writable_cells, NULL);
1045 XtVaSetValues (name_to_widget (top, "unfadeToggle"), XtNsensitive,
1046 found_any_writable_cells, NULL);
1052 sensitize_demo_widgets (Widget toplevel, Bool sensitive_p)
1054 const char *names[] = { "cmdLabel", "cmdText", "enabled",
1055 "visLabel", "combo", "demo", "man" };
1057 for (i = 0; i < sizeof(names)/countof(*names); i++)
1059 Widget w = name_to_widget (toplevel, names[i]);
1060 XtVaSetValues (w, XtNsensitive, sensitive_p, NULL);
1063 /* I don't know how to handle these yet... */
1065 const char *names2[] = { "cut", "copy", "paste" };
1066 for (i = 0; i < sizeof(names2)/countof(*names2); i++)
1068 Widget w = name_to_widget (toplevel, names2[i]);
1069 XtVaSetValues (w, XtNsensitive, FALSE, NULL);
1076 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1081 static char *up_arrow_xpm[] = {
1083 " c None s background",
1105 static char *down_arrow_xpm[] = {
1107 " c None s background",
1129 #endif /* HAVE_XPM */
1133 pixmapify_buttons (Widget toplevel)
1137 Display *dpy = XtDisplay (toplevel);
1138 Window window = XtWindow (toplevel);
1139 XWindowAttributes xgwa;
1140 XpmAttributes xpmattrs;
1141 Pixmap up_pixmap = 0, down_pixmap = 0;
1143 Widget up = name_to_widget (toplevel, "up");
1144 Widget dn = name_to_widget (toplevel, "down");
1145 # ifdef XpmColorSymbols
1147 XpmColorSymbol symbols[2];
1151 XGetWindowAttributes (dpy, window, &xgwa);
1153 xpmattrs.valuemask = 0;
1155 # ifdef XpmColorSymbols
1156 symbols[0].name = "background";
1157 symbols[0].pixel = 0;
1158 symbols[1].name = 0;
1159 XtVaGetValues (up, XmNbackground, &xc, NULL);
1160 XQueryColor (dpy, xgwa.colormap, &xc);
1161 sprintf (color, "#%04X%04X%04X", xc.red, xc.green, xc.blue);
1162 symbols[0].value = color;
1163 symbols[0].pixel = xc.pixel;
1165 xpmattrs.valuemask |= XpmColorSymbols;
1166 xpmattrs.colorsymbols = symbols;
1167 xpmattrs.numsymbols = 1;
1170 # ifdef XpmCloseness
1171 xpmattrs.valuemask |= XpmCloseness;
1172 xpmattrs.closeness = 40000;
1175 xpmattrs.valuemask |= XpmVisual;
1176 xpmattrs.visual = xgwa.visual;
1179 xpmattrs.valuemask |= XpmDepth;
1180 xpmattrs.depth = xgwa.depth;
1183 xpmattrs.valuemask |= XpmColormap;
1184 xpmattrs.colormap = xgwa.colormap;
1187 result = XpmCreatePixmapFromData(dpy, window, up_arrow_xpm,
1188 &up_pixmap, 0 /* mask */, &xpmattrs);
1189 if (!up_pixmap || (result != XpmSuccess && result != XpmColorError))
1191 fprintf (stderr, "%s: Can't load pixmaps\n", progname);
1195 result = XpmCreatePixmapFromData(dpy, window, down_arrow_xpm,
1196 &down_pixmap, 0 /* mask */, &xpmattrs);
1197 if (!down_pixmap || (result != XpmSuccess && result != XpmColorError))
1199 fprintf (stderr, "%s: Can't load pixmaps\n", progname);
1203 XtVaSetValues (up, XmNlabelType, XmPIXMAP, XmNlabelPixmap, up_pixmap, NULL);
1204 XtVaSetValues (dn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, down_pixmap,NULL);
1206 #endif /* HAVE_XPM */
1212 get_hack_blurb (Display *dpy, screenhack *hack)
1215 char *prog_name = strdup (hack->command);
1216 char *pretty_name = (hack->name
1217 ? strdup (hack->name)
1218 : make_hack_name (dpy, hack->command));
1219 char doc_name[255], doc_class[255];
1222 for (s = prog_name; *s && !isspace(*s); s++)
1225 s = strrchr (prog_name, '/');
1226 if (s) strcpy (prog_name, s+1);
1228 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1229 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1233 doc_string = get_string_resource (dpy, doc_name, doc_class);
1236 for (s = doc_string; *s; s++)
1240 /* skip over whitespace at beginning of line */
1242 while (*s && (*s == ' ' || *s == '\t'))
1245 else if (*s == ' ' || *s == '\t')
1247 /* compress all other horizontal whitespace. */
1250 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1252 if (s2 > s) strcpy (s, s2);
1257 while (*s && isspace (*s)) /* Strip trailing whitespace */
1260 /* Delete whitespace at end of each line. */
1261 for (; s > doc_string; s--)
1262 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1265 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1269 if (s2 < s) strcpy (s2, s);
1273 /* Delete leading blank lines. */
1274 for (s = doc_string; *s == '\n'; s++)
1276 if (s > doc_string) strcpy (doc_string, s);
1281 static int doc_installed = 0;
1282 if (doc_installed == 0)
1284 if (get_boolean_resource ("hacks.documentation.isInstalled",
1285 "hacks.documentation.isInstalled"))
1291 if (doc_installed < 0)
1293 strdup ("Error:\n\n"
1294 "The documentation strings do not appear to be "
1295 "installed. This is probably because there is "
1296 "an \"XScreenSaver\" app-defaults file installed "
1297 "that is from an older version of the program. "
1298 "To fix this problem, delete that file, or "
1299 "install a current version (either will work.)");
1302 doc_string = strdup (
1304 "This is the Motif version of \"xscreensaver-demo\". The Motif "
1305 "version is no longer maintained. Please use the GTK version "
1306 "instead, which has many more features."
1308 "If you were running the GTK version, there would be a preview "
1309 "of this screen saver mode displayed here, along with graphical "
1310 "configuration options.");
1318 populate_demo_window (Widget toplevel, int which, prefs_pair *pair)
1320 saver_preferences *p = pair->a;
1321 screenhack *hack = (which >= 0 ? p->screenhacks[which] : 0);
1322 Widget frameL = name_to_widget (toplevel, "frameLabel");
1323 Widget doc = name_to_widget (toplevel, "doc");
1324 Widget cmd = name_to_widget (toplevel, "cmdText");
1325 Widget enabled = name_to_widget (toplevel, "enabled");
1326 Widget vis = name_to_widget (toplevel, "combo");
1329 char *pretty_name = (hack
1331 ? strdup (hack->name)
1332 : make_hack_name (XtDisplay (toplevel), hack->command))
1334 char *doc_string = hack ? get_hack_blurb (XtDisplay (toplevel), hack) : 0;
1338 xmstr = XmStringCreate (pretty_name, XmSTRING_DEFAULT_CHARSET);
1339 XtVaSetValues (frameL, XmNlabelString, xmstr, NULL);
1340 XmStringFree (xmstr);
1342 XtVaSetValues (doc, XmNvalue, doc_string, NULL);
1343 XtVaSetValues (cmd, XmNvalue, (hack ? hack->command : ""), NULL);
1345 XtVaSetValues (enabled, XmNset, (hack ? hack->enabled_p : False), NULL);
1348 if (hack && hack->visual && *hack->visual)
1349 for (i = 0; visual_menu[i]; i++)
1350 if (!strcasecmp (hack->visual, visual_menu[i]))
1352 if (!visual_menu[i]) i = -1;
1355 # ifdef HAVE_XMCOMBOBOX
1357 XtVaGetValues (vis, XmNtextField, &text, NULL);
1358 XtVaSetValues (vis, XmNselectedPosition, i, NULL);
1360 XtVaSetValues (text, XmNvalue, hack->visual, NULL);
1361 # else /* !HAVE_XMCOMBOBOX */
1366 XtVaGetValues (vis, XmNsubMenuId, &menu, NULL);
1367 if (!menu) abort ();
1368 XtVaGetValues (menu, XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
1371 XtVaSetValues (vis, XmNmenuHistory, kids[i], NULL);
1372 # endif /* !HAVE_XMCOMBOBOX */
1375 sensitize_demo_widgets (toplevel, (hack ? True : False));
1377 if (pretty_name) free (pretty_name);
1378 if (doc_string) free (doc_string);
1380 _selected_hack_number = which;
1386 maybe_reload_init_file (Widget widget, prefs_pair *pair)
1389 saver_preferences *p = pair->a;
1391 static Bool reentrant_lock = False;
1392 if (reentrant_lock) return 0;
1393 reentrant_lock = True;
1395 if (init_file_changed_p (p))
1397 const char *f = init_file_name();
1402 if (!f || !*f) return 0;
1403 b = (char *) malloc (strlen(f) + 1024);
1406 "file \"%s\" has changed, reloading.\n",
1408 warning_dialog (widget, b, 100);
1411 load_init_file (XtDisplay (widget), p);
1413 which = selected_hack_number (widget);
1414 list = name_to_widget (widget, "list");
1416 XtVaSetValues (list, XmNitemCount, 0, NULL);
1418 populate_hack_list (widget, pair);
1420 XmListDeselectAllItems (list); /* LessTif lossage */
1421 XmListSelectPos (list, which+1, True);
1423 populate_prefs_page (widget, pair);
1424 populate_demo_window (widget, which, pair);
1425 ensure_selected_item_visible (list);
1430 reentrant_lock = False;
1436 /* Attach all callback functions to widgets
1440 add_callbacks (Widget toplevel, prefs_pair *pair)
1444 # define CB(NAME,FN) \
1445 w = name_to_widget (toplevel, (NAME)); \
1446 XtAddCallback (w, XmNactivateCallback, (FN), pair)
1448 CB ("blank", activate_menu_cb);
1449 CB ("lock", lock_menu_cb);
1450 CB ("kill", kill_menu_cb);
1451 CB ("restart", restart_menu_cb);
1452 CB ("exit", exit_menu_cb);
1454 CB ("cut", cut_menu_cb);
1455 CB ("copy", copy_menu_cb);
1456 CB ("paste", paste_menu_cb);
1458 CB ("about", about_menu_cb);
1459 CB ("docMenu", doc_menu_cb);
1461 CB ("down", run_next_cb);
1462 CB ("up", run_prev_cb);
1463 CB ("demo", run_this_cb);
1464 CB ("man", manual_cb);
1466 CB ("preferencesForm.Cancel", prefs_cancel_cb);
1467 CB ("preferencesForm.OK", prefs_ok_cb);
1474 sanity_check_resources (Widget toplevel)
1476 const char *names[] = { "demoTab", "optionsTab", "cmdLabel", "visLabel",
1477 "enabled", "demo", "man", "timeoutLabel",
1478 "cycleLabel", "fadeSecondsLabel", "fadeTicksLabel",
1479 "lockLabel", "passwdLabel" };
1481 for (i = 0; i < sizeof(names)/countof(*names); i++)
1483 Widget w = name_to_widget (toplevel, names[i]);
1484 const char *name = XtName(w);
1487 XtVaGetValues (w, XmNlabelString, &xm, NULL);
1488 if (xm) XmStringGetLtoR (xm, XmSTRING_DEFAULT_CHARSET, &label);
1489 if (w && (!label || !strcmp (name, label)))
1491 xm = XmStringCreate ("ERROR", XmSTRING_DEFAULT_CHARSET);
1492 XtVaSetValues (w, XmNlabelString, xm, NULL);
1497 /* Set certain buttons to be the same size (the max of the set.)
1500 hack_button_sizes (Widget toplevel)
1502 Widget demo = name_to_widget (toplevel, "demo");
1503 Widget man = name_to_widget (toplevel, "man");
1504 Widget ok = name_to_widget (toplevel, "OK");
1505 Widget can = name_to_widget (toplevel, "Cancel");
1506 Widget up = name_to_widget (toplevel, "up");
1507 Widget down = name_to_widget (toplevel, "down");
1510 XtVaGetValues (demo, XmNwidth, &w1, NULL);
1511 XtVaGetValues (man, XmNwidth, &w2, NULL);
1512 XtVaSetValues ((w1 > w2 ? man : demo), XmNwidth, (w1 > w2 ? w1 : w2), NULL);
1514 XtVaGetValues (ok, XmNwidth, &w1, NULL);
1515 XtVaGetValues (can, XmNwidth, &w2, NULL);
1516 XtVaSetValues ((w1 > w2 ? can : ok), XmNwidth, (w1 > w2 ? w1 : w2), NULL);
1518 XtVaGetValues (up, XmNwidth, &w1, NULL);
1519 XtVaGetValues (down, XmNwidth, &w2, NULL);
1520 XtVaSetValues ((w1 > w2 ? down : up), XmNwidth, (w1 > w2 ? w1 : w2), NULL);
1526 /* The main demo-mode command loop.
1531 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1532 XrmRepresentation *type, XrmValue *value, XPointer closure)
1535 for (i = 0; quarks[i]; i++)
1537 if (bindings[i] == XrmBindTightly)
1538 fprintf (stderr, (i == 0 ? "" : "."));
1539 else if (bindings[i] == XrmBindLoosely)
1540 fprintf (stderr, "*");
1542 fprintf (stderr, " ??? ");
1543 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1546 fprintf (stderr, ": %s\n", (char *) value->addr);
1554 the_network_is_not_the_computer (Widget parent)
1556 Display *dpy = XtDisplay (parent);
1557 char *rversion, *ruser, *rhost;
1558 char *luser, *lhost;
1560 struct passwd *p = getpwuid (getuid ());
1561 const char *d = DisplayString (dpy);
1563 # if defined(HAVE_UNAME)
1565 if (uname (&uts) < 0)
1566 lhost = "<UNKNOWN>";
1568 lhost = uts.nodename;
1570 strcpy (lhost, getenv("SYS$NODE"));
1571 # else /* !HAVE_UNAME && !VMS */
1572 strcat (lhost, "<UNKNOWN>");
1573 # endif /* !HAVE_UNAME && !VMS */
1575 if (p && p->pw_name)
1580 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1582 /* Make a buffer that's big enough for a number of copies of all the
1583 strings, plus some. */
1584 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1585 (ruser ? strlen(ruser) : 0) +
1586 (rhost ? strlen(rhost) : 0) +
1593 if (!rversion || !*rversion)
1597 "The XScreenSaver daemon doesn't seem to be running\n"
1598 "on display \"%s\". You can launch it by selecting\n"
1599 "`Restart Daemon' from the File menu, or by typing\n"
1600 "\"xscreensaver &\" in a shell.",
1603 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1605 /* Warn that the two processes are running as different users.
1609 "%s is running as user \"%s\" on host \"%s\".\n"
1610 "But the xscreensaver managing display \"%s\"\n"
1611 "is running as user \"%s\" on host \"%s\".\n"
1613 "Since they are different users, they won't be reading/writing\n"
1614 "the same ~/.xscreensaver file, so %s isn't\n"
1615 "going to work right.\n"
1617 "Either re-run %s as \"%s\", or re-run\n"
1618 "xscreensaver as \"%s\" (which you can do by\n"
1619 "selecting `Restart Daemon' from the File menu.)\n",
1620 progname, luser, lhost,
1622 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1624 progname, (ruser ? ruser : "???"),
1627 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1629 /* Warn that the two processes are running on different hosts.
1633 "%s is running as user \"%s\" on host \"%s\".\n"
1634 "But the xscreensaver managing display \"%s\"\n"
1635 "is running as user \"%s\" on host \"%s\".\n"
1637 "If those two machines don't share a file system (that is,\n"
1638 "if they don't see the same ~%s/.xscreensaver file) then\n"
1639 "%s won't work right.\n"
1641 "You can restart the daemon on \"%s\" as \"%s\" by\n"
1642 "selecting `Restart Daemon' from the File menu.)",
1643 progname, luser, lhost,
1645 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1650 else if (!!strcmp (rversion, short_version))
1652 /* Warn that the version numbers don't match.
1656 "This is %s version %s.\n"
1657 "But the xscreensaver managing display \"%s\"\n"
1658 "is version %s. This could cause problems.",
1659 progname, short_version,
1666 warning_dialog (parent, msg, 1);
1672 /* We use this error handler so that X errors are preceeded by the name
1673 of the program that generated them.
1676 demo_ehandler (Display *dpy, XErrorEvent *error)
1678 fprintf (stderr, "\nX error in %s:\n", progname);
1679 XmuPrintDefaultErrorMessage (dpy, error, stderr);
1687 __extension__ /* shut up about "string length is greater than the length
1688 ISO C89 compilers are required to support" when including
1692 static char *defaults[] = {
1693 #include "XScreenSaver_ad.h"
1694 #include "XScreenSaver_Xm_ad.h"
1700 main (int argc, char **argv)
1703 prefs_pair Pair, *pair;
1704 saver_preferences P, P2, *p, *p2;
1708 Widget toplevel_shell, dialog;
1709 char *real_progname = argv[0];
1712 s = strrchr (real_progname, '/');
1713 if (s) real_progname = s+1;
1720 memset (p, 0, sizeof (*p));
1721 memset (p2, 0, sizeof (*p2));
1723 global_prefs_pair = pair;
1725 progname = real_progname;
1727 /* We must read exactly the same resources as xscreensaver.
1728 That means we must have both the same progclass *and* progname,
1729 at least as far as the resource database is concerned. So,
1730 put "xscreensaver" in argv[0] while initializing Xt.
1732 argv[0] = "xscreensaver";
1736 toplevel_shell = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1739 dpy = XtDisplay (toplevel_shell);
1740 db = XtDatabase (dpy);
1741 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1742 XSetErrorHandler (demo_ehandler);
1744 /* Complain about unrecognized command-line arguments.
1746 for (i = 1; i < argc; i++)
1749 if (s[0] == '-' && s[1] == '-')
1751 if (!strcmp (s, "-prefs"))
1755 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
1761 short_version = (char *) malloc (5);
1762 memcpy (short_version, screensaver_id + 17, 4);
1763 short_version [4] = 0;
1765 /* Load the init file, which may end up consulting the X resource database
1766 and the site-wide app-defaults file. Note that at this point, it's
1767 important that `progname' be "xscreensaver", rather than whatever
1771 load_init_file (dpy, p);
1774 /* Now that Xt has been initialized, and the resources have been read,
1775 we can set our `progname' variable to something more in line with
1778 progname = real_progname;
1783 XrmName name = { 0 };
1784 XrmClass class = { 0 };
1786 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1792 /* Intern the atoms that xscreensaver_command() needs.
1794 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1795 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1796 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1797 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
1798 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1799 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1800 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1801 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1802 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
1803 XA_BLANK = XInternAtom (dpy, "BLANK", False);
1804 XA_LOCK = XInternAtom (dpy, "LOCK", False);
1805 XA_EXIT = XInternAtom (dpy, "EXIT", False);
1806 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1808 /* Create the window and all its widgets.
1810 dialog = create_xscreensaver_demo (toplevel_shell);
1812 /* Set the window's title. */
1815 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1816 char *s1, *s2, *s3, *s4;
1817 s1 = (char *) strchr(v, ' '); s1++;
1818 s2 = (char *) strchr(s1, ' ');
1819 s3 = (char *) strchr(v, '('); s3++;
1820 s4 = (char *) strchr(s3, ')');
1823 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
1824 XtVaSetValues (toplevel_shell, XtNtitle, title, NULL);
1828 sanity_check_resources (toplevel_shell);
1829 add_callbacks (toplevel_shell, pair);
1830 populate_hack_list (toplevel_shell, pair);
1831 populate_prefs_page (toplevel_shell, pair);
1832 sensitize_demo_widgets (toplevel_shell, False);
1833 scroll_to_current_hack (toplevel_shell, pair);
1835 XtManageChild (dialog);
1836 XtRealizeWidget(toplevel_shell);
1838 /* The next few calls must come after XtRealizeWidget(). */
1839 pixmapify_buttons (toplevel_shell);
1840 hack_button_sizes (toplevel_shell);
1841 ensure_selected_item_visible (name_to_widget (toplevel_shell, "list"));
1844 XtVaSetValues (toplevel_shell, XmNallowShellResize, False, NULL);
1847 /* Handle the -prefs command-line argument. */
1850 Widget tabber = name_to_widget (toplevel_shell, "folder");
1851 Widget this_tab = name_to_widget (toplevel_shell, "optionsTab");
1852 Widget this_page = name_to_widget (toplevel_shell, "preferencesForm");
1855 if (!tabber) abort();
1857 XtVaGetValues (tabber, XmNnumChildren, &nkids, XmNchildren, &kids, NULL);
1860 XtUnmanageChildren (kids, nkids);
1862 XtManageChild (this_page);
1864 XmProcessTraversal (this_tab, XmTRAVERSE_CURRENT);
1867 /* Issue any warnings about the running xscreensaver daemon. */
1868 the_network_is_not_the_computer (toplevel_shell);
1871 XtAppMainLoop (app);
1875 #endif /* HAVE_MOTIF -- whole file */