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