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