1 /* demo.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
21 # define HAVE_ATHENA 1
34 /* Only one, please. */
56 # include <pwd.h> /* for getpwuid() */
62 # include <sys/utsname.h> /* for uname() */
63 #endif /* HAVE_UNAME */
67 #include <X11/Intrinsic.h>
68 #include <X11/StringDefs.h>
70 /* We don't actually use any widget internals, but these are included
71 so that gdb will have debug info for the widgets... */
72 #include <X11/IntrinsicP.h>
73 #include <X11/ShellP.h>
77 # include <X11/Xmu/Error.h>
79 # include <Xmu/Error.h>
90 # include <Xm/ToggleB.h>
91 # include <Xm/MessageB.h>
92 # include <Xm/LabelG.h>
93 # include <Xm/RowColumn.h>
95 #elif defined(HAVE_ATHENA)
96 /* Athena demo code contributed by Jon A. Christopher <jac8782@tamu.edu> */
97 /* Copyright 1997, with the same permissions as above. */
98 # include <X11/Shell.h>
99 # include <X11/Xaw/Form.h>
100 # include <X11/Xaw/Box.h>
101 # include <X11/Xaw/List.h>
102 # include <X11/Xaw/Command.h>
103 # include <X11/Xaw/Toggle.h>
104 # include <X11/Xaw/Viewport.h>
105 # include <X11/Xaw/Dialog.h>
106 # include <X11/Xaw/Scrollbar.h>
107 # include <X11/Xaw/Text.h>
109 #elif defined(HAVE_GTK)
110 # include <gtk/gtk.h>
111 extern Display *gdk_display;
112 #endif /* HAVE_ATHENA */
116 #include "resources.h" /* for parse_time() */
117 #include "visual.h" /* for has_writable_cells() */
118 #include "remote.h" /* for xscreensaver_command() */
126 # define WIDGET GtkWidget *
127 # define POINTER gpointer
129 # define WIDGET Widget
130 # define POINTER XtPointer
136 char *progclass = "XScreenSaver";
140 saver_preferences *a, *b;
144 char *blurb (void) { return progname; }
146 static void run_hack (Display *dpy, int n);
149 static saver_preferences *global_prefs_kludge = 0; /* I hate C so much... */
150 #endif /* HAVE_ATHENA */
152 static char *short_version = 0;
155 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
156 Atom XA_SCREENSAVER_TIME, XA_SCREENSAVER_ID, XA_SELECT, XA_DEMO, XA_RESTART;
158 extern void create_demo_dialog (Widget, Visual *, Colormap);
159 extern void create_preferences_dialog (Widget, Visual *, Colormap);
161 extern WIDGET demo_dialog;
162 extern WIDGET label1;
163 extern WIDGET text_line;
164 extern WIDGET text_activate;
165 extern WIDGET demo_form;
166 extern WIDGET demo_list;
170 extern WIDGET restart;
173 extern WIDGET preferences_dialog;
174 extern WIDGET preferences_form;
175 extern WIDGET prefs_done;
176 extern WIDGET prefs_cancel;
177 extern WIDGET timeout_text;
178 extern WIDGET cycle_text;
179 extern WIDGET fade_text;
180 extern WIDGET fade_ticks_text;
181 extern WIDGET lock_timeout_text;
182 extern WIDGET passwd_timeout_text;
183 extern WIDGET verbose_toggle;
184 extern WIDGET install_cmap_toggle;
185 extern WIDGET fade_toggle;
186 extern WIDGET unfade_toggle;
187 extern WIDGET lock_toggle;
192 # define set_toggle_button_state(toggle,state) \
193 XmToggleButtonSetState ((toggle), (state), True)
194 # define set_text_string(text_widget,string) \
195 XmTextSetString ((text_widget), (string))
196 # define add_button_callback(button,cb,arg) \
197 XtAddCallback ((button), XmNactivateCallback, (cb), (arg))
198 # define add_toggle_callback(button,cb,arg) \
199 XtAddCallback ((button), XmNvalueChangedCallback, (cb), (arg))
200 # define add_text_callback add_toggle_callback
201 # define disable_widget(widget) \
202 XtVaSetValues((widget), XtNsensitive, False, 0)
203 # define widget_name(widget) XtName(widget)
204 # define widget_display(widget) XtDisplay(widget)
205 # define widget_screen(widget) XtScreen(widget)
206 # define CB_ARGS(a,b,c) (a,b,c)
208 #elif defined(HAVE_ATHENA)
210 # define set_toggle_button_state(toggle,state) \
211 XtVaSetValues((toggle), XtNstate, (state), 0)
212 # define set_text_string(text_widget,string) \
213 XtVaSetValues ((text_widget), XtNvalue, (string), 0)
214 # define add_button_callback(button,cb,arg) \
215 XtAddCallback ((button), XtNcallback, (cb), (arg))
216 # define add_toggle_callback add_button_callback
217 # define add_text_callback(b,c,a) ERROR!
218 # define disable_widget(widget) \
219 XtVaSetValues((widget), XtNsensitive, False, 0)
220 # define widget_name(widget) XtName(widget)
221 # define widget_display(widget) XtDisplay(widget)
222 # define widget_screen(widget) XtScreen(widget)
223 # define CB_ARGS(a,b,c) (a,b,c)
225 #elif defined(HAVE_GTK)
227 # define set_toggle_button_state(toggle,state) \
228 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(toggle),(state))
229 # define set_text_string(text_widget,string) \
230 gtk_entry_set_text (GTK_ENTRY (text_widget), (string))
231 # define add_button_callback(button,cb,arg) \
232 gtk_signal_connect_object (GTK_OBJECT (button), "clicked", \
233 GTK_SIGNAL_FUNC (cb), (arg))
234 # define add_toggle_callback(button,cb,arg) \
235 gtk_signal_connect_object (GTK_OBJECT (button), "toggled", \
236 GTK_SIGNAL_FUNC (cb), (arg))
237 # define add_text_callback(button,cb,arg) \
238 gtk_signal_connect_object (GTK_OBJECT (button), "activate", \
239 GTK_SIGNAL_FUNC (cb), (arg))
240 # define disable_widget(widget) \
241 gtk_widget_set_sensitive (GTK_WIDGET(widget), FALSE)
242 # define widget_name(widget) gtk_widget_get_name(GTK_WIDGET(widget))
243 # define widget_display(widget) (gdk_display)
244 # define widget_screen(widget) (DefaultScreenOfDisplay(widget_display(widget)))
245 # define CB_ARGS(a,b,c) (b,a)
247 #endif /* HAVE_GTK */
253 get_text_string (WIDGET text_widget)
256 return XmTextGetString (text_widget);
257 #elif defined(HAVE_ATHENA)
259 if (XtIsSubclass(text_widget, textWidgetClass))
260 XtVaGetValues (text_widget, XtNstring, &string, 0);
261 else if (XtIsSubclass(text_widget, dialogWidgetClass))
262 XtVaGetValues (text_widget, XtNvalue, &string, 0);
267 #elif defined(HAVE_GTK)
268 return gtk_entry_get_text (GTK_ENTRY (text_widget));
269 #endif /* HAVE_GTK */
274 get_label_string (WIDGET label_widget)
278 XmString xm_label = 0;
279 XtVaGetValues (label_widget, XmNlabelString, &xm_label, 0);
282 XmStringGetLtoR (xm_label, XmSTRING_DEFAULT_CHARSET, &label);
284 #elif defined(HAVE_ATHENA)
286 XtVaGetValues (label_widget, XtNlabel, &label, 0);
287 return (label ? strdup(label) : 0);
288 #elif defined(HAVE_GTK)
290 gtk_label_get (GTK_LABEL (label_widget), &label);
292 #endif /* HAVE_GTK */
297 set_label_string (WIDGET label_widget, char *string)
300 XmString xm_string = XmStringCreate (string, XmSTRING_DEFAULT_CHARSET);
301 XtVaSetValues (label_widget, XmNlabelString, xm_string, 0);
302 XmStringFree (xm_string);
303 #elif defined(HAVE_ATHENA)
304 XtVaSetValues (label_widget, XtNlabel, string, 0);
305 #elif defined(HAVE_GTK)
306 gtk_label_set_text (GTK_LABEL (label_widget), string);
307 #endif /* HAVE_GTK */
311 /* Given a label widget that has a %s in it, do the printf thing.
312 If the label's string is obviously wrong, complain about resource lossage.
315 format_into_label (WIDGET label, const char *arg)
317 char *text = get_label_string (label);
318 char *buf = (char *) malloc ((text ? strlen(text) : 0) + strlen(arg) + 100);
320 if (!text || !*text || !strcmp (text, widget_name (label)))
321 strcpy (buf, "ERROR: RESOURCES ARE NOT INSTALLED CORRECTLY");
323 sprintf (buf, text, arg);
325 set_label_string (label, buf);
330 # endif /* HAVE_GTK */
334 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
337 ensure_selected_item_visible (WIDGET list)
342 if (XmListGetSelectedPos (list, &pos_list, &pos_count) && pos_count > 0)
347 XmNtopItemPosition, &top,
348 XmNvisibleItemCount, &visible,
350 if (pos_list[0] >= top + visible)
352 int pos = pos_list[0] - visible + 1;
353 if (pos < 0) pos = 0;
354 XmListSetPos (list, pos);
356 else if (pos_list[0] < top)
358 XmListSetPos (list, pos_list[0]);
362 XtFree ((char *) pos_list);
364 #elif defined(HAVE_ATHENA)
365 # ifdef HAVE_XawViewportSetCoordinates
367 int margin = 16; /* should be line height or something. */
370 Dimension list_h = 0, vp_h = 0;
371 Dimension top_margin = 4; /* I don't know where this value comes from */
372 Position vp_x = 0, vp_y = 0, current_y;
374 Widget viewport = XtParent(demo_list);
375 Widget sb = (viewport ? XtNameToWidget(viewport, "*vertical") : 0);
376 float sb_top = 0, sb_size = 0;
377 XawListReturnStruct *current = XawListShowCurrent(demo_list);
378 if (!current || !sb) return;
380 XtVaGetValues(demo_list,
381 XtNnumberStrings, &count,
384 if (count < 2 || list_h < 10) return;
386 XtVaGetValues(viewport, XtNheight, &vp_h, XtNx, &vp_x, XtNy, &vp_y, 0);
387 if (vp_h < 10) return;
389 XtVaGetValues(sb, XtNtopOfThumb, &sb_top, XtNshown, &sb_size, 0);
390 if (sb_size <= 0) return;
392 pos = current->list_index;
393 cratio = ((double) pos) / ((double) count);
394 current_y = (cratio * list_h);
396 if (cratio < sb_top ||
397 cratio > sb_top + sb_size)
400 current_y -= (vp_h - margin - margin);
404 if ((long)current_y >= (long) list_h)
405 current_y = (Position) ((long)list_h - (long)vp_h);
407 if ((long)current_y < (long)top_margin)
408 current_y = (Position)top_margin;
410 XawViewportSetCoordinates (viewport, vp_x, current_y);
412 # endif /* HAVE_XawViewportSetCoordinates */
413 #elif defined(HAVE_GTK)
415 GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (list);
416 GtkViewport *vp = GTK_VIEWPORT (GTK_BIN(scroller)->child);
417 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
420 GtkWidget *selected = 0;
423 gint parent_h, child_y, child_h, children_h, ignore;
424 double ratio_t, ratio_b;
426 GList *slist = list_widget->selection;
427 selected = (slist ? GTK_WIDGET (slist->data) : 0);
431 which = gtk_list_child_position (list_widget, GTK_WIDGET (selected));
433 for (kids = gtk_container_children (GTK_CONTAINER (list_widget));
434 kids; kids = kids->next)
437 adj = gtk_scrolled_window_get_vadjustment (scroller);
439 gdk_window_get_geometry (GTK_WIDGET(vp)->window,
440 &ignore, &ignore, &ignore, &parent_h, &ignore);
441 gdk_window_get_geometry (GTK_WIDGET(selected)->window,
442 &ignore, &child_y, &ignore, &child_h, &ignore);
443 children_h = nkids * child_h;
445 ratio_t = ((double) child_y) / ((double) children_h);
446 ratio_b = ((double) child_y + child_h) / ((double) children_h);
448 if (ratio_t < (adj->value / adj->upper) ||
449 ratio_b > ((adj->value + adj->page_size) / adj->upper))
453 if (ratio_t < (adj->value / adj->upper))
455 double ratio_w = ((double) parent_h) / ((double) children_h);
456 double ratio_l = (ratio_b - ratio_t);
457 target = ((ratio_t - ratio_w + ratio_l) * adj->upper);
459 else /* if (ratio_b > ((adj->value + adj->page_size) / adj->upper))*/
461 target = ratio_t * adj->upper;
464 if (target > adj->upper - adj->page_size)
465 target = adj->upper - adj->page_size;
469 gtk_adjustment_set_value (adj, target);
473 #endif /* HAVE_GTK */
477 /* Callback for the text area:
478 - note the text the user has entered;
479 - change the corresponding element in `screenhacks';
480 - write the .xscreensaver file;
481 - tell the xscreensaver daemon to run that hack.
483 (Note: in GTK, this one has a different arg list than the other callbacks.)
487 text_cb (WIDGET text_widget, POINTER client_data)
488 #else /* !HAVE_GTK */
489 text_cb (WIDGET text_widget, POINTER client_data, POINTER call_data)
490 #endif /* !HAVE_GTK */
492 saver_preferences *p = (saver_preferences *) client_data;
493 char *new_text = get_text_string (text_widget);
494 Display *dpy = widget_display (text_widget);
497 int hack_number = -1; /* 0-based */
500 XawListReturnStruct *current = XawListShowCurrent(demo_list);
501 hack_number = current->list_index;
502 #elif defined(HAVE_MOTIF)
505 if (XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
506 hack_number = pos_list[0] - 1;
508 XtFree ((char *) pos_list);
509 #elif defined(HAVE_GTK)
511 GTK_LIST (GTK_BIN(GTK_BIN(demo_list)->child)->child)->selection;
512 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
515 gtk_list_child_position (
516 GTK_LIST (GTK_BIN(GTK_BIN(demo_list)->child)->child),
517 GTK_WIDGET (selected));
518 #endif /* HAVE_GTK */
520 ensure_selected_item_visible (demo_list);
522 if (hack_number < 0 || hack_number >= p->screenhacks_count)
524 set_text_string (text_widget, "");
527 #else /* !HAVE_GTK */
528 XBell (XtDisplay (text_widget), 0);
529 #endif /* !HAVE_GTK */
533 if (p->screenhacks [hack_number])
534 free (p->screenhacks [hack_number]);
535 p->screenhacks [hack_number] = strdup (new_text);
539 XmListDeselectAllItems (demo_list);
541 XmString xmstr = XmStringCreate (new_text, XmSTRING_DEFAULT_CHARSET);
542 XmListReplaceItemsPos (demo_list, &xmstr, 1, hack_number+1);
543 XmStringFree (xmstr);
545 XmListSelectPos (demo_list, hack_number+1, True);
547 #elif defined(HAVE_ATHENA)
550 Widget vp = XtParent(demo_list);
551 Widget sb = (vp ? XtNameToWidget(vp, "*vertical") : 0);
552 Dimension list_h = 0;
553 Position vp_x = 0, vp_y = 0;
556 XawListUnhighlight (demo_list);
558 XtVaGetValues (vp, XtNx, &vp_x, 0);
559 XtVaGetValues (sb, XtNtopOfThumb, &sb_top, 0);
560 XtVaGetValues (demo_list, XtNheight, &list_h, 0);
561 vp_y = (sb_top * list_h);
562 XtVaSetValues (demo_list,
563 XtNlist, p->screenhacks,
564 XtNnumberStrings, p->screenhacks_count,
566 XawViewportSetCoordinates (vp, vp_x, vp_y);
567 XawListHighlight (demo_list, hack_number);
570 #elif defined(HAVE_GTK)
572 GtkList *list_widget =
573 GTK_LIST (GTK_BIN(GTK_BIN(demo_list)->child)->child);
574 GList *slist = list_widget->selection;
575 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
576 GtkLabel *label = (selected
577 ? GTK_LABEL (GTK_BIN (selected)->child) : 0);
579 gtk_label_get (label, &old_text);
580 save = !!strcmp (new_text, old_text);
582 gtk_label_set_text (label, new_text);
584 #endif /* HAVE_GTK */
587 write_init_file (p, short_version);
590 usleep (500000); /* give the disk time to settle down */
592 run_hack (dpy, hack_number+1);
598 /* Bend over backwards to make hitting Return in the text field do the
601 static void text_enter (Widget w, XEvent *event, String *av, Cardinal *ac)
603 text_cb (w, global_prefs_kludge, 0); /* I hate C so much... */
606 static XtActionsRec actions[] = {{"done", text_enter}
608 static char translations[] = ("<Key>Return: done()\n"
609 "<Key>Linefeed: done()\n"
610 "Ctrl<Key>M: done()\n"
611 "Ctrl<Key>J: done()\n");
612 #endif /* HAVE_ATHENA */
616 /* Helper for the Gtk versions of the Run Next and Run Previous buttons.
619 next_internal (GtkEntry *entry, gboolean next_p)
621 GtkScrolledWindow *scroller = GTK_SCROLLED_WINDOW (demo_list);
622 GtkList *list_widget = GTK_LIST(GTK_BIN(GTK_BIN(scroller)->child)->child);
623 GtkWidget *target = 0;
628 GList *slist = list_widget->selection;
629 target = (slist ? GTK_WIDGET (slist->data) : 0);
631 for (kids = gtk_container_children (GTK_CONTAINER (list_widget));
632 kids; kids = kids->next)
637 n = gtk_list_child_position (GTK_LIST (list_widget), target);
638 n += (next_p ? 1 : -1);
639 if (n >= nkids) n = 0;
640 if (n < 0) n = nkids-1;
647 gtk_list_select_item (GTK_LIST (list_widget), n);
649 ensure_selected_item_visible ((WIDGET) scroller);
651 run_hack (widget_display (scroller), n + 1);
654 #endif /* HAVE_GTK */
658 /* Callback for the Run Next button.
661 next_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
664 XawListReturnStruct *current = XawListShowCurrent(demo_list);
666 XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0);
667 if (current->list_index == XAW_LIST_NONE ||
668 current->list_index + 1 >= cnt)
669 current->list_index = 0;
671 current->list_index++;
672 XawListHighlight(demo_list, current->list_index);
674 ensure_selected_item_visible (demo_list);
675 current = XawListShowCurrent(demo_list);
676 XtVaSetValues(text_line, XtNstring, current->string, 0);
678 run_hack (XtDisplay (button), current->list_index + 1);
680 #elif defined(HAVE_MOTIF)
682 saver_preferences *p = (saver_preferences *) client_data;
686 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
689 XmListDeselectAllItems (demo_list); /* LessTif lossage */
690 XmListSelectPos (demo_list, pos, True);
694 pos = pos_list[0] + 1;
695 if (pos > p->screenhacks_count)
697 XmListDeselectAllItems (demo_list); /* LessTif lossage */
698 XmListSelectPos (demo_list, pos, True);
701 ensure_selected_item_visible (demo_list);
702 run_hack (XtDisplay (button), pos);
704 XtFree ((char *) pos_list);
706 #elif defined(HAVE_GTK)
707 next_internal (GTK_ENTRY (text_line), TRUE);
708 #endif /* HAVE_GTK */
712 /* Callback for the Run Previous button.
715 prev_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
718 XawListReturnStruct *current = XawListShowCurrent(demo_list);
720 XtVaGetValues (demo_list, XtNnumberStrings, &cnt, 0);
721 if (current->list_index == XAW_LIST_NONE ||
722 current->list_index <= 0)
723 current->list_index = cnt-1;
725 current->list_index--;
726 XawListHighlight(demo_list, current->list_index);
728 ensure_selected_item_visible (demo_list);
729 current = XawListShowCurrent(demo_list);
730 XtVaSetValues(text_line, XtNstring, current->string, 0);
732 run_hack (XtDisplay (button), current->list_index + 1);
734 #elif defined(HAVE_MOTIF)
736 saver_preferences *p = (saver_preferences *) client_data;
740 if (! XmListGetSelectedPos (demo_list, &pos_list, &pos_count))
742 pos = p->screenhacks_count;
743 XmListDeselectAllItems (demo_list); /* LessTif lossage */
744 XmListSelectPos (demo_list, pos, True);
748 pos = pos_list[0] - 1;
750 pos = p->screenhacks_count;
751 XmListDeselectAllItems (demo_list); /* LessTif lossage */
752 XmListSelectPos (demo_list, pos, True);
755 ensure_selected_item_visible (demo_list);
756 run_hack (XtDisplay (button), pos);
758 XtFree ((char *) pos_list);
760 #elif defined(HAVE_GTK)
761 next_internal (GTK_ENTRY (text_line), FALSE);
762 #endif /* HAVE_GTK */
766 /* Callback run when a list element is double-clicked.
767 (Note: in GTK, this one has a different arg list than the other callbacks.)
771 select_cb (GtkWidget *button, GdkEventButton *event, gpointer client_data)
772 #else /* !HAVE_GTK */
774 select_cb (WIDGET button, POINTER client_data, POINTER call_data)
775 #endif /* !HAVE_GTK */
777 /* saver_preferences *p = (saver_preferences *) client_data; */
780 XawListReturnStruct *item = (XawListReturnStruct*)call_data;
781 XtVaSetValues(text_line, XtNstring, item->string, 0);
782 run_hack (XtDisplay (button), item->list_index + 1);
784 #elif defined(HAVE_MOTIF)
785 XmListCallbackStruct *lcb = (XmListCallbackStruct *) call_data;
788 XmStringGetLtoR (lcb->item, XmSTRING_DEFAULT_CHARSET, &string);
789 set_text_string (text_line, (string ? string : ""));
791 if (lcb->reason == XmCR_DEFAULT_ACTION && string)
792 run_hack (XtDisplay (button), lcb->item_position);
797 #elif defined(HAVE_GTK)
799 gtk_label_get (GTK_LABEL (GTK_BIN(button)->child), &string);
800 set_text_string (text_line, (string ? string : ""));
802 if (event->type == GDK_2BUTTON_PRESS)
804 GtkViewport *vp = GTK_VIEWPORT (GTK_BIN(demo_list)->child);
805 GtkList *lw = GTK_LIST (GTK_BIN(vp)->child);
806 int which = gtk_list_child_position (lw, GTK_WIDGET (button));
807 run_hack (gdk_display, which + 1);
811 #endif /* HAVE_GTK */
815 static void pop_preferences_dialog (prefs_pair *pair);
816 static void make_preferences_dialog (prefs_pair *pair, Widget parent);
818 /* Callback for the Preferences button.
821 preferences_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
823 prefs_pair *pair = (prefs_pair *) client_data;
826 #else /* !HAVE_GTK */
827 Widget parent = button;
830 parent = XtParent(parent);
831 } while (XtParent(parent));
832 #endif /* !HAVE_GTK */
834 if (! preferences_dialog)
835 make_preferences_dialog (pair, parent);
837 pop_preferences_dialog (pair);
841 /* Callback for the Quit button.
844 quit_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
846 /* Save here? Right now we don't need to, because we save every time
847 the text field is edited, or the Preferences OK button is pressed.
853 /* Callback for the (now unused) Restart button.
856 restart_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
858 xscreensaver_command (widget_display (button), XA_RESTART, 0, False);
863 pop_up_dialog_box (WIDGET dialog, WIDGET form)
866 XtRealizeWidget (dialog);
867 XtPopup (dialog, XtGrabNone);
868 #elif defined(HAVE_MOTIF)
869 XtRealizeWidget (form);
870 XtManageChild (form);
871 #endif /* HAVE_MOTIF */
874 gtk_widget_show (dialog);
875 gdk_window_show (GTK_WIDGET (dialog)->window);
876 gdk_window_raise (GTK_WIDGET (dialog)->window);
877 #else /* !HAVE_GTK */
878 XMapRaised (XtDisplay (dialog), XtWindow (dialog));
879 #endif /* !HAVE_GTK */
884 /* Callback for WM_DELETE_WINDOW on the main demo window.
887 destroy (GtkWidget *widget, gpointer data)
892 /* Callback for the "Run" button to the right of the text entry line.
895 select_button_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
897 gtk_signal_emit_by_name (GTK_OBJECT (text_line), "activate");
899 #endif /* HAVE_GTK */
903 make_demo_dialog (Widget toplevel_shell, prefs_pair *pair)
905 saver_preferences *p = pair->a;
906 /* saver_preferences *p2 = pair->b; */
907 Widget parent = toplevel_shell;
908 char **hacks = p->screenhacks;
910 create_demo_dialog (parent,
911 DefaultVisualOfScreen (widget_screen (parent)),
912 DefaultColormapOfScreen (widget_screen (parent)));
915 gtk_window_set_title (GTK_WINDOW (demo_dialog), progclass);
916 gtk_signal_connect (GTK_OBJECT (demo_dialog), "delete_event",
917 GTK_SIGNAL_FUNC (destroy), NULL);
918 gtk_signal_connect (GTK_OBJECT (demo_dialog), "destroy",
919 GTK_SIGNAL_FUNC (destroy), NULL);
920 #endif /* HAVE_GTK */
922 format_into_label (label1, short_version);
923 add_button_callback (next, next_cb, (POINTER) p);
924 add_button_callback (prev, prev_cb, (POINTER) p);
925 add_button_callback (done, quit_cb, (POINTER) p);
927 add_button_callback(restart,restart_cb, (POINTER) p);
928 add_button_callback (edit, preferences_cb, (POINTER) pair);
931 XtAddCallback (demo_list, XmNbrowseSelectionCallback,
932 select_cb, (POINTER) p);
933 XtAddCallback (demo_list, XmNdefaultActionCallback,
934 select_cb, (POINTER) p);
935 XtAddCallback (text_line, XmNactivateCallback, text_cb, (POINTER) p);
938 for (; *hacks; hacks++)
940 XmString xmstr = XmStringCreate (*hacks, XmSTRING_DEFAULT_CHARSET);
941 XmListAddItem (demo_list, xmstr, 0);
942 XmStringFree (xmstr);
945 #elif defined(HAVE_ATHENA)
947 /* Hook up the text line. */
949 XtAppAddActions(XtWidgetToApplicationContext(text_line),
950 actions, XtNumber(actions));
951 XtOverrideTranslations(text_line, XtParseTranslationTable(translations));
954 /* Must realize the widget before populating the list, or the dialog
955 will be as wide as the longest string.
957 XtRealizeWidget (demo_dialog);
959 XtVaSetValues (demo_list,
961 XtNnumberStrings, p->screenhacks_count,
963 XtAddCallback (demo_list, XtNcallback, select_cb, p);
965 /* Now that we've populated the list, make sure that the list is as
966 wide as the dialog itself.
969 Widget viewport = XtParent(demo_list);
970 Widget subform = XtParent(viewport);
971 Widget box = XtNameToWidget(demo_dialog, "*box");
972 Widget label1 = XtNameToWidget(demo_dialog, "*label1");
973 Widget label2 = XtNameToWidget(demo_dialog, "*label2");
974 Dimension x=0, y=0, w=0, h=0, bw=0, w2=0;
975 XtVaGetValues(subform,
976 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
977 XtVaGetValues(box, XtNwidth, &w2, 0);
979 XtResizeWidget(subform, w2, h, bw);
981 /* Why isn't the viewport getting centered? */
982 XtVaGetValues(viewport,
983 XtNx, &x, XtNy, &y, XtNheight, &h, XtNborderWidth, &bw, 0);
984 XtConfigureWidget(viewport, x, y, w2-x-x, h, bw);
986 /* And the text line, too. */
987 XtVaGetValues(text_line,
988 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
989 XtVaGetValues(viewport, XtNwidth, &w2, 0);
991 XtResizeWidget(text_line, w2, h, bw);
993 /* And the labels too. */
994 XtVaGetValues(label1,
995 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
997 XtResizeWidget(label1, w2, h, bw);
999 XtVaGetValues(label2,
1000 XtNwidth, &w, XtNheight, &h, XtNborderWidth, &bw, 0);
1002 XtResizeWidget(label2, w2, h, bw);
1006 #elif defined(HAVE_GTK)
1008 GtkList *list = GTK_LIST(GTK_BIN(GTK_BIN(demo_list)->child)->child);
1010 for (s = hacks; *s; s++)
1012 GtkWidget *line = gtk_list_item_new_with_label (*s);
1013 gtk_container_add (GTK_CONTAINER (list), line);
1014 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1015 GTK_SIGNAL_FUNC (select_cb),
1017 GTK_WIDGET (GTK_BIN(line)->child)->style =
1018 gtk_style_copy (GTK_WIDGET (text_line)->style);
1019 gtk_widget_show (line);
1021 gtk_signal_connect (GTK_OBJECT (text_line), "activate",
1022 GTK_SIGNAL_FUNC (text_cb),
1024 gtk_signal_connect (GTK_OBJECT (text_activate), "clicked",
1025 GTK_SIGNAL_FUNC (select_button_cb),
1028 #endif /* HAVE_GTK */
1030 pop_up_dialog_box(demo_dialog, demo_form);
1033 /* For Athena, have to do this after the dialog is managed. */
1034 ensure_selected_item_visible (demo_list);
1035 #endif /* HAVE_ATHENA */
1039 /* the Preferences dialog
1042 /* Helper for the text fields that contain time specifications:
1043 this parses the text, and does error checking.
1046 hack_time_text (Display *dpy, char *line, Time *store, Bool sec_p)
1051 value = parse_time (line, sec_p, True);
1052 value *= 1000; /* Time measures in microseconds */
1061 /* Callback for text fields that hold a time that default to seconds,
1062 when not fully spelled out. client_data is a Time* where the value goes.
1065 prefs_sec_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
1067 hack_time_text (widget_display (button), get_text_string (button),
1068 (Time *) client_data, True);
1072 /* Callback for text fields that hold a time that default to minutes,
1073 when not fully spelled out. client_data is an Time* where the value goes.
1076 prefs_min_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
1078 hack_time_text (widget_display (button), get_text_string (button),
1079 (Time *) client_data, False);
1083 /* Callback for text fields that hold an integer value.
1084 client_data is an int* where the value goes.
1087 prefs_int_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
1089 char *line = get_text_string (button);
1090 int *store = (int *) client_data;
1095 else if (sscanf (line, "%u%c", &value, &c) != 1)
1098 #else /* !HAVE_GTK */
1099 XBell (XtDisplay (button), 0);
1100 #endif /* !HAVE_GTK */
1106 /* Callback for toggle buttons. client_data is a Bool* where the value goes.
1109 prefs_bool_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data)
1111 Bool *store = (Bool *) client_data;
1113 *store = ((XmToggleButtonCallbackStruct *) call_data)->set;
1114 #elif defined(HAVE_ATHENA)
1115 Boolean state = FALSE;
1116 XtVaGetValues (button, XtNstate, &state, 0);
1118 #elif defined(HAVE_GTK)
1119 *store = GTK_TOGGLE_BUTTON (button)->active;
1120 #endif /* HAVE_GTK */
1124 /* Callback for the Cancel button on the Preferences dialog.
1127 prefs_cancel_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER ignored)
1130 gdk_window_hide (GTK_WIDGET (preferences_dialog)->window);
1131 gtk_widget_show (demo_dialog);
1132 gdk_window_show (GTK_WIDGET (demo_dialog)->window);
1133 gdk_window_raise (GTK_WIDGET (demo_dialog)->window);
1134 #else /* !HAVE_GTK */
1135 XtDestroyWidget (preferences_dialog);
1136 preferences_dialog = 0;
1137 XMapRaised (XtDisplay (demo_dialog), XtWindow (demo_dialog));
1138 #endif /* !HAVE_GTK */
1142 /* Callback for the OK button on the Preferences dialog.
1145 prefs_ok_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data)
1147 prefs_pair *pair = (prefs_pair *) client_data;
1148 saver_preferences *p = pair->a;
1149 saver_preferences *p2 = pair->b;
1151 prefs_cancel_cb CB_ARGS(button, client_data, call_data);
1154 /* Athena doesn't let us put callbacks on these widgets, so run
1155 all the callbacks by hand when OK is pressed. */
1156 prefs_min_cb (timeout_text, (POINTER) &p2->timeout, 0);
1157 prefs_min_cb (cycle_text, (POINTER) &p2->cycle, 0);
1158 prefs_sec_cb (fade_text, (POINTER) &p2->fade_seconds, 0);
1159 prefs_int_cb (fade_ticks_text, (POINTER) &p2->fade_ticks, 0);
1160 prefs_min_cb (lock_timeout_text, (POINTER) &p2->lock_timeout, 0);
1161 prefs_sec_cb (passwd_timeout_text, (POINTER) &p2->passwd_timeout, 0);
1162 #elif defined(HAVE_GTK)
1163 /* Do it again anyway for GTK. */
1164 prefs_min_cb ((POINTER) &p2->timeout, timeout_text);
1165 prefs_min_cb ((POINTER) &p2->cycle, cycle_text);
1166 prefs_sec_cb ((POINTER) &p2->fade_seconds, fade_text);
1167 prefs_int_cb ((POINTER) &p2->fade_ticks, fade_ticks_text);
1168 prefs_min_cb ((POINTER) &p2->lock_timeout, lock_timeout_text);
1169 prefs_sec_cb ((POINTER) &p2->passwd_timeout, passwd_timeout_text);
1170 #endif /* HAVE_GTK */
1172 p->timeout = p2->timeout;
1173 p->cycle = p2->cycle;
1174 p->lock_timeout = p2->lock_timeout;
1175 p->passwd_timeout = p2->passwd_timeout;
1176 p->fade_seconds = p2->fade_seconds;
1177 p->fade_ticks = p2->fade_ticks;
1178 p->verbose_p = p2->verbose_p;
1179 p->install_cmap_p = p2->install_cmap_p;
1180 p->fade_p = p2->fade_p;
1181 p->unfade_p = p2->unfade_p;
1182 p->lock_p = p2->lock_p;
1184 write_init_file (p, short_version);
1190 close_prefs_cb CB_ARGS(WIDGET button, POINTER client_data, POINTER call_data)
1192 prefs_cancel_cb CB_ARGS(button, client_data, call_data);
1194 #endif /* HAVE_GTK */
1198 make_preferences_dialog (prefs_pair *pair, Widget parent)
1200 saver_preferences *p = pair->a;
1201 saver_preferences *p2 = pair->b;
1203 Screen *screen = widget_screen (parent);
1204 Display *dpy = widget_display (parent);
1206 *p2 = *p; /* copy all slots of p into p2. */
1208 create_preferences_dialog (parent,
1209 DefaultVisualOfScreen (screen),
1210 DefaultColormapOfScreen (screen));
1213 gtk_window_set_title (GTK_WINDOW (preferences_dialog), progclass);
1214 gtk_signal_connect (GTK_OBJECT (preferences_dialog), "delete_event",
1215 GTK_SIGNAL_FUNC (close_prefs_cb), NULL);
1216 gtk_signal_connect (GTK_OBJECT (preferences_dialog), "destroy",
1217 GTK_SIGNAL_FUNC (close_prefs_cb), NULL);
1218 #endif /* HAVE_GTK */
1220 add_button_callback (prefs_done, prefs_ok_cb, (POINTER) pair);
1221 add_button_callback (prefs_cancel, prefs_cancel_cb, 0);
1223 #define CB(widget,type,slot) \
1224 add_text_callback ((widget), (type), (POINTER) (slot))
1225 #define CBT(widget,type,slot) \
1226 add_toggle_callback ((widget), (type), (POINTER) (slot))
1229 /* When using Athena widgets, we can't set callbacks for these,
1230 so in that case, we run them by hand when "OK" is pressed. */
1231 CB (timeout_text, prefs_min_cb, &p2->timeout);
1232 CB (cycle_text, prefs_min_cb, &p2->cycle);
1233 CB (fade_text, prefs_sec_cb, &p2->fade_seconds);
1234 CB (fade_ticks_text, prefs_int_cb, &p2->fade_ticks);
1235 CB (lock_timeout_text, prefs_min_cb, &p2->lock_timeout);
1236 CB (passwd_timeout_text, prefs_sec_cb, &p2->passwd_timeout);
1238 #endif /* !HAVE_ATHENA */
1240 CBT (verbose_toggle, prefs_bool_cb, &p2->verbose_p);
1241 CBT (install_cmap_toggle, prefs_bool_cb, &p2->install_cmap_p);
1242 CBT (fade_toggle, prefs_bool_cb, &p2->fade_p);
1243 CBT (unfade_toggle, prefs_bool_cb, &p2->unfade_p);
1244 CBT (lock_toggle, prefs_bool_cb, &p2->lock_p);
1249 Bool found_any_writable_cells = False;
1250 int nscreens = ScreenCount(dpy);
1252 for (i = 0; i < nscreens; i++)
1254 Screen *s = ScreenOfDisplay (dpy, i);
1255 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1257 found_any_writable_cells = True;
1262 if (! found_any_writable_cells) /* fading isn't possible */
1264 disable_widget (fade_text);
1265 disable_widget (fade_ticks_text);
1266 disable_widget (install_cmap_toggle);
1267 disable_widget (fade_toggle);
1268 disable_widget (unfade_toggle);
1274 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
1277 format_time (char *buf, Time time)
1279 int s = time / 1000;
1280 unsigned int h = 0, m = 0;
1291 sprintf (buf, "%u:%02u:%02u", h, m, s);
1296 pop_preferences_dialog (prefs_pair *pair)
1298 /* saver_preferences *p = pair->a; */
1299 saver_preferences *p2 = pair->b;
1302 format_time (s, p2->timeout); set_text_string(timeout_text, s);
1303 format_time (s, p2->cycle); set_text_string(cycle_text, s);
1304 format_time (s, p2->lock_timeout); set_text_string(lock_timeout_text, s);
1305 format_time (s, p2->passwd_timeout); set_text_string(passwd_timeout_text, s);
1306 format_time (s, p2->fade_seconds); set_text_string(fade_text, s);
1307 sprintf (s, "%u", p2->fade_ticks); set_text_string(fade_ticks_text, s);
1309 set_toggle_button_state (verbose_toggle, p2->verbose_p);
1310 set_toggle_button_state (install_cmap_toggle, p2->install_cmap_p);
1311 set_toggle_button_state (fade_toggle, p2->fade_p);
1312 set_toggle_button_state (unfade_toggle, p2->unfade_p);
1313 set_toggle_button_state (lock_toggle, p2->lock_p);
1315 pop_up_dialog_box (preferences_dialog, preferences_form);
1320 run_hack (Display *dpy, int n)
1322 if (n <= 0) abort();
1323 xscreensaver_command (dpy, XA_DEMO, n, False);
1328 warning_dialog_dismiss_cb CB_ARGS(WIDGET button, POINTER client_data,
1331 WIDGET shell = (WIDGET) client_data;
1333 gdk_window_hide (GTK_WIDGET (shell)->window);
1334 #else /* !HAVE_GTK */
1335 XtDestroyWidget (shell);
1336 #endif /* !HAVE_GTK */
1341 warning_dialog (WIDGET parent, const char *message)
1343 char *msg = strdup (message);
1360 dialog = XmCreateWarningDialog (parent, "versionWarning", av, ac);
1362 w = XmMessageBoxGetChild (dialog, XmDIALOG_MESSAGE_LABEL);
1363 if (w) XtUnmanageChild (w);
1364 w = XmMessageBoxGetChild (dialog, XmDIALOG_CANCEL_BUTTON);
1365 if (w) XtUnmanageChild (w);
1366 w = XmMessageBoxGetChild (dialog, XmDIALOG_HELP_BUTTON);
1367 if (w) XtUnmanageChild (w);
1369 ok = XmMessageBoxGetChild (dialog, XmDIALOG_OK_BUTTON);
1372 XtSetArg (av[ac], XmNnumColumns, 1); ac++;
1373 XtSetArg (av[ac], XmNorientation, XmVERTICAL); ac++;
1374 XtSetArg (av[ac], XmNpacking, XmPACK_COLUMN); ac++;
1375 XtSetArg (av[ac], XmNrowColumnType, XmWORK_AREA); ac++;
1376 XtSetArg (av[ac], XmNspacing, 0); ac++;
1377 container = XmCreateRowColumn (dialog, "container", av, ac);
1379 #elif defined(HAVE_ATHENA)
1382 dialog = XtVaCreatePopupShell("warning_dialog", transientShellWidgetClass,
1384 form = XtVaCreateManagedWidget("warning_form", formWidgetClass, dialog, 0);
1386 #elif defined(HAVE_GTK)
1387 dialog = gtk_dialog_new ();
1388 #endif /* HAVE_GTK */
1394 char *s = strchr (head, '\n');
1397 sprintf (name, "label%d", i++);
1400 xmstr = XmStringCreate (head, XmSTRING_DEFAULT_CHARSET);
1402 XtSetArg (av[ac], XmNlabelString, xmstr); ac++;
1403 label = XmCreateLabelGadget (container, name, av, ac);
1404 XtManageChild (label);
1405 XmStringFree (xmstr);
1406 #elif defined(HAVE_ATHENA)
1408 label = XtVaCreateManagedWidget (name, labelWidgetClass,
1410 XtNleft, XtChainLeft,
1411 XtNright, XtChainRight,
1413 (label ? XtNfromVert : XtNtop),
1414 (label ? label : XtChainTop),
1417 #elif defined(HAVE_GTK)
1420 label = gtk_label_new (head);
1421 sprintf (buf, "warning_dialog.%s.font", name);
1422 GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
1423 GTK_WIDGET (label)->style->font =
1424 gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
1425 /* gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5); */
1426 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1427 label, TRUE, TRUE, 0);
1428 gtk_widget_show (label);
1430 #endif /* HAVE_GTK */
1440 XtManageChild (container);
1441 XtRealizeWidget (dialog);
1442 XtManageChild (dialog);
1444 #elif defined(HAVE_ATHENA)
1446 ok = XtVaCreateManagedWidget ("ok", commandWidgetClass, form,
1447 XtNleft, XtChainLeft,
1448 XtNbottom, XtChainBottom,
1452 XtRealizeWidget (dialog);
1453 XtPopup (dialog, XtGrabNone);
1455 #elif defined(HAVE_GTK)
1456 label = gtk_label_new ("");
1457 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1458 label, TRUE, TRUE, 0);
1459 gtk_widget_show (label);
1461 label = gtk_hbutton_box_new ();
1462 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
1463 label, TRUE, TRUE, 0);
1465 ok = gtk_button_new_with_label (
1466 get_string_resource ("warning_dialog.ok.label",
1467 "warning_dialog.Button.Label"));
1468 gtk_box_pack_start (GTK_BOX (label), ok, TRUE, FALSE, 0);
1469 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
1470 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
1471 gtk_widget_show (ok);
1472 gtk_widget_show (label);
1473 gtk_widget_show (dialog);
1474 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
1476 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
1477 GTK_WIDGET (preferences_dialog
1478 ? preferences_dialog
1479 : demo_dialog)->window);
1481 gdk_window_show (GTK_WIDGET (dialog)->window);
1482 gdk_window_raise (GTK_WIDGET (dialog)->window);
1483 #endif /* HAVE_GTK */
1485 add_button_callback (ok, warning_dialog_dismiss_cb, (POINTER) dialog);
1492 /* The main demo-mode command loop.
1497 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1498 XrmRepresentation *type, XrmValue *value, XPointer closure)
1501 for (i = 0; quarks[i]; i++)
1503 if (bindings[i] == XrmBindTightly)
1504 fprintf (stderr, (i == 0 ? "" : "."));
1505 else if (bindings[i] == XrmBindLoosely)
1506 fprintf (stderr, "*");
1508 fprintf (stderr, " ??? ");
1509 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1512 fprintf (stderr, ": %s\n", (char *) value->addr);
1520 the_network_is_not_the_computer (WIDGET parent)
1522 Display *dpy = widget_display (parent);
1523 char *rversion, *ruser, *rhost;
1524 char *luser, *lhost;
1526 struct passwd *p = getpwuid (getuid ());
1527 const char *d = DisplayString (dpy);
1529 # if defined(HAVE_UNAME)
1531 if (uname (&uts) < 0)
1532 lhost = "<UNKNOWN>";
1534 lhost = uts.nodename;
1536 strcpy (lhost, getenv("SYS$NODE"));
1537 # else /* !HAVE_UNAME && !VMS */
1538 strcat (lhost, "<UNKNOWN>");
1539 # endif /* !HAVE_UNAME && !VMS */
1541 if (p && p->pw_name)
1546 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1548 /* Make a buffer that's big enough for a number of copies of all the
1549 strings, plus some. */
1550 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1551 (ruser ? strlen(ruser) : 0) +
1552 (rhost ? strlen(rhost) : 0) +
1559 if (!rversion || !*rversion)
1563 "xscreensaver doesn't seem to be running on display \"%s\".",
1566 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1568 /* Warn that the two processes are running as different users.
1572 "%s is running as user \"%s\" on host \"%s\".\n"
1573 "But the xscreensaver managing display \"%s\"\n"
1574 "is running as user \"%s\" on host \"%s\".\n"
1576 "Since they are different users, they won't be reading/writing\n"
1577 "the same ~/.xscreensaver file, so %s isn't\n"
1578 "going to work right.\n"
1580 "Either re-run %s as \"%s\", or re-run\n"
1581 "xscreensaver as \"%s\".\n",
1582 progname, luser, lhost,
1584 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1586 progname, (ruser ? ruser : "???"),
1589 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1591 /* Warn that the two processes are running on different hosts.
1595 "%s is running as user \"%s\" on host \"%s\".\n"
1596 "But the xscreensaver managing display \"%s\"\n"
1597 "is running as user \"%s\" on host \"%s\".\n"
1599 "If those two machines don't share a file system (that is,\n"
1600 "if they don't see the same ~%s/.xscreensaver file) then\n"
1601 "%s won't work right.",
1602 progname, luser, lhost,
1604 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1608 else if (!!strcmp (rversion, short_version))
1610 /* Warn that the version numbers don't match.
1614 "This is %s version %s.\n"
1615 "But the xscreensaver managing display \"%s\"\n"
1616 "is version %s. This could cause problems.",
1617 progname, short_version,
1624 warning_dialog (parent, msg);
1630 /* We use this error handler so that X errors are preceeded by the name
1631 of the program that generated them.
1634 demo_ehandler (Display *dpy, XErrorEvent *error)
1636 fprintf (stderr, "\nX error in %s:\n", progname);
1637 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1640 fprintf (stderr, " (nonfatal.)\n");
1647 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1648 of the program that generated them; and also that we can ignore one
1649 particular bogus error message that Gdk madly spews.
1652 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1653 const gchar *message, gpointer user_data)
1655 /* Ignore the message "Got event for unknown window: 0x...".
1656 Apparently some events are coming in for the xscreensaver window
1657 (presumably reply events related to the ClientMessage) and Gdk
1658 feels the need to complain about them. So, just suppress any
1659 messages that look like that one.
1661 if (strstr (message, "unknown window"))
1664 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1665 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1666 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1667 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1668 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1669 log_level == G_LOG_LEVEL_INFO ? "info" :
1670 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1672 ((!*message || message[strlen(message)-1] != '\n')
1675 #endif /* HAVE_GTK */
1679 static char *defaults[] = {
1680 #include "XScreenSaver_ad.h"
1685 main (int argc, char **argv)
1688 prefs_pair Pair, *pair;
1689 saver_preferences P, P2, *p, *p2;
1693 Widget toplevel_shell;
1694 char *real_progname = argv[0];
1697 s = strrchr (real_progname, '/');
1698 if (s) real_progname = s+1;
1705 memset (p, 0, sizeof (*p));
1706 memset (p2, 0, sizeof (*p2));
1708 progname = real_progname;
1711 /* Register our error message logger for every ``log domain'' known.
1712 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1713 for all of the domains that seem to be in use.
1716 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1717 "GThread", "Gnome", "GnomeUI", 0 };
1718 for (i = 0; domains[i]; i++)
1719 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1722 /* This is gross, but Gtk understands --display and not -display... */
1723 for (i = 1; i < argc; i++)
1724 if (argv[i][0] && argv[i][1] &&
1725 !strncmp(argv[i], "-display", strlen(argv[i])))
1726 argv[i] = "--display";
1728 /* Let Gtk open the X connection, then initialize Xt to use that
1729 same connection. Doctor Frankenstein would be proud. */
1730 gtk_init (&argc, &argv);
1731 #endif /* HAVE_GTK */
1734 /* We must read exactly the same resources as xscreensaver.
1735 That means we must have both the same progclass *and* progname,
1736 at least as far as the resource database is concerned. So,
1737 put "xscreensaver" in argv[0] while initializing Xt.
1739 argv[0] = "xscreensaver";
1744 /* If we're using Gtk, the X connection is already open.
1745 Now teach Xt about it.
1747 XtToolkitInitialize ();
1748 app = XtCreateApplicationContext ();
1750 XtAppSetFallbackResources (app, defaults);
1751 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1752 toplevel_shell = XtAppCreateShell (progname, progclass,
1753 applicationShellWidgetClass,
1756 #else /* !HAVE_GTK */
1757 /* No Gtk -- open the X connection here. */
1758 toplevel_shell = XtAppInitialize (&app, progclass, 0, 0, &argc, argv,
1760 #endif /* !HAVE_GTK */
1762 dpy = XtDisplay (toplevel_shell);
1763 db = XtDatabase (dpy);
1764 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1765 XSetErrorHandler (demo_ehandler);
1767 /* Complain about unrecognized command-line arguments.
1769 for (i = 1; i < argc; i++)
1772 if (s[0] == '-' && s[1] == '-')
1774 if (!strcmp (s, "-prefs"))
1778 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
1784 short_version = (char *) malloc (5);
1785 memcpy (short_version, screensaver_id + 17, 4);
1786 short_version [4] = 0;
1788 /* Load the init file, which may end up consulting the X resource database
1789 and the site-wide app-defaults file. Note that at this point, it's
1790 important that `progname' be "xscreensaver", rather than whatever
1797 /* Now that Xt has been initialized, and the resources have been read,
1798 we can set our `progname' variable to something more in line with
1801 progname = real_progname;
1805 global_prefs_kludge = p; /* I hate C so much... */
1806 #endif /* HAVE_ATHENA */
1810 XrmName name = { 0 };
1811 XrmClass class = { 0 };
1813 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1819 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1820 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1821 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1822 XA_SCREENSAVER_TIME = XInternAtom (dpy, "_SCREENSAVER_TIME", False);
1823 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1824 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1825 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1826 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1827 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1829 make_demo_dialog (toplevel_shell, pair);
1833 make_preferences_dialog (pair, toplevel_shell);
1834 pop_preferences_dialog (pair);
1837 the_network_is_not_the_computer (preferences_dialog
1838 ? preferences_dialog
1843 /* Run the Gtk event loop, and not the Xt event loop. This means that
1844 if there were Xt timers or fds registered, they would never get serviced,
1845 and if there were any Xt widgets, they would never have events delivered.
1846 Fortunately, we're using Gtk for all of the UI, and only initialized
1847 Xt so that we could process the command line and use the X resource
1852 #else /* !HAVE_GTK */
1854 XtAppMainLoop (app);
1856 #endif /* !HAVE_GTK */