http://x.cybermirror.org/R5contrib/xscreensaver-1.21.tar.Z
[xscreensaver] / driver / demo.c
1 /* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #include <X11/Intrinsic.h>
13
14 #if !__STDC__
15 # define _NO_PROTO
16 #endif
17
18 #include <Xm/Xm.h>
19 #include <Xm/Text.h>
20 #include <Xm/List.h>
21 #include <Xm/ToggleB.h>
22
23 #include "xscreensaver.h"
24 #include <stdio.h>
25
26 extern Time timeout, cycle, lock_timeout;
27 #ifndef NO_LOCKING
28 extern Time passwd_timeout;
29 #endif
30 extern int fade_seconds, fade_ticks;
31 extern Bool verbose_p, install_cmap_p, fade_p, unfade_p;
32 extern Bool lock_p, locking_disabled_p;
33
34 static void demo_mode_hack P((char *));
35 static void demo_mode_done P((void));
36
37 extern void demo_mode_restart_process ();
38
39 extern Widget demo_dialog;
40 extern Widget label1;
41 extern Widget text_line;
42 extern Widget demo_form;
43 extern Widget demo_list;
44 extern Widget next, prev, done, restart, edit;
45
46 extern Widget resources_dialog;
47 extern Widget resources_form;
48 extern Widget res_done, res_cancel;
49 extern Widget timeout_text, cycle_text, fade_text, ticks_text;
50 extern Widget lock_time_text, passwd_time_text;
51 extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
52   lock_toggle;
53
54 extern create_demo_dialog ();
55 extern create_resources_dialog ();
56
57 static void
58 focus_fuckus (dialog)
59      Widget dialog;
60 {
61   XSetInputFocus (XtDisplay (dialog), XtWindow (dialog),
62                   RevertToParent, CurrentTime);
63 }
64
65 static void
66 raise_screenhack_dialog ()
67 {
68   XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
69   if (resources_dialog)
70     XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
71   focus_fuckus (resources_dialog ? resources_dialog : demo_dialog);
72 }
73
74 static void
75 destroy_screenhack_dialogs ()
76 {
77   if (demo_dialog) XtDestroyWidget (demo_dialog);
78   if (resources_dialog) XtDestroyWidget (resources_dialog);
79   demo_dialog = resources_dialog = 0;
80 }
81
82 static void
83 text_cb (button, client_data, call_data)
84      Widget button;
85      XtPointer client_data, call_data;
86 {
87   char *line = XmTextGetString (button);
88   demo_mode_hack (line);
89 }
90
91
92 static void
93 select_cb (button, client_data, call_data)
94      Widget button;
95      XtPointer client_data, call_data;
96 {
97   char **hacks = (char **) client_data;
98   XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
99   XmTextSetString (text_line, hacks [lcb->item_position - 1]);
100   if (lcb->reason == XmCR_DEFAULT_ACTION)
101     text_cb (text_line, 0, 0);
102   focus_fuckus (demo_dialog);
103 }
104
105 static void
106 next_cb (button, client_data, call_data)
107      Widget button;
108      XtPointer client_data, call_data;
109 {
110   int *pos_list;
111   int pos_count;
112   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
113     XmListSelectPos (demo_list, 1, True);
114   else
115     {
116       int pos = pos_list [0];
117       XmListSelectPos (demo_list, pos + 1, True);
118       XtFree ((char *) pos_list);
119       if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
120         abort ();
121       if (pos_list [0] == pos)
122         XmListSelectPos (demo_list, 1, True);
123       XtFree ((char *) pos_list);
124     }
125   text_cb (text_line, 0, 0);
126 }
127
128 static void
129 prev_cb (button, client_data, call_data)
130      Widget button;
131      XtPointer client_data, call_data;
132 {
133   int *pos_list;
134   int pos_count;
135   if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
136     XmListSelectPos (demo_list, 0, True);
137   else
138     {
139       XmListSelectPos (demo_list, pos_list [0] - 1, True);
140       XtFree ((char *) pos_list);
141     }
142   text_cb (text_line, 0, 0);
143 }
144
145
146 static void pop_resources_dialog ();
147 static void make_resources_dialog ();
148
149 static void
150 edit_cb (button, client_data, call_data)
151      Widget button;
152      XtPointer client_data, call_data;
153 {
154   Widget parent = (Widget) client_data;
155   if (! resources_dialog)
156     make_resources_dialog (parent);
157   pop_resources_dialog ();
158 }
159
160 static void
161 done_cb (button, client_data, call_data)
162      Widget button;
163      XtPointer client_data, call_data;
164 {
165   demo_mode_done ();
166 }
167
168
169 static void
170 restart_cb (button, client_data, call_data)
171      Widget button;
172      XtPointer client_data, call_data;
173 {
174   demo_mode_restart_process ();
175 }
176
177 void
178 pop_up_dialog_box (dialog, form, where)
179      Widget dialog, form;
180      int where;
181 {
182   /* I'm sure this is the wrong way to pop up a dialog box, but I can't
183      figure out how else to do it.
184
185      It's important that the screensaver dialogs not get decorated or
186      otherwise reparented by the window manager, because they need to be
187      children of the *real* root window, not the WM's virtual root, in
188      order for us to guarentee tha they are visible above the screensaver
189      window itself.
190    */
191   Arg av [100];
192   int ac = 0;
193   Dimension sw, sh, x, y, w, h;
194   XtRealizeWidget (form);
195   sw = WidthOfScreen (XtScreen (dialog));
196   sh = HeightOfScreen (XtScreen (dialog));
197   ac = 0;
198   XtSetArg (av [ac], XmNwidth, &w); ac++;
199   XtSetArg (av [ac], XmNheight, &h); ac++;
200   XtGetValues (form, av, ac);
201   switch (where)
202     {
203     case 0:     /* center it in the top-right quadrant */
204       x = (sw/2 + w) / 2 + (sw/2) - w;
205       y = (sh/2 + h) / 2 - h;
206       break;
207     case 1:     /* center it in the bottom-right quadrant */
208       x = (sw/2 + w) / 2 + (sw/2) - w;
209       y = (sh/2 + h) / 2 + (sh/2) - h;
210       break;
211     case 2:     /* center it on the screen */
212       x = (sw + w) / 2 - w;
213       y = (sh + h) / 2 - h;
214       break;
215     default:
216       abort ();
217     }
218   if (x + w > sw) x = sw - w;
219   if (y + h > sh) y = sh - h;
220   ac = 0;
221   XtSetArg (av [ac], XmNx, x); ac++;
222   XtSetArg (av [ac], XmNy, y); ac++;
223   XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
224   XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
225   /* I wonder whether this does anything useful? */
226   /*  XtSetArg (av [ac], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); ac++; */
227   XtSetValues (dialog, av, ac);
228   XtSetValues (form, av, ac);
229   XtManageChild (form);
230
231   focus_fuckus (dialog);
232 }
233
234
235 static void
236 make_screenhack_dialog (parent, hacks)
237      Widget parent;
238      char **hacks;
239 {
240   char buf [255];
241   Arg av[10];
242   int ac;
243   char *label;
244   Dimension max_w = 0;
245   XmString xm_label = 0;
246   XmString new_xm_label;
247
248   create_demo_dialog (parent);
249   ac = 0;
250   XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
251   XtGetValues (label1, av, ac);
252   XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
253   if (!strcmp (label, XtName (label1)))
254     strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
255   else
256     sprintf (buf, label, screensaver_version);
257   new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
258   ac = 0;
259   XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
260   XtSetValues (label1, av, ac);
261   XmStringFree (new_xm_label);
262   XtFree (label);
263
264   XtAddCallback (demo_list, XmNbrowseSelectionCallback, select_cb,
265                  (XtPointer) hacks);
266   XtAddCallback (demo_list, XmNdefaultActionCallback, select_cb,
267                  (XtPointer) hacks);
268
269   XtAddCallback (text_line, XmNactivateCallback, text_cb, 0);
270   XtAddCallback (next, XmNactivateCallback, next_cb, 0);
271   XtAddCallback (prev, XmNactivateCallback, prev_cb, 0);
272   XtAddCallback (done, XmNactivateCallback, done_cb, 0);
273   XtAddCallback (restart, XmNactivateCallback, restart_cb, 0);
274   XtAddCallback (edit, XmNactivateCallback, edit_cb, (XtPointer) parent);
275
276   for (; *hacks; hacks++)
277     {
278       XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
279       XmListAddItem (demo_list, xmstr, 0);
280       /* XmListSelectPos (widget, i, False); */
281       XmStringFree (xmstr);
282     }
283
284 #if 0
285   /* Dialogs that have scroll-lists don't obey maxWidth!  Fuck!!  Hack it. */
286   ac = 0;
287   XtSetArg (av [ac], XmNmaxWidth, &max_w); ac++;
288   XtGetValues (demo_dialog, av, ac); /* great, this SEGVs */
289 #endif
290
291   pop_up_dialog_box (demo_dialog, demo_form, 0);
292 }
293
294 \f
295 /* the Screensaver Parameters dialog */
296
297 static struct resources {
298   int timeout, cycle, secs, ticks, lock_time, passwd_time;
299   int verb, cmap, fade, unfade, lock_p;
300 } res;
301
302
303 extern int parse_time ();
304
305 static void 
306 hack_time_cb (dpy, line, store, sec_p)
307      Display *dpy;
308      char *line;
309      int *store;
310      Bool sec_p;
311 {
312   if (*line)
313     {
314       int value;
315       value = parse_time (line, sec_p, True);
316       if (value < 0)
317         /*XBell (dpy, 0)*/;
318       else
319         *store = value;
320     }
321 }
322
323 static void
324 res_sec_cb (button, client_data, call_data)
325      Widget button;
326      XtPointer client_data, call_data;
327 {
328   hack_time_cb (XtDisplay (button), XmTextGetString (button),
329                 (int *) client_data, True);
330 }
331
332 static void
333 res_min_cb (button, client_data, call_data)
334      Widget button;
335      XtPointer client_data, call_data;
336 {
337   hack_time_cb (XtDisplay (button), XmTextGetString (button),
338                 (int *) client_data, False);
339 }
340
341 static void
342 res_int_cb (button, client_data, call_data)
343      Widget button;
344      XtPointer client_data, call_data;
345 {
346   char *line = XmTextGetString (button);
347   int *store = (int *) client_data;
348   unsigned int value;
349   char c;
350   if (! *line)
351     ;
352   else if (sscanf (line, "%u%c", &value, &c) != 1)
353     XBell (XtDisplay (button), 0);
354   else
355     *store = value;
356 }
357
358 static void
359 res_bool_cb (button, client_data, call_data)
360      Widget button;
361      XtPointer client_data, call_data;
362 {
363   int *store = (int *) client_data;
364   *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
365 }
366
367 static void
368 res_cancel_cb (button, client_data, call_data)
369      Widget button;
370      XtPointer client_data, call_data;
371 {
372   XtDestroyWidget (resources_dialog);
373   resources_dialog = 0;
374   raise_screenhack_dialog ();
375 }
376
377
378 static void
379 res_done_cb (button, client_data, call_data)
380      Widget button;
381      XtPointer client_data, call_data;
382 {
383   res_cancel_cb (button, client_data, call_data);
384
385   if (res.timeout < 10) res.timeout = 10;
386   if (res.cycle < 2) res.cycle = 2;
387   if (res.passwd_time < 2) res.passwd_time = 30;
388
389   timeout = res.timeout * 1000;
390   cycle = res.cycle * 1000;
391   lock_timeout = res.lock_time * 1000;
392 #ifndef NO_LOCKING
393   passwd_timeout = res.passwd_time * 1000;
394 #endif
395   fade_seconds = res.secs;
396   fade_ticks = res.ticks;
397   verbose_p = res.verb;
398   install_cmap_p = res.cmap;
399   fade_p = res.fade;
400   unfade_p = res.unfade;
401   lock_p = res.lock_p;
402 }
403
404
405 static void
406 make_resources_dialog (parent)
407      Widget parent;
408 {
409   Arg av[10];
410   int ac;
411
412   create_resources_dialog (parent);
413
414   XtAddCallback (res_done, XmNactivateCallback, res_done_cb, 0);
415   XtAddCallback (res_cancel, XmNactivateCallback, res_cancel_cb, 0);
416
417 #define CB(widget,type,slot) \
418         XtAddCallback ((widget), XmNvalueChangedCallback, (type), \
419                        (XtPointer) (slot))
420   CB (timeout_text,     res_min_cb,  &res.timeout);
421   CB (cycle_text,       res_min_cb,  &res.cycle);
422   CB (fade_text,        res_sec_cb,  &res.secs);
423   CB (ticks_text,       res_int_cb,  &res.ticks);
424   CB (lock_time_text,   res_min_cb,  &res.lock_time);
425   CB (passwd_time_text, res_sec_cb,  &res.passwd_time);
426   CB (verbose_toggle,   res_bool_cb, &res.verb);
427   CB (cmap_toggle,      res_bool_cb, &res.cmap);
428   CB (fade_toggle,      res_bool_cb, &res.fade);
429   CB (unfade_toggle,    res_bool_cb, &res.unfade);
430   CB (lock_toggle,      res_bool_cb, &res.lock_p);
431 #undef CB
432   ac = 0;
433   XtSetArg (av[ac], XmNsensitive, False); ac++;
434
435   if (locking_disabled_p)
436     {
437       XtSetValues (passwd_time_text, av, ac);
438       XtSetValues (lock_time_text, av, ac);
439       XtSetValues (lock_toggle, av, ac);
440     }
441   if (CellsOfScreen (XtScreen (parent)) <= 2)
442     {
443       XtSetValues (fade_text, av, ac);
444       XtSetValues (ticks_text, av, ac);
445       XtSetValues (cmap_toggle, av, ac);
446       XtSetValues (fade_toggle, av, ac);
447       XtSetValues (unfade_toggle, av, ac);
448     }
449 }
450
451
452 static void
453 fmt_time (buf, s, min_p)
454      char *buf;
455      unsigned int s;
456      int min_p;
457 {
458   unsigned int h = 0, m = 0;
459   if (s >= 60)
460     {
461       m += (s / 60);
462       s %= 60;
463     }
464   if (m >= 60)
465     {
466       h += (m / 60);
467       m %= 60;
468     }
469 /*
470   if (min_p && h == 0 && s == 0)
471     sprintf (buf, "%u", m);
472   else if (!min_p && h == 0 && m == 0)
473     sprintf (buf, "%u", s);
474   else
475   if (h == 0)
476     sprintf (buf, "%u:%02u", m, s);
477   else
478 */
479     sprintf (buf, "%u:%02u:%02u", h, m, s);
480 }
481
482 static void
483 pop_resources_dialog ()
484 {
485   char buf [100];
486
487   res.timeout = timeout / 1000;
488   res.cycle = cycle / 1000;
489   res.lock_time = lock_timeout / 1000;
490 #ifndef NO_LOCKING
491   res.passwd_time = passwd_timeout / 1000;
492 #endif
493   res.secs = fade_seconds;
494   res.ticks = fade_ticks;
495   res.verb = verbose_p;
496   res.cmap = install_cmap_p;
497   res.fade = fade_p;
498   res.unfade = unfade_p;
499   res.lock_p = (lock_p && !locking_disabled_p);
500
501   fmt_time (buf, res.timeout, 1);     XmTextSetString (timeout_text, buf);
502   fmt_time (buf, res.cycle, 1);       XmTextSetString (cycle_text, buf);
503   fmt_time (buf, res.lock_time, 1);   XmTextSetString (lock_time_text, buf);
504   fmt_time (buf, res.passwd_time, 0); XmTextSetString (passwd_time_text, buf);
505   fmt_time (buf, res.secs, 0);        XmTextSetString (fade_text, buf);
506   sprintf (buf, "%u", res.ticks);     XmTextSetString (ticks_text, buf);
507
508   XmToggleButtonSetState (verbose_toggle, res.verb, True);
509   XmToggleButtonSetState (cmap_toggle, res.cmap, True);
510   XmToggleButtonSetState (fade_toggle, res.fade, True);
511   XmToggleButtonSetState (unfade_toggle, res.unfade, True);
512   XmToggleButtonSetState (lock_toggle, res.lock_p, True);
513
514   pop_up_dialog_box (resources_dialog, resources_form, 1);
515 }
516
517 \f
518 /* The code on this page isn't actually Motif-specific */
519
520 Bool dbox_up_p = False;
521 Bool demo_mode_p = False;
522
523 extern XtAppContext app;
524 extern Widget toplevel_shell;
525 extern Bool use_xidle;
526 extern Time notice_events_timeout;
527
528 extern char **screenhacks;
529 extern char *demo_hack;
530
531 extern void notice_events_timer P((XtPointer closure, void *timer));
532 extern Bool handle_clientmessage P((/*XEvent *, Bool*/));
533
534 void
535 demo_mode ()
536 {
537   dbox_up_p = True;
538   initialize_screensaver_window ();
539   raise_window (True, False);
540   make_screenhack_dialog (toplevel_shell, screenhacks);
541   while (demo_mode_p)
542     {
543       XEvent event;
544       XtAppNextEvent (app, &event);
545       switch (event.xany.type)
546         {
547         case 0:         /* synthetic "timeout" event */
548           break;
549
550         case ClientMessage:
551           handle_clientmessage (&event, False);
552           break;
553
554         case CreateNotify:
555 #ifdef HAVE_XIDLE
556           if (! use_xidle)
557 #endif
558             XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer,
559                              (XtPointer) event.xcreatewindow.window);
560           break;
561
562         case ButtonPress:
563         case ButtonRelease:
564           if (!XtWindowToWidget (dpy, event.xbutton.window))
565             raise_screenhack_dialog ();
566           /* fall through */
567
568         default:
569           XtDispatchEvent (&event);
570           break;
571         }
572     }
573   destroy_screenhack_dialogs ();
574   initialize_screensaver_window ();
575   unblank_screen ();
576 }
577
578 static void
579 demo_mode_hack (hack)
580      char *hack;
581 {
582   if (! demo_mode_p) abort ();
583   kill_screenhack ();
584   if (! demo_hack)
585     blank_screen ();
586   demo_hack = hack;
587   spawn_screenhack (False);
588 }
589
590 static void
591 demo_mode_done ()
592 {
593   kill_screenhack ();
594   if (demo_hack)
595     unblank_screen ();
596   demo_mode_p = False;
597   dbox_up_p = False;
598   demo_hack = 0;
599 }