1 /* demo.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-1998 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_ATHENA_KLUDGE /* don't ask */
19 # define HAVE_ATHENA 1
29 # include <pwd.h> /* for getpwuid() */
35 # include <sys/utsname.h> /* for uname() */
36 #endif /* HAVE_UNAME */
40 #include <X11/Intrinsic.h>
41 #include <X11/StringDefs.h>
43 /* We don't actually use any widget internals, but these are included
44 so that gdb will have debug info for the widgets... */
45 #include <X11/IntrinsicP.h>
46 #include <X11/ShellP.h>
52 # include <Xm/ToggleB.h>
53 # include <Xm/MessageB.h>
54 # include <Xm/LabelG.h>
55 # include <Xm/RowColumn.h>
57 #else /* HAVE_ATHENA */
58 /* Athena demo code contributed by Jon A. Christopher <jac8782@tamu.edu> */
59 /* Copyright 1997, with the same permissions as above. */
60 # include <X11/Shell.h>
61 # include <X11/Xaw/Form.h>
62 # include <X11/Xaw/Box.h>
63 # include <X11/Xaw/List.h>
64 # include <X11/Xaw/Command.h>
65 # include <X11/Xaw/Toggle.h>
66 # include <X11/Xaw/Viewport.h>
67 # include <X11/Xaw/Dialog.h>
68 # include <X11/Xaw/Scrollbar.h>
69 # include <X11/Xaw/Text.h>
70 #endif /* HAVE_ATHENA */
74 #include "resources.h" /* for parse_time() */
75 #include "visual.h" /* for has_writable_cells() */
76 #include "remote.h" /* for xscreensaver_command() */
85 char *progclass = "XScreenSaver";
89 saver_preferences *a, *b;
93 char *blurb (void) { return progname; }
95 static void run_hack (Display *dpy, int n);
98 static saver_preferences *global_prefs_kludge = 0; /* I hate C so much... */
99 #endif /* HAVE_ATHENA */
101 static char *short_version = 0;
104 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
105 Atom XA_SCREENSAVER_TIME, XA_SCREENSAVER_ID, XA_SELECT, XA_DEMO, XA_RESTART;
107 extern void create_demo_dialog (Widget, Visual *, Colormap);
108 extern void create_preferences_dialog (Widget, Visual *, Colormap);
110 extern Widget demo_dialog;
111 extern Widget label1;
112 extern Widget text_line;
113 extern Widget demo_form;
114 extern Widget demo_list;
115 extern Widget next, prev, done, restart, edit;
117 extern Widget preferences_dialog;
118 extern Widget preferences_form;
119 extern Widget prefs_done, prefs_cancel;
120 extern Widget timeout_text, cycle_text, fade_text, fade_ticks_text;
121 extern Widget lock_timeout_text, passwd_timeout_text;
122 extern Widget verbose_toggle, install_cmap_toggle, fade_toggle, unfade_toggle,
128 # define set_toggle_button_state(toggle,state) \
129 XmToggleButtonSetState ((toggle), (state), True)
130 # define set_text_string(text_widget,string) \
131 XmTextSetString ((text_widget), (string))
132 # define add_button_callback(button,cb,arg) \
133 XtAddCallback ((button), XmNactivateCallback, (cb), (arg))
134 # define add_toggle_callback(button,cb,arg) \
135 XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg))
136 # define add_text_callback add_toggle_callback
138 #else /* HAVE_ATHENA */
140 # define set_toggle_button_state(toggle,state) \
141 XtVaSetValues((toggle), XtNstate, (state), 0)
142 # define set_text_string(text_widget,string) \
143 XtVaSetValues ((text_widget), XtNvalue, (string), 0)
144 # define add_button_callback(button,cb,arg) \
145 XtAddCallback ((button), XtNcallback, (cb), (arg))
146 # define add_toggle_callback add_button_callback
147 # define add_text_callback(b,c,a) ERROR!
149 #endif /* HAVE_ATHENA */
152 #define disable_widget(widget) \
153 XtVaSetValues((widget), XtNsensitive, False, 0)
157 get_text_string (Widget text_widget)
160 return XmTextGetString (text_widget);
161 #else /* HAVE_ATHENA */
163 if (XtIsSubclass(text_widget, textWidgetClass))
164 XtVaGetValues (text_widget, XtNstring, &string, 0);
165 else if (XtIsSubclass(text_widget, dialogWidgetClass))
166 XtVaGetValues (text_widget, XtNvalue, &string, 0);
171 #endif /* HAVE_ATHENA */
175 get_label_string (Widget label_widget)
179 XmString xm_label = 0;
180 XtVaGetValues (label_widget, XmNlabelString, &xm_label, 0);
183 XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
185 #else /* HAVE_ATHENA */
187 XtVaGetValues (label_widget, XtNlabel, &label, 0);
188 return (label ? strdup(label) : 0);
189 #endif /* HAVE_ATHENA */
194 set_label_string (Widget label_widget, char *string)
197 XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET);
198 XtVaSetValues (label_widget, XmNlabelString, xm_string, 0);
199 XmStringFree (xm_string);
200 #else /* HAVE_ATHENA */
201 XtVaSetValues (label_widget, XtNlabel, string, 0);
202 #endif /* HAVE_ATHENA */
207 format_into_label (Widget label, const char *arg)
209 char *text = get_label_string (label);
210 char *buf = (char *) malloc ((text ? strlen(text) : 0) + strlen(arg) + 100);
212 if (!text || !strcmp (text, XtName (label)))
213 strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
215 sprintf (buf, text, arg);
217 set_label_string (label, buf);
223 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
226 ensure_selected_item_visible (Widget list)
231 if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
236 XmNtopItemPosition, &top,
237 XmNvisibleItemCount, &visible,
239 if (pos_list[0] >= top + visible)
241 int pos = pos_list[0] - visible + 1;
242 if (pos < 0) pos = 0;
243 XmListSetPos (list, pos);
245 else if (pos_list[0] < top)
247 XmListSetPos (list, pos_list[0]);
251 XtFree ((char *) pos_list);
253 #else /* HAVE_ATHENA */
254 # ifdef HAVE_XawViewportSetCoordinates
256 int margin = 16; /* should be line height or something. */
259 Dimension list_h = 0, vp_h = 0;
260 Dimension top_margin = 4; /* I don't know where this value comes from */
261 Position vp_x = 0, vp_y = 0, current_y;
263 Widget viewport = XtParent(demo_list);
264 Widget sb = (viewport ? XtNameToWidget(viewport, "*vertical") : 0);
265 float sb_top = 0, sb_size = 0;
266 XawListReturnStruct *current = XawListShowCurrent(demo_list);
267 if (!current || !sb) return;
269 XtVaGetValues(demo_list,
270 XtNnumberStrings, &count,
273 if (count < 2 || list_h < 10) return;
275 XtVaGetValues(viewport, XtNheight, &vp_h, XtNx, &vp_x, XtNy, &vp_y, 0);
276 if (vp_h < 10) return;
278 XtVaGetValues(sb, XtNtopOfThumb, &sb_top, XtNshown, &sb_size, 0);
279 if (sb_size <= 0) return;
281 pos = current->list_index;
282 cratio = ((double) pos) / ((double) count);
283 current_y = (cratio * list_h);
285 if (cratio < sb_top ||
286 cratio > sb_top + sb_size)
289 current_y -= (vp_h - margin - margin);
293 if ((long)current_y >= (long) list_h)
294 current_y = (Position) ((long)list_h - (long)vp_h);
296 if ((long)current_y < (long)top_margin)
297 current_y = (Position)top_margin;
299 XawViewportSetCoordinates (viewport, vp_x, current_y);
301 # endif /* HAVE_XawViewportSetCoordinates */
302 #endif /* HAVE_ATHENA */
306 /* Callback for the text area:
307 - note the text the user has entered;
308 - change the corresponding element in `screenhacks';
309 - write the .xscreensaver file;
310 - tell the xscreensaver daemon to run that hack.
313 text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data)
315 Display *dpy = XtDisplay (text_widget);
316 saver_preferences *p = (saver_preferences *) client_data;
317 char *new_text = get_text_string (text_widget);
319 int hack_number = -1; /* 0-based */
322 XawListReturnStruct *current = XawListShowCurrent(demo_list);
323 hack_number = current->list_index;
324 #else /* HAVE_MOTIF */
327 if (XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
328 hack_number = pos_list[0] - 1;
330 XtFree ((char *) pos_list);
331 #endif /* HAVE_MOTIF */
333 ensure_selected_item_visible (demo_list);
335 if (hack_number < 0 || hack_number >= p->screenhacks_count)
337 set_text_string (text_widget, "");
342 fprintf(stderr, "%d:\nold: %s\nnew: %s\n",
343 hack_number, p->screenhacks [hack_number], new_text);
345 if (p->screenhacks [hack_number])
346 free (p->screenhacks [hack_number]);
347 p->screenhacks [hack_number] = strdup (new_text);
351 XmListDeselectAllItems (demo_list);
353 XmString xmstr = XmStringCreate (new_text, XmSTRING_DEFAULT_CHARSET);
354 XmListReplaceItemsPos (demo_list, &xmstr, 1, hack_number+1);
355 XmStringFree (xmstr);
357 XmListSelectPos (demo_list, hack_number+1, True);
359 #else /* HAVE_ATHENA */
362 Widget vp = XtParent(demo_list);
363 Widget sb = (vp ? XtNameToWidget(vp, "*vertical") : 0);
364 Dimension list_h = 0;
365 Position vp_x = 0, vp_y = 0;
368 XawListUnhighlight (demo_list);
370 XtVaGetValues (vp, XtNx, &vp_x, 0);
371 XtVaGetValues (sb, XtNtopOfThumb, &sb_top, 0);
372 XtVaGetValues (demo_list, XtNheight, &list_h, 0);
373 vp_y = (sb_top * list_h);
374 XtVaSetValues (demo_list,
375 XtNlist, p->screenhacks,
376 XtNnumberStrings, p->screenhacks_count,
378 XawViewportSetCoordinates (vp, vp_x, vp_y);
379 XawListHighlight (demo_list, hack_number);
382 #endif /* HAVE_ATHENA */
384 write_init_file (p, short_version);
386 usleep (500000); /* give the disk time to settle down */
388 run_hack (dpy, hack_number+1);
394 /* Bend over backwards to make hitting Return in the text field do the
397 static void text_enter (Widget w, XEvent *event, String *av, Cardinal *ac)
399 text_cb (w, global_prefs_kludge, 0); /* I hate C so much... */
402 static XtActionsRec actions[] = {{"done", text_enter}
404 static char translations[] = ("<Key>Return: done()\n"
405 "<Key>Linefeed: done()\n"
406 "Ctrl<Key>M: done()\n"
407 "Ctrl<Key>J: done()\n");
408 #endif /* HAVE_ATHENA */
411 /* Callback for the Run Next button.
414 next_cb (Widget button, XtPointer client_data, XtPointer call_data)
417 XawListReturnStruct *current = XawListShowCurrent(demo_list);
419 XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0);
420 if (current->list_index == XAW_LIST_NONE ||
421 current->list_index + 1 >= cnt)
422 current->list_index = 0;
424 current->list_index++;
425 XawListHighlight(demo_list, current->list_index);
427 ensure_selected_item_visible (demo_list);
428 current = XawListShowCurrent(demo_list);
429 XtVaSetValues(text_line, XtNstring, current->string, 0);
431 run_hack (XtDisplay (button), current->list_index + 1);
433 #else /* HAVE_MOTIF */
435 saver_preferences *p = (saver_preferences *) client_data;
439 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
442 XmListDeselectAllItems (demo_list); /* LessTif lossage */
443 XmListSelectPos (demo_list, pos, True);
447 pos = pos_list[0] + 1;
448 if (pos > p->screenhacks_count)
450 XmListDeselectAllItems (demo_list); /* LessTif lossage */
451 XmListSelectPos (demo_list, pos, True);
454 ensure_selected_item_visible (demo_list);
455 run_hack (XtDisplay (button), pos);
457 XtFree ((char *) pos_list);
459 #endif /* HAVE_MOTIF */
463 /* Callback for the Run Previous button.
466 prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
469 XawListReturnStruct *current = XawListShowCurrent(demo_list);
471 XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0);
472 if (current->list_index == XAW_LIST_NONE ||
473 current->list_index <= 0)
474 current->list_index = cnt-1;
476 current->list_index--;
477 XawListHighlight(demo_list, current->list_index);
479 ensure_selected_item_visible (demo_list);
480 current = XawListShowCurrent(demo_list);
481 XtVaSetValues(text_line, XtNstring, current->string, 0);
483 run_hack (XtDisplay (button), current->list_index + 1);
485 #else /* HAVE_MOTIF */
487 saver_preferences *p = (saver_preferences *) client_data;
491 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
493 pos = p->screenhacks_count;
494 XmListDeselectAllItems (demo_list); /* LessTif lossage */
495 XmListSelectPos (demo_list, pos, True);
499 pos = pos_list[0] - 1;
501 pos = p->screenhacks_count;
502 XmListDeselectAllItems (demo_list); /* LessTif lossage */
503 XmListSelectPos (demo_list, pos, True);
506 ensure_selected_item_visible (demo_list);
507 run_hack (XtDisplay (button), pos);
509 XtFree ((char *) pos_list);
511 #endif /* HAVE_MOTIF */
515 /* Callback run when a list element is double-clicked.
518 select_cb (Widget button, XtPointer client_data, XtPointer call_data)
520 /* saver_preferences *p = (saver_preferences *) client_data; */
523 XawListReturnStruct *item = (XawListReturnStruct*)call_data;
524 XtVaSetValues(text_line, XtNstring, item->string, 0);
525 run_hack (XtDisplay (button), item->list_index + 1);
527 #else /* HAVE_MOTIF */
528 XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
531 XmStringGetLtoR (lcb->item, XmSTRING_DEFAULT_CHARSET, &string);
532 set_text_string (text_line, (string ? string : ""));
534 if (lcb->reason == XmCR_DEFAULT_ACTION && string)
535 run_hack (XtDisplay (button), lcb->item_position);
539 #endif /* HAVE_MOTIF */
544 static void pop_preferences_dialog (prefs_pair *pair);
545 static void make_preferences_dialog (prefs_pair *pair, Widget parent);
547 /* Callback for the Preferences button.
550 preferences_cb (Widget button, XtPointer client_data, XtPointer call_data)
552 prefs_pair *pair = (prefs_pair *) client_data;
553 Widget parent = button;
556 parent = XtParent(parent);
557 } while (XtParent(parent));
559 if (! preferences_dialog)
560 make_preferences_dialog (pair, parent);
561 pop_preferences_dialog (pair);
564 /* Callback for the Quit button.
567 quit_cb (Widget button, XtPointer client_data, XtPointer call_data)
569 /* Save here? Right now we don't need to, because we save every time
570 the text field is edited, or the Preferences OK button is pressed.
576 /* Callback for the (now unused) Restart button.
579 restart_cb (Widget button, XtPointer client_data, XtPointer call_data)
581 xscreensaver_command (XtDisplay (button), XA_RESTART, 0, False);
586 pop_up_dialog_box (Widget dialog, Widget form)
589 XtRealizeWidget (dialog);
590 XtPopup (dialog, XtGrabNone);
591 #else /* HAVE_MOTIF */
592 XtRealizeWidget (form);
593 XtManageChild (form);
594 #endif /* HAVE_MOTIF */
595 XMapRaised (XtDisplay (dialog), XtWindow (dialog));
600 make_demo_dialog (Widget toplevel_shell, prefs_pair *pair)
602 saver_preferences *p = pair->a;
603 /* saver_preferences *p2 = pair->b; */
605 Widget parent = toplevel_shell;
606 char **hacks = p->screenhacks;
608 create_demo_dialog (parent,
609 DefaultVisualOfScreen (XtScreen (parent)),
610 DefaultColormapOfScreen (XtScreen (parent)));
611 format_into_label (label1, short_version);
613 add_button_callback (next, next_cb, (XtPointer) p);
614 add_button_callback (prev, prev_cb, (XtPointer) p);
615 add_button_callback (done, quit_cb, (XtPointer) p);
617 add_button_callback(restart,restart_cb, (XtPointer) p);
618 add_button_callback (edit, preferences_cb, (XtPointer) pair);
621 XtAddCallback (demo_list, XmNbrowseSelectionCallback,
622 select_cb, (XtPointer) p);
623 XtAddCallback (demo_list, XmNdefaultActionCallback,
624 select_cb, (XtPointer) p);
625 XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) p);
628 for (; *hacks; hacks++)
630 XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
631 XmListAddItem (demo_list, xmstr, 0);
632 XmStringFree (xmstr);
635 #else /* HAVE_ATHENA */
637 /* Hook up the text line. */
639 XtAppAddActions(XtWidgetToApplicationContext(text_line),
640 actions, XtNumber(actions));
641 XtOverrideTranslations(text_line, XtParseTranslationTable(translations));
644 /* Must realize the widget before populating the list, or the dialog
645 will be as wide as the longest string.
647 XtRealizeWidget (demo_dialog);
649 XtVaSetValues (demo_list,
651 XtNnumberStrings, p->screenhacks_count,
653 XtAddCallback (demo_list, XtNcallback, select_cb, p);
655 /* Now that we've populated the list, make sure that the list is as
656 wide as the dialog itself.
659 Widget viewport = XtParent(demo_list);
660 Widget subform = XtParent(viewport);
661 Widget box = XtNameToWidget(demo_dialog, "*box");
662 Widget label1 = XtNameToWidget(demo_dialog, "*label1");
663 Widget label2 = XtNameToWidget(demo_dialog, "*label2");
664 Dimension x=0, y=0, w=0, h=0, bw=0, w2=0;
665 XtVaGetValues(subform,
666 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
667 XtVaGetValues(box, XtNwidth, &w2, 0);
669 XtResizeWidget(subform, w2, h, bw);
671 /* Why isn't the viewport getting centered? */
672 XtVaGetValues(viewport,
673 XtNx, &x, XtNy, &y, XtNheight, &h, XtNborderWidth, &bw, 0);
674 XtConfigureWidget(viewport, x, y, w2-x-x, h, bw);
676 /* And the text line, too. */
677 XtVaGetValues(text_line,
678 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
679 XtVaGetValues(viewport, XtNwidth, &w2, 0);
681 XtResizeWidget(text_line, w2, h, bw);
683 /* And the labels too. */
684 XtVaGetValues(label1,
685 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
687 XtResizeWidget(label1, w2, h, bw);
689 XtVaGetValues(label2,
690 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
692 XtResizeWidget(label2, w2, h, bw);
696 #endif /* HAVE_ATHENA */
698 pop_up_dialog_box(demo_dialog, demo_form);
701 /* For Athena, have to do this after the dialog is managed. */
702 ensure_selected_item_visible (demo_list);
703 #endif /* HAVE_ATHENA */
707 /* the Preferences dialog
710 /* Helper for the text fields that contain time specifications:
711 this parses the text, and does error checking.
714 hack_time_text (Display *dpy, char *line, Time *store, Bool sec_p)
719 value = parse_time (line, sec_p, True);
720 value *= 1000; /* Time measures in microseconds */
729 /* Callback for text fields that hold a time that default to seconds,
730 when not fully spelled out. client_data is an Time* where the value goes.
733 prefs_sec_cb (Widget button, XtPointer client_data, XtPointer call_data)
735 hack_time_text (XtDisplay (button), get_text_string (button),
736 (Time *) client_data, True);
740 /* Callback for text fields that hold a time that default to minutes,
741 when not fully spelled out. client_data is an Time* where the value goes.
744 prefs_min_cb (Widget button, XtPointer client_data, XtPointer call_data)
746 hack_time_text (XtDisplay (button), get_text_string (button),
747 (Time *) client_data, False);
751 /* Callback for text fields that hold an integer value.
752 client_data is an int* where the value goes.
755 prefs_int_cb (Widget button, XtPointer client_data, XtPointer call_data)
757 char *line = get_text_string (button);
758 int *store = (int *) client_data;
763 else if (sscanf (line, "%u%c", &value, &c) != 1)
764 XBell (XtDisplay (button), 0);
769 /* Callback for toggle buttons. client_data is an Bool* where the value goes.
772 prefs_bool_cb (Widget button, XtPointer client_data, XtPointer call_data)
774 Bool *store = (Bool *) client_data;
776 *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
777 #else /* HAVE_ATHENA */
778 Boolean state = FALSE;
779 XtVaGetValues (button, XtNstate, &state, 0);
781 #endif /* HAVE_ATHENA */
785 /* Callback for the Cancel button on the Preferences dialog.
788 prefs_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
790 XtDestroyWidget (preferences_dialog);
791 preferences_dialog = 0;
792 XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
796 /* Callback for the OK button on the Preferences dialog.
799 prefs_ok_cb (Widget button, XtPointer client_data, XtPointer call_data)
801 prefs_pair *pair = (prefs_pair *) client_data;
802 saver_preferences *p = pair->a;
803 saver_preferences *p2 = pair->b;
805 prefs_cancel_cb (button, 0, call_data);
808 /* Athena doesn't let us put callbacks on these widgets, so run
809 all the callbacks by hand when OK is pressed. */
810 prefs_min_cb (timeout_text, (XtPointer) &p2->timeout, 0);
811 prefs_min_cb (cycle_text, (XtPointer) &p2->cycle, 0);
812 prefs_sec_cb (fade_text, (XtPointer) &p2->fade_seconds, 0);
813 prefs_int_cb (fade_ticks_text, (XtPointer) &p2->fade_ticks, 0);
814 prefs_min_cb (lock_timeout_text, (XtPointer) &p2->lock_timeout, 0);
815 prefs_sec_cb (passwd_timeout_text, (XtPointer) &p2->passwd_timeout, 0);
816 #endif /* HAVE_ATHENA */
818 p->timeout = p2->timeout;
819 p->cycle = p2->cycle;
820 p->lock_timeout = p2->lock_timeout;
821 p->passwd_timeout = p2->passwd_timeout;
822 p->fade_seconds = p2->fade_seconds;
823 p->fade_ticks = p2->fade_ticks;
824 p->verbose_p = p2->verbose_p;
825 p->install_cmap_p = p2->install_cmap_p;
826 p->fade_p = p2->fade_p;
827 p->unfade_p = p2->unfade_p;
828 p->lock_p = p2->lock_p;
830 write_init_file (p, short_version);
835 make_preferences_dialog (prefs_pair *pair, Widget parent)
837 saver_preferences *p = pair->a;
838 saver_preferences *p2 = pair->b;
840 Screen *screen = XtScreen (parent);
841 Display *dpy = XtDisplay (parent);
843 *p2 = *p; /* copy all slots of p into p2. */
845 create_preferences_dialog (parent,
846 DefaultVisualOfScreen (screen),
847 DefaultColormapOfScreen (screen));
849 add_button_callback (prefs_done, prefs_ok_cb, (XtPointer) pair);
850 add_button_callback (prefs_cancel, prefs_cancel_cb, 0);
852 #define CB(widget,type,slot) \
853 add_text_callback ((widget), (type), (XtPointer) (slot))
854 #define CBT(widget,type,slot) \
855 add_toggle_callback ((widget), (type), (XtPointer) (slot))
858 /* When using Athena widgets, we can't set callbacks for these,
859 so in that case, we run them by hand when "OK" is pressed. */
860 CB (timeout_text, prefs_min_cb, &p2->timeout);
861 CB (cycle_text, prefs_min_cb, &p2->cycle);
862 CB (fade_text, prefs_sec_cb, &p2->fade_seconds);
863 CB (fade_ticks_text, prefs_int_cb, &p2->fade_ticks);
864 CB (lock_timeout_text, prefs_min_cb, &p2->lock_timeout);
865 CB (passwd_timeout_text, prefs_sec_cb, &p2->passwd_timeout);
866 #endif /* HAVE_MOTIF */
868 CBT (verbose_toggle, prefs_bool_cb, &p2->verbose_p);
869 CBT (install_cmap_toggle, prefs_bool_cb, &p2->install_cmap_p);
870 CBT (fade_toggle, prefs_bool_cb, &p2->fade_p);
871 CBT (unfade_toggle, prefs_bool_cb, &p2->unfade_p);
872 CBT (lock_toggle, prefs_bool_cb, &p2->lock_p);
877 Bool found_any_writable_cells = False;
878 int nscreens = ScreenCount(dpy);
880 for (i = 0; i < nscreens; i++)
882 Screen *s = ScreenOfDisplay (dpy, i);
883 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
885 found_any_writable_cells = True;
890 if (! found_any_writable_cells) /* fading isn't possible */
892 disable_widget (fade_text);
893 disable_widget (fade_ticks_text);
894 disable_widget (install_cmap_toggle);
895 disable_widget (fade_toggle);
896 disable_widget (unfade_toggle);
902 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
905 format_time (char *buf, Time time)
908 unsigned int h = 0, m = 0;
919 sprintf (buf, "%u:%02u:%02u", h, m, s);
924 pop_preferences_dialog (prefs_pair *pair)
926 /* saver_preferences *p = pair->a; */
927 saver_preferences *p2 = pair->b;
930 format_time (s, p2->timeout); set_text_string(timeout_text, s);
931 format_time (s, p2->cycle); set_text_string(cycle_text, s);
932 format_time (s, p2->lock_timeout); set_text_string(lock_timeout_text, s);
933 format_time (s, p2->passwd_timeout); set_text_string(passwd_timeout_text, s);
934 format_time (s, p2->fade_seconds); set_text_string(fade_text, s);
935 sprintf (s, "%u", p2->fade_ticks); set_text_string(fade_ticks_text, s);
937 set_toggle_button_state (verbose_toggle, p2->verbose_p);
938 set_toggle_button_state (install_cmap_toggle, p2->install_cmap_p);
939 set_toggle_button_state (fade_toggle, p2->fade_p);
940 set_toggle_button_state (unfade_toggle, p2->unfade_p);
941 set_toggle_button_state (lock_toggle, p2->lock_p);
943 pop_up_dialog_box (preferences_dialog, preferences_form);
948 run_hack (Display *dpy, int n)
951 xscreensaver_command (dpy, XA_DEMO, n, False);
956 warning_dialog_dismiss_cb (Widget button, XtPointer client_data,
959 Widget shell = (Widget) client_data;
960 XtDestroyWidget (shell);
964 warning_dialog (Widget parent, const char *message)
966 char *msg = strdup (message);
983 dialog = XmCreateWarningDialog (parent, "versionWarning", av, ac);
985 w = XmMessageBoxGetChild (dialog, XmDIALOG_MESSAGE_LABEL);
986 if (w) XtUnmanageChild (w);
987 w = XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON);
988 if (w) XtUnmanageChild (w);
989 w = XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
990 if (w) XtUnmanageChild (w);
992 ok = XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON);
995 XtSetArg (av[ac], XmNnumColumns, 1); ac++;
996 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++;
997 XtSetArg (av[ac], XmNpacking, XmPACK_COLUMN); ac++;
998 XtSetArg (av[ac], XmNrowColumnType, XmWORK_AREA); ac++;
999 XtSetArg (av[ac], XmNspacing, 0); ac++;
1000 container = XmCreateRowColumn (dialog, "container", av, ac);
1002 #else /* HAVE_ATHENA */
1005 dialog = XtVaCreatePopupShell("warning_dialog", transientShellWidgetClass,
1007 form = XtVaCreateManagedWidget("warning_form", formWidgetClass, dialog, 0);
1009 #endif /* HAVE_ATHENA */
1015 char *s = strchr (head, '\n');
1018 sprintf (name, "label%d", i++);
1021 xmstr = XmStringCreate (head, XmSTRING_DEFAULT_CHARSET);
1023 XtSetArg (av[ac], XmNlabelString, xmstr); ac++;
1024 label = XmCreateLabelGadget (container, name, av, ac);
1025 XtManageChild (label);
1026 XmStringFree (xmstr);
1027 #else /* HAVE_ATHENA */
1029 label = XtVaCreateManagedWidget (name, labelWidgetClass,
1031 XtNleft, XtChainLeft,
1032 XtNright, XtChainRight,
1034 (label ? XtNfromVert : XtNtop),
1035 (label ? label : XtChainTop),
1038 #endif /* HAVE_ATHENA */
1048 XtManageChild (container);
1049 XtRealizeWidget (dialog);
1050 XtManageChild (dialog);
1052 #else /* HAVE_ATHENA */
1054 ok = XtVaCreateManagedWidget ("ok", commandWidgetClass, form,
1055 XtNleft, XtChainLeft,
1056 XtNbottom, XtChainBottom,
1060 XtRealizeWidget (dialog);
1061 XtPopup (dialog, XtGrabNone);
1063 #endif /* HAVE_ATHENA */
1065 add_button_callback (ok, warning_dialog_dismiss_cb, dialog);
1072 /* The main demo-mode command loop.
1077 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1078 XrmRepresentation *type, XrmValue *value, XPointer closure)
1081 for (i = 0; quarks[i]; i++)
1083 if (bindings[i] == XrmBindTightly)
1084 fprintf (stderr, (i == 0 ? "" : "."));
1085 else if (bindings[i] == XrmBindLoosely)
1086 fprintf (stderr, "*");
1088 fprintf (stderr, " ??? ");
1089 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1092 fprintf (stderr, ": %s\n", (char *) value->addr);
1099 the_network_is_not_the_computer (Widget parent)
1101 Display *dpy = XtDisplay (parent);
1102 char *rversion, *ruser, *rhost;
1103 char *luser, *lhost;
1105 struct passwd *p = getpwuid (getuid ());
1106 const char *d = DisplayString (dpy);
1108 # if defined(HAVE_UNAME)
1110 if (uname (&uts) < 0)
1111 lhost = "<UNKNOWN>";
1113 lhost = uts.nodename;
1115 strcpy (lhost, getenv("SYS$NODE"));
1116 # else /* !HAVE_UNAME && !VMS */
1117 strcat (lhost, "<UNKNOWN>");
1118 # endif /* !HAVE_UNAME && !VMS */
1120 if (p && p->pw_name)
1125 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1127 /* Make a buffer that's big enough for a number of copies of all the
1128 strings, plus some. */
1129 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1130 (ruser ? strlen(ruser) : 0) +
1131 (rhost ? strlen(rhost) : 0) +
1138 if (!rversion || !*rversion)
1142 "xscreensaver doesn't seem to be running on display \"%s\".",
1145 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1147 /* Warn that the two processes are running as different users.
1151 "%s is running as user \"%s\" on host \"%s\".\n"
1152 "But the xscreensaver managing display \"%s\"\n"
1153 "is running as user \"%s\" on host \"%s\".\n"
1155 "Since they are different users, they won't be reading/writing\n"
1156 "the same ~/.xscreensaver file, so %s isn't\n"
1157 "going to work right.\n"
1159 "Either re-run %s as \"%s\", or re-run\n"
1160 "xscreensaver as \"%s\".\n",
1161 progname, luser, lhost,
1163 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1165 progname, (ruser ? ruser : "???"),
1168 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1170 /* Warn that the two processes are running on different hosts.
1174 "%s is running as user \"%s\" on host \"%s\".\n"
1175 "But the xscreensaver managing display \"%s\"\n"
1176 "is running as user \"%s\" on host \"%s\".\n"
1178 "If those two machines don't share a file system (that is,\n"
1179 "if they don't see the same ~%s/.xscreensaver file) then\n"
1180 "%s won't work right.",
1181 progname, luser, lhost,
1183 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1187 else if (!!strcmp (rversion, short_version))
1189 /* Warn that the version numbers don't match.
1193 "This is %s version %s.\n"
1194 "But the xscreensaver managing display \"%s\"\n"
1195 "is version %s. This could cause problems.",
1196 progname, short_version,
1203 warning_dialog (parent, msg);
1209 static char *defaults[] = {
1210 #include "XScreenSaver_ad.h"
1215 main (int argc, char **argv)
1218 prefs_pair Pair, *pair;
1219 saver_preferences P, P2, *p, *p2;
1223 Widget toplevel_shell;
1224 char *real_progname = argv[0];
1227 s = strrchr (real_progname, '/');
1228 if (s) real_progname = s+1;
1235 memset (p, 0, sizeof (*p));
1236 memset (p2, 0, sizeof (*p2));
1238 /* We must read exactly the same resources as xscreensaver.
1239 That means we must have both the same progclass *and* progname,
1240 at least as far as the resource database is concerned. So,
1241 put "xscreensaver" in argv[0] while initializing Xt.
1243 argv[0] = "xscreensaver";
1245 toplevel_shell = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1247 dpy = XtDisplay (toplevel_shell);
1248 db = XtDatabase (dpy);
1249 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1251 for (i = 1; i < argc; i++)
1254 if (s[0] == '-' && s[1] == '-')
1256 if (!strcmp (s, "-prefs"))
1260 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
1266 short_version = (char *) malloc (5);
1267 memcpy (short_version, screensaver_id + 17, 4);
1268 short_version [4] = 0;
1271 p->fading_possible_p = True;
1276 /* Now that Xt has been initialized, we can set our `progname' variable
1277 to something that makes more sense (like our "real" argv[0].)
1279 progname = real_progname;
1283 global_prefs_kludge = p; /* I hate C so much... */
1284 #endif /* HAVE_ATHENA */
1288 XrmName name = { 0 };
1289 XrmClass class = { 0 };
1291 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1292 (XtPointer) &count);
1297 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1298 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1299 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1300 XA_SCREENSAVER_TIME = XInternAtom (dpy, "_SCREENSAVER_TIME", False);
1301 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1302 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1303 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1304 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1305 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1307 make_demo_dialog (toplevel_shell, pair);
1311 make_preferences_dialog (pair, toplevel_shell);
1312 pop_preferences_dialog (pair);
1315 the_network_is_not_the_computer (preferences_dialog
1316 ? preferences_dialog