ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-2.07.tar.gz
[xscreensaver] / driver / demo.c
1 /* demo.c --- implements the interactive demo-mode and options dialogs.
2  * xscreensaver, Copyright (c) 1993-1997 Jamie Zawinski <jwz@netscape.com>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <X11/Intrinsic.h>
18
19 #ifdef HAVE_MOTIF
20 # include <Xm/Xm.h>
21 # include <Xm/Text.h>
22 # include <Xm/List.h>
23 # include <Xm/ToggleB.h>
24
25 #else  /* HAVE_ATHENA */
26   /* Athena demo code contributed by Jon A. Christopher <jac8782@tamu.edu> */
27   /* Copyright 1997, with the same permissions as above. */
28 # include <X11/StringDefs.h>
29 # include <X11/Shell.h>
30 # include <X11/Xaw/Form.h>
31 # include <X11/Xaw/Box.h>
32 # include <X11/Xaw/List.h>
33 # include <X11/Xaw/Command.h>
34 # include <X11/Xaw/Toggle.h>
35 # include <X11/Xaw/Viewport.h>
36 # include <X11/Xaw/Dialog.h>
37 # include <X11/Xaw/Scrollbar.h>
38 #endif /* HAVE_ATHENA */
39
40 #include "xscreensaver.h"
41 #include "resources.h"          /* for parse_time() */
42 #include <stdio.h>
43 #include <string.h>
44 #include <ctype.h>
45
46 static void demo_mode_hack (saver_info *si, char *);
47 static void demo_mode_done (saver_info *si);
48
49 extern Widget demo_dialog;
50 extern Widget label1;
51 extern Widget text_line;
52 extern Widget demo_form;
53 extern Widget demo_list;
54 extern Widget next, prev, done, restart, edit;
55
56 extern Widget resources_dialog;
57 extern Widget resources_form;
58 extern Widget res_done, res_cancel;
59 extern Widget timeout_text, cycle_text, fade_text, ticks_text;
60 extern Widget lock_time_text, passwd_time_text;
61 extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
62   lock_toggle;
63
64
65 #ifdef HAVE_MOTIF
66
67 # define set_toggle_button_state(toggle,state) \
68   XmToggleButtonSetState ((toggle), (state), True)
69 # define set_text_string(text_widget,string) \
70   XmTextSetString ((text_widget), (string))
71 # define add_button_callback(button,cb,arg) \
72   XtAddCallback ((button), XmNactivateCallback, (cb), (arg))
73 # define add_toggle_callback(button,cb,arg) \
74   XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg))
75 # define add_text_callback add_toggle_callback
76
77 #else  /* HAVE_ATHENA */
78
79 # define set_toggle_button_state(toggle,state) \
80   XtVaSetValues((toggle), XtNstate, (state),  0)
81 # define set_text_string(text_widget,string) \
82   XtVaSetValues ((text_widget), XtNvalue, (string), 0)
83 # define add_button_callback(button,cb,arg) \
84   XtAddCallback ((button), XtNcallback, (cb), (arg))
85 # define add_toggle_callback add_button_callback
86 # define add_text_callback(b,c,a) ERROR!
87
88 #endif /* HAVE_ATHENA */
89
90
91 #define disable_widget(widget) \
92   XtVaSetValues((widget), XtNsensitive, False, 0)
93
94
95 static char *
96 get_text_string (Widget text_widget)
97 {
98 #ifdef HAVE_MOTIF
99   return XmTextGetString (text_widget);
100 #else  /* HAVE_ATHENA */
101   char *string = 0;
102   XtVaGetValues (text_widget, XtNvalue, &string, 0);
103   return string;
104 #endif /* HAVE_ATHENA */
105 }
106
107 static char *
108 get_label_string (Widget label_widget)
109 {
110 #ifdef HAVE_MOTIF
111   char *label = 0;
112   XmString xm_label = 0;
113   XtVaGetValues (label_widget, XmNlabelString, &xm_label, 0);
114   if (!xm_label)
115     return 0;
116   XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
117   return label;
118 #else  /* HAVE_ATHENA */
119   char *label = 0;
120   XtVaGetValues (label_widget, XtNlabel, &label, 0);
121   return (label ? strdup(label) : 0);
122 #endif /* HAVE_ATHENA */
123 }
124
125
126 static void
127 set_label_string (Widget label_widget, char *string)
128 {
129 #ifdef HAVE_MOTIF
130   XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET);
131   XtVaSetValues (label_widget, XmNlabelString, xm_string, 0);
132   XmStringFree (xm_string);
133 #else  /* HAVE_ATHENA */
134   XtVaSetValues (label_widget, XtNlabel, string, 0);
135 #endif /* HAVE_ATHENA */
136 }
137
138
139 void
140 format_into_label (Widget label, const char *arg)
141 {
142   char *text = get_label_string (label);
143   char *buf = (char *) malloc ((text ? strlen(text) : 100) + strlen(arg) + 10);
144
145   if (!text || !strcmp (text, XtName (label)))
146       strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
147     else
148       sprintf (buf, text, arg);
149
150     set_label_string (label, buf);
151     free (buf);
152     XtFree (text);
153 }
154
155
156 void
157 steal_focus_and_colormap (Widget dialog)
158 {
159   Display *dpy = XtDisplay (dialog);
160   Window window = XtWindow (dialog);
161   Colormap cmap = 0;
162   XSetInputFocus (dpy, window, RevertToParent, CurrentTime);
163
164   XtVaGetValues (dialog, XtNcolormap, &cmap, 0);
165   if (cmap)
166     XInstallColormap (dpy, cmap);
167 }
168
169 static void
170 raise_screenhack_dialog (void)
171 {
172   XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
173   if (resources_dialog)
174     XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
175   steal_focus_and_colormap (resources_dialog ? resources_dialog : demo_dialog);
176 }
177
178 static void
179 destroy_screenhack_dialogs (saver_info *si)
180 {
181   saver_screen_info *ssi = si->default_screen;
182
183   if (demo_dialog) XtDestroyWidget (demo_dialog);
184   if (resources_dialog) XtDestroyWidget (resources_dialog);
185   demo_dialog = resources_dialog = 0;
186
187   if (ssi->demo_cmap &&
188       ssi->demo_cmap != ssi->cmap &&
189       ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
190     {
191       XFreeColormap (si->dpy, ssi->demo_cmap);
192       ssi->demo_cmap = 0;
193     }
194
195   /* Since we installed our colormap to display the dialogs properly, put
196      the old one back, so that the screensaver_window is now displayed
197      properly. */
198   if (ssi->cmap)
199     XInstallColormap (si->dpy, ssi->cmap);
200 }
201
202 #ifdef HAVE_MOTIF
203
204 static void
205 text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data)
206 {
207   saver_info *si = (saver_info *) client_data;
208   char *line;
209   line = get_text_string (text_widget);
210   demo_mode_hack (si, line);
211 }
212
213 #endif /* HAVE_MOTIF */
214
215
216 static void
217 select_cb (Widget button, XtPointer client_data, XtPointer call_data)
218 {
219   saver_info *si = (saver_info *) client_data;
220
221 #ifdef HAVE_ATHENA
222   XawListReturnStruct *item = (XawListReturnStruct*)call_data;
223   demo_mode_hack (si, item->string);
224 #else  /* HAVE_MOTIF */
225   XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
226   char *string = 0;
227   if (lcb->item)
228     XmStringGetLtoR (lcb->item, XmSTRING_DEFAULT_CHARSET, &string);
229   set_text_string (text_line, (string ? string : ""));
230   if (lcb->reason == XmCR_DEFAULT_ACTION && string)
231     demo_mode_hack (si, string);
232   if (string)
233     XtFree (string);
234 #endif /* HAVE_MOTIF */
235   steal_focus_and_colormap (demo_dialog);
236 }
237
238
239 #if 0  /* configure does this now */
240 #ifdef HAVE_ATHENA
241 # if !defined(_Viewport_h)
242    /* The R4 Athena libs don't have this function.  I don't know the right
243       way to tell, but I note that the R5 version of Viewport.h defines
244       _XawViewport_h, while the R4 version defines _Viewport_h.  So we'll
245      try and key off of that... */
246 #  define HAVE_XawViewportSetCoordinates
247 # endif
248 #endif /* HAVE_ATHENA */
249 #endif /* 0 */
250
251
252 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
253  */
254 static void
255 ensure_selected_item_visible (Widget list)
256 {
257 #ifdef HAVE_MOTIF
258   int *pos_list = 0;
259   int pos_count = 0;
260   if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
261     {
262       int top = -2;
263       int visible = 0;
264       XtVaGetValues (list,
265                      XmNtopItemPosition, &top,
266                      XmNvisibleItemCount, &visible,
267                      0);
268       if (pos_list[0] >= top + visible)
269         {
270           int pos = pos_list[0] - visible + 1;
271           if (pos < 0) pos = 0;
272           XmListSetPos (list, pos);
273         }
274       else if (pos_list[0] < top)
275         {
276           XmListSetPos (list, pos_list[0]);
277         }
278     }
279   if (pos_list)
280     XtFree ((char *) pos_list);
281
282 #else  /* HAVE_ATHENA */
283 # ifdef HAVE_XawViewportSetCoordinates
284
285   int margin = 16;      /* should be line height or something. */
286   int count = 0;
287   int pos;
288   Dimension list_h = 0, vp_h = 0;
289   Dimension top_margin = 4;  /* I don't know where this value comes from */
290   Position vp_x = 0, vp_y = 0, current_y;
291   double cratio;
292   Widget viewport = XtParent(demo_list);
293   Widget sb = (viewport ? XtNameToWidget(viewport, "*vertical") : 0);
294   float sb_top = 0, sb_size = 0;
295   XawListReturnStruct *current = XawListShowCurrent(demo_list);
296   if (!current || !sb) return;
297
298   XtVaGetValues(demo_list,
299                 XtNnumberStrings, &count,
300                 XtNheight, &list_h,
301                 0);
302   if (count < 2 || list_h < 10) return;
303
304   XtVaGetValues(viewport, XtNheight, &vp_h, XtNx, &vp_x, XtNy, &vp_y, 0);
305   if (vp_h < 10) return;
306
307   XtVaGetValues(sb, XtNtopOfThumb, &sb_top, XtNshown, &sb_size, 0);
308   if (sb_size <= 0) return;
309
310   pos = current->list_index;
311   cratio = ((double) pos)  / ((double) count);
312   current_y = (cratio * list_h);
313
314   if (cratio < sb_top ||
315       cratio > sb_top + sb_size)
316     {
317       if (cratio < sb_top)
318         current_y -= (vp_h - margin - margin);
319       else
320         current_y -= margin;
321
322       if ((long)current_y >= (long) list_h)
323         current_y = (Position) ((long)list_h - (long)vp_h);
324
325       if ((long)current_y < (long)top_margin)
326         current_y = (Position)top_margin;
327
328       XawViewportSetCoordinates (viewport, vp_x, current_y);
329     }
330 # endif /* HAVE_XawViewportSetCoordinates */
331 #endif /* HAVE_ATHENA */
332 }
333
334
335 static void
336 next_cb (Widget button, XtPointer client_data, XtPointer call_data)
337 {
338   saver_info *si = (saver_info *) client_data;
339
340 #ifdef HAVE_ATHENA
341   int cnt;
342   XawListReturnStruct *current = XawListShowCurrent(demo_list);
343   if (current->list_index == XAW_LIST_NONE)
344     XawListHighlight(demo_list,1);
345   else
346     {
347       XtVaGetValues(demo_list,
348                     XtNnumberStrings, &cnt,
349                     NULL);
350       if (current->list_index + 1 < cnt)
351         {
352           current->list_index++;
353           XawListHighlight(demo_list, current->list_index);
354         }
355     }
356
357   ensure_selected_item_visible (demo_list);
358   current = XawListShowCurrent(demo_list);
359   demo_mode_hack (si, current->string);
360
361 #else  /* HAVE_MOTIF */
362
363   int *pos_list;
364   int pos_count;
365   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
366     XmListSelectPos (demo_list, 1, True);
367   else
368     {
369       int pos = pos_list [0];
370       XmListSelectPos (demo_list, pos + 1, True);
371       XtFree ((char *) pos_list);
372       if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
373         abort ();
374       if (pos_list [0] == pos)
375         XmListSelectPos (demo_list, 1, True);
376       XtFree ((char *) pos_list);
377     }
378   ensure_selected_item_visible (demo_list);
379   demo_mode_hack (si, get_text_string (text_line));
380
381 #endif /* HAVE_MOTIF */
382 }
383
384
385 static void
386 prev_cb (Widget button, XtPointer client_data, XtPointer call_data)
387 {
388   saver_info *si = (saver_info *) client_data;
389
390 #ifdef HAVE_ATHENA
391   XawListReturnStruct *current=XawListShowCurrent(demo_list);
392   if (current->list_index == XAW_LIST_NONE)
393     XawListHighlight(demo_list,1);
394   else
395     {
396       if (current->list_index>=1)
397         {
398           current->list_index--;
399           XawListHighlight(demo_list, current->list_index);
400         }
401     }
402
403   ensure_selected_item_visible (demo_list);
404   current = XawListShowCurrent(demo_list);
405   demo_mode_hack (si, current->string);
406
407 #else  /* HAVE_MOTIF */
408
409   int *pos_list;
410   int pos_count;
411   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
412     XmListSelectPos (demo_list, 0, True);
413   else
414     {
415       XmListSelectPos (demo_list, pos_list [0] - 1, True);
416       XtFree ((char *) pos_list);
417     }
418   ensure_selected_item_visible (demo_list);
419   demo_mode_hack (si, get_text_string (text_line));
420
421 #endif /* HAVE_MOTIF */
422 }
423
424
425 static void pop_resources_dialog (saver_info *si);
426 static void make_resources_dialog (saver_info *si, Widget parent);
427
428 static void
429 edit_cb (Widget button, XtPointer client_data, XtPointer call_data)
430 {
431   saver_info *si = (saver_info *) client_data;
432   saver_screen_info *ssi = si->default_screen;
433   Widget parent = ssi->toplevel_shell;
434   if (! resources_dialog)
435     make_resources_dialog (si, parent);
436   pop_resources_dialog (si);
437 }
438
439 static void
440 done_cb (Widget button, XtPointer client_data, XtPointer call_data)
441 {
442   saver_info *si = (saver_info *) client_data;
443   demo_mode_done (si);
444 }
445
446
447 static void
448 restart_cb (Widget button, XtPointer client_data, XtPointer call_data)
449 {
450   saver_info *si = (saver_info *) client_data;
451   demo_mode_restart_process (si);
452 }
453
454 void
455 pop_up_dialog_box (Widget dialog, Widget form, int where)
456 {
457   /* I'm sure this is the wrong way to pop up a dialog box, but I can't
458      figure out how else to do it.
459
460      It's important that the screensaver dialogs not get decorated or
461      otherwise reparented by the window manager, because they need to be
462      children of the *real* root window, not the WM's virtual root, in
463      order for us to guarentee that they are visible above the screensaver
464      window itself.
465    */
466   Arg av [100];
467   int ac = 0;
468   Dimension sw, sh, x, y, w, h;
469
470 #ifdef HAVE_ATHENA
471   XtRealizeWidget (dialog);
472 #else  /* HAVE_MOTIF */
473   /* Motif likes us to realize the *child* of the shell... */
474   XtRealizeWidget (form);
475 #endif /* HAVE_MOTIF */
476
477   sw = WidthOfScreen (XtScreen (dialog));
478   sh = HeightOfScreen (XtScreen (dialog));
479   ac = 0;
480   XtSetArg (av [ac], XtNwidth, &w); ac++;
481   XtSetArg (av [ac], XtNheight, &h); ac++;
482   XtGetValues (form, av, ac);
483
484 #ifdef DEBUG
485   if (where >= 69)
486     {
487       where -= 69;
488       sw = (sw * 7) / 12;
489     }
490 #endif
491
492   switch (where)
493     {
494     case 0:     /* center it in the top-right quadrant */
495       x = (sw/2 + w) / 2 + (sw/2) - w;
496       y = (sh/2 + h) / 2 - h;
497       break;
498     case 1:     /* center it in the bottom-right quadrant */
499       x = (sw/2 + w) / 2 + (sw/2) - w;
500       y = (sh/2 + h) / 2 + (sh/2) - h;
501       break;
502     case 2:     /* center it on the screen */
503       x = (sw + w) / 2 - w;
504       y = (sh + h) / 2 - h;
505       break;
506     default:
507       abort ();
508     }
509   if (x + w > sw) x = sw - w;
510   if (y + h > sh) y = sh - h;
511   ac = 0;
512   XtSetArg (av [ac], XtNx, x); ac++;
513   XtSetArg (av [ac], XtNy, y); ac++;
514   XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
515
516 #ifdef HAVE_MOTIF
517   XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
518 #endif /* HAVE_MOTIF */
519
520   XtSetValues (dialog, av, ac);
521   XtSetValues (form, av, ac);
522
523 #ifdef HAVE_ATHENA
524   XtPopup (dialog, XtGrabNone);
525 #else  /* HAVE_MOTIF */
526   XtManageChild (form);
527 #endif /* HAVE_MOTIF */
528
529   steal_focus_and_colormap (dialog);
530 }
531
532
533 static void
534 make_screenhack_dialog (saver_info *si)
535 {
536   saver_screen_info *ssi = si->default_screen;
537   Widget parent = ssi->toplevel_shell;
538   char **hacks = si->prefs.screenhacks;
539
540   if (ssi->demo_cmap &&
541       ssi->demo_cmap != ssi->cmap &&
542       ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
543     {
544       XFreeColormap (si->dpy, ssi->demo_cmap);
545       ssi->demo_cmap = 0;
546     }
547
548   if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen))
549     ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen);
550   else
551     ssi->demo_cmap = XCreateColormap (si->dpy,
552                                       RootWindowOfScreen (ssi->screen),
553                                       ssi->default_visual, AllocNone);
554
555   create_demo_dialog (parent, ssi->default_visual, ssi->demo_cmap);
556   format_into_label (label1, si->version);
557
558   add_button_callback (next,    next_cb,    (XtPointer) si);
559   add_button_callback (prev,    prev_cb,    (XtPointer) si);
560   add_button_callback (done,    done_cb,    (XtPointer) si);
561   add_button_callback (restart, restart_cb, (XtPointer) si);
562   add_button_callback (edit,    edit_cb,    (XtPointer) si);
563
564 #ifdef HAVE_MOTIF
565   XtAddCallback (demo_list, XmNbrowseSelectionCallback,
566                  select_cb, (XtPointer) si);
567   XtAddCallback (demo_list, XmNdefaultActionCallback,
568                  select_cb, (XtPointer) si);
569   XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) si);
570
571   for (; *hacks; hacks++)
572     {
573       XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
574       XmListAddItem (demo_list, xmstr, 0);
575       XmStringFree (xmstr);
576     }
577
578 #else  /* HAVE_ATHENA */
579
580   XtVaSetValues (demo_list,
581                  XtNlist, hacks,
582                  XtNnumberStrings, si->prefs.screenhacks_count,
583                  0);
584   XtAddCallback (demo_list, XtNcallback, select_cb, si);
585
586 #endif /* HAVE_ATHENA */
587
588   pop_up_dialog_box(demo_dialog, demo_form,
589 #ifdef DEBUG
590                     (si->prefs.debug_p ? 69 : 0) +
591 #endif
592                     0);
593 }
594
595 \f
596 /* the Screensaver Parameters dialog */
597
598 static struct resources {
599   int timeout, cycle, secs, ticks, lock_time, passwd_time;
600   int verb, cmap, fade, unfade, lock_p;
601 } res;
602
603
604 static void 
605 hack_time_cb (Display *dpy, char *line, int *store, Bool sec_p)
606 {
607   if (*line)
608     {
609       int value;
610       value = parse_time (line, sec_p, True);
611       if (value < 0)
612         /*XBell (dpy, 0)*/;
613       else
614         *store = value;
615     }
616 }
617
618 static void
619 res_sec_cb (Widget button, XtPointer client_data, XtPointer call_data)
620 {
621   hack_time_cb (XtDisplay (button), get_text_string (button),
622                 (int *) client_data, True);
623 }
624
625 static void
626 res_min_cb (Widget button, XtPointer client_data, XtPointer call_data)
627 {
628   hack_time_cb (XtDisplay (button), get_text_string (button),
629                 (int *) client_data, False);
630 }
631
632 static void
633 res_int_cb (Widget button, XtPointer client_data, XtPointer call_data)
634 {
635   char *line = get_text_string (button);
636   int *store = (int *) client_data;
637   unsigned int value;
638   char c;
639   if (! *line)
640     ;
641   else if (sscanf (line, "%u%c", &value, &c) != 1)
642     XBell (XtDisplay (button), 0);
643   else
644     *store = value;
645 }
646
647 static void
648 res_bool_cb (Widget button, XtPointer client_data, XtPointer call_data)
649 {
650   int *store = (int *) client_data;
651 #ifdef HAVE_MOTIF
652   *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
653 #else /* HAVE_ATHENA */
654   Boolean state = FALSE;
655   XtVaGetValues (button, XtNstate, &state, NULL);
656   *store = state;
657 #endif /* HAVE_ATHENA */
658 }
659
660 static void
661 res_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data)
662 {
663   XtDestroyWidget (resources_dialog);
664   resources_dialog = 0;
665   raise_screenhack_dialog ();
666 }
667
668
669 static void
670 res_done_cb (Widget button, XtPointer client_data, XtPointer call_data)
671 {
672   saver_info *si = (saver_info *) client_data;
673   saver_preferences *p = &si->prefs;
674
675   res_cancel_cb (button, client_data, call_data);
676
677 #ifdef HAVE_ATHENA
678   /* Check all text widgets, since we don't have callbacks for these. */
679   res_min_cb (timeout_text,     (XtPointer) &res.timeout,     NULL);
680   res_min_cb (cycle_text,       (XtPointer) &res.cycle,       NULL);
681   res_sec_cb (fade_text,        (XtPointer) &res.secs,        NULL);
682   res_int_cb (ticks_text,       (XtPointer) &res.ticks,       NULL);
683   res_min_cb (lock_time_text,   (XtPointer) &res.lock_time,   NULL);
684   res_sec_cb (passwd_time_text, (XtPointer) &res.passwd_time, NULL);
685 #endif /* HAVE_ATHENA */
686
687   /* Throttle the timeouts to minimum sane values. */
688   if (res.timeout < 5) res.timeout = 5;
689   if (res.cycle < 2) res.cycle = 2;
690   if (res.passwd_time < 10) res.passwd_time = 10;
691
692   p->timeout = res.timeout * 1000;
693   p->cycle = res.cycle * 1000;
694   p->lock_timeout = res.lock_time * 1000;
695 #ifndef NO_LOCKING
696   p->passwd_timeout = res.passwd_time * 1000;
697 #endif
698   p->fade_seconds = res.secs;
699   p->fade_ticks = res.ticks;
700   p->verbose_p = res.verb;
701   p->install_cmap_p = res.cmap;
702   p->fade_p = res.fade;
703   p->unfade_p = res.unfade;
704   p->lock_p = res.lock_p;
705
706 #ifdef DEBUG
707   if (p->debug_p && p->verbose_p)
708     fprintf (stderr, "%s: parameters changed:\n\
709         timeout: %d\n\tcycle:   %d\n\tlock:    %d\n\tpasswd:  %d\n\
710         fade:    %d\n\tfade:    %d\n\tverbose: %d\n\tinstall: %d\n\
711         fade:    %d\n\tunfade:  %d\n\tlock:    %d\n",
712              progname, p->timeout, p->cycle, p->lock_timeout,
713 # ifdef NO_LOCKING
714              0,
715 # else
716              p->passwd_timeout,
717 # endif
718              p->fade_seconds, p->fade_ticks, p->verbose_p, p->install_cmap_p,
719              p->fade_p, p->unfade_p, p->lock_p);
720 #endif /* DEBUG */
721
722 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
723   if (p->use_mit_saver_extension || p->use_sgi_saver_extension)
724     {
725       /* Need to set the server timeout to the new one the user has picked.
726        */
727       int server_timeout, server_interval, prefer_blank, allow_exp;
728       XGetScreenSaver (si->dpy, &server_timeout, &server_interval,
729                        &prefer_blank, &allow_exp);
730       if (server_timeout != (p->timeout / 1000))
731         {
732           server_timeout = (p->timeout / 1000);
733           if (p->verbose_p)
734             fprintf (stderr,
735                    "%s: configuring server for saver timeout of %d seconds.\n",
736                      progname, server_timeout);
737           /* Leave all other parameters the same. */
738           XSetScreenSaver (si->dpy, server_timeout, server_interval,
739                            prefer_blank, allow_exp);
740         }
741     }
742 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
743 }
744
745
746 static void
747 make_resources_dialog (saver_info *si, Widget parent)
748 {
749   saver_screen_info *ssi = si->default_screen;
750
751   if (ssi->demo_cmap &&
752       ssi->demo_cmap != ssi->cmap &&
753       ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen))
754     {
755       XFreeColormap (si->dpy, ssi->demo_cmap);
756       ssi->demo_cmap = 0;
757     }
758
759   if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen))
760     ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen);
761   else
762     ssi->demo_cmap = XCreateColormap (si->dpy,
763                                      RootWindowOfScreen (ssi->screen),
764                                      ssi->default_visual, AllocNone);
765
766   create_resources_dialog (parent, ssi->default_visual, ssi->demo_cmap);
767
768   add_button_callback (res_done,   res_done_cb,   (XtPointer) si);
769   add_button_callback (res_cancel, res_cancel_cb, (XtPointer) si);
770
771 #define CB(widget,type,slot) \
772         add_text_callback ((widget), (type), (XtPointer) (slot))
773 #define CBT(widget,type,slot) \
774         add_toggle_callback ((widget), (type), (XtPointer) (slot))
775
776 #ifdef HAVE_MOTIF
777   /* When using Athena widgets, we can't set callbacks for these,
778      so we'll check them all if "done" gets pressed.
779    */
780   CB (timeout_text,     res_min_cb,  &res.timeout);
781   CB (cycle_text,       res_min_cb,  &res.cycle);
782   CB (fade_text,        res_sec_cb,  &res.secs);
783   CB (ticks_text,       res_int_cb,  &res.ticks);
784   CB (lock_time_text,   res_min_cb,  &res.lock_time);
785   CB (passwd_time_text, res_sec_cb,  &res.passwd_time);
786 #endif /* HAVE_MOTIF */
787
788   CBT (verbose_toggle,  res_bool_cb, &res.verb);
789   CBT (cmap_toggle,     res_bool_cb, &res.cmap);
790   CBT (fade_toggle,     res_bool_cb, &res.fade);
791   CBT (unfade_toggle,   res_bool_cb, &res.unfade);
792   CBT (lock_toggle,     res_bool_cb, &res.lock_p);
793 #undef CB
794 #undef CBT
795
796   if (si->locking_disabled_p)
797     {
798       disable_widget (passwd_time_text);
799       disable_widget (lock_time_text);
800       disable_widget (lock_toggle);
801     }
802   if (CellsOfScreen (XtScreen (parent)) <= 2)
803     {
804       disable_widget (fade_text);
805       disable_widget (ticks_text);
806       disable_widget (cmap_toggle);
807       disable_widget (fade_toggle);
808       disable_widget (unfade_toggle);
809     }
810 }
811
812
813 static void
814 fmt_time (char *buf, unsigned int s, int min_p)
815 {
816   unsigned int h = 0, m = 0;
817   if (s >= 60)
818     {
819       m += (s / 60);
820       s %= 60;
821     }
822   if (m >= 60)
823     {
824       h += (m / 60);
825       m %= 60;
826     }
827 /*
828   if (min_p && h == 0 && s == 0)
829     sprintf (buf, "%u", m);
830   else if (!min_p && h == 0 && m == 0)
831     sprintf (buf, "%u", s);
832   else
833   if (h == 0)
834     sprintf (buf, "%u:%02u", m, s);
835   else
836 */
837     sprintf (buf, "%u:%02u:%02u", h, m, s);
838 }
839
840 static void
841 pop_resources_dialog (saver_info *si)
842 {
843   saver_preferences *p = &si->prefs;
844   char buf [100];
845
846   res.timeout = p->timeout / 1000;
847   res.cycle = p->cycle / 1000;
848   res.lock_time = p->lock_timeout / 1000;
849 #ifndef NO_LOCKING
850   res.passwd_time = p->passwd_timeout / 1000;
851 #endif
852   res.secs = p->fade_seconds;
853   res.ticks = p->fade_ticks;
854   res.verb = p->verbose_p;
855   res.cmap = p->install_cmap_p;
856   res.fade = p->fade_p;
857   res.unfade = p->unfade_p;
858   res.lock_p = (p->lock_p && !si->locking_disabled_p);
859
860   fmt_time (buf, res.timeout, 1);     set_text_string (timeout_text, buf);
861   fmt_time (buf, res.cycle, 1);       set_text_string (cycle_text, buf);
862   fmt_time (buf, res.lock_time, 1);   set_text_string (lock_time_text, buf);
863   fmt_time (buf, res.passwd_time, 0); set_text_string (passwd_time_text, buf);
864   fmt_time (buf, res.secs, 0);        set_text_string (fade_text, buf);
865   sprintf (buf, "%u", res.ticks);     set_text_string (ticks_text, buf);
866
867   set_toggle_button_state (verbose_toggle, res.verb);
868   set_toggle_button_state (cmap_toggle, res.cmap);
869   set_toggle_button_state (fade_toggle, res.fade);
870   set_toggle_button_state (unfade_toggle, res.unfade);
871   set_toggle_button_state (lock_toggle, res.lock_p);
872
873   pop_up_dialog_box (resources_dialog, resources_form,
874 #ifdef DEBUG
875                      (si->prefs.debug_p ? 69 : 0) +
876 #endif
877                      1);
878 }
879
880 \f
881 /* The main demo-mode command loop.
882  */
883
884 void
885 demo_mode (saver_info *si)
886 {
887   saver_preferences *p = &si->prefs;
888   si->dbox_up_p = True;
889   initialize_screensaver_window (si);
890   raise_window (si, True, False, False);
891   make_screenhack_dialog (si);
892   while (si->demo_mode_p)
893     {
894       XEvent event;
895       XtAppNextEvent (si->app, &event);
896       switch (event.xany.type)
897         {
898         case 0:         /* synthetic "timeout" event */
899           break;
900
901         case ClientMessage:
902           handle_clientmessage (si, &event, False);
903           break;
904
905         case CreateNotify:
906           if (!p->use_xidle_extension &&
907               !p->use_mit_saver_extension &&
908               !p->use_sgi_saver_extension)
909             {
910               start_notice_events_timer (si, event.xcreatewindow.window);
911 #ifdef DEBUG_TIMERS
912               if (p->verbose_p)
913                 printf ("%s: starting notice_events_timer for 0x%X (%lu)\n",
914                         progname,
915                         (unsigned int) event.xcreatewindow.window,
916                         p->notice_events_timeout);
917 #endif /* DEBUG_TIMERS */
918             }
919           break;
920
921         case ButtonPress:
922         case ButtonRelease:
923           if (!XtWindowToWidget (si->dpy, event.xbutton.window))
924             raise_screenhack_dialog ();
925           /* fall through */
926
927         default:
928 #ifdef HAVE_MIT_SAVER_EXTENSION
929           if (event.type == si->mit_saver_ext_event_number)
930             {
931               /* Get the "real" server window(s) out of the way as soon
932                  as possible. */
933               int i = 0;
934               for (i = 0; i < si->nscreens; i++)
935                 {
936                   saver_screen_info *ssi = &si->screens[i];
937                   if (ssi->server_mit_saver_window &&
938                       window_exists_p (si->dpy, ssi->server_mit_saver_window))
939                     XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
940                 }
941             }
942           else
943 #endif /* HAVE_MIT_SAVER_EXTENSION */
944
945           XtDispatchEvent (&event);
946           break;
947         }
948     }
949   destroy_screenhack_dialogs (si);
950   initialize_screensaver_window (si);
951
952   si->demo_mode_p = True;  /* kludge to inhibit unfade... */
953   unblank_screen (si);
954   si->demo_mode_p = False;
955 }
956
957 static void
958 demo_mode_hack (saver_info *si, char *hack)
959 {
960   if (! si->demo_mode_p) abort ();
961   kill_screenhack (si);
962   if (! si->demo_hack)
963     blank_screen (si);
964   si->demo_hack = hack;
965   spawn_screenhack (si, False);
966   /* raise_screenhack_dialog(); */
967 }
968
969 static void
970 demo_mode_done (saver_info *si)
971 {
972   kill_screenhack (si);
973   if (si->demo_hack)
974     unblank_screen (si);
975   si->demo_mode_p = False;
976   si->dbox_up_p = False;
977   si->demo_hack = 0;
978 }