X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=driver%2Fdemo.c;h=e73a1f5eff9edda994d7d83d3567bcafed76bba3;hb=0ed85ca0e4b0eae40a4f50a51d63f2f41e45373a;hp=10a177efbf258d2939d9b3dc400e21428f489c0c;hpb=481b95e2617b69e6fd4444432747d7e1e0c3dc85;p=xscreensaver diff --git a/driver/demo.c b/driver/demo.c index 10a177ef..e73a1f5e 100644 --- a/driver/demo.c +++ b/driver/demo.c @@ -1,5 +1,5 @@ /* demo.c --- implements the interactive demo-mode and options dialogs. - * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski + * xscreensaver, Copyright (c) 1993-1998 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 @@ -14,23 +14,76 @@ # include "config.h" #endif + +#ifdef FORCE_ATHENA +# undef HAVE_MOTIF +# define HAVE_ATHENA 1 +#endif +#ifdef FORCE_MOTIF +# undef HAVE_ATHENA +# define HAVE_MOTIF 1 +#endif + +/* Only one, please. */ +#ifdef HAVE_MOTIF +# undef HAVE_ATHENA +#endif +#ifdef HAVE_ATHENA +# undef HAVE_MOTIF +#endif + + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifndef VMS +# include /* for getpwuid() */ +#else /* VMS */ +# include "vms-pwd.h" +#endif /* VMS */ + +#ifdef HAVE_UNAME +# include /* for uname() */ +#endif /* HAVE_UNAME */ + +#include + +#include /* for CARD32 */ +#include /* for XA_INTEGER */ #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_XMU +# ifndef VMS +# include +# else /* VMS */ +# include +# endif +#else +# include "xmu.h" +#endif + + #ifdef HAVE_MOTIF # include # include # include # include +# include +# include +# include -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) /* Athena demo code contributed by Jon A. Christopher */ /* Copyright 1997, with the same permissions as above. */ -# include # include # include # include @@ -41,31 +94,78 @@ # include # include # include + #endif /* HAVE_ATHENA */ -#include "xscreensaver.h" +#include "version.h" +#include "prefs.h" #include "resources.h" /* for parse_time() */ +#include "visual.h" /* for has_writable_cells() */ +#include "remote.h" /* for xscreensaver_command() */ +#include "usleep.h" + #include #include #include -static void demo_mode_hack (saver_info *si, char *); -static void demo_mode_done (saver_info *si); +#define WIDGET Widget +#define POINTER XtPointer + -extern Widget demo_dialog; -extern Widget label1; -extern Widget text_line; -extern Widget demo_form; -extern Widget demo_list; -extern Widget next, prev, done, restart, edit; +char *progname = 0; +char *progclass = "XScreenSaver"; +XrmDatabase db; -extern Widget resources_dialog; -extern Widget resources_form; -extern Widget res_done, res_cancel; -extern Widget timeout_text, cycle_text, fade_text, ticks_text; -extern Widget lock_time_text, passwd_time_text; -extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle, - lock_toggle; +typedef struct { + saver_preferences *a, *b; +} prefs_pair; + + +char *blurb (void) { return progname; } + +static void run_hack (Display *dpy, int n); + +#ifdef HAVE_ATHENA +static saver_preferences *global_prefs_kludge = 0; /* I hate C so much... */ +#endif /* HAVE_ATHENA */ + +static char *short_version = 0; + +Atom XA_VROOT; +Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION; +Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO; +Atom XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT; + +extern void create_demo_dialog (Widget, Visual *, Colormap); +extern void create_preferences_dialog (Widget, Visual *, Colormap); + +extern WIDGET demo_dialog; +extern WIDGET label1; +extern WIDGET text_line; +extern WIDGET text_activate; +extern WIDGET demo_form; +extern WIDGET demo_list; +extern WIDGET next; +extern WIDGET prev; +extern WIDGET done; +extern WIDGET restart; +extern WIDGET edit; + +extern WIDGET preferences_dialog; +extern WIDGET preferences_form; +extern WIDGET prefs_done; +extern WIDGET prefs_cancel; +extern WIDGET timeout_text; +extern WIDGET cycle_text; +extern WIDGET fade_text; +extern WIDGET fade_ticks_text; +extern WIDGET lock_timeout_text; +extern WIDGET passwd_timeout_text; +extern WIDGET verbose_toggle; +extern WIDGET install_cmap_toggle; +extern WIDGET fade_toggle; +extern WIDGET unfade_toggle; +extern WIDGET lock_toggle; #ifdef HAVE_MOTIF @@ -79,8 +179,14 @@ extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle, # define add_toggle_callback(button,cb,arg) \ XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg)) # define add_text_callback add_toggle_callback +# define disable_widget(widget) \ + XtVaSetValues((widget), XtNsensitive, False, 0) +# define widget_name(widget) XtName(widget) +# define widget_display(widget) XtDisplay(widget) +# define widget_screen(widget) XtScreen(widget) +# define CB_ARGS(a,b,c) (a,b,c) -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) # define set_toggle_button_state(toggle,state) \ XtVaSetValues((toggle), XtNstate, (state), 0) @@ -90,20 +196,24 @@ extern Widget verbose_toggle, cmap_toggle, fade_toggle, unfade_toggle, XtAddCallback ((button), XtNcallback, (cb), (arg)) # define add_toggle_callback add_button_callback # define add_text_callback(b,c,a) ERROR! +# define disable_widget(widget) \ + XtVaSetValues((widget), XtNsensitive, False, 0) +# define widget_name(widget) XtName(widget) +# define widget_display(widget) XtDisplay(widget) +# define widget_screen(widget) XtScreen(widget) +# define CB_ARGS(a,b,c) (a,b,c) #endif /* HAVE_ATHENA */ -#define disable_widget(widget) \ - XtVaSetValues((widget), XtNsensitive, False, 0) static char * -get_text_string (Widget text_widget) +get_text_string (WIDGET text_widget) { #ifdef HAVE_MOTIF return XmTextGetString (text_widget); -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) char *string = 0; if (XtIsSubclass(text_widget, textWidgetClass)) XtVaGetValues (text_widget, XtNstring, &string, 0); @@ -116,8 +226,9 @@ get_text_string (Widget text_widget) #endif /* HAVE_ATHENA */ } + static char * -get_label_string (Widget label_widget) +get_label_string (WIDGET label_widget) { #ifdef HAVE_MOTIF char *label = 0; @@ -127,7 +238,7 @@ get_label_string (Widget label_widget) return 0; XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label); return label; -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) char *label = 0; XtVaGetValues (label_widget, XtNlabel, &label, 0); return (label ? strdup(label) : 0); @@ -136,25 +247,28 @@ get_label_string (Widget label_widget) static void -set_label_string (Widget label_widget, char *string) +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 */ +#elif defined(HAVE_ATHENA) XtVaSetValues (label_widget, XtNlabel, string, 0); #endif /* HAVE_ATHENA */ } -void -format_into_label (Widget label, const char *arg) +/* Given a label widget that has a %s in it, do the printf thing. + If the label's string is obviously wrong, complain about resource lossage. + */ +static 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); + char *buf = (char *) malloc ((text ? strlen(text) : 0) + strlen(arg) + 100); - if (!text || !strcmp (text, XtName (label))) + if (!text || !*text || !strcmp (text, widget_name (label))) strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY"); else sprintf (buf, text, arg); @@ -165,131 +279,10 @@ format_into_label (Widget label, const char *arg) } -void -steal_focus_and_colormap (Widget dialog) -{ - 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 (void) -{ - XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog)); - if (resources_dialog) - XMapRaised (XtDisplay (resources_dialog), XtWindow (resources_dialog)); - steal_focus_and_colormap (resources_dialog ? resources_dialog : demo_dialog); -} - -static void -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); -} - - -static void -text_cb (Widget text_widget, XtPointer client_data, XtPointer call_data) -{ - saver_info *si = (saver_info *) client_data; - char *line; - line = get_text_string (text_widget); - demo_mode_hack (si, line); -} - - -#ifdef HAVE_ATHENA -/* Bend over backwards to make hitting Return in the text field do the - right thing. - */ -extern saver_info *global_si_kludge; -static void text_enter (Widget w, XEvent *event, String *av, Cardinal *ac) -{ - text_cb (w, global_si_kludge, 0); -} - -static XtActionsRec actions[] = {{"done", text_enter} - }; -static char translations[] = ("Return: done()\n" - "Linefeed: done()\n" - "CtrlM: done()\n" - "CtrlJ: done()\n"); -#endif /* HAVE_ATHENA */ - - -static void -select_cb (Widget button, XtPointer client_data, XtPointer call_data) -{ - saver_info *si = (saver_info *) client_data; - -#ifdef HAVE_ATHENA - XawListReturnStruct *item = (XawListReturnStruct*)call_data; - XtVaSetValues(text_line, XtNstring, item->string, 0); - - demo_mode_hack (si, item->string); - if (item->list_index >= 0) - si->default_screen->current_hack = item->list_index; - -#else /* HAVE_MOTIF */ - XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data; - 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 (lcb->item_position > 0) - si->default_screen->current_hack = lcb->item_position - 1; - } - 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) +ensure_selected_item_visible (WIDGET list) { #ifdef HAVE_MOTIF int *pos_list = 0; @@ -316,7 +309,7 @@ ensure_selected_item_visible (Widget list) if (pos_list) XtFree ((char *) pos_list); -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) # ifdef HAVE_XawViewportSetCoordinates int margin = 16; /* should be line height or something. */ @@ -369,284 +362,418 @@ ensure_selected_item_visible (Widget list) } +#ifdef HAVE_ATHENA static void -next_cb (Widget button, XtPointer client_data, XtPointer call_data) +set_hack_list (Widget demo_list, saver_preferences *p) { - saver_info *si = (saver_info *) client_data; + char **strings = (char **) calloc (sizeof (char *), p->screenhacks_count); + int i; + for (i = 0; i < p->screenhacks_count; i++) + strings[i] = format_hack (p->screenhacks[i], False); + XtVaSetValues (demo_list, + XtNlist, strings, + XtNnumberStrings, p->screenhacks_count, + 0); +# if 0 + for (i = 0; i < p->screenhacks_count; i++) + { + free (strings[i]); + strings[i] = (char *) 0xDEADBEEF; + } + free (strings); +# endif +} +#endif /* HAVE_ATHENA */ + + + +/* Callback for the text area: + - note the text the user has entered; + - change the corresponding element in `screenhacks'; + - write the .xscreensaver file; + - tell the xscreensaver daemon to run that hack. + */ +static void +text_cb (WIDGET text_widget, POINTER client_data, POINTER call_data) +{ + saver_preferences *p = (saver_preferences *) client_data; + char *new_text = get_text_string (text_widget); + Display *dpy = widget_display (text_widget); + Bool save = TRUE; + + int hack_number = -1; /* 0-based */ #ifdef HAVE_ATHENA - int cnt; XawListReturnStruct *current = XawListShowCurrent(demo_list); - if (current->list_index == XAW_LIST_NONE) - XawListHighlight(demo_list, 0); + hack_number = current->list_index; +#elif defined(HAVE_MOTIF) + int *pos_list = 0; + int pos_count = 0; + if (XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) + hack_number = pos_list[0] - 1; + if (pos_list) + XtFree ((char *) pos_list); +#endif /* HAVE_ATHENA */ + + ensure_selected_item_visible (demo_list); + + if (hack_number < 0 || hack_number >= p->screenhacks_count) + { + set_text_string (text_widget, ""); + XBell (XtDisplay (text_widget), 0); + } else { - XtVaGetValues(demo_list, - XtNnumberStrings, &cnt, - NULL); - if (current->list_index + 1 < cnt) - { - current->list_index++; - XawListHighlight(demo_list, current->list_index); - } + screenhack *new_hack = parse_screenhack (new_text); + if (p->screenhacks [hack_number]) + free_screenhack (p->screenhacks [hack_number]); + p->screenhacks [hack_number] = new_hack; + +#ifdef HAVE_MOTIF + + XmListDeselectAllItems (demo_list); + { + XmString xmstr = XmStringCreate (new_text, XmSTRING_DEFAULT_CHARSET); + XmListReplaceItemsPos (demo_list, &xmstr, 1, hack_number+1); + XmStringFree (xmstr); + } + XmListSelectPos (demo_list, hack_number+1, True); + +#elif defined(HAVE_ATHENA) + + { + Widget vp = XtParent(demo_list); + Widget sb = (vp ? XtNameToWidget(vp, "*vertical") : 0); + Dimension list_h = 0; + Position vp_x = 0, vp_y = 0; + float sb_top = 0; + + XawListUnhighlight (demo_list); + XtVaGetValues (vp, XtNx, &vp_x, 0); + XtVaGetValues (sb, XtNtopOfThumb, &sb_top, 0); + XtVaGetValues (demo_list, XtNheight, &list_h, 0); + vp_y = (sb_top * list_h); + set_hack_list (demo_list, p); + XawViewportSetCoordinates (vp, vp_x, vp_y); + XawListHighlight (demo_list, hack_number); + } + +#endif /* HAVE_ATHENA */ + + if (save) + write_init_file (p, short_version, p->verbose_p); + + XSync (dpy, False); + usleep (500000); /* give the disk time to settle down */ + + run_hack (dpy, hack_number+1); } +} + + +#ifdef HAVE_ATHENA +/* Bend over backwards to make hitting Return in the text field do the + right thing. + */ +static void text_enter (Widget w, XEvent *event, String *av, Cardinal *ac) +{ + text_cb (w, global_prefs_kludge, 0); /* I hate C so much... */ +} + +static XtActionsRec actions[] = {{"done", text_enter} + }; +static char translations[] = ("Return: done()\n" + "Linefeed: done()\n" + "CtrlM: done()\n" + "CtrlJ: done()\n"); +#endif /* HAVE_ATHENA */ + + +/* Callback for the Run Next button. + */ +static void +next_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) +{ +#ifdef HAVE_ATHENA + XawListReturnStruct *current = XawListShowCurrent(demo_list); + int cnt; + XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0); + if (current->list_index == XAW_LIST_NONE || + current->list_index + 1 >= cnt) + current->list_index = 0; + else + current->list_index++; + XawListHighlight(demo_list, current->list_index); ensure_selected_item_visible (demo_list); current = XawListShowCurrent(demo_list); XtVaSetValues(text_line, XtNstring, current->string, 0); - demo_mode_hack (si, current->string); -#else /* HAVE_MOTIF */ + run_hack (XtDisplay (button), current->list_index + 1); - int *pos_list; - int pos_count; +#elif defined(HAVE_MOTIF) + + saver_preferences *p = (saver_preferences *) client_data; + int *pos_list = 0; + int pos_count = 0; + int pos; if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) { - XmListDeselectAllItems(demo_list); /* LessTif lossage */ - XmListSelectPos (demo_list, 1, True); + pos = 1; + XmListDeselectAllItems (demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, pos, True); } else { - int pos = pos_list[0] + 1; - if (pos > si->prefs.screenhacks_count) + pos = pos_list[0] + 1; + if (pos > p->screenhacks_count) pos = 1; - XmListDeselectAllItems(demo_list); /* LessTif lossage */ + XmListDeselectAllItems (demo_list); /* LessTif lossage */ XmListSelectPos (demo_list, pos, True); } - XtFree ((char *) pos_list); + ensure_selected_item_visible (demo_list); - demo_mode_hack (si, get_text_string (text_line)); + run_hack (XtDisplay (button), pos); + if (pos_list) + XtFree ((char *) pos_list); #endif /* HAVE_MOTIF */ } +/* Callback for the Run Previous button. + */ static void -prev_cb (Widget button, XtPointer client_data, XtPointer call_data) +prev_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - 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, 0); + XawListReturnStruct *current = XawListShowCurrent(demo_list); + int cnt; + XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0); + if (current->list_index == XAW_LIST_NONE || + current->list_index <= 0) + current->list_index = cnt-1; else - { - if (current->list_index >= 1) - { - current->list_index--; - XawListHighlight(demo_list, current->list_index); - } - } + current->list_index--; + XawListHighlight(demo_list, current->list_index); ensure_selected_item_visible (demo_list); current = XawListShowCurrent(demo_list); XtVaSetValues(text_line, XtNstring, current->string, 0); - demo_mode_hack (si, current->string); -#else /* HAVE_MOTIF */ + run_hack (XtDisplay (button), current->list_index + 1); + +#elif defined(HAVE_MOTIF) - int *pos_list; - int pos_count; + saver_preferences *p = (saver_preferences *) client_data; + int *pos_list = 0; + int pos_count = 0; + int pos; if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count)) { - XmListDeselectAllItems(demo_list); /* LessTif lossage */ - XmListSelectPos (demo_list, 0, True); + pos = p->screenhacks_count; + XmListDeselectAllItems (demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, pos, True); } else { - XmListDeselectAllItems(demo_list); /* LessTif lossage */ - XmListSelectPos (demo_list, pos_list [0] - 1, True); - XtFree ((char *) pos_list); + pos = pos_list[0] - 1; + if (pos == 0) + pos = p->screenhacks_count; + XmListDeselectAllItems (demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, pos, True); } + ensure_selected_item_visible (demo_list); - demo_mode_hack (si, get_text_string (text_line)); + run_hack (XtDisplay (button), pos); + if (pos_list) + XtFree ((char *) pos_list); #endif /* HAVE_MOTIF */ } -static void pop_resources_dialog (saver_info *si); -static void make_resources_dialog (saver_info *si, Widget parent); - +/* Callback run when a list element is double-clicked. + */ static void -edit_cb (Widget button, XtPointer client_data, XtPointer call_data) +select_cb (WIDGET button, POINTER client_data, POINTER call_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 (si, parent); - pop_resources_dialog (si); +/* saver_preferences *p = (saver_preferences *) client_data; */ + +#ifdef HAVE_ATHENA + XawListReturnStruct *item = (XawListReturnStruct*)call_data; + XtVaSetValues(text_line, XtNstring, item->string, 0); + run_hack (XtDisplay (button), item->list_index + 1); + +#elif defined(HAVE_MOTIF) + XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data; + 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) + run_hack (XtDisplay (button), lcb->item_position); + + if (string) + XtFree (string); + +#endif /* HAVE_MOTIF */ } + +static void pop_preferences_dialog (prefs_pair *pair); +static void make_preferences_dialog (prefs_pair *pair, Widget parent); + +/* Callback for the Preferences button. + */ static void -done_cb (Widget button, XtPointer client_data, XtPointer call_data) +preferences_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - saver_info *si = (saver_info *) client_data; - demo_mode_done (si); + prefs_pair *pair = (prefs_pair *) client_data; + Widget parent = button; + + do { + parent = XtParent(parent); + } while (XtParent(parent)); + + if (! preferences_dialog) + make_preferences_dialog (pair, parent); + *pair->b = *pair->a; + pop_preferences_dialog (pair); } +/* Callback for the Quit button. + */ static void -restart_cb (Widget button, XtPointer client_data, XtPointer call_data) +quit_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - saver_info *si = (saver_info *) client_data; - demo_mode_restart_process (si); + /* Save here? Right now we don't need to, because we save every time + the text field is edited, or the Preferences OK button is pressed. + */ + exit (0); } -void -pop_up_dialog_box (Widget dialog, Widget form, int where) +/* Callback for the (now unused) Restart button. + */ +static void +restart_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - /* 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. - - 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 that they are visible above the screensaver - window itself. - */ - Arg av [100]; - int ac = 0; - Dimension sw, sh, x, y, w, h; + xscreensaver_command (widget_display (button), XA_RESTART, 0, False, NULL); +} -#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], XtNwidth, &w); ac++; - XtSetArg (av [ac], XtNheight, &h); ac++; - XtGetValues (form, av, ac); +/* Finds the number of the last hack to run, and makes that item be + selected by default. + */ +static void +scroll_to_current_hack (WIDGET dialog) +{ + Atom type; + int format; + unsigned long nitems, bytesafter; + CARD32 *data = 0; + Display *dpy = widget_display (dialog); + int hack = 0; + + if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */ + XA_SCREENSAVER_STATUS, + 0, 3, False, XA_INTEGER, + &type, &format, &nitems, &bytesafter, + (unsigned char **) &data) + == Success + && type == XA_INTEGER + && nitems >= 3 + && data) + hack = (int) data[2]; + + if (data) free (data); + + if (hack <= 0) + return; - /* for debugging -- don't ask */ - if (where >= 69) - { - where -= 69; - sw = (sw * 7) / 12; - } +#ifdef HAVE_MOTIF + XmListDeselectAllItems (demo_list); /* LessTif lossage */ + XmListSelectPos (demo_list, hack, False); + ensure_selected_item_visible (demo_list); - switch (where) - { - case 0: /* center it in the top-right quadrant */ - x = (sw/2 + w) / 2 + (sw/2) - w; - y = (sh/2 + h) / 2 - h; - break; - case 1: /* center it in the bottom-right quadrant */ - x = (sw/2 + w) / 2 + (sw/2) - w; - y = (sh/2 + h) / 2 + (sh/2) - h; - break; - case 2: /* center it on the screen */ - x = (sw + w) / 2 - w; - y = (sh + h) / 2 - h; - break; - default: - abort (); - } - if (x + w > sw) x = sw - w; - if (y + h > sh) y = sh - h; - ac = 0; - XtSetArg (av [ac], XtNx, x); ac++; - XtSetArg (av [ac], XtNy, y); ac++; - XtSetArg (av [ac], XtNoverrideRedirect, True); ac++; +#elif defined(HAVE_ATHENA) + XawListUnhighlight (demo_list); + XawListHighlight (demo_list, hack - 1); -#ifdef HAVE_MOTIF - XtSetArg (av [ac], XmNdefaultPosition, False); ac++; -#endif /* HAVE_MOTIF */ +#endif /* HAVE_ATHENA */ +} - XtSetValues (dialog, av, ac); - XtSetValues (form, av, ac); +static void +pop_up_dialog_box (WIDGET dialog, WIDGET form) +{ #ifdef HAVE_ATHENA + XtRealizeWidget (dialog); XtPopup (dialog, XtGrabNone); -#else /* HAVE_MOTIF */ +#elif defined(HAVE_MOTIF) + XtRealizeWidget (form); XtManageChild (form); + + /* Motif likes to make the dialog wider than the screen; throttle it. */ + { + Dimension w=0, h=0, bw=0; + Dimension max_w; + Screen *screen = 0; + XtVaGetValues (dialog, XtNscreen, &screen, 0); + max_w = WidthOfScreen (screen) * 0.8; + XtVaGetValues(dialog, XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0); + if (w > max_w) + XtResizeWidget(dialog, max_w, h, bw); + } #endif /* HAVE_MOTIF */ - steal_focus_and_colormap (dialog); + XMapRaised (XtDisplay (dialog), XtWindow (dialog)); } -void -make_screenhack_dialog (saver_info *si) +static void +make_demo_dialog (Widget toplevel_shell, prefs_pair *pair) { - saver_screen_info *ssi = si->default_screen; - Widget parent = ssi->toplevel_shell; - char **hacks = si->prefs.screenhacks; - - 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); + saver_preferences *p = pair->a; + /* saver_preferences *p2 = pair->b; */ + Widget parent = toplevel_shell; +#ifdef HAVE_MOTIF + screenhack **hacks = p->screenhacks; +#endif /* HAVE_MOTIF */ - create_demo_dialog (parent, ssi->default_visual, ssi->demo_cmap); - format_into_label (label1, si->version); + create_demo_dialog (parent, + DefaultVisualOfScreen (widget_screen (parent)), + DefaultColormapOfScreen (widget_screen (parent))); - 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); + format_into_label (label1, short_version); + add_button_callback (next, next_cb, (POINTER) p); + add_button_callback (prev, prev_cb, (POINTER) p); + add_button_callback (done, quit_cb, (POINTER) p); + if (restart) + add_button_callback(restart,restart_cb, (POINTER) p); + add_button_callback (edit, preferences_cb, (POINTER) pair); #ifdef HAVE_MOTIF XtAddCallback (demo_list, XmNbrowseSelectionCallback, - select_cb, (XtPointer) si); + select_cb, (POINTER) p); XtAddCallback (demo_list, XmNdefaultActionCallback, - select_cb, (XtPointer) si); - XtAddCallback (text_line, XmNactivateCallback, text_cb, (XtPointer) si); + select_cb, (POINTER) p); + XtAddCallback (text_line, XmNactivateCallback, text_cb, (POINTER) p); if (hacks) for (; *hacks; hacks++) { - XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET); + char *hs = format_hack (*hacks, False); + XmString xmstr = XmStringCreate (hs, XmSTRING_DEFAULT_CHARSET); XmListAddItem (demo_list, xmstr, 0); XmStringFree (xmstr); + free (hs); } - /* 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 */ +#elif defined(HAVE_ATHENA) /* Hook up the text line. */ @@ -660,13 +787,8 @@ make_screenhack_dialog (saver_info *si) */ XtRealizeWidget (demo_dialog); - XtVaSetValues (demo_list, - XtNlist, hacks, - XtNnumberStrings, si->prefs.screenhacks_count, - 0); - XtAddCallback (demo_list, XtNcallback, select_cb, si); - if (ssi->current_hack > 0) - XawListHighlight(demo_list, ssi->current_hack); + set_hack_list (demo_list, p); + XtAddCallback (demo_list, XtNcallback, select_cb, p); /* Now that we've populated the list, make sure that the list is as wide as the dialog itself. @@ -687,7 +809,6 @@ make_screenhack_dialog (saver_info *si) /* Why isn't the viewport getting centered? */ XtVaGetValues(viewport, XtNx, &x, XtNy, &y, XtNheight, &h, XtNborderWidth, &bw, 0); - printf("%d %d %d %d\n", x, y, w, h); XtConfigureWidget(viewport, x, y, w2-x-x, h, bw); /* And the text line, too. */ @@ -712,34 +833,31 @@ make_screenhack_dialog (saver_info *si) #endif /* HAVE_ATHENA */ - monitor_power_on (si); - pop_up_dialog_box(demo_dialog, demo_form, - /* for debugging -- don't ask */ - (si->prefs.debug_p ? 69 : 0) + - 0); + scroll_to_current_hack (demo_dialog); -#ifdef HAVE_ATHENA - /* For Athena, have to do this after the dialog is managed. */ + pop_up_dialog_box(demo_dialog, demo_form); + +#if defined(HAVE_ATHENA) + /* For Athena and Gtk, have to do this after the dialog is managed. */ ensure_selected_item_visible (demo_list); #endif /* HAVE_ATHENA */ } -/* the Screensaver Parameters dialog */ - -static struct resources { - int timeout, cycle, secs, ticks, lock_time, passwd_time; - int verb, cmap, fade, unfade, lock_p; -} res; - +/* the Preferences dialog + */ +/* Helper for the text fields that contain time specifications: + this parses the text, and does error checking. + */ static void -hack_time_cb (Display *dpy, char *line, int *store, Bool sec_p) +hack_time_text (Display *dpy, char *line, Time *store, Bool sec_p) { if (*line) { int value; value = parse_time (line, sec_p, True); + value *= 1000; /* Time measures in microseconds */ if (value < 0) /*XBell (dpy, 0)*/; else @@ -747,22 +865,34 @@ hack_time_cb (Display *dpy, char *line, int *store, Bool sec_p) } } + +/* Callback for text fields that hold a time that default to seconds, + when not fully spelled out. client_data is a Time* where the value goes. + */ static void -res_sec_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_sec_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - hack_time_cb (XtDisplay (button), get_text_string (button), - (int *) client_data, True); + hack_time_text (widget_display (button), get_text_string (button), + (Time *) client_data, True); } + +/* Callback for text fields that hold a time that default to minutes, + when not fully spelled out. client_data is an Time* where the value goes. + */ static void -res_min_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_min_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - hack_time_cb (XtDisplay (button), get_text_string (button), - (int *) client_data, False); + hack_time_text (widget_display (button), get_text_string (button), + (Time *) client_data, False); } + +/* Callback for text fields that hold an integer value. + client_data is an int* where the value goes. + */ static void -res_int_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_int_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { char *line = get_text_string (button); int *store = (int *) client_data; @@ -776,174 +906,147 @@ res_int_cb (Widget button, XtPointer client_data, XtPointer call_data) *store = value; } + +/* Callback for toggle buttons. client_data is a Bool* where the value goes. + */ static void -res_bool_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_bool_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data) { - int *store = (int *) client_data; + Bool *store = (Bool *) client_data; #ifdef HAVE_MOTIF *store = ((XmToggleButtonCallbackStruct *) call_data)->set; -#else /* HAVE_ATHENA */ +#elif defined(HAVE_ATHENA) Boolean state = FALSE; - XtVaGetValues (button, XtNstate, &state, NULL); + XtVaGetValues (button, XtNstate, &state, 0); *store = state; #endif /* HAVE_ATHENA */ } + +/* Callback for the Cancel button on the Preferences dialog. + */ static void -res_cancel_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_cancel_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored) { - XtDestroyWidget (resources_dialog); - resources_dialog = 0; - raise_screenhack_dialog (); + XtDestroyWidget (preferences_dialog); + preferences_dialog = 0; + XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog)); } +/* Callback for the OK button on the Preferences dialog. + */ static void -res_done_cb (Widget button, XtPointer client_data, XtPointer call_data) +prefs_ok_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data) { - saver_info *si = (saver_info *) client_data; - saver_preferences *p = &si->prefs; + prefs_pair *pair = (prefs_pair *) client_data; + saver_preferences *p = pair->a; + saver_preferences *p2 = pair->b; - res_cancel_cb (button, client_data, call_data); + prefs_cancel_cb CB_ARGS(button, client_data, call_data); #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); + /* Athena doesn't let us put callbacks on these widgets, so run + all the callbacks by hand when OK is pressed. */ + prefs_min_cb (timeout_text, (POINTER) &p2->timeout, 0); + prefs_min_cb (cycle_text, (POINTER) &p2->cycle, 0); + prefs_sec_cb (fade_text, (POINTER) &p2->fade_seconds, 0); + prefs_int_cb (fade_ticks_text, (POINTER) &p2->fade_ticks, 0); + prefs_min_cb (lock_timeout_text, (POINTER) &p2->lock_timeout, 0); + prefs_sec_cb (passwd_timeout_text, (POINTER) &p2->passwd_timeout, 0); #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 < 10) res.passwd_time = 10; - - p->timeout = res.timeout * 1000; - p->cycle = res.cycle * 1000; - p->lock_timeout = res.lock_time * 1000; -#ifndef NO_LOCKING - p->passwd_timeout = res.passwd_time * 1000; -#endif - 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", - blurb(), 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", - blurb(), 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 */ + p->timeout = p2->timeout; + p->cycle = p2->cycle; + p->lock_timeout = p2->lock_timeout; + p->passwd_timeout = p2->passwd_timeout; + p->fade_seconds = p2->fade_seconds; + p->fade_ticks = p2->fade_ticks; + p->verbose_p = p2->verbose_p; + p->install_cmap_p = p2->install_cmap_p; + p->fade_p = p2->fade_p; + p->unfade_p = p2->unfade_p; + p->lock_p = p2->lock_p; + + write_init_file (p, short_version, p->verbose_p); } static void -make_resources_dialog (saver_info *si, Widget parent) +make_preferences_dialog (prefs_pair *pair, Widget parent) { - saver_screen_info *ssi = si->default_screen; + saver_preferences *p = pair->a; + saver_preferences *p2 = pair->b; - 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; - } + Screen *screen = widget_screen (parent); + Display *dpy = widget_display (parent); - 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); + *p2 = *p; /* copy all slots of p into p2. */ - create_resources_dialog (parent, ssi->default_visual, ssi->demo_cmap); + create_preferences_dialog (parent, + DefaultVisualOfScreen (screen), + DefaultColormapOfScreen (screen)); - add_button_callback (res_done, res_done_cb, (XtPointer) si); - add_button_callback (res_cancel, res_cancel_cb, (XtPointer) si); + add_button_callback (prefs_done, prefs_ok_cb, (POINTER) pair); + add_button_callback (prefs_cancel, prefs_cancel_cb, 0); #define CB(widget,type,slot) \ - add_text_callback ((widget), (type), (XtPointer) (slot)) + add_text_callback ((widget), (type), (POINTER) (slot)) #define CBT(widget,type,slot) \ - add_toggle_callback ((widget), (type), (XtPointer) (slot)) + add_toggle_callback ((widget), (type), (POINTER) (slot)) -#ifdef HAVE_MOTIF +#ifndef HAVE_ATHENA /* 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); -#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); + so in that case, we run them by hand when "OK" is pressed. */ + CB (timeout_text, prefs_min_cb, &p2->timeout); + CB (cycle_text, prefs_min_cb, &p2->cycle); + CB (fade_text, prefs_sec_cb, &p2->fade_seconds); + CB (fade_ticks_text, prefs_int_cb, &p2->fade_ticks); + CB (lock_timeout_text, prefs_min_cb, &p2->lock_timeout); + CB (passwd_timeout_text, prefs_sec_cb, &p2->passwd_timeout); + +#endif /* !HAVE_ATHENA */ + + CBT (verbose_toggle, prefs_bool_cb, &p2->verbose_p); + CBT (install_cmap_toggle, prefs_bool_cb, &p2->install_cmap_p); + CBT (fade_toggle, prefs_bool_cb, &p2->fade_p); + CBT (unfade_toggle, prefs_bool_cb, &p2->unfade_p); + CBT (lock_toggle, prefs_bool_cb, &p2->lock_p); #undef CB #undef CBT - if (si->locking_disabled_p) - { - disable_widget (passwd_time_text); - disable_widget (lock_time_text); - disable_widget (lock_toggle); - } - if (CellsOfScreen (XtScreen (parent)) <= 2) - { - disable_widget (fade_text); - disable_widget (ticks_text); - disable_widget (cmap_toggle); - disable_widget (fade_toggle); - disable_widget (unfade_toggle); - } + { + Bool found_any_writable_cells = False; + int nscreens = ScreenCount(dpy); + int i; + for (i = 0; i < nscreens; i++) + { + Screen *s = ScreenOfDisplay (dpy, i); + if (has_writable_cells (s, DefaultVisualOfScreen (s))) + { + found_any_writable_cells = True; + break; + } + } + + if (! found_any_writable_cells) /* fading isn't possible */ + { + disable_widget (fade_text); + disable_widget (fade_ticks_text); + disable_widget (install_cmap_toggle); + disable_widget (fade_toggle); + disable_widget (unfade_toggle); + } + } } +/* Formats a `Time' into "H:MM:SS". (Time is microseconds.) + */ static void -fmt_time (char *buf, unsigned int s, int min_p) +format_time (char *buf, Time time) { + int s = time / 1000; unsigned int h = 0, m = 0; if (s >= 60) { @@ -955,155 +1058,437 @@ fmt_time (char *buf, unsigned int s, int min_p) h += (m / 60); m %= 60; } -/* - if (min_p && h == 0 && s == 0) - sprintf (buf, "%u", m); - else if (!min_p && h == 0 && m == 0) - sprintf (buf, "%u", s); - else - if (h == 0) - sprintf (buf, "%u:%02u", m, s); - else -*/ - sprintf (buf, "%u:%02u:%02u", h, m, s); + sprintf (buf, "%u:%02u:%02u", h, m, s); } + static void -pop_resources_dialog (saver_info *si) +pop_preferences_dialog (prefs_pair *pair) { - saver_preferences *p = &si->prefs; - char buf [100]; - - res.timeout = p->timeout / 1000; - res.cycle = p->cycle / 1000; - res.lock_time = p->lock_timeout / 1000; -#ifndef NO_LOCKING - res.passwd_time = p->passwd_timeout / 1000; -#endif - 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); - - monitor_power_on (si); - pop_up_dialog_box (resources_dialog, resources_form, - /* for debugging -- don't ask */ - (si->prefs.debug_p ? 69 : 0) + - 1); + /* saver_preferences *p = pair->a; */ + saver_preferences *p2 = pair->b; + char s[100]; + + format_time (s, p2->timeout); set_text_string(timeout_text, s); + format_time (s, p2->cycle); set_text_string(cycle_text, s); + format_time (s, p2->lock_timeout); set_text_string(lock_timeout_text, s); + format_time (s, p2->passwd_timeout); set_text_string(passwd_timeout_text, s); + format_time (s, p2->fade_seconds); set_text_string(fade_text, s); + sprintf (s, "%u", p2->fade_ticks); set_text_string(fade_ticks_text, s); + + set_toggle_button_state (verbose_toggle, p2->verbose_p); + set_toggle_button_state (install_cmap_toggle, p2->install_cmap_p); + set_toggle_button_state (fade_toggle, p2->fade_p); + set_toggle_button_state (unfade_toggle, p2->unfade_p); + set_toggle_button_state (lock_toggle, p2->lock_p); + + pop_up_dialog_box (preferences_dialog, preferences_form); } + +static void +run_hack (Display *dpy, int n) +{ + if (n <= 0) abort(); + xscreensaver_command (dpy, XA_DEMO, n, False, NULL); +} + + +static void +warning_dialog_dismiss_cb CB_ARGS(WIDGET button, POINTER client_data, + POINTER ignored) +{ + WIDGET shell = (WIDGET) client_data; + XtDestroyWidget (shell); +} + + +static void +warning_dialog (WIDGET parent, const char *message) +{ + char *msg = strdup (message); + char *head; + + WIDGET dialog = 0; + WIDGET label = 0; + WIDGET ok = 0; + int i = 0; + +#ifdef HAVE_MOTIF + + Widget w; + Widget container; + XmString xmstr; + Arg av[10]; + int ac = 0; + + ac = 0; + dialog = XmCreateWarningDialog (parent, "versionWarning", av, ac); + + w = XmMessageBoxGetChild (dialog, XmDIALOG_MESSAGE_LABEL); + if (w) XtUnmanageChild (w); + w = XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON); + if (w) XtUnmanageChild (w); + w = XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON); + if (w) XtUnmanageChild (w); + + ok = XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON); + + ac = 0; + XtSetArg (av[ac], XmNnumColumns, 1); ac++; + XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++; + XtSetArg (av[ac], XmNpacking, XmPACK_COLUMN); ac++; + XtSetArg (av[ac], XmNrowColumnType, XmWORK_AREA); ac++; + XtSetArg (av[ac], XmNspacing, 0); ac++; + container = XmCreateRowColumn (dialog, "container", av, ac); + +#elif defined(HAVE_ATHENA) + + Widget form; + dialog = XtVaCreatePopupShell("warning_dialog", transientShellWidgetClass, + parent, 0); + form = XtVaCreateManagedWidget("warning_form", formWidgetClass, dialog, 0); +#endif /* HAVE_ATHENA */ + + head = msg; + while (head) + { + char name[20]; + char *s = strchr (head, '\n'); + if (s) *s = 0; + + sprintf (name, "label%d", i++); + +#ifdef HAVE_MOTIF + xmstr = XmStringCreate (head, XmSTRING_DEFAULT_CHARSET); + ac = 0; + XtSetArg (av[ac], XmNlabelString, xmstr); ac++; + label = XmCreateLabelGadget (container, name, av, ac); + XtManageChild (label); + XmStringFree (xmstr); +#elif defined(HAVE_ATHENA) + + label = XtVaCreateManagedWidget (name, labelWidgetClass, + form, + XtNleft, XtChainLeft, + XtNright, XtChainRight, + XtNlabel, head, + (label ? XtNfromVert : XtNtop), + (label ? label : XtChainTop), + 0); + +#endif /* HAVE_ATHENA */ + + if (s) + head = s+1; + else + head = 0; + } + +#ifdef HAVE_MOTIF + + XtManageChild (container); + XtRealizeWidget (dialog); + XtManageChild (dialog); + +#elif defined(HAVE_ATHENA) + + ok = XtVaCreateManagedWidget ("ok", commandWidgetClass, form, + XtNleft, XtChainLeft, + XtNbottom, XtChainBottom, + XtNfromVert, label, + 0); + + XtRealizeWidget (dialog); + XtPopup (dialog, XtGrabNone); +#endif /* HAVE_ATHENA */ + + add_button_callback (ok, warning_dialog_dismiss_cb, (POINTER) dialog); + + free (msg); +} + + /* The main demo-mode command loop. */ -void -demo_mode (saver_info *si) +#if 0 +static Bool +mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks, + XrmRepresentation *type, XrmValue *value, XPointer closure) { - saver_preferences *p = &si->prefs; - si->dbox_up_p = True; - monitor_power_on (si); - raise_window (si, True, False, False); - make_screenhack_dialog (si); - while (si->demo_mode_p) + int i; + for (i = 0; quarks[i]; i++) { - XEvent event; - XtAppNextEvent (si->app, &event); - switch (event.xany.type) - { - case 0: /* synthetic "timeout" event */ - break; - - case ClientMessage: - handle_clientmessage (si, &event, False); - break; - - case CreateNotify: - 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", - blurb(), - (unsigned int) event.xcreatewindow.window, - p->notice_events_timeout); -#endif /* DEBUG_TIMERS */ - } - break; - - case ButtonPress: - case ButtonRelease: - 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; - } + if (bindings[i] == XrmBindTightly) + fprintf (stderr, (i == 0 ? "" : ".")); + else if (bindings[i] == XrmBindLoosely) + fprintf (stderr, "*"); + else + fprintf (stderr, " ??? "); + fprintf(stderr, "%s", XrmQuarkToString (quarks[i])); } - 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; + fprintf (stderr, ": %s\n", (char *) value->addr); + + return False; } +#endif + static void -demo_mode_hack (saver_info *si, char *hack) +the_network_is_not_the_computer (WIDGET parent) +{ + Display *dpy = widget_display (parent); + char *rversion, *ruser, *rhost; + char *luser, *lhost; + char *msg = 0; + struct passwd *p = getpwuid (getuid ()); + const char *d = DisplayString (dpy); + +# if defined(HAVE_UNAME) + struct utsname uts; + if (uname (&uts) < 0) + lhost = ""; + else + lhost = uts.nodename; +# elif defined(VMS) + strcpy (lhost, getenv("SYS$NODE")); +# else /* !HAVE_UNAME && !VMS */ + strcat (lhost, ""); +# endif /* !HAVE_UNAME && !VMS */ + + if (p && p->pw_name) + luser = p->pw_name; + else + luser = "???"; + + server_xscreensaver_version (dpy, &rversion, &ruser, &rhost); + + /* Make a buffer that's big enough for a number of copies of all the + strings, plus some. */ + msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) + + (ruser ? strlen(ruser) : 0) + + (rhost ? strlen(rhost) : 0) + + strlen(lhost) + + strlen(luser) + + strlen(d) + + 30)); + *msg = 0; + + if (!rversion || !*rversion) + { + sprintf (msg, + "Warning:\n\n" + "xscreensaver doesn't seem to be running on display \"%s\".", + d); + } + else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name)) + { + /* Warn that the two processes are running as different users. + */ + sprintf(msg, + "Warning:\n\n" + "%s is running as user \"%s\" on host \"%s\".\n" + "But the xscreensaver managing display \"%s\"\n" + "is running as user \"%s\" on host \"%s\".\n" + "\n" + "Since they are different users, they won't be reading/writing\n" + "the same ~/.xscreensaver file, so %s isn't\n" + "going to work right.\n" + "\n" + "Either re-run %s as \"%s\", or re-run\n" + "xscreensaver as \"%s\".\n", + progname, luser, lhost, + d, + (ruser ? ruser : "???"), (rhost ? rhost : "???"), + progname, + progname, (ruser ? ruser : "???"), + luser); + } + else if (rhost && *rhost && !!strcmp (rhost, lhost)) + { + /* Warn that the two processes are running on different hosts. + */ + sprintf (msg, + "Warning:\n\n" + "%s is running as user \"%s\" on host \"%s\".\n" + "But the xscreensaver managing display \"%s\"\n" + "is running as user \"%s\" on host \"%s\".\n" + "\n" + "If those two machines don't share a file system (that is,\n" + "if they don't see the same ~%s/.xscreensaver file) then\n" + "%s won't work right.", + progname, luser, lhost, + d, + (ruser ? ruser : "???"), (rhost ? rhost : "???"), + luser, + progname); + } + else if (!!strcmp (rversion, short_version)) + { + /* Warn that the version numbers don't match. + */ + sprintf (msg, + "Warning:\n\n" + "This is %s version %s.\n" + "But the xscreensaver managing display \"%s\"\n" + "is version %s. This could cause problems.", + progname, short_version, + d, + rversion); + } + + + if (*msg) + warning_dialog (parent, msg); + + free (msg); +} + + +/* We use this error handler so that X errors are preceeded by the name + of the program that generated them. + */ +static int +demo_ehandler (Display *dpy, XErrorEvent *error) { - 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(); */ + fprintf (stderr, "\nX error in %s:\n", progname); + if (XmuPrintDefaultErrorMessage (dpy, error, stderr)) + exit (-1); + else + fprintf (stderr, " (nonfatal.)\n"); + return 0; } -static void -demo_mode_done (saver_info *si) + +static char *defaults[] = { +#include "XScreenSaver_ad.h" + 0 +}; + +int +main (int argc, char **argv) { - kill_screenhack (si); - if (si->demo_hack) - unblank_screen (si); - si->demo_mode_p = False; - si->dbox_up_p = False; - si->demo_hack = 0; + XtAppContext app; + prefs_pair Pair, *pair; + saver_preferences P, P2, *p, *p2; + Bool prefs = False; + int i; + Display *dpy; + Widget toplevel_shell; + char *real_progname = argv[0]; + char *s; + + s = strrchr (real_progname, '/'); + if (s) real_progname = s+1; + + p = &P; + p2 = &P2; + pair = &Pair; + pair->a = p; + pair->b = p2; + memset (p, 0, sizeof (*p)); + memset (p2, 0, sizeof (*p2)); + + progname = real_progname; + + /* We must read exactly the same resources as xscreensaver. + That means we must have both the same progclass *and* progname, + at least as far as the resource database is concerned. So, + put "xscreensaver" in argv[0] while initializing Xt. + */ + argv[0] = "xscreensaver"; + progname = argv[0]; + + + toplevel_shell = XtAppInitialize (&app, progclass, 0, 0, &argc, argv, + defaults, 0, 0); + + dpy = XtDisplay (toplevel_shell); + db = XtDatabase (dpy); + XtGetApplicationNameAndClass (dpy, &progname, &progclass); + XSetErrorHandler (demo_ehandler); + + /* Complain about unrecognized command-line arguments. + */ + for (i = 1; i < argc; i++) + { + char *s = argv[i]; + if (s[0] == '-' && s[1] == '-') + s++; + if (!strcmp (s, "-prefs")) + prefs = True; + else + { + fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", + real_progname); + exit (1); + } + } + + short_version = (char *) malloc (5); + memcpy (short_version, screensaver_id + 17, 4); + short_version [4] = 0; + + /* Load the init file, which may end up consulting the X resource database + and the site-wide app-defaults file. Note that at this point, it's + important that `progname' be "xscreensaver", rather than whatever + was in argv[0]. + */ + p->db = db; + load_init_file (p); + *p2 = *p; + + /* Now that Xt has been initialized, and the resources have been read, + we can set our `progname' variable to something more in line with + reality. + */ + progname = real_progname; + + +#ifdef HAVE_ATHENA + global_prefs_kludge = p; /* I hate C so much... */ +#endif /* HAVE_ATHENA */ + +#if 0 + { + XrmName name = { 0 }; + XrmClass class = { 0 }; + int count = 0; + XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper, + (POINTER) &count); + } +#endif + + + XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False); + XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False); + XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False); + XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False); + XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False); + XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False); + XA_SELECT = XInternAtom (dpy, "SELECT", False); + XA_DEMO = XInternAtom (dpy, "DEMO", False); + XA_BLANK = XInternAtom (dpy, "BLANK", False); + XA_LOCK = XInternAtom (dpy, "LOCK", False); + XA_EXIT = XInternAtom (dpy, "EXIT", False); + XA_RESTART = XInternAtom (dpy, "RESTART", False); + + make_demo_dialog (toplevel_shell, pair); + + if (prefs) + { + make_preferences_dialog (pair, toplevel_shell); + pop_preferences_dialog (pair); + } + + the_network_is_not_the_computer (preferences_dialog + ? preferences_dialog + : demo_dialog); + + XtAppMainLoop (app); + + exit (0); }