1 /* xscreensaver, Copyright (c) 1993-1996 Jamie Zawinski <jwz@netscape.com>
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
12 #include <X11/Intrinsic.h>
21 #include <Xm/ToggleB.h>
23 #include "xscreensaver.h"
26 #ifdef HAVE_MIT_SAVER_EXTENSION
27 extern int mit_saver_ext_event_number;
28 extern Window server_mit_saver_window;
29 #endif /* HAVE_MIT_SAVER_EXTENSION */
31 #ifdef HAVE_SGI_SAVER_EXTENSION
32 /* extern int sgi_saver_ext_event_number; */
33 #endif /* HAVE_SGI_SAVER_EXTENSION */
35 extern Bool use_mit_saver_extension;
36 extern Bool use_sgi_saver_extension;
38 extern Time timeout, cycle, lock_timeout;
40 extern Time passwd_timeout;
42 extern int fade_seconds, fade_ticks;
43 extern Bool verbose_p, install_cmap_p, fade_p, unfade_p;
44 extern Bool lock_p, locking_disabled_p;
46 static void demo_mode_hack P((char *));
47 static void demo_mode_done P((void));
49 static void focus_fuckus P((Widget dialog));
50 static void text_cb P((Widget button, XtPointer, XtPointer));
52 extern void demo_mode_restart_process ();
54 extern Widget demo_dialog;
56 extern Widget text_line;
57 extern Widget demo_form;
58 extern Widget demo_list;
59 extern Widget next, prev, done, restart, edit;
61 extern Widget resources_dialog;
62 extern Widget resources_form;
63 extern Widget res_done, res_cancel;
64 extern Widget timeout_text, cycle_text, fade_text, ticks_text;
65 extern Widget lock_time_text, passwd_time_text;
66 extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle,
69 extern create_demo_dialog ();
70 extern create_resources_dialog ();
76 XSetInputFocus (XtDisplay (dialog), XtWindow (dialog),
77 RevertToParent, CurrentTime);
81 raise_screenhack_dialog ()
83 XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
85 XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog));
86 focus_fuckus (resources_dialog ? resources_dialog : demo_dialog);
90 destroy_screenhack_dialogs ()
92 if (demo_dialog) XtDestroyWidget (demo_dialog);
93 if (resources_dialog) XtDestroyWidget (resources_dialog);
94 demo_dialog = resources_dialog = 0;
98 text_cb (button, client_data, call_data)
100 XtPointer client_data, call_data;
102 char *line = XmTextGetString (button);
103 demo_mode_hack (line);
108 select_cb (button, client_data, call_data)
110 XtPointer client_data, call_data;
112 char **hacks = (char **) client_data;
113 XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
114 XmTextSetString (text_line, hacks [lcb->item_position - 1]);
115 if (lcb->reason == XmCR_DEFAULT_ACTION)
116 text_cb (text_line, 0, 0);
117 focus_fuckus (demo_dialog);
121 ensure_selected_item_visible (list)
126 if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
131 XmNtopItemPosition, &top,
132 XmNvisibleItemCount, &visible,
134 if (pos_list[0] >= top + visible)
136 int pos = pos_list[0] - visible + 1;
137 if (pos < 0) pos = 0;
138 XmListSetPos (list, pos);
140 else if (pos_list[0] < top)
142 XmListSetPos (list, pos_list[0]);
146 XtFree ((char *) pos_list);
150 next_cb (button, client_data, call_data)
152 XtPointer client_data, call_data;
156 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
157 XmListSelectPos (demo_list, 1, True);
160 int pos = pos_list [0];
161 XmListSelectPos (demo_list, pos + 1, True);
162 XtFree ((char *) pos_list);
163 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
165 if (pos_list [0] == pos)
166 XmListSelectPos (demo_list, 1, True);
167 XtFree ((char *) pos_list);
169 ensure_selected_item_visible (demo_list);
170 text_cb (text_line, 0, 0);
174 prev_cb (button, client_data, call_data)
176 XtPointer client_data, call_data;
180 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
181 XmListSelectPos (demo_list, 0, True);
184 XmListSelectPos (demo_list, pos_list [0] - 1, True);
185 XtFree ((char *) pos_list);
187 ensure_selected_item_visible (demo_list);
188 text_cb (text_line, 0, 0);
192 static void pop_resources_dialog ();
193 static void make_resources_dialog ();
196 edit_cb (button, client_data, call_data)
198 XtPointer client_data, call_data;
200 Widget parent = (Widget) client_data;
201 if (! resources_dialog)
202 make_resources_dialog (parent);
203 pop_resources_dialog ();
207 done_cb (button, client_data, call_data)
209 XtPointer client_data, call_data;
216 restart_cb (button, client_data, call_data)
218 XtPointer client_data, call_data;
220 demo_mode_restart_process ();
224 pop_up_dialog_box (dialog, form, where)
228 /* I'm sure this is the wrong way to pop up a dialog box, but I can't
229 figure out how else to do it.
231 It's important that the screensaver dialogs not get decorated or
232 otherwise reparented by the window manager, because they need to be
233 children of the *real* root window, not the WM's virtual root, in
234 order for us to guarentee that they are visible above the screensaver
239 Dimension sw, sh, x, y, w, h;
240 XtRealizeWidget (form);
241 sw = WidthOfScreen (XtScreen (dialog));
242 sh = HeightOfScreen (XtScreen (dialog));
244 XtSetArg (av [ac], XmNwidth, &w); ac++;
245 XtSetArg (av [ac], XmNheight, &h); ac++;
246 XtGetValues (form, av, ac);
249 case 0: /* center it in the top-right quadrant */
250 x = (sw/2 + w) / 2 + (sw/2) - w;
251 y = (sh/2 + h) / 2 - h;
253 case 1: /* center it in the bottom-right quadrant */
254 x = (sw/2 + w) / 2 + (sw/2) - w;
255 y = (sh/2 + h) / 2 + (sh/2) - h;
257 case 2: /* center it on the screen */
258 x = (sw + w) / 2 - w;
259 y = (sh + h) / 2 - h;
264 if (x + w > sw) x = sw - w;
265 if (y + h > sh) y = sh - h;
267 XtSetArg (av [ac], XmNx, x); ac++;
268 XtSetArg (av [ac], XmNy, y); ac++;
269 XtSetArg (av [ac], XtNoverrideRedirect, True); ac++;
270 XtSetArg (av [ac], XmNdefaultPosition, False); ac++;
271 /* I wonder whether this does anything useful? */
272 /* XtSetArg (av [ac], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); ac++; */
273 XtSetValues (dialog, av, ac);
274 XtSetValues (form, av, ac);
275 XtManageChild (form);
277 focus_fuckus (dialog);
282 make_screenhack_dialog (parent, hacks)
290 XmString xm_label = 0;
291 XmString new_xm_label;
293 create_demo_dialog (parent);
295 XtSetArg (av [ac], XmNlabelString, &xm_label); ac++;
296 XtGetValues (label1, av, ac);
297 XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
298 if (!strcmp (label, XtName (label1)))
299 strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
301 sprintf (buf, label, screensaver_version);
302 new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET);
304 XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++;
305 XtSetValues (label1, av, ac);
306 XmStringFree (new_xm_label);
309 XtAddCallback (demo_list, XmNbrowseSelectionCallback, select_cb,
311 XtAddCallback (demo_list, XmNdefaultActionCallback, select_cb,
314 XtAddCallback (text_line, XmNactivateCallback, text_cb, 0);
315 XtAddCallback (next, XmNactivateCallback, next_cb, 0);
316 XtAddCallback (prev, XmNactivateCallback, prev_cb, 0);
317 XtAddCallback (done, XmNactivateCallback, done_cb, 0);
318 XtAddCallback (restart, XmNactivateCallback, restart_cb, 0);
319 XtAddCallback (edit, XmNactivateCallback, edit_cb, (XtPointer) parent);
321 for (; *hacks; hacks++)
323 XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
324 XmListAddItem (demo_list, xmstr, 0);
325 /* XmListSelectPos (widget, i, False); */
326 XmStringFree (xmstr);
330 /* Dialogs that have scroll-lists don't obey maxWidth! Fuck!! Hack it. */
332 XtSetArg (av [ac], XmNmaxWidth, &max_w); ac++;
333 XtGetValues (demo_dialog, av, ac); /* great, this SEGVs */
336 pop_up_dialog_box (demo_dialog, demo_form, 0);
340 /* the Screensaver Parameters dialog */
342 static struct resources {
343 int timeout, cycle, secs, ticks, lock_time, passwd_time;
344 int verb, cmap, fade, unfade, lock_p;
348 extern int parse_time ();
351 hack_time_cb (dpy, line, store, sec_p)
360 value = parse_time (line, sec_p, True);
369 res_sec_cb (button, client_data, call_data)
371 XtPointer client_data, call_data;
373 hack_time_cb (XtDisplay (button), XmTextGetString (button),
374 (int *) client_data, True);
378 res_min_cb (button, client_data, call_data)
380 XtPointer client_data, call_data;
382 hack_time_cb (XtDisplay (button), XmTextGetString (button),
383 (int *) client_data, False);
387 res_int_cb (button, client_data, call_data)
389 XtPointer client_data, call_data;
391 char *line = XmTextGetString (button);
392 int *store = (int *) client_data;
397 else if (sscanf (line, "%u%c", &value, &c) != 1)
398 XBell (XtDisplay (button), 0);
404 res_bool_cb (button, client_data, call_data)
406 XtPointer client_data, call_data;
408 int *store = (int *) client_data;
409 *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
413 res_cancel_cb (button, client_data, call_data)
415 XtPointer client_data, call_data;
417 XtDestroyWidget (resources_dialog);
418 resources_dialog = 0;
419 raise_screenhack_dialog ();
424 res_done_cb (button, client_data, call_data)
426 XtPointer client_data, call_data;
428 res_cancel_cb (button, client_data, call_data);
430 /* Throttle the timeouts to minimum sane values. */
431 if (res.timeout < 5) res.timeout = 5;
432 if (res.cycle < 2) res.cycle = 2;
433 if (res.passwd_time < 10) res.passwd_time = 10;
435 timeout = res.timeout * 1000;
436 cycle = res.cycle * 1000;
437 lock_timeout = res.lock_time * 1000;
439 passwd_timeout = res.passwd_time * 1000;
441 fade_seconds = res.secs;
442 fade_ticks = res.ticks;
443 verbose_p = res.verb;
444 install_cmap_p = res.cmap;
446 unfade_p = res.unfade;
449 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
450 if (use_mit_saver_extension || use_sgi_saver_extension)
452 /* Need to set the server timeout to the new one the user has picked.
454 int server_timeout, server_interval, prefer_blank, allow_exp;
455 XGetScreenSaver (dpy, &server_timeout, &server_interval,
456 &prefer_blank, &allow_exp);
457 if (server_timeout != (timeout / 1000))
459 server_timeout = (timeout / 1000);
462 "%s: configuring server for saver timeout of %d seconds.\n",
463 progname, server_timeout);
464 /* Leave all other parameters the same. */
465 XSetScreenSaver (dpy, server_timeout, server_interval,
466 prefer_blank, allow_exp);
469 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
474 make_resources_dialog (parent)
480 create_resources_dialog (parent);
482 XtAddCallback (res_done, XmNactivateCallback, res_done_cb, 0);
483 XtAddCallback (res_cancel, XmNactivateCallback, res_cancel_cb, 0);
485 #define CB(widget,type,slot) \
486 XtAddCallback ((widget), XmNvalueChangedCallback, (type), \
488 CB (timeout_text, res_min_cb, &res.timeout);
489 CB (cycle_text, res_min_cb, &res.cycle);
490 CB (fade_text, res_sec_cb, &res.secs);
491 CB (ticks_text, res_int_cb, &res.ticks);
492 CB (lock_time_text, res_min_cb, &res.lock_time);
493 CB (passwd_time_text, res_sec_cb, &res.passwd_time);
494 CB (verbose_toggle, res_bool_cb, &res.verb);
495 CB (cmap_toggle, res_bool_cb, &res.cmap);
496 CB (fade_toggle, res_bool_cb, &res.fade);
497 CB (unfade_toggle, res_bool_cb, &res.unfade);
498 CB (lock_toggle, res_bool_cb, &res.lock_p);
501 XtSetArg (av[ac], XmNsensitive, False); ac++;
503 if (locking_disabled_p)
505 XtSetValues (passwd_time_text, av, ac);
506 XtSetValues (lock_time_text, av, ac);
507 XtSetValues (lock_toggle, av, ac);
509 if (CellsOfScreen (XtScreen (parent)) <= 2)
511 XtSetValues (fade_text, av, ac);
512 XtSetValues (ticks_text, av, ac);
513 XtSetValues (cmap_toggle, av, ac);
514 XtSetValues (fade_toggle, av, ac);
515 XtSetValues (unfade_toggle, av, ac);
521 fmt_time (buf, s, min_p)
526 unsigned int h = 0, m = 0;
538 if (min_p && h == 0 && s == 0)
539 sprintf (buf, "%u", m);
540 else if (!min_p && h == 0 && m == 0)
541 sprintf (buf, "%u", s);
544 sprintf (buf, "%u:%02u", m, s);
547 sprintf (buf, "%u:%02u:%02u", h, m, s);
551 pop_resources_dialog ()
555 res.timeout = timeout / 1000;
556 res.cycle = cycle / 1000;
557 res.lock_time = lock_timeout / 1000;
559 res.passwd_time = passwd_timeout / 1000;
561 res.secs = fade_seconds;
562 res.ticks = fade_ticks;
563 res.verb = verbose_p;
564 res.cmap = install_cmap_p;
566 res.unfade = unfade_p;
567 res.lock_p = (lock_p && !locking_disabled_p);
569 fmt_time (buf, res.timeout, 1); XmTextSetString (timeout_text, buf);
570 fmt_time (buf, res.cycle, 1); XmTextSetString (cycle_text, buf);
571 fmt_time (buf, res.lock_time, 1); XmTextSetString (lock_time_text, buf);
572 fmt_time (buf, res.passwd_time, 0); XmTextSetString (passwd_time_text, buf);
573 fmt_time (buf, res.secs, 0); XmTextSetString (fade_text, buf);
574 sprintf (buf, "%u", res.ticks); XmTextSetString (ticks_text, buf);
576 XmToggleButtonSetState (verbose_toggle, res.verb, True);
577 XmToggleButtonSetState (cmap_toggle, res.cmap, True);
578 XmToggleButtonSetState (fade_toggle, res.fade, True);
579 XmToggleButtonSetState (unfade_toggle, res.unfade, True);
580 XmToggleButtonSetState (lock_toggle, res.lock_p, True);
582 pop_up_dialog_box (resources_dialog, resources_form, 1);
586 /* The code on this page isn't actually Motif-specific */
588 Bool dbox_up_p = False;
589 Bool demo_mode_p = False;
591 extern XtAppContext app;
592 extern Widget toplevel_shell;
593 extern Bool use_xidle_extension;
594 extern Bool use_mit_saver_extension;
595 extern Bool use_sgi_saver_extension;
596 extern Time notice_events_timeout;
598 extern char **screenhacks;
599 extern char *demo_hack;
601 extern void notice_events_timer P((XtPointer closure, XtIntervalId *timer));
602 extern Bool handle_clientmessage P((/*XEvent *, Bool*/));
608 initialize_screensaver_window ();
609 raise_window (True, False);
610 make_screenhack_dialog (toplevel_shell, screenhacks);
614 XtAppNextEvent (app, &event);
615 switch (event.xany.type)
617 case 0: /* synthetic "timeout" event */
621 handle_clientmessage (&event, False);
625 if (!use_xidle_extension &&
626 !use_mit_saver_extension &&
627 !use_sgi_saver_extension)
629 XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer,
630 (XtPointer) event.xcreatewindow.window);
633 printf ("%s: starting notice_events_timer for 0x%X (%lu)\n",
635 (unsigned int) event.xcreatewindow.window,
636 notice_events_timeout);
637 #endif /* DEBUG_TIMERS */
643 if (!XtWindowToWidget (dpy, event.xbutton.window))
644 raise_screenhack_dialog ();
648 #ifdef HAVE_MIT_SAVER_EXTENSION
649 if (event.type == mit_saver_ext_event_number)
651 /* Get the "real" server window out of the way as soon
653 if (server_mit_saver_window &&
654 window_exists_p (dpy, server_mit_saver_window))
655 XUnmapWindow (dpy, server_mit_saver_window);
658 #endif /* HAVE_MIT_SAVER_EXTENSION */
660 XtDispatchEvent (&event);
664 destroy_screenhack_dialogs ();
665 initialize_screensaver_window ();
670 demo_mode_hack (hack)
673 if (! demo_mode_p) abort ();
678 spawn_screenhack (False);
679 /* raise_screenhack_dialog(); */