X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fdemo.c;h=0877ad4ef50b89c3a51f55effa429aa5522f604b;hb=df053bcb240bd8d82e3bebf48a9766a8728bca4b;hp=0603a03a3c3461b18786d48cd1508bb1dfec1e06;hpb=0cac953ce8d5139c1a264b417951ee15a3176b51;p=xscreensaver diff --git a/driver/demo.c b/driver/demo.c index 0603a03a..0877ad4e 100644 --- a/driver/demo.c +++ b/driver/demo.c @@ -1,4 +1,5 @@ -/* xscreensaver, Copyright (c) 1993 Jamie Zawinski +/* demo.c --- implements the interactive demo-mode and options dialogs. + * xscreensaver, Copyright (c) 1993-1997 Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -9,32 +10,46 @@ * implied warranty. */ -#include - -#if !__STDC__ -# define _NO_PROTO +#ifdef HAVE_CONFIG_H +# include "config.h" #endif -#include -#include -#include -#include +#include + +/* We don't actually use any widget internals, but these are included + so that gdb will have debug info for the widgets... */ +#include +#include + +#ifdef HAVE_MOTIF +# include +# include +# include +# include + +#else /* HAVE_ATHENA */ + /* Athena demo code contributed by Jon A. Christopher */ + /* Copyright 1997, with the same permissions as above. */ +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#endif /* HAVE_ATHENA */ #include "xscreensaver.h" +#include "resources.h" /* for parse_time() */ #include +#include +#include -extern Time timeout, cycle, lock_timeout; -#ifndef NO_LOCKING -extern Time passwd_timeout; -#endif -extern int fade_seconds, fade_ticks; -extern Bool verbose_p, install_cmap_p, fade_p, unfade_p; -extern Bool lock_p, locking_disabled_p; - -static void demo_mode_hack P((char *)); -static void demo_mode_done P((void)); - -extern void demo_mode_restart_process (); +static void demo_mode_hack (saver_info *si, char *); +static void demo_mode_done (saver_info *si); extern Widget demo_dialog; extern Widget label1; @@ -51,133 +66,404 @@ extern Widget lock_time_text, passwd_time_text; extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle, lock_toggle; -extern create_demo_dialog (); -extern create_resources_dialog (); + +#ifdef HAVE_MOTIF + +# define set_toggle_button_state(toggle,state) \ + XmToggleButtonSetState ((toggle), (state), True) +# define set_text_string(text_widget,string) \ + XmTextSetString ((text_widget), (string)) +# define add_button_callback(button,cb,arg) \ + XtAddCallback ((button), XmNactivateCallback, (cb), (arg)) +# define add_toggle_callback(button,cb,arg) \ + XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg)) +# define add_text_callback add_toggle_callback + +#else /* HAVE_ATHENA */ + +# define set_toggle_button_state(toggle,state) \ + XtVaSetValues((toggle), XtNstate, (state), 0) +# define set_text_string(text_widget,string) \ + XtVaSetValues ((text_widget), XtNvalue, (string), 0) +# define add_button_callback(button,cb,arg) \ + XtAddCallback ((button), XtNcallback, (cb), (arg)) +# define add_toggle_callback add_button_callback +# define add_text_callback(b,c,a) ERROR! + +#endif /* HAVE_ATHENA */ + + +#define disable_widget(widget) \ + XtVaSetValues((widget), XtNsensitive, False, 0) + + +static char * +get_text_string (Widget text_widget) +{ +#ifdef HAVE_MOTIF + return XmTextGetString (text_widget); +#else /* HAVE_ATHENA */ + char *string = 0; + XtVaGetValues (text_widget, XtNvalue, &string, 0); + return string; +#endif /* HAVE_ATHENA */ +} + +static char * +get_label_string (Widget label_widget) +{ +#ifdef HAVE_MOTIF + char *label = 0; + XmString xm_label = 0; + XtVaGetValues (label_widget, XmNlabelString, &xm_label, 0); + if (!xm_label) + return 0; + XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label); + return label; +#else /* HAVE_ATHENA */ + char *label = 0; + XtVaGetValues (label_widget, XtNlabel, &label, 0); + return (label ? strdup(label) : 0); +#endif /* HAVE_ATHENA */ +} + static void -focus_fuckus (dialog) - Widget dialog; +set_label_string (Widget label_widget, char *string) +{ +#ifdef HAVE_MOTIF + XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET); + XtVaSetValues (label_widget, XmNlabelString, xm_string, 0); + XmStringFree (xm_string); +#else /* HAVE_ATHENA */ + XtVaSetValues (label_widget, XtNlabel, string, 0); +#endif /* HAVE_ATHENA */ +} + + +void +format_into_label (Widget label, const char *arg) +{ + char *text = get_label_string (label); + char *buf = (char *) malloc ((text ? strlen(text) : 100) + strlen(arg) + 10); + + if (!text || !strcmp (text, XtName (label))) + strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY"); + else + sprintf (buf, text, arg); + + set_label_string (label, buf); + free (buf); + XtFree (text); +} + + +void +steal_focus_and_colormap (Widget dialog) { - XSetInputFocus (XtDisplay (dialog), XtWindow (dialog), - RevertToParent, CurrentTime); + Display *dpy = XtDisplay (dialog); + Window window = XtWindow (dialog); + Colormap cmap = 0; + XSetInputFocus (dpy, window, RevertToParent, CurrentTime); + + XtVaGetValues (dialog, XtNcolormap, &cmap, 0); + if (cmap) + XInstallColormap (dpy, cmap); } static void -raise_screenhack_dialog () +raise_screenhack_dialog (void) { XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog)); if (resources_dialog) XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog)); - focus_fuckus (resources_dialog ? resources_dialog : demo_dialog); + steal_focus_and_colormap (resources_dialog ? resources_dialog : demo_dialog); } static void -destroy_screenhack_dialogs () +destroy_screenhack_dialogs (saver_info *si) { + saver_screen_info *ssi = si->default_screen; + if (demo_dialog) XtDestroyWidget (demo_dialog); if (resources_dialog) XtDestroyWidget (resources_dialog); demo_dialog = resources_dialog = 0; + + if (ssi->demo_cmap && + ssi->demo_cmap != ssi->cmap && + ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen)) + { + XFreeColormap (si->dpy, ssi->demo_cmap); + ssi->demo_cmap = 0; + } + + /* Since we installed our colormap to display the dialogs properly, put + the old one back, so that the screensaver_window is now displayed + properly. */ + if (ssi->cmap) + XInstallColormap (si->dpy, ssi->cmap); } +#ifdef HAVE_MOTIF + static void -text_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data) { - char *line = XmTextGetString (button); - demo_mode_hack (line); + saver_info *si = (saver_info *) client_data; + char *line; + line = get_text_string (text_widget); + demo_mode_hack (si, line); } +#endif /* HAVE_MOTIF */ + static void -select_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +select_cb (Widget button, XtPointer client_data, XtPointer call_data) { - char **hacks = (char **) client_data; + saver_info *si = (saver_info *) client_data; + +#ifdef HAVE_ATHENA + XawListReturnStruct *item = (XawListReturnStruct*)call_data; + demo_mode_hack (si, item->string); +#else /* HAVE_MOTIF */ XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data; - XmTextSetString (text_line, hacks [lcb->item_position - 1]); - if (lcb->reason == XmCR_DEFAULT_ACTION) - text_cb (text_line, 0, 0); - focus_fuckus (demo_dialog); + char *string = 0; + if (lcb->item) + XmStringGetLtoR (lcb->item, XmSTRING_DEFAULT_CHARSET, &string); + set_text_string (text_line, (string ? string : "")); + if (lcb->reason == XmCR_DEFAULT_ACTION && string) + demo_mode_hack (si, string); + if (string) + XtFree (string); +#endif /* HAVE_MOTIF */ + steal_focus_and_colormap (demo_dialog); +} + + +#if 0 /* configure does this now */ +#ifdef HAVE_ATHENA +# if !defined(_Viewport_h) + /* The R4 Athena libs don't have this function. I don't know the right + way to tell, but I note that the R5 version of Viewport.h defines + _XawViewport_h, while the R4 version defines _Viewport_h. So we'll + try and key off of that... */ +# define HAVE_XawViewportSetCoordinates +# endif +#endif /* HAVE_ATHENA */ +#endif /* 0 */ + + +/* Why this behavior isn't automatic in *either* toolkit, I'll never know. + */ +static void +ensure_selected_item_visible (Widget list) +{ +#ifdef HAVE_MOTIF + int *pos_list = 0; + int pos_count = 0; + if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0) + { + int top = -2; + int visible = 0; + XtVaGetValues (list, + XmNtopItemPosition, &top, + XmNvisibleItemCount, &visible, + 0); + if (pos_list[0] >= top + visible) + { + int pos = pos_list[0] - visible + 1; + if (pos < 0) pos = 0; + XmListSetPos (list, pos); + } + else if (pos_list[0] < top) + { + XmListSetPos (list, pos_list[0]); + } + } + if (pos_list) + XtFree ((char *) pos_list); + +#else /* HAVE_ATHENA */ +# ifdef HAVE_XawViewportSetCoordinates + + int margin = 16; /* should be line height or something. */ + int count = 0; + int pos; + Dimension list_h = 0, vp_h = 0; + Dimension top_margin = 4; /* I don't know where this value comes from */ + Position vp_x = 0, vp_y = 0, current_y; + double cratio; + Widget viewport = XtParent(demo_list); + Widget sb = (viewport ? XtNameToWidget(viewport, "*vertical") : 0); + float sb_top = 0, sb_size = 0; + XawListReturnStruct *current = XawListShowCurrent(demo_list); + if (!current || !sb) return; + + XtVaGetValues(demo_list, + XtNnumberStrings, &count, + XtNheight, &list_h, + 0); + if (count < 2 || list_h < 10) return; + + XtVaGetValues(viewport, XtNheight, &vp_h, XtNx, &vp_x, XtNy, &vp_y, 0); + if (vp_h < 10) return; + + XtVaGetValues(sb, XtNtopOfThumb, &sb_top, XtNshown, &sb_size, 0); + if (sb_size <= 0) return; + + pos = current->list_index; + cratio = ((double) pos) / ((double) count); + current_y = (cratio * list_h); + + if (cratio < sb_top || + cratio > sb_top + sb_size) + { + if (cratio < sb_top) + current_y -= (vp_h - margin - margin); + else + current_y -= margin; + + if ((long)current_y >= (long) list_h) + current_y = (Position) ((long)list_h - (long)vp_h); + + if ((long)current_y < (long)top_margin) + current_y = (Position)top_margin; + + XawViewportSetCoordinates (viewport, vp_x, current_y); + } +# endif /* HAVE_XawViewportSetCoordinates */ +#endif /* HAVE_ATHENA */ } + static void -next_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +next_cb (Widget button, XtPointer client_data, XtPointer call_data) { + saver_info *si = (saver_info *) client_data; + +#ifdef HAVE_ATHENA + int cnt; + XawListReturnStruct *current = XawListShowCurrent(demo_list); + if (current->list_index == XAW_LIST_NONE) + XawListHighlight(demo_list,1); + else + { + XtVaGetValues(demo_list, + XtNnumberStrings, &cnt, + NULL); + if (current->list_index + 1 < cnt) + { + current->list_index++; + XawListHighlight(demo_list, current->list_index); + } + } + + ensure_selected_item_visible (demo_list); + current = XawListShowCurrent(demo_list); + demo_mode_hack (si, current->string); + +#else /* HAVE_MOTIF */ + int *pos_list; int pos_count; if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) - XmListSelectPos (demo_list, 1, True); + { + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, 1, True); + } else { - int pos = pos_list [0]; - XmListSelectPos (demo_list, pos + 1, True); - XtFree ((char *) pos_list); - if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) - abort (); - if (pos_list [0] == pos) - XmListSelectPos (demo_list, 1, True); - XtFree ((char *) pos_list); + int pos = pos_list[0] + 1; + if (pos > si->prefs.screenhacks_count) + pos = 1; + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, pos, True); } - text_cb (text_line, 0, 0); + XtFree ((char *) pos_list); + ensure_selected_item_visible (demo_list); + demo_mode_hack (si, get_text_string (text_line)); + +#endif /* HAVE_MOTIF */ } + static void -prev_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +prev_cb (Widget button, XtPointer client_data, XtPointer call_data) { + saver_info *si = (saver_info *) client_data; + +#ifdef HAVE_ATHENA + XawListReturnStruct *current=XawListShowCurrent(demo_list); + if (current->list_index == XAW_LIST_NONE) + XawListHighlight(demo_list,1); + else + { + if (current->list_index>=1) + { + current->list_index--; + XawListHighlight(demo_list, current->list_index); + } + } + + ensure_selected_item_visible (demo_list); + current = XawListShowCurrent(demo_list); + demo_mode_hack (si, current->string); + +#else /* HAVE_MOTIF */ + int *pos_list; int pos_count; if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) - XmListSelectPos (demo_list, 0, True); + { + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, 0, True); + } else { + XmListDeselectAllItems(demo_list); /* LessTif lossage */ XmListSelectPos (demo_list, pos_list [0] - 1, True); XtFree ((char *) pos_list); } - text_cb (text_line, 0, 0); + ensure_selected_item_visible (demo_list); + demo_mode_hack (si, get_text_string (text_line)); + +#endif /* HAVE_MOTIF */ } -static void pop_resources_dialog (); -static void make_resources_dialog (); +static void pop_resources_dialog (saver_info *si); +static void make_resources_dialog (saver_info *si, Widget parent); static void -edit_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +edit_cb (Widget button, XtPointer client_data, XtPointer call_data) { - Widget parent = (Widget) client_data; + saver_info *si = (saver_info *) client_data; + saver_screen_info *ssi = si->default_screen; + Widget parent = ssi->toplevel_shell; if (! resources_dialog) - make_resources_dialog (parent); - pop_resources_dialog (); + make_resources_dialog (si, parent); + pop_resources_dialog (si); } static void -done_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +done_cb (Widget button, XtPointer client_data, XtPointer call_data) { - demo_mode_done (); + saver_info *si = (saver_info *) client_data; + demo_mode_done (si); } static void -restart_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +restart_cb (Widget button, XtPointer client_data, XtPointer call_data) { - demo_mode_restart_process (); + saver_info *si = (saver_info *) client_data; + demo_mode_restart_process (si); } + void -pop_up_dialog_box (dialog, form, where) - Widget dialog, form; - int where; +pop_up_dialog_box (Widget dialog, Widget form, int where) { /* I'm sure this is the wrong way to pop up a dialog box, but I can't figure out how else to do it. @@ -185,19 +471,34 @@ pop_up_dialog_box (dialog, form, where) It's important that the screensaver dialogs not get decorated or otherwise reparented by the window manager, because they need to be children of the *real* root window, not the WM's virtual root, in - order for us to guarentee tha they are visible above the screensaver + order for us to guarentee that they are visible above the screensaver window itself. */ Arg av [100]; int ac = 0; Dimension sw, sh, x, y, w, h; + +#ifdef HAVE_ATHENA + XtRealizeWidget (dialog); +#else /* HAVE_MOTIF */ + /* Motif likes us to realize the *child* of the shell... */ XtRealizeWidget (form); +#endif /* HAVE_MOTIF */ + sw = WidthOfScreen (XtScreen (dialog)); sh = HeightOfScreen (XtScreen (dialog)); ac = 0; - XtSetArg (av [ac], XmNwidth, &w); ac++; - XtSetArg (av [ac], XmNheight, &h); ac++; + XtSetArg (av [ac], XtNwidth, &w); ac++; + XtSetArg (av [ac], XtNheight, &h); ac++; XtGetValues (form, av, ac); + + /* for debugging -- don't ask */ + if (where >= 69) + { + where -= 69; + sw = (sw * 7) / 12; + } + switch (where) { case 0: /* center it in the top-right quadrant */ @@ -218,77 +519,116 @@ pop_up_dialog_box (dialog, form, where) if (x + w > sw) x = sw - w; if (y + h > sh) y = sh - h; ac = 0; - XtSetArg (av [ac], XmNx, x); ac++; - XtSetArg (av [ac], XmNy, y); ac++; + XtSetArg (av [ac], XtNx, x); ac++; + XtSetArg (av [ac], XtNy, y); ac++; XtSetArg (av [ac], XtNoverrideRedirect, True); ac++; + +#ifdef HAVE_MOTIF XtSetArg (av [ac], XmNdefaultPosition, False); ac++; - /* I wonder whether this does anything useful? */ - /* XtSetArg (av [ac], XmNdialogStyle, XmDIALOG_SYSTEM_MODAL); ac++; */ +#endif /* HAVE_MOTIF */ + XtSetValues (dialog, av, ac); XtSetValues (form, av, ac); + +#ifdef HAVE_ATHENA + XtPopup (dialog, XtGrabNone); +#else /* HAVE_MOTIF */ XtManageChild (form); +#endif /* HAVE_MOTIF */ - focus_fuckus (dialog); + steal_focus_and_colormap (dialog); } static void -make_screenhack_dialog (parent, hacks) - Widget parent; - char **hacks; +make_screenhack_dialog (saver_info *si) { - char buf [255]; - Arg av[10]; - int ac; - char *label; - Dimension max_w = 0; - XmString xm_label = 0; - XmString new_xm_label; + saver_screen_info *ssi = si->default_screen; + Widget parent = ssi->toplevel_shell; + char **hacks = si->prefs.screenhacks; - create_demo_dialog (parent); - ac = 0; - XtSetArg (av [ac], XmNlabelString, &xm_label); ac++; - XtGetValues (label1, av, ac); - XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label); - if (!strcmp (label, XtName (label1))) - strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY"); + if (ssi->demo_cmap && + ssi->demo_cmap != ssi->cmap && + ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen)) + { + XFreeColormap (si->dpy, ssi->demo_cmap); + ssi->demo_cmap = 0; + } + + if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen)) + ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen); else - sprintf (buf, label, screensaver_version); - new_xm_label = XmStringCreate (buf, XmSTRING_DEFAULT_CHARSET); - ac = 0; - XtSetArg (av [ac], XmNlabelString, new_xm_label); ac++; - XtSetValues (label1, av, ac); - XmStringFree (new_xm_label); - XtFree (label); - - XtAddCallback (demo_list, XmNbrowseSelectionCallback, select_cb, - (XtPointer) hacks); - XtAddCallback (demo_list, XmNdefaultActionCallback, select_cb, - (XtPointer) hacks); - - XtAddCallback (text_line, XmNactivateCallback, text_cb, 0); - XtAddCallback (next, XmNactivateCallback, next_cb, 0); - XtAddCallback (prev, XmNactivateCallback, prev_cb, 0); - XtAddCallback (done, XmNactivateCallback, done_cb, 0); - XtAddCallback (restart, XmNactivateCallback, restart_cb, 0); - XtAddCallback (edit, XmNactivateCallback, edit_cb, (XtPointer) parent); + ssi->demo_cmap = XCreateColormap (si->dpy, + RootWindowOfScreen (ssi->screen), + ssi->default_visual, AllocNone); + + create_demo_dialog (parent, ssi->default_visual, ssi->demo_cmap); + format_into_label (label1, si->version); + + add_button_callback (next, next_cb, (XtPointer) si); + add_button_callback (prev, prev_cb, (XtPointer) si); + add_button_callback (done, done_cb, (XtPointer) si); + add_button_callback (restart, restart_cb, (XtPointer) si); + add_button_callback (edit, edit_cb, (XtPointer) si); + +#ifdef HAVE_MOTIF + XtAddCallback (demo_list, XmNbrowseSelectionCallback, + select_cb, (XtPointer) si); + XtAddCallback (demo_list, XmNdefaultActionCallback, + select_cb, (XtPointer) si); + XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) si); for (; *hacks; hacks++) { XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET); XmListAddItem (demo_list, xmstr, 0); - /* XmListSelectPos (widget, i, False); */ XmStringFree (xmstr); } -#if 0 - /* Dialogs that have scroll-lists don't obey maxWidth! Fuck!! Hack it. */ - ac = 0; - XtSetArg (av [ac], XmNmaxWidth, &max_w); ac++; - XtGetValues (demo_dialog, av, ac); /* great, this SEGVs */ -#endif + /* Cause the most-recently-run hack to be selected in the list. + Do some voodoo to make it be roughly centered in the list (really, + just make it not be within +/- 5 of the top/bottom if possible.) + */ + if (ssi->current_hack > 0) + { + int i = ssi->current_hack+1; + int top = i + 5; + int bot = i - 5; + if (bot < 1) bot = 1; + if (top > si->prefs.screenhacks_count) + top = si->prefs.screenhacks_count; + + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, bot, False); + ensure_selected_item_visible (demo_list); + + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, top, False); + ensure_selected_item_visible (demo_list); + + XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, i, False); + ensure_selected_item_visible (demo_list); + } + +#else /* HAVE_ATHENA */ + + XtVaSetValues (demo_list, + XtNlist, hacks, + XtNnumberStrings, si->prefs.screenhacks_count, + 0); + XtAddCallback (demo_list, XtNcallback, select_cb, si); + + /* #### still need to do the "select most-recently-run hack" + #### thing for Athena. + */ - pop_up_dialog_box (demo_dialog, demo_form, 0); +#endif /* HAVE_ATHENA */ + + pop_up_dialog_box(demo_dialog, demo_form, + /* for debugging -- don't ask */ + (si->prefs.debug_p ? 69 : 0) + + 0); } @@ -300,14 +640,8 @@ static struct resources { } res; -extern int parse_time (); - static void -hack_time_cb (dpy, line, store, sec_p) - Display *dpy; - char *line; - int *store; - Bool sec_p; +hack_time_cb (Display *dpy, char *line, int *store, Bool sec_p) { if (*line) { @@ -321,29 +655,23 @@ hack_time_cb (dpy, line, store, sec_p) } static void -res_sec_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_sec_cb (Widget button, XtPointer client_data, XtPointer call_data) { - hack_time_cb (XtDisplay (button), XmTextGetString (button), + hack_time_cb (XtDisplay (button), get_text_string (button), (int *) client_data, True); } static void -res_min_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_min_cb (Widget button, XtPointer client_data, XtPointer call_data) { - hack_time_cb (XtDisplay (button), XmTextGetString (button), + hack_time_cb (XtDisplay (button), get_text_string (button), (int *) client_data, False); } static void -res_int_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_int_cb (Widget button, XtPointer client_data, XtPointer call_data) { - char *line = XmTextGetString (button); + char *line = get_text_string (button); int *store = (int *) client_data; unsigned int value; char c; @@ -356,18 +684,20 @@ res_int_cb (button, client_data, call_data) } static void -res_bool_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_bool_cb (Widget button, XtPointer client_data, XtPointer call_data) { int *store = (int *) client_data; +#ifdef HAVE_MOTIF *store = ((XmToggleButtonCallbackStruct *) call_data)->set; +#else /* HAVE_ATHENA */ + Boolean state = FALSE; + XtVaGetValues (button, XtNstate, &state, NULL); + *store = state; +#endif /* HAVE_ATHENA */ } static void -res_cancel_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data) { XtDestroyWidget (resources_dialog); resources_dialog = 0; @@ -376,84 +706,150 @@ res_cancel_cb (button, client_data, call_data) static void -res_done_cb (button, client_data, call_data) - Widget button; - XtPointer client_data, call_data; +res_done_cb (Widget button, XtPointer client_data, XtPointer call_data) { + saver_info *si = (saver_info *) client_data; + saver_preferences *p = &si->prefs; + res_cancel_cb (button, client_data, call_data); - if (res.timeout < 10) res.timeout = 10; +#ifdef HAVE_ATHENA + /* Check all text widgets, since we don't have callbacks for these. */ + res_min_cb (timeout_text, (XtPointer) &res.timeout, NULL); + res_min_cb (cycle_text, (XtPointer) &res.cycle, NULL); + res_sec_cb (fade_text, (XtPointer) &res.secs, NULL); + res_int_cb (ticks_text, (XtPointer) &res.ticks, NULL); + res_min_cb (lock_time_text, (XtPointer) &res.lock_time, NULL); + res_sec_cb (passwd_time_text, (XtPointer) &res.passwd_time, NULL); +#endif /* HAVE_ATHENA */ + + /* Throttle the timeouts to minimum sane values. */ + if (res.timeout < 5) res.timeout = 5; if (res.cycle < 2) res.cycle = 2; - if (res.passwd_time < 2) res.passwd_time = 30; + if (res.passwd_time < 10) res.passwd_time = 10; - timeout = res.timeout * 1000; - cycle = res.cycle * 1000; - lock_timeout = res.lock_time * 1000; + p->timeout = res.timeout * 1000; + p->cycle = res.cycle * 1000; + p->lock_timeout = res.lock_time * 1000; #ifndef NO_LOCKING - passwd_timeout = res.passwd_time * 1000; + p->passwd_timeout = res.passwd_time * 1000; #endif - fade_seconds = res.secs; - fade_ticks = res.ticks; - verbose_p = res.verb; - install_cmap_p = res.cmap; - fade_p = res.fade; - unfade_p = res.unfade; - lock_p = res.lock_p; + p->fade_seconds = res.secs; + p->fade_ticks = res.ticks; + p->verbose_p = res.verb; + p->install_cmap_p = res.cmap; + p->fade_p = res.fade; + p->unfade_p = res.unfade; + p->lock_p = res.lock_p; + + if (p->debug_p && p->verbose_p) + fprintf (stderr, "%s: parameters changed:\n\ + timeout: %d\n\tcycle: %d\n\tlock: %d\n\tpasswd: %d\n\ + fade: %d\n\tfade: %d\n\tverbose: %d\n\tinstall: %d\n\ + fade: %d\n\tunfade: %d\n\tlock: %d\n", + progname, p->timeout, p->cycle, p->lock_timeout, +#ifdef NO_LOCKING + 0, +#else + p->passwd_timeout, +#endif + p->fade_seconds, p->fade_ticks, p->verbose_p, p->install_cmap_p, + p->fade_p, p->unfade_p, p->lock_p); + + +#if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION) + if (p->use_mit_saver_extension || p->use_sgi_saver_extension) + { + /* Need to set the server timeout to the new one the user has picked. + */ + int server_timeout, server_interval, prefer_blank, allow_exp; + XGetScreenSaver (si->dpy, &server_timeout, &server_interval, + &prefer_blank, &allow_exp); + if (server_timeout != (p->timeout / 1000)) + { + server_timeout = (p->timeout / 1000); + if (p->verbose_p) + fprintf (stderr, + "%s: configuring server for saver timeout of %d seconds.\n", + progname, server_timeout); + /* Leave all other parameters the same. */ + XSetScreenSaver (si->dpy, server_timeout, server_interval, + prefer_blank, allow_exp); + } + } +#endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */ } static void -make_resources_dialog (parent) - Widget parent; +make_resources_dialog (saver_info *si, Widget parent) { - Arg av[10]; - int ac; + saver_screen_info *ssi = si->default_screen; - create_resources_dialog (parent); + if (ssi->demo_cmap && + ssi->demo_cmap != ssi->cmap && + ssi->demo_cmap != DefaultColormapOfScreen (ssi->screen)) + { + XFreeColormap (si->dpy, ssi->demo_cmap); + ssi->demo_cmap = 0; + } + + if (ssi->default_visual == DefaultVisualOfScreen (ssi->screen)) + ssi->demo_cmap = DefaultColormapOfScreen (ssi->screen); + else + ssi->demo_cmap = XCreateColormap (si->dpy, + RootWindowOfScreen (ssi->screen), + ssi->default_visual, AllocNone); - XtAddCallback (res_done, XmNactivateCallback, res_done_cb, 0); - XtAddCallback (res_cancel, XmNactivateCallback, res_cancel_cb, 0); + create_resources_dialog (parent, ssi->default_visual, ssi->demo_cmap); + + add_button_callback (res_done, res_done_cb, (XtPointer) si); + add_button_callback (res_cancel, res_cancel_cb, (XtPointer) si); #define CB(widget,type,slot) \ - XtAddCallback ((widget), XmNvalueChangedCallback, (type), \ - (XtPointer) (slot)) + add_text_callback ((widget), (type), (XtPointer) (slot)) +#define CBT(widget,type,slot) \ + add_toggle_callback ((widget), (type), (XtPointer) (slot)) + +#ifdef HAVE_MOTIF + /* When using Athena widgets, we can't set callbacks for these, + so we'll check them all if "done" gets pressed. + */ CB (timeout_text, res_min_cb, &res.timeout); CB (cycle_text, res_min_cb, &res.cycle); CB (fade_text, res_sec_cb, &res.secs); CB (ticks_text, res_int_cb, &res.ticks); CB (lock_time_text, res_min_cb, &res.lock_time); CB (passwd_time_text, res_sec_cb, &res.passwd_time); - CB (verbose_toggle, res_bool_cb, &res.verb); - CB (cmap_toggle, res_bool_cb, &res.cmap); - CB (fade_toggle, res_bool_cb, &res.fade); - CB (unfade_toggle, res_bool_cb, &res.unfade); - CB (lock_toggle, res_bool_cb, &res.lock_p); +#endif /* HAVE_MOTIF */ + + CBT (verbose_toggle, res_bool_cb, &res.verb); + CBT (cmap_toggle, res_bool_cb, &res.cmap); + CBT (fade_toggle, res_bool_cb, &res.fade); + CBT (unfade_toggle, res_bool_cb, &res.unfade); + CBT (lock_toggle, res_bool_cb, &res.lock_p); #undef CB - ac = 0; - XtSetArg (av[ac], XmNsensitive, False); ac++; +#undef CBT - if (locking_disabled_p) + if (si->locking_disabled_p) { - XtSetValues (passwd_time_text, av, ac); - XtSetValues (lock_time_text, av, ac); - XtSetValues (lock_toggle, av, ac); + disable_widget (passwd_time_text); + disable_widget (lock_time_text); + disable_widget (lock_toggle); } if (CellsOfScreen (XtScreen (parent)) <= 2) { - XtSetValues (fade_text, av, ac); - XtSetValues (ticks_text, av, ac); - XtSetValues (cmap_toggle, av, ac); - XtSetValues (fade_toggle, av, ac); - XtSetValues (unfade_toggle, av, ac); + disable_widget (fade_text); + disable_widget (ticks_text); + disable_widget (cmap_toggle); + disable_widget (fade_toggle); + disable_widget (unfade_toggle); } } static void -fmt_time (buf, s, min_p) - char *buf; - unsigned int s; - int min_p; +fmt_time (char *buf, unsigned int s, int min_p) { unsigned int h = 0, m = 0; if (s >= 60) @@ -480,120 +876,140 @@ fmt_time (buf, s, min_p) } static void -pop_resources_dialog () +pop_resources_dialog (saver_info *si) { + saver_preferences *p = &si->prefs; char buf [100]; - res.timeout = timeout / 1000; - res.cycle = cycle / 1000; - res.lock_time = lock_timeout / 1000; + res.timeout = p->timeout / 1000; + res.cycle = p->cycle / 1000; + res.lock_time = p->lock_timeout / 1000; #ifndef NO_LOCKING - res.passwd_time = passwd_timeout / 1000; + res.passwd_time = p->passwd_timeout / 1000; #endif - res.secs = fade_seconds; - res.ticks = fade_ticks; - res.verb = verbose_p; - res.cmap = install_cmap_p; - res.fade = fade_p; - res.unfade = unfade_p; - res.lock_p = (lock_p && !locking_disabled_p); - - fmt_time (buf, res.timeout, 1); XmTextSetString (timeout_text, buf); - fmt_time (buf, res.cycle, 1); XmTextSetString (cycle_text, buf); - fmt_time (buf, res.lock_time, 1); XmTextSetString (lock_time_text, buf); - fmt_time (buf, res.passwd_time, 0); XmTextSetString (passwd_time_text, buf); - fmt_time (buf, res.secs, 0); XmTextSetString (fade_text, buf); - sprintf (buf, "%u", res.ticks); XmTextSetString (ticks_text, buf); - - XmToggleButtonSetState (verbose_toggle, res.verb, True); - XmToggleButtonSetState (cmap_toggle, res.cmap, True); - XmToggleButtonSetState (fade_toggle, res.fade, True); - XmToggleButtonSetState (unfade_toggle, res.unfade, True); - XmToggleButtonSetState (lock_toggle, res.lock_p, True); - - pop_up_dialog_box (resources_dialog, resources_form, 1); + res.secs = p->fade_seconds; + res.ticks = p->fade_ticks; + res.verb = p->verbose_p; + res.cmap = p->install_cmap_p; + res.fade = p->fade_p; + res.unfade = p->unfade_p; + res.lock_p = (p->lock_p && !si->locking_disabled_p); + + fmt_time (buf, res.timeout, 1); set_text_string (timeout_text, buf); + fmt_time (buf, res.cycle, 1); set_text_string (cycle_text, buf); + fmt_time (buf, res.lock_time, 1); set_text_string (lock_time_text, buf); + fmt_time (buf, res.passwd_time, 0); set_text_string (passwd_time_text, buf); + fmt_time (buf, res.secs, 0); set_text_string (fade_text, buf); + sprintf (buf, "%u", res.ticks); set_text_string (ticks_text, buf); + + set_toggle_button_state (verbose_toggle, res.verb); + set_toggle_button_state (cmap_toggle, res.cmap); + set_toggle_button_state (fade_toggle, res.fade); + set_toggle_button_state (unfade_toggle, res.unfade); + set_toggle_button_state (lock_toggle, res.lock_p); + + pop_up_dialog_box (resources_dialog, resources_form, + /* for debugging -- don't ask */ + (si->prefs.debug_p ? 69 : 0) + + 1); } -/* The code on this page isn't actually Motif-specific */ - -Bool dbox_up_p = False; -Bool demo_mode_p = False; - -extern XtAppContext app; -extern Widget toplevel_shell; -extern Bool use_xidle; -extern Time notice_events_timeout; - -extern char **screenhacks; -extern char *demo_hack; - -extern void notice_events_timer P((XtPointer closure, void *timer)); -extern Bool handle_clientmessage P((/*XEvent *, Bool*/)); +/* The main demo-mode command loop. + */ void -demo_mode () +demo_mode (saver_info *si) { - dbox_up_p = True; - initialize_screensaver_window (); - raise_window (True, False); - make_screenhack_dialog (toplevel_shell, screenhacks); - while (demo_mode_p) + saver_preferences *p = &si->prefs; + si->dbox_up_p = True; + initialize_screensaver_window (si); + raise_window (si, True, False, False); + make_screenhack_dialog (si); + while (si->demo_mode_p) { XEvent event; - XtAppNextEvent (app, &event); + XtAppNextEvent (si->app, &event); switch (event.xany.type) { case 0: /* synthetic "timeout" event */ break; case ClientMessage: - handle_clientmessage (&event, False); + handle_clientmessage (si, &event, False); break; case CreateNotify: -#ifdef HAVE_XIDLE - if (! use_xidle) -#endif - XtAppAddTimeOut (app, notice_events_timeout, notice_events_timer, - (XtPointer) event.xcreatewindow.window); + if (!p->use_xidle_extension && + !p->use_mit_saver_extension && + !p->use_sgi_saver_extension) + { + start_notice_events_timer (si, event.xcreatewindow.window); +#ifdef DEBUG_TIMERS + if (p->verbose_p) + printf ("%s: starting notice_events_timer for 0x%X (%lu)\n", + progname, + (unsigned int) event.xcreatewindow.window, + p->notice_events_timeout); +#endif /* DEBUG_TIMERS */ + } break; case ButtonPress: case ButtonRelease: - if (!XtWindowToWidget (dpy, event.xbutton.window)) + if (!XtWindowToWidget (si->dpy, event.xbutton.window)) raise_screenhack_dialog (); /* fall through */ default: +#ifdef HAVE_MIT_SAVER_EXTENSION + if (event.type == si->mit_saver_ext_event_number) + { + /* Get the "real" server window(s) out of the way as soon + as possible. */ + int i = 0; + for (i = 0; i < si->nscreens; i++) + { + saver_screen_info *ssi = &si->screens[i]; + if (ssi->server_mit_saver_window && + window_exists_p (si->dpy, ssi->server_mit_saver_window)) + XUnmapWindow (si->dpy, ssi->server_mit_saver_window); + } + } + else +#endif /* HAVE_MIT_SAVER_EXTENSION */ + XtDispatchEvent (&event); break; } } - destroy_screenhack_dialogs (); - initialize_screensaver_window (); - unblank_screen (); + destroy_screenhack_dialogs (si); + initialize_screensaver_window (si); + + si->demo_mode_p = True; /* kludge to inhibit unfade... */ + unblank_screen (si); + si->demo_mode_p = False; } static void -demo_mode_hack (hack) - char *hack; +demo_mode_hack (saver_info *si, char *hack) { - if (! demo_mode_p) abort (); - kill_screenhack (); - if (! demo_hack) - blank_screen (); - demo_hack = hack; - spawn_screenhack (False); + if (! si->demo_mode_p) abort (); + kill_screenhack (si); + if (! si->demo_hack) + blank_screen (si); + si->demo_hack = hack; + spawn_screenhack (si, False); + /* raise_screenhack_dialog(); */ } static void -demo_mode_done () +demo_mode_done (saver_info *si) { - kill_screenhack (); - if (demo_hack) - unblank_screen (); - demo_mode_p = False; - dbox_up_p = False; - demo_hack = 0; + kill_screenhack (si); + if (si->demo_hack) + unblank_screen (si); + si->demo_mode_p = False; + si->dbox_up_p = False; + si->demo_hack = 0; }