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